ジョイジョイジョイ

ジョイジョイジョイジョイジョイ

Batch Normalization

Batch Normalization [1] を chainer で実装しました。

色々な場合に適用できて、学習速度が速くなったり汎化性能が上がったりするすごいテクです。

Batch Normalization の説明

上層(出力層に近い層)の入力は、当然下層(入力層に近い側)のパラメータに依存します。

学習が進むにしたがって下層のパラーメータは変化するので、それにしたがって上層の入力の分布が変化します。

このような中間層の入力の分布の変化を Internal Covariate Shift と呼びます

入力の分布が変化した層はそれに合わせてパラメータも学習しなおさなければなりません。

これが、学習の速度を下げる要因になります。

Batch Normalization は、Internal Covariate Shift が起きないように各層の入力の分布を一定に保とうとするテクです。

具体的には、各層の入力 ( = 前層の出力 ) をバッチごとに標準化します。

 \displaystyle \mu = \frac{1}{m} \sum_{i=1}^{m} x_i

 \displaystyle \sigma^{2} = \frac{1}{m} \sum_{i=1}^m ( x_i - \mu )^{2}

 \displaystyle \hat{x} = \frac{ x - \mu }{ \sqrt{ \sigma^{2} + \varepsilon } }

ここで、 \varepsilon \sigma^{2} 0 に近い時に数値的な安定を保つためのハイパーパラメーターです。

ただ標準化するだけでは、例えば活性化関数にシグモイドを使っていた場合に線形部分しか使われなくなるかもしれないなどの問題が生じるかもしれません。

そこで、パラメータとして新しく  \beta \gamma を用意して、

 \displaystyle y = \gamma \hat{x} + \beta

と線形変換して、これを新しい入力とすれば完成です。

Batch Normalization は、Internal Covariate Shift を抑制するだけでなく、層の入力が異常に大きくなって勾配が消失してしまう問題を防いだり、学習率を大きくしたときにパラメータが発散してしまう問題を防ぐなどの効果もあるようです。

実装

gist.github.com

学習が終わって推論の段階で、バッチの組み合わせによって同じ入力が違う出力になるのがつらいときは、学習時の統計を使って  \hat{x} の変換式を固定すると良いようですが、今回は実装していません。

実験

三層のパーセプトロンで MNIST の分類を行いました。

Batch Normalization なし

f:id:joisino:20170706120414p:plain

Batch Normalization あり

f:id:joisino:20170706120428p:plain

links.BatchNormalization を使った場合

f:id:joisino:20170706120441p:plain

Batch Normalization を入れると、最終的な汎化性能は変わりませんが学習速度は速くなっています。

自作の BatchNormalization は chainer に入っている links.BatchNormalization と性能はほとんど同じになっています。

ただし、自作の BatchNormalization は自分で勾配を計算したわけではなく既存の functions を組み合わせて作ったので、速度は 4 割ほど落ちます。

最後に

何か間違いや質問などがあればお願いします。

最後まで読んでいただきありがとうございました。

参考文献

[1] Ioffe, S. et. al. (2015). Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift