Chainerによる畳み込みニューラルネットワークの実装
Chainerによる多層パーセプトロンの実装(2015/10/5)のつづき。今回はChainerで畳み込みニューラルネットワーク(CNN:Convolutional Neural Network)を実装した。Theanoによる畳み込みニューラルネットワークの実装 (1)(2015/6/26)で書いたのと同じ構造をChainerで試しただけ。タスクは前回と同じくMNIST。
今回は、MNISTデータの取得や訓練/テストの分割にscikit-learnの関数を使ってみた。
Chainerで畳み込みをするためには、訓練データの画像セットを(ミニバッチサイズ、チャンネル数、高さ、幅)の4次元テンソルに変換する必要がある(ここに書いてある)。今回はチャンネル数が1なので単純にreshapeで変形できる。
3チャンネルのカラー画像だとnumpyのtranspose()
で4次元テンソルに変換できるみたい。transpose()
は転置行列作るときに使うけどこのnumpyサンプルの3例目によるとndarrayの次元を入れ替えるときにも使えるようだ。あとで物体認識をやるときに確認しよう。
訓練時の誤差とテスト精度を描いてみると下のようになった。エポックが進むにつれて誤差が減り、学習が進んでいることがわかる。テスト精度は多少がたがたするが徐々に向上し、最大で99.3%くらいになる。今回はEarly-Stoppingのような高度な収束判定は使わず、単純に20エポック回しただけなので手を抜いている。GTX760で20エポックの学習に984秒かかった。
学習したモデルはcPickleでファイルにダンプできる。このフォーラムの記事によると学習したモデルをファイルにダンプするときはmodel.to_cpu()
でGPUからCPUに戻した方がよいとのこと。こうしておけばGPUがないマシンでも学習済みモデルを読み込める。
畳み込みニューラルネットは、学習対象の重みがフィルタに当たるので画像として描画できる。試しに学習したモデルの重みを可視化してみよう。下のようなコードで描ける。
ちょっと解釈できない。ガボールフィルタみたいなのができるはずなのだけれど、ランダムだった初期状態からあまり変わらない気もする。もう少しエポック回せばよかったのかな?でも精度は十分上がったしなぁ。もっと別の例でも確認してみよう。