chainerで気軽にスケールできる事前学習器付きニューラルネット生成
のためのコードを書きました。
やりたいこと
1.スケーラブル/コンフィギュラブルなニューラルネット生成
ニューラルネットでは難しい問題を解かせるためには中間層の数を増やす必要があります、
chainerでは普通は↓こんな風にハードコーディングして層を増やしていきますが、
そうではなく、[784,100,100,10]と配列を食わせるだけで、
784次元の入力層、100次元の第一中間層、100次元の第二中間層、10次元の出力層という風にネットを生成し気軽に層数、次元数を変えながら解析が進められるようにします。
2.事前学習できること
中間層数を増やしていくと、バックプロパゲーションにおいて計算される勾配が入力側に近づくにつれて消えていく…ことにより学習が進まなくなる問題(勾配消失問題)があります。
これを解消するのが各層ごとの事前学習です。
事前学習には各層ごとに自己符号化器(オートエンコーダ)として計算して初期値を決めるやり方と、
制約付きボルツマンマシンとして初期値を決めるやり方の二つがあります。
後者は良く分かっていないので前者は簡単そうなので作ってみます、、
ここで、自己符号化器にはエンコーダとデコーダの重みが独立しているもの(united)と、デコーダの重みがエンコーダの転置行列であるもの(tied weight)ありますが、Bengio先生の論文(http://arxiv.org/pdf/1206.5538.pdf)では後者が使われているので、そのようにしました。
(でも、手元の深層学習(機械学習プロフェッショナルシリーズ)には特にtied weightであるかは明記されていません。どっちがいいのかしら?)
使い方
インストール:
$ pip install PreTrainingChain
でインストールできます。
PreTrainingChain.AbstractChain.AbstractChainをimportして継承してください。
MNISTでの使用例はExample.pyにあります。
$ python Example.py
で走ります。
編集
AbstractChainの中でオーバーライドが必要な関数
loss_function:損失関数
add_last_layer:最終層のリンク
最終層は事前学習されません。
全体の学習であるlearnとoptimizerを定義するset_optimizerは必要に応じてオーバーライドしてください。
実行
Example.pyではAbstractChainを継承したPreTrainingDNN(n_units)によってインスタンシエートしています。
n_unitsはリストで、例えばn_units=[784,400,300,150,100,10]とします。
これだけでn_units[0]が入力層(例えばMNISTなら28*28=784)、n_units[-1]が出力層(MNISTなら10種類の分類なので10)、残りが中間層の次元数となるニューラルネットが生成されます。楽チンですね。
AbstractChain.pre_trainingを呼ぶことにより、pre_trainingを実行します。
AbstractChain.learnを呼ぶことにより、全層としての学習を行います。
こんな感じで叩きます↓
実装の中身
学習方式管理
各層の学習方式を事前学習中とそうでない時とで切り替える必要があるので、
SingletonのPT_Managerクラスでフラグ管理します。
(※追記、今にして思うと事前学習にて学習済の重みWをinitialWとして改めてF.Linearを呼び出すほうがシンプルで正解な気がしています。ここでやってるフラグでforwardの動きを変えるのはトリッキーな気が。あまりまねして欲しくない感じです。)
事前学習器付きLinear(PT_Linear)
chainer.functions.Linearの子クラスです。
forwardはPT_Manager().is_pre_training == Trueの時はエンコード結果をデコードしたものであるWT(W*x+b)+b2を出力し、そうでないときはエンコード結果W*x+bを出力します。ここでWTはWの転置行列です。
backwardの振る舞いもPT_Manager().is_pre_trainingで切り替えます。(Falseなら通常のLinear、Trueならtied weirht自己符号化器としてのバックプロパゲーション)
tied weightな自己符号化器は↓こちらを参考にしてPreTrainableLinear実装しました。
これがまた何気にややこしい…
Chainerでtied weightなAutoencoderを作った - Qiita
実装の詳細はこちら↓
結果
MNISTだと同じサンプル数ならネットは浅めのほうが正解率は出ますが、
あえて深めにして事前学習の効果を見ています。
中間層:3 [784,400,300,150,10] | 中間層:4 [784,400,300,150,100,10] | |
---|---|---|
事前学習あり(サンプル5000) | 81.2% | 73.0% |
事前学習なし | 78.5% | 69.5% |
んー…事前学習で正解率は上がってるけど微妙ですね。
でも実行するとCPUがほのかに暖かくなるので寒い冬の夜におすすめ。
おまけ
ぼくが考えた最強のニューラルネット
暖を取るには最適(筆者環境)。
それではみなさまよいお年をー