まんぼう日記

takataka's diary

Theano で Multi Layer Perceptron

昨日の MNIST の Logistic Regression Theano版 - まんぼう日記 のつづき.Logistic Regression のネットワークに隠れ層を追加して多層パーセプトロン(Multi Layer Perceptron, MLP)化します.

 

関連記事:

 

隠れ層を追加する前に… Version 5  プログラムを整理する

まずは,MNIST の Logistic Regression Theano版 - まんぼう日記 の v4 のプログラムを整理することから.Theano の theano.tensor.dmatrix とかを引数としてネットワークの入出力等を記述してる部分と,学習アルゴリズムの theano.function を書いたクラスとをそれぞれ別のソースファイルにします.前者は後でMLPのプログラムでも使い回します.

 

できたソースはこちら: nnet0130.py  logreg_theano0130.py  logreg_mnist0130.py

 

nnet0130 には,後のために sigmoid ニューロンの層とか,rectified linear unit (ReLu) の層とかも書きました.それから,logreg_theano0130 の方は,nnet0130 を使うように書き直すついでに冗長な所を削ってすっきりさせました.mnist0130 の実行のためには,これらの他に MNISTのデータを読み込むPythonプログラム - まんぼう日記 の mnist0117.py も必要です.

 

実験結果は当然昨日と変わらないので省略.

 

ちなみに,nnet0130.py の ReLu の実装は,

Z = T.switch( Y > 0, Y, 0 )
Z = T.maximum( Y, 0 )
Z = Y * ( Y > 0 )

の3通りを試しましたが,実行時間に違いは見られませんでした.

 

隠れ層を追加してMLPにする

上記のようにプログラムを整理したおかげで,ちょちょいっとソースをいじるだけで,隠れ層を追加して多層パーセプトロン化することができます.

 

できたソースはこちら: mlp_2layer0130.py  mlp_3layer0130.py  mnist_mlp0130.py

 

mnist_mlp0130 は,2層3層共通で使えるようにしてあります.あ,そうそう,たかたかみたいに前世紀にニューラルネットの研究してた人の中には,入力層も含めて層の数を数える人もいるかもしれませんが,上記の「2層」ってのは

入力 => 隠れ層(sigmoid or rectified linear)=> 出力層(softmax)

って構造のことです.入力層を数えてません.

 

動作確認できたので,昨日のとか pylearn2 での実験結果と比較してみます.比較対象:

ただし,実験条件に細かい違いがあるので,収束までの学習回数とか誤識別率とか単純に優劣を比較できるわけやないので注意.たとえば,Pylearn2での2層の実験は SGD じゃないとか,SGD での実験でも batchsize とか慣性項の係数違うとか….

 

以下,今回の実験共通の条件:

  • MNIST のデータを使うので,入力次元数 D = 784, 出力 K = 10
  • 学習定数 eta = 0.5, 慣性係数 mu = 0.8, バッチサイズ batchsize = 1000 の慣性項付きSGD
  • マシンは iMac (27-inch, Late 2012),  Intel Core i7 3.4GHz(クアッドコア),メモリ32GB (上記 Pylearn2 での実験と同じマシン)

 

2層での実験

入力から順に素子数 D - H - K の2層MLPで実験.H = 500.

 

(1) 隠れ層素子がシグモイドの場合.

In [2]: %time %run mnist_mlp0130.py
### 2-layer MLP: D = 784 H = 500 K = 10
### training: NL = 50000 NV = 10000 D = 784 K = 10 batchsize = 1000
0 2.41748890423 89.798 89.7
10 0.25457169175 7.062 6.6
20 0.199364248594 5.656 5.89
30 0.176263765219 5.092 5.48
40 0.157833093682 4.574 5.46
50 0.144846770838 4.214 5.24
60 0.143428107046 4.31 5.52
70 0.122799404126 3.494 4.9
80 0.11403989861 3.234 4.78
90 0.109765007161 3.13 4.75
100 0.0989960190161 2.75 4.65
# NT = 10000
100 0.17166778569 2.75 4.65 5.03
CPU times: user 7min 49s, sys: 8.67 s, total: 7min 58s
Wall time: 3min 5s

隠れ層なしの logistic regression よりは誤識別率下がってますが,100 epoch では十分学習が収束してない感じですな.もっと繰り返し回数増やせばええんですが省略.

 

(2) 隠れ層素子がReLuの場合.

In [4]: %time %run mnist_mlp0130.py     ReLu
### 2-layer MLP: D = 784 H = 500 K = 10
### training: NL = 50000 NV = 10000 D = 784 K = 10 batchsize = 1000
0 2.28258002818 85.774 85.62
10 0.0268689994591 0.508 1.98
20 0.00842629562862 0.064 1.84
30 0.00362461588105 0.002 1.84
40 0.00226260463091 0.0 1.83
50 0.00160511089576 0.0 1.79
60 0.00124066271756 0.0 1.8
70 0.000998563092114 0.0 1.77
80 0.000835008790528 0.0 1.76
90 0.00071484537096 0.0 1.77
100 0.000620496075363 0.0 1.76
# NT = 10000
100 0.0700069603957 0.0 1.76 1.8
CPU times: user 7min 39s, sys: 4.39 s, total: 7min 43s
Wall time: 2min 50s

こちらはむしろ繰り返し回数もっと減らしてもよさげ.誤識別率は十分低い値が得られてます( Pylearn2 の tutorial でお勉強 - まんぼう日記 の「ちょっと寄り道」では2%).

 

3層での実験

入力から順に素子数 D - H1 - H2 - K の3層MLP.Pylearn2 のチュートリアルにあわせて,H1 = 500, H2 = 1000. 隠れ層素子は ReLu の場合のみ.

 

In [5]: %time %run mnist_mlp0130.py
### 3-layer MLP: D = 784 H1 = 500 H2 = 1000 K = 10
### training: NL = 50000 NV = 10000 D = 784 K = 10 batchsize = 1000
0 2.2950117846 87.024 86.23
10 0.0162487196691 0.454 2.01
20 0.0013363220299 0.0 1.9
30 0.000560243039788 0.0 1.88
40 0.00034294256852 0.0 1.88
50 0.000247346072713 0.0 1.86
60 0.000190158548888 0.0 1.85
70 0.000153755322158 0.0 1.86
80 0.000128249762799 0.0 1.85
90 0.000109674979399 0.0 1.85
100 9.55789555264e-05 0.0 1.85
# NT = 10000
100 0.0949902994974 0.0 1.85 1.74
CPU times: user 21min 34s, sys: 25.2 s, total: 21min 59s
Wall time: 7min 49s

層をひとつ増やしてるので実行時間もっとかかるようになるかと思いましたが,それほどでもありませんでした.繰り返し回数少なくてもよさげなので, nepoch = 20 と 30 でもやってみると,こうなりました.

20 0.0741193218036 0.0 1.9 1.77
CPU times: user 4min 24s, sys: 5.71 s, total: 4min 30s
Wall time: 1min 38s
30 0.0794410192758 0.0 1.88 1.8
CPU times: user 6min 30s, sys: 8.2 s, total: 6min 38s
Wall time: 2min 23s

 

Pylearn2 でほぼ同様の条件で実行した場合( Pylearn2 の tutorial でお勉強 - 2時間目 - まんぼう日記 )よりも誤識別率/実行時間ともによい結果.誤識別率については1回限りの実験であまりどうこう言えませんが.実行時間については,Pylearn2 の方は epoch 毎に収束判定したりパラメータを保存したりいろいろやってるから,ってものあるでしょう.

 

ついでにもうひとつ,H1 = 1000, H2 = 500 (上記と個数が逆)とした場合.

In [9]: %time %run mnist_mlp0130.py
### 3-layer MLP: D =  784  H1 =  1000  H2 =  500  K =  10
### training:   NL =  50000 NV =  10000  D =  784  K =  10  batchsize =  1000
0 2.30852659338 91.686 92.25
10 0.00941974809128 0.168 1.89
20 0.000862513766485 0.0 1.74
# NT =  10000
20 0.064581840028 0.0 1.74 1.63
CPU times: user 5min 39s, sys: 5.92 s, total: 5min 45s
Wall time: 1min 57s

 

というわけで,次はいよいよ convolutional net か…な.