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 の開発で力つきたのでマークダウンファイルでそのまま行くことにしました。#vimconf2016
— 暗黒美夢王(deoplete dev) (@ShougoMatsu) 2016年11月5日
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
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-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はこれにて終了です。
(直接会って話していても新卒に見られたことが無いので大丈夫だと思います)
vimで折りたたみの状態を保存する方法
vimを使ってそれなりに経つのに、最近になって設定したのでメモ。
vimにはmkview
という、現在の折りたたみの状態を保存するコマンドと、
loadview
という保存した折りたたみ状態を読み込むコマンドがある。
もちろん自分でコマンドを入力するのはめんどくさいので、 ファイルを保存した時と読み込んだ時に勝手にコマンドを実行して欲しい。
ということでautocmd
を使って、勝手に実行してくれるようにするわけだが、
先人が色々なことを考慮した上で mkview
とloadview
を自動呼び出しする設定を
公開してくれている。
細かい説明もリンク先に書いてあるので、自分はリンク先の設定をそのまま以下のようにコピペしただけ。
" 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
こうすることで、それぞれのペットの画像がディレクトリ名の
Abyssinian
やBengal
といったラベルごとに分類されることになる。
次に、分類した画像からCaffeに流し込むためのデータセットを作成する。
下の画像のように、「New Dataset」の「Images」から、「Classification」を選択。
「New Image Classification Dataset」というページに飛んだら、 下図の赤丸の部分を同じように編集する。
編集をしたら、「Create」ボタンをクリック。 クリックしたら別ページに飛んでデータセットが作成され始める。
ダウンロードしたペット画像全部を使っていると ちょっと時間がかかるので少しだけ待つ。 飛ばされたページを定期的に更新すれば、今どれぐらい終わったかがわかる。
終わるまで待ったらデータセットの作成は終了。簡単!
モデルの作成
データセットができたら、それを学習したデータモデルを作成する。
データセットを作成した時の横にある「New Model」から、 同じようにClassificationを選択する。
以下の様な画面が出てくるので、赤丸の部分を同じように設定。 設定が終わったら名前をつけて「Create」をクリック。
クリックすると、また別ページに遷移して学習が始まる。 終わったら学習終了。簡単!
学習結果を試す
モデルデータを作成する時に飛ばされるページの下部に、下図のようなフォームがある。
図中の「Test a single image」の「Upload image」から識別させたい画像を選択して、 「Classify One」をクリック。
クリックすると別ページが開き、学習させたモデルから選択した画像が何に近いのかを、 教えてくれる。
下図だと柴犬ちゃんがしっかり「shiba inu」と認識されている。すごい。
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_TOKEN
をJSONにまとめておきたい場合は、
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。brewでopencvが導入済み。 使用しているエディタはvimで、補完はneocomplete + jedi-vimで行っている、
結論だけ言うと、$PYENV_ROOT/versions/anaconda-*/lib/python2.7/site-packages/
の
cv.py
とcv2.so
を、/usr/local/Cellar/opencv/*/lib/python2.7/site-packages
にある
cv.py
とcv2.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
とかの、width
やheight
のことである。
しかし、カプセル化の概念からすると、直接プロパティをいじれてしまうのは良くない。
そこで、オブジェクト指向プログラミングでは以下のコードのような
アクセサというメソッドとアクセス修飾子を使って、プロパティが
不用意にいじくりまわされるのを防いでいる。以下の例で言うと、
getWidth
やgetHeight
、setWidth
やsetHeight
がアクセサである。
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()); } }
JavaやC++などではこのようにしてプロパティへアクセス制御をしているが、 ただアクセスを制御したいだけなら、確かに冗長な感じはする。
PythonやC#ではプロパティをインスタンス(使う側)からはメンバ変数に見えるが、 クラス(実装)ではコードブロック(メソッド)のようにして制御を行う。
具体的な例を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() ~~~
このようにプロパティを制御することで、クラスの設計者が意図しない値の代入や、 読み出し、不用意なプロパティの削除を防ぐことができる。
デコレータの基本について理解したのでまとめる
Pythonのデコレータに関して、理解していることをまとめてみる。
@
を使ったデコレータの書き方はただのシンタックスシュガー
(読み書きのしやすさのために導入される構文)。
それでは、何に対するシンタックスシュガーなのか。
まず、以下のようなプログラムがあるとする。
def egg(): return "egg" if __name__ == '__main__': print(egg()) # egg
実行すると、当たり前だが以下の様な結果になる。
egg
次に、先ほどのファイルにscramble
というメソッドを追加する。
def scramble(egg): def _scramble(): return "scramble " + egg() + "!" return _scramble def egg(): return "egg" if __name__ == '__main__': scramble_egg = scramble(egg) print(scramble_egg()) # scramble egg!
scramble
メソッドは、オブジェクトを1つ受け取り、内部に定義されている_scramble
メソッドを返している。
つまり、scramble
メソッド自体は引数に対して何かを行うことはなく、
ただ内部のメソッドを返しているだけの機能しか持っていない。
返される内部メソッドの_scramble
は、scramble
メソッドが受け取ったの返り値に、
"scramble "と"!"という文字列を装飾(デコレート)して返している。
if __name__ == '__main__'
では、scramble
メソッドにegg
メソッド渡し、
返り値をscramble_egg
という変数に格納している。
scramble
メソッドの返り値は_scramble
のため、scramble_egg
変数は
_scramble
メソッドの内容と同じ挙動をする。
そのため、ファイルを実行すると以下の様な実行結果になる。
scramble egg!
さて、if __name__ == '__main__'
の中ではscramble
メソッドの返り値はscramble_egg
という変数に格納していた。
ここで、すでに定義されているegg
メソッドにscramble
の返り値を格納してみる。
Pythonはメソッドも変数も全てがオブジェクトのため、こういうことができる。
def scramble(egg): def _scramble(): return "scramble " + egg() + "!" return _scramble def egg(): return "egg" if __name__ == '__main__': egg = scramble(egg) # この部分と print(egg()) # この部分
実行結果は上記と同じscramble egg!
。
egg
に対してscramble
メソッドの返り値を格納しているため、egg
メソッドは
元の「"egg"という文字列を返す」という機能が上書きされている。
しかし、ただ上書きされたわけではなく、scramble
メソッドに元の機能を引数として渡しているため、
「"egg"という文字列を返す」機能は、_scramble
内で使われることになる。
この状態におけるscramble
メソッドがデコレータとなる。
文字通り別のメソッドを装飾することができる。
これまでの手順を@
を使って書き換えると、以下のようなコードになる。
def scramble(egg): def _scramble(): return "scramble " + egg() + "!" return _scramble @scramble def egg(): return "egg" if __name__ == '__main__': print(egg()) # scramble egg!