Capitalicoでのchainer 1.1→1.5
バージョンアップ事例
J U N - Y A N O R I M A T S U
Engineer
http://alpaca.ai jnory@alpacadb.com
2015/12/19 Chainer Meetup #01
自己紹介
乗松潤矢(Twitter: arrow_elpis, Github: jnory)
Alpaca (Engineer)
フリーランス
博士課程在学中(専門:自然言語処理, 統計翻訳)
今日の肩書
Entry Point
FXチャートにはパターンがある
すべて同一カテゴリの事象
パターン認識で検出したい
プログラミングなしでパターンを発見
Chainerによるモデル学習
入力:為替時系列データ
出力:学習時に指定したパターンっぽさ
今日の発表
弊社環境をChainer 1.5にバージョンアップしました
バージョンアップでハマったところは?
バージョンアップで良くなったところは?
バージョンアップで悪くなったところは?
Chainerバージョンアップはどの程度のタスク?
今日の発表
弊社環境をChainer 1.5にバージョンアップしました
バージョンアップでハマったところは?
バージョンアップで良くなったところは?
バージョンアップで悪くなったところは?
Chainerバージョンアップはどの程度のタスク?
本題の前に…CapitalicoでのChainerバージョンアップのトラウマ
2015年9月2日 Chainer 1.3リリース
弊社環境もバージョンアップを試みるが… v1.1と比較してモデル学習が約1.5倍遅い
バージョンアップ失敗
Chainer 1.3の変更点 CuPyの導入
どうもこれが遅いらしい
バージョンアップで良くなったところ
ボトルネックだったCuPyが高速化
速くなりました!!!
Chainer 1.1 :約22分
Chainer 1.5 :約16分
(ありがとうございます!!!)
弊社サービス上でのモデル学習時間
Training Loss収束の様子
Chainer 1.1 Chainer 1.5
ほぼ同じ学習ができた
反復回数 反復回数
Chainerの速度で気になっていること
Dropoutが全体の12%の時間
Linearより重い…?
モデル学習時のProfileを取った
実行時間に大きな偏りはない
今日の発表
弊社環境をChainer 1.5にバージョンアップしました
バージョンアップでハマったところは?
バージョンアップで良くなったところは?
バージョンアップで悪くなったところは?
Chainerバージョンアップはどの程度のタスク?
バージョンアップで悪くなったところ
一度GPUメモリを確保すると開放されない
学習終了後もプロセスは起動したまま
サーバープログラム内で学習・テスト
メモリ解放したい
幾つかのプロセスがGPUを使用
GPUメモリが開放されないと同時起動プロセス数に影響
用途ごとにプロセスを分離
モデル学習
テスト実行
大量のユーザーに対応できない
CapitalicoはBtoCなサービス
目標:1万人程度が同時アクセス
数千人が同時にモデル学習を走らせても動くようにしたい
[解決策] ちょっとだけChainerを改造
MemoryPoolにこんなコードを追加
(とにかく全部捨てる…という意味)
PRしました
今日の発表
弊社環境をChainer 1.5にバージョンアップしました
バージョンアップでハマったところは?
バージョンアップで良くなったところは?
バージョンアップで悪くなったところは?
Chainerバージョンアップはどの程度のタスク?
バージョンアップでハマったところ
1. インストール
2. FunctionSet → Chain
4. モデルの保存形式をHDF5に変更
5. 過去に学習したモデルを変換
3. その他の非互換を修正
これ
バージョンアップの流れ
バージョンアップでハマったところ
HDF5からの読込:一部のパラメータが読み込まれない
chain.linear = Linear(…, nobias=True)
from chainer.serializers.hdf5 import HDF5Deserializer
group = h5file["chainer"]
serializer = HDF5Deserializer(group)
serializer.load(chain)
モデルファイルにbiasが書かれていても読まれない
今日の発表
弊社環境をChainer 1.5にバージョンアップしました
バージョンアップでハマったところは?
バージョンアップで良くなったところは?
バージョンアップで悪くなったところは?
Chainerバージョンアップはどの程度のタスク?
Chainerバージョンアップはどの程度のタスク?
コード修正:5.5人日
動作検証に要した期間:3人日
修正開始 11/26 本番環境適用 12/11
デプロイ等々:2人日
コード修正量
工数
追加:500行(くらい)
削除:100行
コミット回数:30回
Chainerに期待すること
コミュニティが大きくなってほしいと思います
Numpy非互換部分が少しずつでも減っていくと嬉しいです
CuPyは単体でも十分インパクト大だと思います
モデルフォーマットは今後固定していただけるとありがたい!
ロゴがあると人に紹介するときにより大きいインパクト
まとめ
CapitalicoのChainerをバージョンアップ
学習機能が高速化
メモリ使用効率は悪化
PRしましたm(_ _)m
バージョンアップ作業はそこそこ重いタスク
ハマりどころもそこそこある
おまけ
Chainer 1.5での修正必要箇所一覧
Reference: https://groups.google.com/forum/#!topic/chainer/eXyL11thcNY
インストール
pip install cython==0.23.4
pip install h5py==2.5.0
pip install chainer==1.5.0.2
何のつまづきもなくすんなり
FunctionSet → Chain
何のつまづきもなくすんなり
self.model = FunctionSet(**args)
self.model = Chain(**args)
API互換性有
その他非互換部分
レイヤー内の変数が(Numpy/gpuarrayから)Variableになった
ohlc.W.shape[1]
ohlc.W.data.shape[1]
旧FunctionがFunctionとLinkに分離
import chainer.functions as F
F.Linear(x_size, self.n_units)
import chainer.links as L
L.Linear(x_size, self.n_units)
過去に学習したモデルを変換
Chainer 1.1形式のモデル (pickle)を読み込み1.5の形式(HDF5)で出力
import sys
from chainer.links.connection import linear
sys.modules['chainer.functions.linear'] = linear
パッケージの配置が変わっているのでトリックを入れる
with open(path) as fp:
chain = cPickle.loads(fp.read())
一応読めるようになる
newchain.linear.W.data[...] = model.W[...]
newchain.linear.W.grad[...] = model.gW[...]
newchain.linear.b.data[...] = model.b[...]
newchain.linear.b.grad[...] = model.gb[...]
newchain = Chain(linear=linear.Linear(x, y))
変数の値を淡々とコピー
nobias=Trueのとき不要
モデルの保存形式をHDF5に変更
保存:何のつまづきもなくすんなり
from chainer.serializers.hdf5 import HDF5Serializer
group = h5file.create_group("/chainer”)
serializer = HDF5Serializer(group)
serializer.save(model)
読込:一部のパラメータが読み込まれなくてハマる
model = Linear(…, nobias=True)
from chainer.serializers.hdf5 import HDF5Deserializer
group = h5file["chainer"]
serializer = HDF5Deserializer(group)
serializer.load(model)
ファイルにbiasが書かれていても読まれない
一応の解決策(おそらく非推奨)
chain.linear = Linear(…, nobias=True)
nobias=Trueなレイヤーを無理やりnobias=Falseに書き換える
del chain.linear.b
out_size = chain.linear.W.data.shape[0]
chain.linear.add_param('b', out_size)
from chainer.serializers.hdf5 import HDF5Deserializer
group = h5file["chainer"]
serializer = HDF5Deserializer(group)
serializer.load(chain)
bをリセット
以下の定義は修正不可とする
モデル読み込み
(ここを変えられるならnobiasを取るのが正攻法)

Capitalicoでのchainer 1.1 → 1.5 バージョンアップ事例