はじめに
この記事は、MicroAd Advent Calendar 2017の17日目の記事です。
MicroAd システム開発部で、分析に関する開発を行っていますが、分析用のスクリプトをローカルのMacやサーバ側のLinuxで書いていると、機械学習の箇所はpythonで、可視化と○○の箇所はRで書くなどのように、いろんな道具を持ってきて使うことがあり、構成管理がやっかいです(WEBなどを見ていると、機械学習に関する開発はpythonで統一できそうですが・・・)。
機械学習を使った実験
機械学習を使った各種実験の主な目的は、実験の条件を変更した時に、予測モデルの予測性能(や各種指標)がどう変化するのかを調べることです。実験でメインで使うスクリプトが完成したら、条件を引数で変更できるようにしておき、予測性能の変化を調べたり、可視化してグラフを出力したりしています。
ここまでは、ごく当たり前のことだと思います。
引数を処理するライブラリ
実験をチームで行っていく際には、同じスクリプトを共有して使うことと、引数に与えた情報の管理が大事になります。
ここで工夫として、2つの言語で引数処理のスタイルを揃えて、管理の煩雑さを少しでも軽減しようと思います。具体的には、docoptという引数を処理するモジュールが両方の言語に用意されているので、それぞれインストールして使います。
具体例
Rとpythonで具体例をひとつだけ記載します。その他の例は github の example を確認してください。引数を処理する部分の特徴としては、文字列で定義してからdocoptに渡すだけです。この文字列の部分は、Rとpythonで内容を共通化させることが可能です。同一実験であれば、使う引数も共通化できるはずなので、管理が楽になると思います。
#!/usr/bin/env Rscript
"Usage: arguments_example.py [-vqrh] [FILE] ...
arguments_example.py (--left | --right) CORRECTION FILE
Process FILE and optionally apply correction to either left-hand side or
right-hand side.
Arguments:
FILE optional input file
CORRECTION correction angle, needs FILE, --left or --right to be present
Options:
-h --help
-v verbose mode
-q quiet mode
-r make report
--left use left-hand side
--right use right-hand side
" -> doc
suppressPackageStartupMessages(library(docopt))
opts <- docopt(doc)
str(opts)
#!/usr/bin/env python
"""Usage: arguments_example.py [-vqrh] [FILE] ...
arguments_example.py (--left | --right) CORRECTION FILE
Process FILE and optionally apply correction to either left-hand side or
right-hand side.
Arguments:
FILE optional input file
CORRECTION correction angle, needs FILE, --left or --right to be present
Options:
-h --help
-v verbose mode
-q quiet mode
-r make report
--left use left-hand side
--right use right-hand side
"""
from docopt import docopt
if __name__ == '__main__':
arguments = docopt(__doc__)
print(arguments)
Python(githubのexampleとインストール方法)
R言語(インストール方法など)
docopt で使える書式ですが、例えば IEEE Std 1003.2(POSIX.2) specification のような仕様としてある程度定まったものをベースに開発されたようです。これは C APIで昔から使われ続けているもので、linuxのmanでよく目にする書式なので違和感はありません。細かいことはさておき、使う際はまず、github の example を一通り試すのが一番良いと思います。linuxに慣れていれば、すんなり習得出来ると思います(引数をオプショナル扱いにするには[]で囲む、等のルールがあります)。
引数の記録
しっかりとした実験フェーズになれば、実験の結果を後の再現性のために、確実にログを記録すべきで、python/Rに渡ってきた引数をそれぞれのスクリプトの冒頭でloggingするなどの工夫をして、実験の成果物と条件の内容をペアで管理します。また、wiki/スプレッドシート等で実験のシナリオを管理している場合、引数に管理番号のようなものを渡すと、一緒に記録されるので良いと思います。
引数の記録(その2)
最後に試行錯誤している箇所について。しっかりとした実験フェーズに至っていない段階で、開発と実験の中間のような状態で進める作業が結構あります。まだまだチューニングする段階に至っていない、方向性が見えていない段階で行う作業です。機械学習でサイズの大きなデータを扱っていると、1回の実行に要する時間が数時間−1日ぐらいになる事が多いので、開発フェーズで生成した成果物であっても、消さずに残すことがあります(もちろんゴミのようなものは消します)。このあたりは、あまりルールに縛られずにやりたいもので、作業内容が変わるタイミングで毎回試行錯誤を繰り返している気がします。jupyter notebookをうまく利用するのが正解なのか、その他のOSSのツールはないのか・・・色々と難しいです。個人的には、開発中でも、成果物などがその後1ヶ月ぐらいは思い出せる(追跡できる)工夫をshellの側に関数として用意して、ごまかしています。また、shellやipythonの履歴情報を作業フォルダ毎に隔離させるなどの工夫をすると、追跡しやすいです。しかし、もっと良い方法を探しています。
おまけ
Jupyterプロジェクトの Juである、 Julia 言語にもdocoptが用意されていたので使ってみました。
https://github.com/docopt/docopt.jl
しかし、完成度が低く、python/Rで使っている文字列をそのまま渡したらエラーになりました・・・