ふかふかブログ

興味のあることについてゆる~く書きます

golang.tokyo #26 に参加してきた

本日(寝るまでが今日)2019/09/25、golang.tokyo #26にブログ枠で参加させていただいたので珍しく参加レポートを書きます。

golangtokyo.connpass.com

参加まで

私自身golangはほぼ経験がなく、またgolang.tokyoといえばいつも人気殺到で参加できるイメージがなかったので応募すらしていなかったのですが同僚から「ブログ枠なら空いているぞ」という情報を聞きつけ、内容も『スマートホームにおけるGo』ということで普段IoTかじっている私にとってはドンピシャだったので当日の朝急遽参加申し込みをしました。

会場はメルカリ様で、入場してすぐ軽食+ドリンクをいただきました。メルカリ様、スタッフのみなさまありがとうございますm(__)m

(おにぎり一つ食べた後慌てて写真撮る人) f:id:nohararc:20190926004240j:plain

発表の感想

Go in Nature

songmuさんの発表。

Nature社とNature Remoの紹介でした。

Nature Remoは名前だけ聞いたことあるレベルでしたが具体的な機能やアーキテクチャを聞いて興味を持ちました。

お話の中でもありましたがサーバーとNature Remo間の常時接続、基盤側に何かあった場合は再リクエストが一斉にくるので気を遣うという話はインフラエンジニアとしては胃がキュッとしました。。。

Nature Remo用のGo API Clientを作った話

tenntennさんの発表。

tenntennさんが作成されたAPI Clientをデモを交えながら紹介するという発表でした。 会場からtenntennさん宅の家電を操作するという不思議な(?)デモは会場を沸かせていました。

LINE BOT→GAE→自作Clientで柔軟に家電を操作するデモも面白くて、思わずNature Remo miniをその場で購入してしまいました。

Nature社からAPIも公開されているとのことなので興味がある方は読んでみるといいかもしれません。

LTの感想

Raspberry Pi + Go で IoT した話

yaegashiさんの発表。

goはエッジデバイスや組み込みシステムの開発に適しているというお話でした。

Raspberry Pi + Goで利用できるライブラリについても紹介いただいたので機会があれば利用したいと思います。

Goを使ったセンサーデータ収集基盤のお話

takeshinodaさんの発表。

こちらもgoはIoTの開発に便利という話でした。 クロスコンパイル、非同期データ通信制御が簡単、デプロイ簡単というのは確かに便利。 TSでも同じくかけるが、GoはCっぽくかけるのでGoのほうが好きというのは私もすごく同感でした(TSわからないので)。

Build real world data collecting architecture with goroutine & channel

banana_umaiさんの発表。

センサーからのデータを収集する際にpipeline/debouncing/bufferingの処理を行うがGoだとこういう実装でできるというお話でした。

ボリュームがすごくてもっとゆっくりお話し聞きたかったという感想でした。発表資料が公開されたらゆっくり拝見したいと思います。

まとめ

いつも後から発表資料を拝見させていただくのですが、やはり実際に会場で登壇される方のお話を生で聞くというのはいいものだなぁと感じました。上でも書きましたがNature Remo mini購入しましたので早速弄り倒したいと思います。

【Splatoon2】ディープラーニングでイカとタコを見分ける

最近機械学習の勉強をしているので練習として、スプラトゥーン2イカとタコを見分けてみたいと思います。

といってもすでに実践している方がいらしたので、さらに精度を上げる+実際に間違えた画像を表示して少しでもディープラーニングのお気持ちを理解したいと思います。

参考 tkgstrator.work

概要

↑で参考にあげているページから学習データをいただきまして、図の人工知能部分に学習させます。 最終的には、画像を与えるとイカガール・イカボーイ・タコガール・タコボーイの中からどちらに近いか判定ができるようになります。

f:id:nohararc:20190728132127p:plain

結論

テストデータ999枚に対し、989枚正解(99.9%)を達成しました。

コードはこちら github.com

誤った画像について、目視で確認していきます。 f:id:nohararc:20190701004025p:plain

3行2列目の画像はもうすこし頑張ってほしいところですが、その他の画像は人間でも判断がつきにくく、 概ねいい感じに学習できている気がします。

実装

詳細は実行環境は省きます(GCPで構築した記憶があるのですがメモを紛失しました...)。

  • フレームワーク: keras
  • モデル: EfficientNet
  • 学習方法: 転移学習(ファインチューニング)
  • 学習データの水増し: horizontal flip, random erase

おまけ

f:id:nohararc:20190728133020p:plain

【Splatoon2】Discordのbotを作った話

いつも利用させてもらっているBOTの調子が悪かったのでいい機会だと思って作ってみました。

できたもの

f:id:nohararc:20190728002814p:plain

github.com

招待リンク

諸注意: 現在お試し環境で動かしているため、予告なく停止する場合があります なにかあればTwitterまで

discordapp.com

使い方

仲間内でのプライベートマッチで利用することを想定しているため、ブキランダムしか実装していません。

/buki: ランダムで1つブキを返す
/bukia: ボイスチャンネルに参加している人数分ランダムブキを返す

自分でBOTを作りたい場合

以下のリポジトリからとってきて、my token goes hereを書き換える github.com

参考リンク

Pythonで実用Discord Bot(discordpy解説) - Qiita

Welcome to discord.py — discord.py 1.3.0a documentation

node-redからzabbixにデータを飛ばす

node-redで取得した値をzabbixに飛ばすメモ。

node-red初めて触ったのでおかしいところあればこっそり教えてください。

方針

すぐ思いつくのは以下の二つだと思います。

  1. node-redからcsv等でログを吐いて、zabbix-agentを使ってアクティブチェックで値を送り付ける
  2. node-redから直接zabbixに値を送り付ける(zabbix_senderのような感じ)

今回は2番目の node-redから直接zabbixに値を送り付ける を実装してみます。

実装した後気づいたのですが、すでにnpmのパッケージとして存在しているようです(未検証)

環境

公式のdockerコンテナを利用

Zabbix: 4.2.4
node-red: 0.20.6

準備

  1. node-redを準備します

    docker run -it -p 1880:1880 --name mynodered nodered/node-red-docker

  2. zabbixサーバーを用意します

    docker run --name some-zabbix-appliance -p 80:80 -p 10051:10051 -d zabbix/zabbix-appliance

  3. zabbixサーバー側にアイテムを登録します

    f:id:nohararc:20190703002913p:plain
    item

    zabbix_sender使う時と同じですが、TypeをZabbix trapperとしているところだけ注意

node-red側の実装

全体図

f:id:nohararc:20190703003202p:plain
node-red全体図

  1. 入力部 Injectノードのペイロードに以下のjsonを記入

    複数の値を飛ばしたい場合は、data配列の中に追加すればよい

     {
         "request": "sender data",
         "data": [
             {
                 "host": "Zabbix server",
                 "key": "node-red",
                 "value": 20
             }
         ]
     }
    
  2. 関数部 functionノードのコード部分に以下を追加

     var payload = new Buffer(JSON.stringify(msg.payload), 'utf8'),
           header  = new Buffer(5 + 4); // ZBXD\1 + packed payload.length
    
     header.write('ZBXD\x01');
     header.writeInt32LE(payload.length, 5);
     msg.payload = Buffer.concat([header, new Buffer('\x00\x00\x00\x00'), payload]);
    
     return msg;
    
  3. 出力部 zabbixの待ち受けポート(デフォルトは10051)にtcpでデータを送り付ける

     ホスト: zabbixサーバーのIP
     種類:  接続
     ポート: 10051
     メッセージを送信するたびに接続を切断: チェック
    

完成

(Injectノードで値を色々変えてます)

f:id:nohararc:20190703005141p:plain
グラフ

おまけ

ハマったところ

  • Zabbix公式でheaderのpython実装はPython2
  • headerという単語だけをみてなぜかhttpでつなぎに行ってしまう(ドキュメント読みましょう)

node-redで実装する前に簡単にPython3で実装したなにか

import struct
import telnetlib
import json

data = {"request": "sender data", "data": [{"host":"Zabbix server", "key": "test_zabbix_sender", "value": 100}]}
data_json = json.dumps(data)
header = b"ZBXD\1" + struct.pack("<Q", len(data_json))

packet = header + data_json.encode()

tn = telnetlib.Telnet(host="127.0.0.1", port="10051")
tn.write(packet)
print(tn.read_all().decode())
tn.close()

参考

GitHub - shamil/node-zabbix-sender: A zabbix_sender implementation, to send zabbix item(s) using the zabbix trapper protocol.

node-red-contrib-zabbix-sender (node) - Node-RED

GolangでPythonのrandom.sampleを実現する

最近趣味でPythonしか書いていなかったので、素振りとしてGoを勉強しているのですが

任意のグループからa個選ぶという処理で少し詰まったので忘備として書いておきます。

Pythonのrandom.sampleについて

任意のグループからa個選ぶというもの。

引数として渡されたリストは変更されません。 [1, 2, 3]部分

>>> random.sample([1, 2, 3], 2)
[2, 1]
>>> random.sample([1, 2, 3], 2)
[1, 3]
>>> random.sample([1, 2, 3], 2)
[3, 1]

9.6. random — 擬似乱数を生成する — Python 3.6.5 ドキュメント

golangで実現

こんな感じになると思います。

func randomSample(s []string, num int) []string {
    rand.Seed(time.Now().UnixNano())
    var sample []string
    n := make([]string, len(s))
    copy(n, s)

    for i := 0; i < num; i++ {
        index := rand.Intn(len(n))
        sample = append(sample, n[index])
        n = append(n[:index], n[index+1:]...)
    }
    return sample
}

ポイントとしては、n := make([]string, len(s)) として元のスライスを変更しないようにしています。

go始めたばかりで右も左もよくわかってないのでツッコミあればこっそり教えてください。

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    s := []string{"a", "b", "c", "d"}
    fmt.Println(randomSample(s, 2)) // [a b] or [a c] or ...
    fmt.Println(s)                  // [a b c d]
}

func randomSample(s []string, num int) []string {
    rand.Seed(time.Now().UnixNano())
    var sample []string
    n := make([]string, len(s))
    copy(n, s)

    for i := 0; i < num; i++ {
        index := rand.Intn(len(n))
        sample = append(sample, n[index])
        n = append(n[:index], n[index+1:]...)
    }
    return sample
}

Splatoon2のスケジュールをGoogle カレンダーで確認しよう

---2021/07/07追記---

現在は動かなくなっています。

---追記終わり---

全国1億人のスプラトゥーンプレイヤーの皆さんこんにちは。

上記ツイートの通りですが、ツイートに貼ってあるikalendar.herokuapp.comの内容をみてもピンとこない人向けにGoogle カレンダーで連携する方法を解説したいと思います。

ikalendar.herokuapp.comではクエリを使って自分に必要な情報に絞ることが可能です。

すべて上げるときりがないので本エントリではいくつかのパターンに分けてイメージが付きやすいように画像付きで紹介します。

Google カレンダーへのカレンダー追加方法

画像のURLを追加から、URLを追加します。

追加するURLは取得したい情報によって変わってくるので後述します。

追加したタイミングでは名前がURLのままなので分かりづらいですが設定からカレンダーの名前は変更できます。 f:id:nohararc:20190127160914p:plain

全ルール取得したい

ikalendar.herokuapp.comの通り、

以下のURLを追加する

https://ikalendar.herokuapp.com/ical/all.ics

f:id:nohararc:20190127153339p:plain

ガチマッチの予定をすべて取得したい

以下のURLを追加する

https://ikalendar.herokuapp.com/ical/all.ics?mode=gachi&title_format=%25%7bgachi%3arule%7d%3a%20%25%7bgachi%3amap1%7d%2c%20%25%7bgachi%3amap2%7d

f:id:nohararc:20190127154104p:plain

ガチマッチ&エリアのスケジュールを取得したい

以下のURLを追加する

https://ikalendar.herokuapp.com/ical/all.ics?mode=gachi&rule=splat_zones&title_format=%25%7bgachi%3arule%7d%3a%20%25%7bgachi%3amap1%7d%2c%20%25%7bgachi%3amap2%7d

f:id:nohararc:20190127155744p:plain

特定のルールのスケジュールのみ取得したい

ガチマッチ・リーグマッチの予定2つのカレンダーを追加し同時に追加する

「ガチマッチ&エリアのスケジュールを取得したい」+ 応用で「リグマ&エリア」を追加してやればよい

「リグマ&エリア」のURLを追加し、「ガチマッチ&エリア」のカレンダーと同時表示する

https://ikalendar.herokuapp.com/ical/all.ics?mode=league&rule=splat_zones&title_format=%25%7bleague%3arule%7d%3a%20%25%7bleague%3amap1%7d%2c%20%25%7bleague%3amap2%7d%0d%0a

f:id:nohararc:20190127160436p:plain

ここで紹介していないパラメータとして、description_formatも指定できます。

詳細はikalendar.herokuapp.comを確認ください。

番外編

LINE版

Vim

github.com

Jupyter notebookでもVim scriptが書きたい!

この記事は、Vim Advent Calendar 2018 その2 1日目の記事です。

Vim その2 Advent Calendar 2018 - Qiita

皆さん、Jupyter notebookでVim scriptが書きたくなる時があると思います。

Jupyter notebookはKernelと呼ばれるものを差し替えることでPython以外も動作させることができます。

というわけで、Vim script kernel作ってみました。

動作確認はWindows10でのみ行っていますが、ほかのOSでも動くと思います。

完成図

f:id:nohararc:20181130234158p:plain

実装

json(connection)ファイル

{"argv":["python","-m","vim-kernel", "-f", "{connection_file}"],
 "display_name":"Vim"
}

python(kernel)ファイル

from ipykernel.kernelbase import Kernel
from subprocess import Popen, STDOUT, PIPE


class Vim(Kernel):
    implementation = 'Vim'
    implementation_version = '0.1'
    language = 'no-op'
    language_version = '0.1'
    language_info = {'name': 'Vim', 'mimetype': 'text/plain'}
    banner = 'Vim script'
    _d = {}
    def do_execute(self, code, silent, store_history=True,
             user_expressions=None, allow_stdin=False):

        with open('prog.vim', 'w') as f:
            f.write("\n".join(code.splitlines()))

        p = Popen(['vim', '-X', '-N', '-u', 'NONE', '-i', 'NONE', '-V1', '-e', '-s', '-S', 'prog.vim', '+qall!'], stdout=PIPE, stderr=STDOUT, shell=True)
        p.wait()
        exitcode = p.returncode
        output = p.communicate()[0].decode()
        self.send_response(self.iopub_socket, 'stream', {'name': 'stdout', 'text': output})
        return {'status': 'ok',
                'execution_count': self.execution_count,
                'payload': [],
                'user_expressions': {},
               }

if __name__ == '__main__':
    from ipykernel.kernelapp import IPKernelApp
    IPKernelApp.launch_instance(kernel_class=Vim)

2018/01/08追記

なんとあのmattnさんが改良版を作ってくださいました。

Vim scriptカーネルのインストール方法も詳細に記載されいているので試したい方はこちらを参照ください

Vim script で機械学習 - Qiita

まとめ

意外と簡単にJupyter kernelを作ることができました。

このkernelがVIm script普及拡大の一助となれば幸いです。

以下参考にしたもの

jupyter kernel作り方

Making kernels for Jupyter — jupyter_client 6.0.0.dev documentation

Vim script

Vimスクリプト基礎文法最速マスター - 永遠に未完成

vimのコマンド

$ vim -X -N -u NONE -i NONE -V1 -e -s -S prog.vim +qall!

wandboxから拝借