Wo rufe ich die BatchNormalization-Funktion in Keras auf?

166

Wenn ich die BatchNormalization-Funktion in Keras verwenden möchte, muss ich sie dann nur zu Beginn einmal aufrufen?

Ich habe diese Dokumentation dafür gelesen: http://keras.io/layers/normalization/

Ich sehe nicht, wo ich es nennen soll. Unten ist mein Code, der versucht, ihn zu verwenden:

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)

Ich frage, denn wenn ich den Code mit der zweiten Zeile einschließlich der Batch-Normalisierung ausführe und wenn ich den Code ohne die zweite Zeile ausführe, erhalte ich ähnliche Ausgaben. Entweder rufe ich die Funktion nicht an der richtigen Stelle auf, oder ich denke, das macht keinen großen Unterschied.

pr338
quelle

Antworten:

225

Um diese Frage etwas detaillierter zu beantworten, und wie Pavel sagte, ist die Stapelnormalisierung nur eine weitere Ebene, sodass Sie sie als solche verwenden können, um Ihre gewünschte Netzwerkarchitektur zu erstellen.

Der allgemeine Anwendungsfall besteht darin, BN zwischen der linearen und der nichtlinearen Schicht in Ihrem Netzwerk zu verwenden, da dadurch die Eingabe für Ihre Aktivierungsfunktion normalisiert wird, sodass Sie im linearen Bereich der Aktivierungsfunktion (z. B. Sigmoid) zentriert sind. Es gibt eine kleine Diskussion davon hier

In Ihrem obigen Fall könnte dies folgendermaßen aussehen:


# 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)

Hoffe das klärt die Dinge ein bisschen mehr.

Lucas Ramadan
quelle
25
Zu
Claudiu
10
Hallo @Claudiu, würde es Ihnen etwas ausmachen, dieses FYI zu erweitern? Es scheint der obigen Antwort direkt zu widersprechen.
Ben Ogorek
7
@benogorek: Sicher, im Grunde habe ich es ganz auf die Ergebnisse hier gestützt, bei denen die Platzierung der Chargennorm nach dem Relu besser lief. FWIW Ich hatte keinen Erfolg damit, es auf die eine oder andere Weise auf das eine Netz anzuwenden, das ich versucht habe
Claudiu
32
Interessant. Wenn Sie in dieser Zusammenfassung weiterlesen, heißt es, dass das beste Modell [GoogLeNet128_BN_lim0606] tatsächlich die BN-Schicht VOR der ReLU hat. Während BN nach der Aktivierung die Genauigkeit in einem Einzelfall verbessern kann, wenn das gesamte Modell erstellt wird, bevor es am besten ausgeführt wird. Wahrscheinlich ist es möglich, dass das Platzieren von BN nach der Aktivierung die Genauigkeit verbessert, ist aber wahrscheinlich problemabhängig.
Lucas Ramadan
7
@ CarlThomé Art von. Siehe zum Beispiel diesen reddit- Kommentar von ReginaldIII. Sie besagen: "BN normalisiert die Verteilung von Merkmalen, die aus einer Faltung hervorgehen. Einige dieser Merkmale sind möglicherweise negativ [und] werden durch eine Nichtlinearität wie ReLU abgeschnitten. Wenn Sie vor der Aktivierung normalisieren, schließen Sie diese negativen Werte in ein die Normalisierung unmittelbar vor dem Ausmerzen aus dem Merkmalsraum. BN nach der Aktivierung normalisiert die positiven Merkmale, ohne sie statistisch mit Merkmalen zu versehen, die es nicht bis zur nächsten Faltungsschicht schaffen. "
Mab
60

Dieser Thread ist irreführend. Ich habe versucht, die Antwort von Lucas Ramadan zu kommentieren, aber ich habe noch nicht die richtigen Privilegien, also werde ich dies hier einfügen.

Die Chargennormalisierung funktioniert am besten nach der Aktivierungsfunktion, und hier oder hier ist der Grund: Sie wurde entwickelt, um eine interne Kovariatenverschiebung zu verhindern. Interne Kovariatenverschiebung tritt bei der Verteilung der Aktivierungen aufeiner Schicht verschiebt sich während des Trainings signifikant. Die Chargennormalisierung wird verwendet, damit sich die Verteilung der Eingaben (und diese Eingaben sind buchstäblich das Ergebnis einer Aktivierungsfunktion) auf eine bestimmte Schicht im Laufe der Zeit aufgrund von Parameteraktualisierungen von jeder Charge nicht ändert (oder zumindest eine Änderung ermöglicht) in vorteilhafter Weise). Es verwendet Stapelstatistiken, um die Normalisierung durchzuführen, und verwendet dann die Stapelnormalisierungsparameter (Gamma und Beta im Originalpapier), "um sicherzustellen, dass die in das Netzwerk eingefügte Transformation die Identitätstransformation darstellen kann" (Zitat aus dem Originalpapier). Der Punkt ist jedoch, dass wir versuchen, die Eingaben auf eine Ebene zu normalisieren, sodass sie immer unmittelbar vor der nächsten Ebene im Netzwerk erfolgen sollten. Ob das oder nicht '

jmancuso
quelle
27
Ich habe gerade in der Klasse deeplearning.ai gesehen, dass Andrew Ng sagt, dass es in der Deep Learning-Community eine Debatte darüber gibt. Er bevorzugt die Chargennormalisierung vor der Nichtlinearität.
Shahensha
3
@kRazzyR Ich meinte, dass Prof. Andrew Ng in seinen Deep-Learning-Kursen zum Thema Deeplearning über dieses Thema sprach .
Shahensha
3
@jmancuso, BN wird vor der Aktivierung angewendet. Aus dem Papier selbst geht hervor g(BN(Wx + b)), wo gsich die Aktivierungsfunktion befindet.
Yashgarg1232
43

Dieser Thread hat einige erhebliche Debatten darüber, ob BN vor der Nichtlinearität der aktuellen Schicht oder auf die Aktivierungen der vorherigen Schicht angewendet werden sollte.

Obwohl es keine richtige Antwort gibt, sagen die Autoren der Chargennormalisierung, dass sie unmittelbar vor der Nichtlinearität der aktuellen Ebene angewendet werden sollte. Der Grund (zitiert aus Originalpapier) -

"Wir fügen die BN-Transformation unmittelbar vor der Nichtlinearität hinzu, indem wir x = Wu + b normalisieren. Wir hätten auch die Ebeneneingaben u normalisieren können, aber da u wahrscheinlich die Ausgabe einer anderen Nichtlinearität ist, ändert sich wahrscheinlich die Form ihrer Verteilung während Das Training und die Einschränkung des ersten und zweiten Moments würden die kovariate Verschiebung nicht beseitigen. Im Gegensatz dazu weist Wu + b eher eine symmetrische, nicht spärliche Verteilung auf, die „mehr Gauß“ ist (Hyvéarinen & Oja, 2000). Eine Normalisierung führt wahrscheinlich zu Aktivierungen mit einer stabilen Verteilung. "

user12340
quelle
3
Nach meiner persönlichen Erfahrung macht es keinen großen Unterschied, aber wenn alles andere gleich ist, habe ich immer gesehen, dass BN etwas besser abschneidet, wenn die Batch-Normalisierung vor der Nichtlinearität (vor der Aktivierungsfunktion) angewendet wird.
Brad Hesse
31

Keras unterstützt jetzt die use_bias=FalseOption, sodass wir einige Berechnungen speichern können, indem wir wie schreiben

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

oder

model.add(Convolution2D(64, 3, 3, use_bias=False))
model.add(BatchNormalization(axis=bn_axis))
model.add(Activation('relu'))
dontloo
quelle
wie model.add(BatchNormalization())unterscheidet sich vonmodel.add(BatchNormalization(axis=bn_axis))
kRazzy R
@kRazzR es unterscheidet sich nicht, wenn Sie tensorflowals Backend verwenden. Es ist hier geschrieben, weil er dies aus dem keras.applicationsModul kopiert hat , wo bn_axisangegeben werden muss, um sowohl channels_firstals auch channels_lastFormate zu unterstützen.
ldavid
9
Kann jemand bitte näher erläutern, wie dies mit der OP-Frage zusammenhängt? (Ich bin eher Anfänger in NNs, also vermisse ich vielleicht etwas.)
Pepacz
30

Es ist mittlerweile fast ein Trend geworden, eine Conv2Dgefolgt von einer ReLugefolgt von einer BatchNormalizationSchicht zu haben. Also habe ich mir eine kleine Funktion ausgedacht, um alle auf einmal aufzurufen. Lässt die Modelldefinition viel sauberer und leichter lesbar aussehen.

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)))
stochastic_zeitgeist
quelle
7
Vielleicht schieben Sie dies zu Keras?
Sachinruk
6

Es ist eine andere Art von Ebene, daher sollten Sie sie als Ebene an einer geeigneten Stelle Ihres Modells hinzufügen

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

Ein Beispiel finden Sie hier: https://github.com/fchollet/keras/blob/master/examples/kaggle_otto_nn.py

Pavel Surmenok
quelle
1
Nachdem ich BatchNormalization hinzugefügt hatte, hörte val_acc auf, mit jeder Epoche zuzunehmen. Der val_acc blieb nach jeder Epoche auf der gleichen Zahl stagnieren, nachdem ich BatchNormalization hinzugefügt hatte. Ich dachte, die Chargennormalisierung sollte den Wert von val_acc erhöhen. Woher weiß ich, ob es richtig funktioniert? Wissen Sie, was dies verursacht haben könnte?
Pr338
Leider ist der Link nicht mehr gültig :(
user2324712
Es gibt Kopien dieses Beispiels in Gabeln von Keras (z. B. github.com/WenchenLi/kaggle/blob/master/otto/keras/… ), aber ich weiß nicht, warum es aus dem ursprünglichen Keras-Repo entfernt wurde und ob das Code ist mit den neuesten Keras-Versionen kompatibel.
Pavel Surmenok
4

Die Stapelnormalisierung wird verwendet, um sowohl die Eingabeebene als auch die ausgeblendeten Ebenen zu normalisieren, indem der Mittelwert und die Skalierung der Aktivierungen angepasst werden. Aufgrund dieses Normalisierungseffekts mit zusätzlicher Schicht in tiefen neuronalen Netzen kann das Netzwerk eine höhere Lernrate verwenden, ohne Gradienten zu verschwinden oder zu explodieren. Darüber hinaus reguliert die Batch-Normalisierung das Netzwerk so, dass es einfacher zu verallgemeinern ist, und es ist daher nicht erforderlich, Dropout zu verwenden, um eine Überanpassung zu verringern.

Unmittelbar nach der Berechnung der linearen Funktion mit Dense () oder Conv2D () in Keras verwenden wir BatchNormalization (), das die lineare Funktion in einer Ebene berechnet, und fügen dann die Nichtlinearität mit Layivation () zur Ebene hinzu.

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)

Wie wird die Chargennormalisierung angewendet?

Angenommen, wir haben ein [l-1] in eine Ebene l eingegeben. Wir haben auch Gewichte W [l] und Vorspannungseinheit b [l] für die Schicht l. Sei a [l] der Aktivierungsvektor, der für die Schicht l berechnet wird (dh nach dem Hinzufügen der Nichtlinearität), und z [l] der Vektor vor dem Hinzufügen der Nichtlinearität

  1. Mit a [l-1] und W [l] können wir z [l] für die Schicht l berechnen
  2. Normalerweise fügen wir bei der Vorwärtsausbreitung in diesem Stadium eine Vorspannungseinheit zum z [l] hinzu, wie z [l] + b [l], aber bei der Chargennormalisierung ist dieser Schritt der Addition von b [l] nicht erforderlich und nein Der Parameter b [l] wird verwendet.
  3. Berechnen Sie die Mittelwerte für z [l] und subtrahieren Sie sie von jedem Element
  4. Teilen Sie (z [l] - Mittelwert) mit der Standardabweichung. Nenne es Z_temp [l]
  5. Definieren Sie nun die neuen Parameter γ und β, die den Maßstab der verborgenen Schicht wie folgt ändern:

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

In diesem Code-Auszug nimmt Dense () das a [l-1], verwendet W [l] und berechnet z [l]. Dann führt die sofortige BatchNormalization () die obigen Schritte aus, um z_norm [l] zu erhalten. Und dann berechnet die sofortige Aktivierung () tanh (z_norm [l]), um ein [l] zu ergeben

a[l] = tanh(z_norm[l])
Aishwarya Radhakrishnan
quelle