つまりなにしたの
Chainerの抽象度を飛躍的に高めたTrainerにはextensionsがある。
せっかくだからextensionsを全部使ってみた。
2017年11月10日 追記
Extensionを自分で作ってみました。
ensekitt.hatenablog.com
背景
最近やっとChainerのバージョンを上げました。
qiita.com
を読んで、すごい勢いで僕のソースコードも抽象化したわけですが、
僕はまだまだextensionsの素敵機能を素敵に使いこなせてない!
というわけで、勤労感謝の日にChainerの勤労(Training)に感謝してextensionsを全部試した。
Trainer extensions
dump_graph
概要
グラフをDOT Languageで描画してくれる
使い方
trainer.extend(extensions.dump_graph(root_name="main/loss", out_name="cg.dot"))
使った結果
cg.dotがResultディレクトリに出力される。
Cg.dotの使い方
sudo apt install graphviz
今は論文に埋め込むわけではないので、Dotファイルをpng形式に変換したい
dot -Tpng cg.dot -o cg.png dot -Tフォーマット dotファイル -o 出力ファイル名
こんな感じになる
まとめ
これを自動的にpngまで変換してウェブから参照できるようにするもよし、プレゼン資料や論文に載せるのに使うもよしです。
Evaluator
概要
Training中でも評価することができる。
使った結果
このあと紹介するLogReportと合わせて使うと、テスト結果がLogに現れる。
可視化するとこんな感じ。
まとめ
テストしながら見る必要がある。
Exponential Shift
概要
最適化のパラメータを指数関数的に変更することができる
使い方
trainer.extend(extensions.ExponentialShift("alpha", 1.000001))
ここではAdamを使っているため学習率を左右するαを指数関数的に変更してみている。
使った結果
ExponentialShiftなし
ExponentialShiftあり(1)
trainer.extend(extensions.ExponentialShift("alpha", 1.000001))
ExponentialShiftあり(2)
trainer.extend(extensions.ExponentialShift("alpha", 1.0001))
※事故です。
Adamのざっくりした仕組みが「あんまり触ってない変数いじって局所に落ちないようにしよう!」
なので、学習率が指数関数的に急増すると落ちる方に引っ張られるんじゃないかと思ってる。
学習率を下げる方向にすればよかった。
まとめ
指数関数的に変化するので扱いは難しそう。
使い方の例に出せる論文が見つかったら追記する。いい感じ例をご存じの方はコメントを頂けるとうれしいです。
LinearShift
概要
オプティマイザのパラメータを線形に変更させることができる
使い方
trainer.extend(extensions.LinearShift("alpha", (0.01,0.001), (20000,30000)))
attr:対象とするパタメータ、 value_range:変更幅、time_range:変更するiterationレンジ
ここではAdamを使っているため学習率を左右するαを指数関数的に変更してみている。
使った結果
LinearShiftなし
LinearShiftあり(1)
trainer.extend(extensions.LinearShift("alpha", (0.001,0.0001), (20000,30000)))
LinearShiftあり(2)
trainer.extend(extensions.LinearShift("alpha", (0.01,0.001), (20000,30000)))
まとめ
序盤は荒く、終盤は細かくといったことを実現するときとか逆にオーバーフィットし始めるあたりからパラメータを調整するなどもできそう。
LogReport
概要
trainerの途中経過をログファイルに蓄積する。
使い方
trainer.extend(extensions.LogReport(logname="log", trigger=(1, 'epoch')))
trigger=(1, 'epoch’)なら1epochごとに出力される。
trigger=(1, 'iteration’)なら1iterationごとに出力される。
使った結果
表示はされないが、
./result/log
にJSON形式でログが出力される。
中身はこんな感じ。
[ { "elapsed_time": 1.9452495574951172, "epoch": 1, "main/accuracy": 0.9067500013237199, "main/loss": 0.33314116835594176, "iteration": 600 }, ]
snapshot
概要
trainerをTriggerに応じてスナップショットする
使い方
trainer.extend(extensions.snapshot())
使った結果
./result/の中に
snapshot_iter_12000 snapshot_iter_18600 snapshot_iter_25200 snapshot_iter_31800 snapshot_iter_38400 snapshot_iter_45000 snapshot_iter_51600 snapshot_iter_58200 snapshot_iter_12600 snapshot_iter_19200 snapshot_iter_25800 snapshot_iter_32400 snapshot_iter_39000 snapshot_iter_45600 snapshot_iter_52200 snapshot_iter_58800
こんなのが出てくる。これらは特に指定しなければsave_npzが使われるため、
serializers.load_npz('./result/snapshot_iter_50000', trainer)
で呼び出して
trainer.run()
を実行すると
epoch main/loss main/accuracy elapsed_time 68 0.000235376 1 163.02 69 0.00452771 0.998514 165.511 70 0.00306396 0.999117 167.919 71 0.00277979 0.9992 170.311
こんな感じで途中のepochから始める。
まとめ
中断しても途中からスタートできるのでめちゃくちゃ時間がかかるときなどはやっておいたほうが安心。
snapshot_object
概要
指定したオブジェクト(optimizerとかmodel)をTriggerに応じてスナップショットする
使い方
trainer.extend(extensions.snapshot_object(optimizer, 'optimizer_snapshot_{.updater.epoch}', trigger=(10,'epoch')))
optimizerを10 epochごとに’optimizer_snapshot_{エポック数}の名前でスナップショットすることができる。
使った結果
./result/に
optimizer_snapshot_10 optimizer_snapshot_20 optimizer_snapshot_40 optimizer_snapshot_60 optimizer_snapshot_80 optimizer_snapshot_100 optimizer_snapshot_30 optimizer_snapshot_50 optimizer_snapshot_70 optimizer_snapshot_90
こんなのが出てくる。これらは特に指定しなければsave_npzが使われるため、
serializers.load_npz('./result/optimizer_snapshot_50', optimizer)
で呼び出して
trainer.run()
を実行すると保存したoptimizerが使われる。
まとめ
ここではoptimizerなのであんまり意味はないけれども、trainerとは別に動く物があればそれを保存しておけるので便利そう。
PrintReport
概要
LogReportの中身を出力する。
使い方
trainer.extend(extensions.LogReport() trainer.extend(extensions.PrintReport( entries=['epoch', 'main/loss', 'main/accuracy', 'elapsed_time' ]))
entriesにLogReportで出力される項目の名前を入れる。
使った結果
epoch main/loss main/accuracy elapsed_time 1 0.334851 0.904833 1.94594 2 0.13853 0.959233 3.97545 3 0.0977319 0.97095 6.07704 4 0.0765065 0.97635 8.14663 5 0.0601246 0.9816 10.2338
まとめ
進み具合がすぐに分かるので序盤でミスに気づくことができるし結果を待っている側としては心に優しい。
ProgressBar
概要
進捗どうですか?にChainerが答えてくれる。
使い方
trainer.extend(extensions.ProgressBar())
使った結果
total [*..............................................] 8.50% this epoch [*.........................] 50.00% 5100 iter, 8 epoch / 100 epochs 292.74 iters/sec. Estimated time to finish: 0:03:07.535695.
まとめ
進んでいる感じがするのでとても心に優しい。
今回書いたコード
さいごに
勤労に感謝してたら勤労感謝の日が終わっていた。