読者です 読者をやめる 読者になる 読者になる

Go言語LT大会! 「最近、Go言語始めました」の会でLTしました

Go言語LT大会でLTしてきました。

資料です。

見る人が見ればわかっちゃうんですが、Rob Pikeの発表を丸パクリLT用に焼き直して、デザインパターンとか絡めたものです。

もっと詳しく知りたい方は、Concurrency is not Parallelismとか Concurrency is not parallelism - The Go Blogとかを見ると良いと思います。 初めてみたときは結構感動しました。

LT上では時間の関係上スレッドという単語を使っていましたが、正確にはgoroutineはスレッドとは異なるものです。 その辺の説明はWEB+DB PRESS Vol.95とかにわかりやすい説明が載っているので、 詳しく知りたい方は読んでみると良いかもしれません。

最近Go言語の波が来ている気がするのでその波に乗っていきたい所存。 (そしてやっぱり実年齢を言うと驚かれるので、見た目の若々しさを手に入れたい)

VimConf2016行ってきました

VimConf2016に行ってきました。

発表資料のまとめと軽く所感をば書いてみます。

Introduction to Vim 8.0

2016年9月にリリースされたVim8.0の新機能紹介とVimの歴史についてのスライドでした。

Vimのコントリビュータの上位10人に日本人が5人含まれている、という情報が一番驚きでした。 最近上司に、「どうして最近Vimは流行ってるの?」みたいなことを聞かれましたが、 この事が無関係では無い気がします。

Vim as the MAIN text editor

他のエディタからVimに移行したお話。

Vimを使っていると、よく「教えて」と言われるので、質問であったアンチパターンは 他人に教えるときのアンチパターンにしていこうと思います。

Denite.nvim ~The next generation of unite~

https://gist.github.com/Shougo/7c78b3a1725f70c1435d004ed14f2558

Vim界のアイドル兼暗黒美夢王ことShougoさんの発表。

VimのFold機能を利用して、Markdownをスライド代わりにするという発表方法でした。

denite.nvimの簡単な説明、Unite.vimがなぜ遅いのか、denite.nvimはVim8.0で動くのか、おまけ、という構成でした。

個人的注目ポイントは、おまけでShougoさんがおっしゃっていた、既存のShougoさん作のプラグイン (neocomplete, neosnippet, vimfiler, etc...)をDark poweredで書き直す(かも)と言っていたことですかね。

Go、C、Pythonのためのdeoplete.nvimのソースの紹介と、Neovim専用にpure Goでvim-goをスクラッチした話

http://go-talks.appspot.com/github.com/zchee/talks/vimconf2016.slide

個人的に非常に熱かった発表。

内容としてはdeoplete.nvim用に既存の補完ツールを書き換えた、というお話だったのですが、 deoplete-goでDelveの機能を使えるのが最高すぎました。

これでGoをIntelliJで書いてる派の人たちにデバッグのことで胸を張っていけます。 (ちょっと中身を見てみようかと思ってる)

エディタの壁を越えるGoの開発ツールの文化と作成法

Go界隈で有名なtenntennさんの発表。

Goの文化とエディタのプラグイン作成の親和性がテーマでした。

懇親会でも、Shell ScriptのフォーマッタがGoで書かれていたという話をしたので、 Goでプラグインやツールを作る文化ががっつり来ている気がします。

vim-mode-plus for Atom editor

http://qiita.com/t9md/items/0bc7eaff726d099943eb

Atomプラグイン開発者t9mdさんの発表。

vim-mode-plusしゅごい(小並感)。

恥ずかしながらテキストオブジェクトとオペレータの組み合わせ操作を初めて知ったので、 今後はそれらも意識して使って、手癖にしていきたい。

vimの日本語ドキュメント

https://drive.google.com/file/d/0ByQIX4Ls1SHlZ3JtOWxHUUkwaDA/view

Koronさん(kaoriyaさん)の日本語ドキュメント翻訳の話。

https://github.com/vim-jp/vimdoc-ja https://github.com/vim-jp/vimdoc-ja-working

Vim script parser written in Go

https://docs.google.com/presentation/d/1A6_A7XzPoHv_wG5N_R6zbgYKBX2ycii6BCzR-7b-nOw/pub

VimのパーサをGoで書いたお話。 将来的にはフォーマッタのような機能も実装されるそうです。呼び方はvimfmt(ゔぃむふむとぅ)なんですかね?

僕の友達を紹介するよ

https://aiya000.github.io/Maid/my-vim-friends/my-vim-friends#/

vimプラグインの紹介。

気になったのは * vim-alignta * undotree * vim-textobj-indent

aligntaはalignとの比較をしてみて良さそうだったら乗り換えてみようと思います。 vim-textobj-indentは、テキストオブジェクトとセットで覚えていこうかと。

Best practices for building Vim plugins

https://gist.github.com/thinca/785171e327e66c48d2d293690dc2f65a

Vimプラグインを作る時に気をつけてほしいことのまとめ記事でした。 :help desgin-documentedを熟読しようと思います。

全体所感

後半に行くに連れて集中力が下がっていってるのが伝わってしまう

Vimを使い始めて3年弱ですが、まだまだVim弱者なので、得た情報を糧にしていこうと思います。 あとは、会場でもGoを書いている人が多く、VimだけじゃなくてGoの強さも感じました。

とりあえずdeoplete-goが使いたすぎるのでnvim移行を開始します。 zcheeさんと少しお話をして、中身がほぼGoだということも聞いたので、 使いながら中身も見てみようと思います。

Vimmerの集まりに参加するのは初めてだったのですが、非常に濃い内容で楽しかったです。 発表者の方々と会場の準備をしてくださった方々に感謝です。

ブログ書いたので私のVimConf2016はこれにて終了です。

(直接会って話していても新卒に見られたことが無いので大丈夫だと思います)


VimConf 2016

vimで折りたたみの状態を保存する方法

vimを使ってそれなりに経つのに、最近になって設定したのでメモ。

vimにはmkviewという、現在の折りたたみの状態を保存するコマンドと、 loadviewという保存した折りたたみ状態を読み込むコマンドがある。

もちろん自分でコマンドを入力するのはめんどくさいので、 ファイルを保存した時と読み込んだ時に勝手にコマンドを実行して欲しい。

ということでautocmdを使って、勝手に実行してくれるようにするわけだが、 先人が色々なことを考慮した上で mkviewloadviewを自動呼び出しする設定を 公開してくれている。

Hack #84: バッファの表示設定を保存する

細かい説明もリンク先に書いてあるので、自分はリンク先の設定をそのまま以下のようにコピペしただけ。

" Save fold settings.
autocmd BufWritePost * if expand('%') != '' && &buftype !~ 'nofile' | mkview | endif
autocmd BufRead * if expand('%') != '' && &buftype !~ 'nofile' | silent loadview | endif
" Don't save options.
set viewoptions-=options

1つ躓いたところとして、Go言語を開いて保存したときには、その時点での折りたたみが保存されずに 全て折りたたまれる、という現象が起きた。

少し探ってみると、vim-goの設定で、保存時に自動でfmtをかける機能がONなのが原因だった。

ということで、vim-goの設定の一部を以下のように変更して、Fmtコマンドを自動で行ってくれる設定を追加した。

" Not working
" let g:go_fmt_autosave = 1
let g:go_fmt_autosave = 0
autocm BufWritePre *.go silent Fmt

これで大規模なコードをvimで見てもストレスなくコードが書けるように!

機械学習の環境をDIGITSとDockerを使って簡単に整える話

機械学習が何をやっているのか全くわかっていなくても 簡単に画像処理の機械学習を行える環境を整えた話。

この記事の目標は、何もわからなくてもとりあえず画像を機械に学習させる、です。 (細かい部分が全くわからないことの言い訳)

今回は、Digitsという、NVIDIAが作っている Caffeという機械学習ライブラリのWebアプリを使ってみる。 また、めんどくさい導入部分を全部Dockerにやってもらう。

事前準備

  • docker-machine導入済み
  • docker-compose導入済み

docker-machineでdefaultという名前のマシンを作ってある前提で進めます。

docker-machineってなんだよって人は 公式ドキュメントのDocker Machineの項目を 読めばいいと思う。

Digitsが動いているコンテナを立てるまで

以下のdocker-compose.ymlファイルを適当なディレクトリに配置し、 同じ階層でdocker-compose up -dを実行する。以上。

実行が終わったらdocker-machine env defaultコマンドで出てくるIPに ポート5000でアクセスすればWebアプリが動いているのが確認できるはず。

これだけで画像の学習させる環境ができちゃう。便利。

# docker-compose.yml
digits:
  image:
    kaixhin/digits
  ports:
    - "5000:5000"
  volumes:
    - ./images/:/mnt/volumes/images

Docker HubにDigitsのコンテナイメージが あったので、ありがたく使わせて頂いた。

コマンドを実行した時に作られるimagesディレクトリは、 後で学習する画像ファイルを設置する場所になるのでそのままにしておく。 もし作成されてなかったら、imagesディレクトリを作成してから もう一回docker-compose up -d

学習させてみる

とりあえず、右上の「ログイン」ボタンからログインしておく。 出てきたフォームに適当に名前を入れるだけでOK。

データセットの作成

学習させるためには、データセットが必要なのでまずはそれの作成から。

自動で作成されたimagesの中に、学習させたい画像をディレクトリ毎にわけて設置する。 例としてオクスフォード大学で公開されている ペット画像のデータセットを使ってみる。

上記リンク先の「Dataset」から、圧縮されたペット画像をダウンロードして展開。 展開すると、images/ディレクトリとその下に37種類のペットの画像ができるはず。

展開された画像を、以下のようなディレクトリ構造になるように配置する。

ちなみに、全種類の動物を使うと非常に重いので、 お試しの人は、3、4種類ぐらいを配置すればいいと思う。

docker-compose.yml
images
├── Abyssinian
│   ├── Abyssinian_1.jpg
│   ├── Abyssinian_2.jpg
│   ├── Abyssinian_3.jpg
~ ~ ~
│   ├── Abyssinian_197.jpg
│   ├── Abyssinian_198.jpg
│   └── Abyssinian_199.jpg
├── Bengal
│   ├── Bengal_1.jpg
│   ├── Bengal_2.jpg
│   ├── Bengal_3.jpg
~ ~ ~
│   ├── Bengal_197.jpg
│   ├── Bengal_198.jpg
│   └── Bengal_199.jpg

こうすることで、それぞれのペットの画像がディレクトリ名の AbyssinianBengalといったラベルごとに分類されることになる。

次に、分類した画像からCaffeに流し込むためのデータセットを作成する。

下の画像のように、「New Dataset」の「Images」から、「Classification」を選択。

f:id:nametake-1009:20160707010753p:plain

「New Image Classification Dataset」というページに飛んだら、 下図の赤丸の部分を同じように編集する。

f:id:nametake-1009:20160707010759p:plainf:id:nametake-1009:20160707011028p:plain

編集をしたら、「Create」ボタンをクリック。 クリックしたら別ページに飛んでデータセットが作成され始める。

ダウンロードしたペット画像全部を使っていると ちょっと時間がかかるので少しだけ待つ。 飛ばされたページを定期的に更新すれば、今どれぐらい終わったかがわかる。

終わるまで待ったらデータセットの作成は終了。簡単!

モデルの作成

データセットができたら、それを学習したデータモデルを作成する。

データセットを作成した時の横にある「New Model」から、 同じようにClassificationを選択する。

以下の様な画面が出てくるので、赤丸の部分を同じように設定。 設定が終わったら名前をつけて「Create」をクリック。

f:id:nametake-1009:20160707010802p:plain

クリックすると、また別ページに遷移して学習が始まる。 終わったら学習終了。簡単!

学習結果を試す

モデルデータを作成する時に飛ばされるページの下部に、下図のようなフォームがある。

f:id:nametake-1009:20160707010804p:plain

図中の「Test a single image」の「Upload image」から識別させたい画像を選択して、 「Classify One」をクリック。

クリックすると別ページが開き、学習させたモデルから選択した画像が何に近いのかを、 教えてくれる。

下図だと柴犬ちゃんがしっかり「shiba inu」と認識されている。すごい。

f:id:nametake-1009:20160707010809p:plain

DigitsのRest API

なんとDigitsではRest APIが実装されている。

使い方はissueに書いてある通り。

コレを使えば割と簡単に学習結果をアプリケーションに反映させられる。

総括

機械学習の仕組みを全くわからなくても機械学習ができた!

hubotをSlackと連携してデーモン化するまでの手順

Hubotをデーモン化してSlackと連携させた時のメモ。

以下のツールは導入してあること前提。

  • apt
    • nodejs
    • npm
  • npm
    • hubot
    • pm2

hubotとSlackの初期設定

まず、以下のコマンドでhubotを準備。

$ mkdir nametake-bot
$ cd nametake-bot
$ yo hubot
                     _____________________________
                    /                             \
   //\              |      Extracting input for    |
  ////\    _____    |   self-replication process   |
 //////\  /_____\   \                             /
 ======= |[^_/\_]|   /----------------------------
  |   | _|___@@__|__
  +===+/  ///     \_\
   | |_\ /// HUBOT/\\
   |___/\//      /  \\
         \      /   +---+
          \____/    |   |
           | //|    +===+
            \//      |xx|

? Owner: nametake <nametake.kyarabuki@gmail.com>
? Bot name: nametake-bot
? Description: A simple helpful robot for your Company
? Bot adapter: (campfire) slack # ここでSlackをしっかり指定する
? Bot adapter: slack

以下のコマンドで、ちゃんとhubotが動くか確認。

$ ./bin/hubot
~~~
いろいろ出る
~~~
nametake-bot> nametake-bot ping
nametake-bot> PONG

次に、SlackでhubotのConfigure Appsからhubotを連携させる。 連携させた後に、連携させた設定からHUBOT_SLACK_TOKENを取得。

取得したTOKENを元に環境変数を設定。

$ export HUBOT_SLACK_TOKEN="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

環境を設定したらSlackと連携。

$ ./bin/hubot -a slack

Slackで@nametake-bot pingとかやって連携しているか確認。

pm2でhubotをデーモン化

hubotを永続化するためにpm2というnode.js製のツールを使う。

pm2をjsonから起動するために、以下の様なapp.jsonファイルを作成。

{
    "apps":[
        {
            "name"             : "hilbot",
            "args"             : ["-a", "slack"],
            "script"           : "./bin/hubot",
            "exec_mode"        : "fork",
            "exec_interpreter" : "bash",
            "autorestart"      : true,
            "env": {
                "NODE_ENV"           : "production",
                "PORT"               : "8080",
            }
        }
    ]
}

HUBOT_SLACK_TOKENJSONにまとめておきたい場合は、 envの項目を以下のように書き換える。

"env": {
    "NODE_ENV"               : "production",
    "PORT"                   : "8080"
    "HUBOT_SLACK_TOKEN"      : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

以下のコマンドでpm2でhubotをデーモン化。

$ pm2 start app.json

以下のコマンドでちゃんと動いているか確認。

$ pm2 list
┌──────────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name     │ id │ mode │ pid   │ status │ restart │ uptime │ memory      │ watching │
├──────────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ nametake-bot │ 0  │ fork │ 32342 │ online │ 1       │ 4D     │ 79.945 MB   │ disabled │
└──────────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘

statusの欄がerroredになっていたら、pm2 logsというコマンドでログを確認して エラーを修正する。

今回はリモートリポジトリに上げたhubotのソースをSlack上からpullさせたかったので、 ここnew_update.coffeeを 丸々参考にさせて頂きました。

参考サイト

VimでOpenCVのneocompleteの補完が落ちる問題の解決

pyenvのanacondaで、condaで入れたopencvの補完をしようとすると、

Vim: Caught deadly signal SEGV
Vim: Finished.

と出て、落ちる問題の解決方法。

環境はOSX10.10。brewopencvが導入済み。 使用しているエディタはvimで、補完はneocomplete + jedi-vimで行っている、

結論だけ言うと、$PYENV_ROOT/versions/anaconda-*/lib/python2.7/site-packages/cv.pycv2.soを、/usr/local/Cellar/opencv/*/lib/python2.7/site-packagesにある cv.pycv2.soへのシンボリックリンクに置き換えることで解決した。

以下、全体のコマンド

$ cd $PYENV_ROOT/versions/anaconda-*/lib/python2.7/site-packages/
$ mv cv.py cv.py.org    # バックアップ
$ mv cv2.so cv2.so.org  # バックアップ
$ ln -s /usr/local/Cellar/opencv/*/lib/python2.7/site-packages/cv.py $PYENV_ROOT/versions/anaconda-*/lib/python2.7/site-packages/cv.py
$ ln -s /usr/local/Cellar/opencv/*/lib/python2.7/site-packages/cv2.so $PYENV_ROOT/versions/anaconda-*/lib/python2.7/site-packages/cv2.so

ぶっちゃけ原因がわからなかったので教えて偉い人。

プロパティについて理解したのでまとめる

プロパティについて

研究室で質問されたのでPythonのプロパティについて解説しようと思う。

最初にプロパティとはなにかをIT用語辞典で引いていみると、

プロパティとは、オブジェクト指向プログラミングで使用される オブジェクトが保持している、そのオブジェクトの性質を表すデータ。 例えば、画像データのオブジェクトならば、高さや幅などのデータを プロパティとして持っている。

という定義になっている。 つまり、オブジェクト指向プログラミングでクラスのインスタンスから アクセスできるimg.widthとかimg.heightとかの、widthheightのことである。

しかし、カプセル化の概念からすると、直接プロパティをいじれてしまうのは良くない。 そこで、オブジェクト指向プログラミングでは以下のコードのような アクセサというメソッドとアクセス修飾子を使って、プロパティが 不用意にいじくりまわされるのを防いでいる。以下の例で言うと、 getWidthgetHeightsetWidthsetHeightがアクセサである。

class Image {
    private int width;
    private int height;

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }

}

class Spam {
    public static void main(String args[]) {
        Image img = new Image();
        img.setWidth(200);
        img.setHeight(100);
        System.out.println(img.getWidth());
        System.out.println(img.getHeight());
    }
}

JavaC++などではこのようにしてプロパティへアクセス制御をしているが、 ただアクセスを制御したいだけなら、確かに冗長な感じはする。

PythonC#ではプロパティをインスタンス(使う側)からはメンバ変数に見えるが、 クラス(実装)ではコードブロック(メソッド)のようにして制御を行う。

具体的な例をPythonで示してみる。 以下のコードがプロパティを利用してアクセス制御を行っているコードになる。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
class Image(object):
    def __init__(self):
        self._width = 300
        self._height = 400

    @property
    def width(self):
        return self._width

    @width.setter
    def width(self, width):
        self._width = width

    @property
    def height(self):
        return self._height

    @height.setter
    def height(self, height):
        self._height = height

if __name__ == '__main__':
    img = Image()
    img.width = 200
    img.height = 100
    print img.width
    print img.height

クラスのメンバである_width_heightに対し、デコレータを利用してwidthメソッドや heightメソッドをproperty型に一度変換している(デコレータに関しては 前の記事を参照)。

propertyの第一引数がgetterになっているため、property型でデコレートした メソッドでは、そのプロパティが返したい値を返している。 また、Pythonのプロパティはsetterメソッドを持っているため、そのsetterメソッドで メソッドをデコレートすることで、img.width = 200のような形でアクセスできるように なっている。

今回の例では代入と読み出しの両方を行っていたが、例えば、 読み出しは許可するが、代入を禁止したい場合、以下のようにsetterメソッドが 呼び出されたら例外を投げるなどをして、プロパティへのアクセス制御が行える。

class Image(object):
    ~~~
    @width.setter
    def width(self, width):
        raise ValueError()
    ~~~

このようにプロパティを制御することで、クラスの設計者が意図しない値の代入や、 読み出し、不用意なプロパティの削除を防ぐことができる。