まんぼう日記

takataka's diary

Batch Normalization を実装する

最近よゆーのーてどよどよな感じのたかたかです.Batch Normalization ちう論文読んだらむしょーにプログラム書いて実験しとーなって,週末にちょこっとやってみました.

 

Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift | ICML 2015 | JMLR W&CP

[1502.03167] Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift

 

Deepなニューラルネットの学習がうまく進まない問題を解決する方法として,各層への入力(実際には活性化関数への入力)をミニバッチ単位で正規化する仕組みを組み込むことを提案してます.それ以上の説明は省略 (^^) 実験結果を見る限り,学習の進行を加速する(正確には,大きな学習係数でいけるようになる)効果は抜群のようです(理論的な面で少し気にかかるとこがありますが).論旨は明快でアルゴリズムも簡単なので,リンク先の論文を読めばすぐわかると思います.

 

ちうわけで,プログラムを書いて実験してみました.これまで同様に Theano を使ってます.ソースはこちら:

やっつけ仕事で効率の悪い処理になってるとこもあるので注意です.まだ convolutional neural network で使えるようにしてへんし.

 

 

 

3層のネットワークでの実験

まずは3層のネットワークに MNIST の識別をさせてみる実験です.主な実験条件は次の通り:

  • Input - ReLu - ReLu - softmax という3層,隠れ層ニューロン数は1000
  • バッチサイズ 128 の stochastic gradient descent
  • 学習係数 eta = 0.1, 慣性項の係数 mu = 0.9, weight decay なし,dropout なし 

 

まず,従来のネットワークで学習するとこんなん:

$ time THEANO_FLAGS='device=gpu1' python ex151220.py
Using gpu device 1: Tesla K20c
# Layer 0 : Input ( 784 ) dropout =  1.0
# Layer 1 : ReLu ( 784 x 1000 ) dropout =  1.0
# Layer 2 : ReLu ( 1000 x 1000 ) dropout =  1.0
# Layer 3 : linear ( 1000 x 10 ) dropout =  1.0
### training:   NL =  50000 NV =  10000  batchsize =  128
#               eta =  0.1 mu =  0.9 lam =  0.0
0 | 2.3023 90.29 | 2.3023 89.84
1 | 0.1007 3.06 | 0.1128 3.31  | eta = 0.1
2 | 0.0617 1.83 | 0.0901 2.75  | eta = 0.1
3 | 0.0428 1.29 | 0.0842 2.49  | eta = 0.1
4 | 0.0302 0.88 | 0.0861 2.19  | eta = 0.1
5 | 0.0237 0.68 | 0.0834 2.13  | eta = 0.1
6 | 0.0140 0.42 | 0.0775 1.95  | eta = 0.1
7 | 0.0137 0.43 | 0.0866 2.03  | eta = 0.1
8 | 0.0099 0.32 | 0.0869 2.11  | eta = 0.1
9 | 0.0049 0.15 | 0.0806 1.78  | eta = 0.1
10 | 0.0024 0.05 | 0.0798 1.73  | eta = 0.1
20 | 0.0001 0.00 | 0.0869 1.62  | eta = 0.1
30 | 0.0000 0.00 | 0.0905 1.61  | eta = 0.1
40 | 0.0000 0.00 | 0.0929 1.62  | eta = 0.1
# NT =  10000
50 | 0.0000 0.00 | 0.0929 1.62 | 0.0862 1.56
real 2m16.864s user 1m25.864s sys 0m48.664s

50epoch で学習,検査,テストデータの誤識別率はそれぞれ 0.00%,1.62%,1.56%となりました.

 

次は,Batch Normalization (BN) を使った場合:

$ time THEANO_FLAGS='device=gpu1' python ex151220bn.py
Using gpu device 1: Tesla K20c
# Layer 0 : Input ( 784 ) dropout =  1.0
# Layer 1 : ReLu ( 784 x 1000 ) dropout =  1.0
# Layer 2 : ReLu ( 1000 x 1000 ) dropout =  1.0
# Layer 3 : linear ( 1000 x 10 ) dropout =  1.0
### training:   NL =  50000 NV =  10000  batchsize =  128
#               eta =  0.1 mu =  0.9 lam =  0.0
0 | 2.3023 90.29 | 2.3023 89.84
1 | 0.1206 3.75 | 0.1412 4.27  | eta = 0.1
2 | 0.0515 1.47 | 0.0815 2.47  | eta = 0.1
3 | 0.0348 0.98 | 0.0727 2.17  | eta = 0.1
4 | 0.0280 0.81 | 0.0748 2.25  | eta = 0.1
5 | 0.0190 0.54 | 0.0693 1.91  | eta = 0.1
6 | 0.0118 0.28 | 0.0591 1.65  | eta = 0.1
7 | 0.0097 0.26 | 0.0584 1.58  | eta = 0.1
8 | 0.0102 0.27 | 0.0640 1.89  | eta = 0.1
9 | 0.0050 0.10 | 0.0562 1.55  | eta = 0.1
10 | 0.0043 0.08 | 0.0568 1.55  | eta = 0.1
20 | 0.0009 0.02 | 0.0632 1.47  | eta = 0.1
30 | 0.0001 0.00 | 0.0510 1.20  | eta = 0.1
40 | 0.0001 0.00 | 0.0537 1.19  | eta = 0.1
# NT =  10000
50 | 0.0001 0.00 | 0.0537 1.19 | 0.0520 1.31

real    3m9.765s
user    2m9.004s
sys    0m57.476s

この条件では,学習の進み方に大きな違いは見えません.少しテスト識別率が下がってて,著者らが主張するように BN には regularization の効果もあるのかもです.それから,学習に要する時間が大きくなってますが,これはたかたかの実装が悪い(特に,バッチごとの平均と分散を使って推論時用の平均と分散を推定する処理の効率が悪い)せいだと思います.プログラムを見直せばたぶんもっと差は縮まるでしょう.

 

15層のネットワークでの実験

次は15層です.こんだけ deep にすると,従来のネットワークでは...

$ time THEANO_FLAGS='device=gpu1' python ex151220.py
Using gpu device 1: Tesla K20c
# Layer 0 : Input ( 784 ) dropout =  1.0
# Layer 1 : ReLu ( 784 x 1000 ) dropout =  1.0
# Layer 2 : ReLu ( 1000 x 1000 ) dropout =  1.0
(中略)
# Layer 14 : ReLu ( 1000 x 1000 ) dropout =  1.0
# Layer 15 : linear ( 1000 x 10 ) dropout =  1.0
### training:   NL =  50000 NV =  10000  batchsize =  128
#               eta =  0.1 mu =  0.9 lam =  0.0
0 | 2.3026 90.14 | 2.3026 90.09
1 | 2.3030 88.64 | 2.3046 89.36  | eta = 0.1
2 | 2.3028 90.06 | 2.3039 90.10  | eta = 0.1
(中略)
40 | 2.3032 88.64 | 2.3038 89.36  | eta = 0.1
# NT =  10000
50 | 2.3032 88.64 | 2.3038 89.36 | 2.3029 88.65

real	9m6.693s
user	5m45.972s
sys	3m10.120s

学習が進まなくなってしまいました.学習定数を大きくしたり小さくしたりしても変わりません.

 

一方,BNの場合...

$ time THEANO_FLAGS='device=gpu1' python ex151220bn.py
Using gpu device 1: Tesla K20c
# Layer 0 : Input ( 784 ) dropout =  1.0
# Layer 1 : ReLu ( 784 x 1000 ) dropout =  1.0
# Layer 2 : ReLu ( 1000 x 1000 ) dropout =  1.0
(中略)
# Layer 14 : ReLu ( 1000 x 1000 ) dropout =  1.0
# Layer 15 : linear ( 1000 x 10 ) dropout =  1.0
### training:   NL =  50000 NV =  10000  batchsize =  128
#               eta =  0.1 mu =  0.9 lam =  0.0
0 | 2.3026 90.14 | 2.3026 90.09
1 | 0.3051 5.57 | 0.3116 5.70  | eta = 0.1
2 | 0.0900 2.54 | 0.1193 3.34  | eta = 0.1
3 | 0.0621 1.75 | 0.0958 2.75  | eta = 0.1
4 | 0.0403 1.16 | 0.0829 2.15  | eta = 0.1
5 | 0.0429 1.12 | 0.0882 2.48  | eta = 0.1
6 | 0.0324 0.90 | 0.0865 2.34  | eta = 0.1
7 | 0.0283 0.72 | 0.0778 2.26  | eta = 0.1
8 | 0.0249 0.65 | 0.0811 2.09  | eta = 0.1
9 | 0.0164 0.42 | 0.0690 1.83  | eta = 0.1
10 | 0.0185 0.47 | 0.0785 2.16  | eta = 0.1
20 | 0.0046 0.07 | 0.0683 1.66  | eta = 0.1
30 | 0.0030 0.04 | 0.0626 1.45  | eta = 0.1
40 | 0.0016 0.03 | 0.0715 1.61  | eta = 0.1
# NT =  10000
50 | 0.0016 0.03 | 0.0715 1.61 | 0.0690 1.58

real	19m1.669s
user	11m13.904s
sys	7m23.208s

ちゃんと学習が進むようになってます.すばらしい.