KerasのBatchNormalization関数はどこで呼び出しますか?


167

KerasでBatchNormalization関数を使用したい場合、最初に一度だけ呼び出す必要がありますか?

私はそれについてこのドキュメントを読みました:http : //keras.io/layers/normalization/

どこに呼ぶべきかわかりません。以下はそれを使用しようとしている私のコードです:

model = Sequential()
keras.layers.normalization.BatchNormalization(epsilon=1e-06, mode=0, momentum=0.9, weights=None)
model.add(Dense(64, input_dim=14, init='uniform'))
model.add(Activation('tanh'))
model.add(Dropout(0.5))
model.add(Dense(64, init='uniform'))
model.add(Activation('tanh'))
model.add(Dropout(0.5))
model.add(Dense(2, init='uniform'))
model.add(Activation('softmax'))

sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='binary_crossentropy', optimizer=sgd)
model.fit(X_train, y_train, nb_epoch=20, batch_size=16, show_accuracy=True, validation_split=0.2, verbose = 2)

バッチ正規化を含む2行目でコードを実行すると、2行目なしでコードを実行すると、同様の出力が得られるため、私は尋ねます。したがって、適切な場所で関数を呼び出していないか、それほど大きな違いはないと思います。

回答:


225

この質問にもう少し詳しく答えると、Pavelが言ったように、バッチ正規化は単なる別のレイヤーなので、それを使用して目的のネットワークアーキテクチャを作成できます。

アクティベーション関数への入力を正規化し、アクティベーション関数の線形セクション(Sigmoidなど)の中央に配置するため、ネットワークの線形層と非線形層の間でBNを使用するのが一般的な使用例です。ここでそれについての小さな議論があります

上記の場合、これは次のようになります。


# import BatchNormalization
from keras.layers.normalization import BatchNormalization

# instantiate model
model = Sequential()

# we can think of this chunk as the input layer
model.add(Dense(64, input_dim=14, init='uniform'))
model.add(BatchNormalization())
model.add(Activation('tanh'))
model.add(Dropout(0.5))

# we can think of this chunk as the hidden layer    
model.add(Dense(64, init='uniform'))
model.add(BatchNormalization())
model.add(Activation('tanh'))
model.add(Dropout(0.5))

# we can think of this chunk as the output layer
model.add(Dense(2, init='uniform'))
model.add(BatchNormalization())
model.add(Activation('softmax'))

# setting up the optimization of our weights 
sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='binary_crossentropy', optimizer=sgd)

# running the fitting
model.fit(X_train, y_train, nb_epoch=20, batch_size=16, show_accuracy=True, validation_split=0.2, verbose = 2)

これがもう少し明確になることを願っています。


25
FYIは明らかにアクティベーション機能の後でバッチの正規化が実際によりよく機能します
Claudiu

10
こんにちは@Claudiu、このFYIを拡張していただけませんか?上記の答えに直接矛盾するようです。
Ben Ogorek

7
@benogorek:確実なこと、基本的に私は結果に完全にそれをベースここ reluが良好に機能した後、バッチノルムを置きます。FWIW私が試した1つのネット
Claudiu

32
面白い。ただフォローアップするために、その要約を読み続けると、彼らの最良のモデル[GoogLeNet128_BN_lim0606]は実際にはReLUの前にBNレイヤーを持っていると言っています。そのため、アクティベーション後のBNは、モデル全体が構築されたときに、最適に実行される前に、孤立したケースで精度を向上させる可能性があります。アクティベーション後にBNを配置すると精度が向上する可能性がありますが、問題に依存している可能性があります。
Lucas Ramadan

7
@CarlThoméのような。たとえば、ReginaldIIIによるこのredditコメントを参照してください。「BNは畳み込みから生じる機能の分布を正規化していますが、これらの機能の一部は負である可能性があり、ReLUのような非線形性によって切り捨てられている可能性があります。アクティブ化する前に正規化すると、これらの負の値がフィーチャ空間からカリングする直前の正規化。アクティブ化後のBNは、次の畳み込み層に到達しないフィーチャで統計的にバイアスをかけることなく、ポジティブフィーチャを正規化します。」
mab 2017

60

このスレッドは誤解を招く可能性があります。ルーカスラマダンの答えについてコメントしようとしましたが、まだ適切な権限を持っていないので、これをここに配置します。

バッチ正規化は、アクティベーション関数の後に最適に機能します。ここまたはここに理由があります。これは、内部共変量シフトを防ぐために開発されました。内部共変量シフトは、活性化の分布時に発生しますレイヤー全体がトレーニング全体で大幅にシフトします。特定のレイヤーへの入力(およびこれらの入力は、文字通りアクティベーション関数の結果です)の分布が、各バッチからのパラメーター更新のために経時的に変化しないように(または少なくとも、それを変更できるように)バッチ正規化が使用されます有利な方法で)。バッチ統計を使用して正規化を行い、次にバッチ正規化パラメーター(元のペーパーのガンマとベータ)を使用して、「ネットワークに挿入された変換が恒等変換を表すことができることを確認します」(元のペーパーからの引用)。しかし重要なのは、レイヤーへの入力を正規化しようとしているため、常にネットワーク内の次のレイヤーの直前に配置する必要があるということです。それかどうか


27
私は、deeplearning.aiクラスで、Andrew Ngがディープラーニングコミュニティでこれについて議論があると言ったのを見ました。彼は非線形性の前にバッチ正規化を適用することを好みます。
shahensha 2017年

3
@kRazzyR私は、Andrew Ng教授がdeeplearning.aiのディープラーニングクラスでこのトピックについて話したことを意味しました 。
shahensha

3
@ jmancuso、BNはアクティベーションの前に適用されます。論文自体から、方程式はですg(BN(Wx + b))。ここgで、は活性化関数です。
yashgarg1232

43

このスレッドは、BNを現在の層の非線形性の前に適用するか、前の層のアクティブ化に適用するかについて、かなりの議論があります。

正解はありませんが、バッチ正規化の作成者は、現在のレイヤーの非線形性の直前に適用する必要があると述べて います。理由(元の論文から引用)-

「x = Wu + bを正規化することにより、非線形変換の直前にBN変換を追加します。層の入力uも正規化できますが、uは別の非線形性の出力である可能性が高いため、分布の形状はトレーニングし、その最初と2番目のモーメントを制約しても、共変量シフトは解消されません。対照的に、Wu + bは、対称的で非スパースな分布、つまり、「ガウス分布が多い」(Hyv¨arinen&Oja、2000)の可能性が高くなります。 ;正規化すると、安定したディストリビューションでアクティベーションが生成される可能性があります。」


3
私自身の個人的な経験では、大きな違いはありませんが、他の条件はすべて同じです。非線形性の前に(アクティベーション関数の前に)バッチ正規化を適用すると、BNのパフォーマンスがわずかに向上します。
Brad Hesse

31

Kerasがuse_bias=Falseオプションをサポートするようになったので、次のように書くことで計算を節約できます。

model.add(Dense(64, use_bias=False))
model.add(BatchNormalization(axis=bn_axis))
model.add(Activation('tanh'))

または

model.add(Convolution2D(64, 3, 3, use_bias=False))
model.add(BatchNormalization(axis=bn_axis))
model.add(Activation('relu'))

ノウハウmodel.add(BatchNormalization())異なるmodel.add(BatchNormalization(axis=bn_axis))
kRazzy R

@kRazzR tensorflowバックエンドとして使用している場合でも違いはありません。これは、彼がこれをkeras.applicationsモジュールからコピーしたため、ここで記述されています。ここでbn_axisは、channels_firstchannels_last形式の両方をサポートするために指定する必要があります。
ldavid

9
これがOPの質問とどのように関連しているかを誰かが詳しく説明してくれませんか?(私はNNの初心者なので、何かを逃したかもしれません。)
Pepacz

30

それに続いてレイヤーが続くというのConv2Dが今のトレンドになりつつあります。そこで、それらすべてを一度に呼び出す小さな関数を作りました。モデル定義を全体的にすっきりとして読みやすくします。ReLuBatchNormalization

def Conv2DReluBatchNorm(n_filter, w_filter, h_filter, inputs):
    return BatchNormalization()(Activation(activation='relu')(Convolution2D(n_filter, w_filter, h_filter, border_mode='same')(inputs)))

7
多分これをケラスにプッシュしますか?
sachinruk 2017年

6

別のタイプのレイヤーなので、モデルの適切な場所にレイヤーとして追加する必要があります

model.add(keras.layers.normalization.BatchNormalization())

こちらの例をご覧くださいhttps : //github.com/fchollet/keras/blob/master/examples/kaggle_otto_nn.py


1
BatchNormalizationを追加した後、val_accはエポックごとに増加しなくなりました。BatchNormalizationを追加した後、すべてのエポックの後、val_accは同じ数で停滞したままでした。Batch Normalizationはval_accを増やすことになっていると思いました。正常に動作しているかどうかはどうすればわかりますか?何が原因なのか知っていますか?
pr338

残念ながら、リンクは有効ではありません:(
user2324712

Kerasのフォーク(例えばgithub.com/WenchenLi/kaggle/blob/master/otto/keras/…)にその例のコピーがありますが、元のKerasリポジトリから削除された理由、およびコードは最新のKerasバージョンと互換性があります。
Pavel Surmenok 2016

4

バッチ正規化は、アクティベーションの平均とスケーリングを調整することにより、入力レイヤーと非表示レイヤーを正規化するために使用されます。ディープニューラルネットワークの追加レイヤーによるこの正規化効果により、ネットワークは勾配を消失または爆発させることなく、より高い学習率を使用できます。さらに、バッチ正規化によりネットワークが正規化され、一般化が容易になるため、ドロップアウトを使用して過剰適合を緩和する必要がありません。

KerasのDense()またはConv2D()などを使用して線形関数を計算した直後に、レイヤーの線形関数を計算するBatchNormalization()を使用し、次にActivation()を使用して非線形をレイヤーに追加します。

from keras.layers.normalization import BatchNormalization
model = Sequential()
model.add(Dense(64, input_dim=14, init='uniform'))
model.add(BatchNormalization(epsilon=1e-06, mode=0, momentum=0.9, weights=None))
model.add(Activation('tanh'))
model.add(Dropout(0.5))
model.add(Dense(64, init='uniform'))
model.add(BatchNormalization(epsilon=1e-06, mode=0, momentum=0.9, weights=None))
model.add(Activation('tanh'))
model.add(Dropout(0.5))
model.add(Dense(2, init='uniform'))
model.add(BatchNormalization(epsilon=1e-06, mode=0, momentum=0.9, weights=None))
model.add(Activation('softmax'))

sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='binary_crossentropy', optimizer=sgd)
model.fit(X_train, y_train, nb_epoch=20, batch_size=16, show_accuracy=True, 
validation_split=0.2, verbose = 2)

バッチ正規化はどのように適用されますか?

レイヤーlにa [l-1]を入力したとします。また、レイヤーlには重みW [l]とバイアス単位b [l]があります。a [l]をレイヤーlに対して計算された(つまり、非線形性を追加した後の)アクティベーションベクトルとし、z [l]を非線形性を追加する前のベクトルとします。

  1. a [l-1]とW [l]を使用して、レイヤーlのz [l]を計算できます
  2. 通常、フィードフォワード伝播では、この段階でz [l] + b [l]のようにz [l]にバイアス単位を追加しますが、バッチ正規化では、b [l]を追加するこの手順は不要であり、 b [l]パラメータが使用されます。
  3. z [l]平均を計算し、それを各要素から減算します
  4. 標準偏差を使用して(z [l]-平均)を割ります。それをZ_temp [l]と呼びます
  5. 次に、次のように非表示レイヤーのスケールを変更する新しいパラメーターγとβを定義します。

    z_norm [l] =γ.Z_temp[l] +β

このコードの抜粋では、Dense()はa [l-1]を取得し、W [l]を使用してz [l]を計算します。次に、即時のBatchNormalization()は上記の手順を実行してz_norm [l]を提供します。そして、即時のActivation()はtanh(z_norm [l])を計算してa [l]を与えます。すなわち

a[l] = tanh(z_norm[l])
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.