雑記chainerエンジョイ勢のためのトラブルシューティング
chainerで遊んでいてつまづいたところのメモ。
インストール編、動作速度編、ランタイムエラー編、動作するけど学習結果がうまくいかないよ編の四つです。
インストール編(Windowsについて)
私がまだWindowsにへばりついているので。
Chainer 1.5のインストールがうまくいかない人への非公式なTips - Qiita
↑基本的にはこの記事の通りにやることで解決しますが、ポイントを挙げるとすれば、
numpy,hdf5.pyはpipではなくインストーラを使う、VC for pythonを入れるだと思います。
hdf5.pyのインストーラ
Obtaining the Latest HDF5 Software
numpyのインストーラ
http://sourceforge.net/projects/numpy/files/latest/download?source=files
VC for python
Download Microsoft Visual C++ Compiler for Python 2.7 from Official Microsoft Download Center
これさえできれば後はpip install chainerできます。
chainer1.6ではインストールは楽にはなるようです。(といってもWindowsの対応予定はないようです。
Windowsは窓から投げ捨てるしかない)
動作速度編
GPUにする、中間層を減らす、は当たり前なので、それ以外で。
・ミニバッチサイズを増やす。(サンプルが多いとき)
・rangeをxrangeに変える(Python2.x系の場合)
私はハマりました。
xrangeのほうが明らかに早いです。
Python3系の人はrangeで構いません。
両バージョンで高速に動作するコードを書きたいならsix.move.rangeを使ってください。
ランタイムエラー編
基本的にはchainerのエラーメッセージどおりですが、よくあるトラブル
・型が違う(InvalidType)
例えばInvalid operation is performed in: SoftmaxCrossEntropy (Forward)というメッセージが出た場合。
分類の誤差損失関数として用いるソフトマックス交差エントロピーはint32型のnumarrayしか受け付けません。numpy.astype(int32)をつかって変換します。
・次元数が違う
Expect: prod(in_types[0].shape[1:]) == in_types[1].shape[1]
Actual: 300 != 301
というメッセージが出ます。
入力データと入力層の次元、教師データの正解と出力層の次元、もしくは途中の接続する中間層同士の次元をあわせます。
例えば5クラスに分ける分類問題の場合は出力層の数は入力データの系列数×5となります。
動作するけど学習結果がおかしいよ編
分類問題の正解率が低すぎる、回帰問題の誤差が大きすぎるとき。
・可視化してみる。
そもそもやっていることが何かが間違っているのかもしれません。
機械学習の難しいところは期待値を設定しづらく、結果が出ていなかったとしても、バグなのか、解こうとする問題が難しすぎるのか切り分けるのに手間がかかることにあると思います。
そこで、自分がおこなっていることが正しいのか、可視化を行います。
一次元データなら
import matplotlib.pyplot
matplotlib.pyplot.plot(np.arange(0, data.size, 1), data)
みたいにしてグラフに出してみます。前処理がまちがっているかもしれません。
結果、重み(の変化)、入力データの可視化、ネットワークの可視化があります。
重みや結果の可視化は↓がものすごく参考になります。
Python - 【機械学習】ディープラーニング フレームワークChainerを試しながら解説してみる。 - Qiita
ネットワークの可視化はlossをbackwordした後、
import chainer.computational_graph as c
g = c.build_computational_graph*1
with open('graph.dot', 'w') as o:
o.write(g.dump())
などとすることによってdotファイルとして出力されます。
・サンプルが少ない場合はミニバッチ数をケチる、もしくはエポック数増やす
・中間層の次元数や層数を変えてみる。思いっきり増やす、減らす。
optimizerをadamからadadeltaに変えてみるとか、もしくはそれらの初期値とか、活性化関数の変更(ReLU、シグモイド)とかは微妙なチューニング程度で高精度を追求するなら試す価値はありますが、ワークしてないモデルがワークするようになることは、私が遊んでる限りではありませんでした。
・前処理をしてみる。
例えばオフセットが大きすぎて、本質的なデータが見えないかもしれません。
(100000,100001,100000)と(100000,99999,100000)の区別をつけるのは大変ですが、
(0,1,0)と(0,-1,0)の区別はつく。だったらすべてのデータからそれ自身の平均値を引いてやることで、変化を見せて学習しやすくなります。
scikit-learnのpreprocessing.scaleが便利です。
・原著論文を読む、書籍に当たる。
学問は基本が大事。
*1:loss,