Dove posso chiamare la funzione BatchNormalization in Keras?


168

Se voglio usare la funzione BatchNormalization in Keras, allora devo chiamarla una sola volta all'inizio?

Ho letto questa documentazione per questo: http://keras.io/layers/normalization/

Non vedo dove dovrei chiamarlo. Di seguito è riportato il mio codice che tenta di utilizzarlo:

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)

Chiedo perché se eseguo il codice con la seconda riga incluso la normalizzazione batch e se eseguo il codice senza la seconda riga ottengo output simili. Quindi o non sto chiamando la funzione nel posto giusto, o immagino che non faccia molta differenza.

Risposte:


225

Giusto per rispondere a questa domanda in modo un po 'più dettagliato, e come ha detto Pavel, la normalizzazione in lotti è solo un altro livello, quindi puoi usarlo come tale per creare l'architettura di rete desiderata.

Il caso d'uso generale è usare BN tra i livelli lineari e non lineari della rete, perché normalizza l'input alla funzione di attivazione, in modo da essere centrati nella sezione lineare della funzione di attivazione (come Sigmoid). C'è una piccola discussione qui

Nel tuo caso sopra, questo potrebbe apparire come:


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

Spero che questo chiarisca le cose un po 'di più.


25
A quanto pare, la normalizzazione in batch funziona meglio in pratica dopo la funzione di attivazione
Claudiu,

10
Ciao @Claudiu, ti dispiacerebbe espandere questo FYI? Sembra contraddire direttamente la risposta sopra.
Ben Ogorek

7
@benogorek: certo, fondamentalmente l'ho basato interamente sui risultati qui posizionando la norma batch dopo che la relu ha funzionato meglio. FWIW Non ho avuto successo applicandolo in un modo o nell'altro su una rete che ho provato
Claudiu

32
Interessante. Solo per continuare, se continui a leggere in quel sommario, si dice che il loro modello migliore [GoogLeNet128_BN_lim0606] ha effettivamente il livello BN PRIMA della ReLU. Quindi, mentre BN dopo l'attivazione potrebbe migliorare l'accuratezza in un caso isolato, quando l'intero modello è costruito, prima di ottenere le migliori prestazioni. È probabile che posizionare BN dopo l'attivazione possa migliorare la precisione, ma è probabilmente dipendente dal problema.
Lucas Ramadan,

7
@ CarlThomé tipo di. Vedi questo commento reddit di ReginaldIII per esempio. Dichiarano: "BN sta normalizzando la distribuzione di funzioni che escono da una convoluzione, alcune [di] queste caratteristiche potrebbero essere negative [e] troncate da una non linearità come ReLU. Se normalizzi prima dell'attivazione stai includendo questi valori negativi in la normalizzazione immediatamente prima di eliminarli dallo spazio delle caratteristiche. BN dopo l'attivazione normalizzerà le caratteristiche positive senza differenziarle statisticamente con caratteristiche che non passano al successivo livello convoluzionale. "
martedì

60

Questa discussione è fuorviante. Ho provato a commentare la risposta di Lucas Ramadan, ma non ho ancora i privilegi giusti, quindi inserirò qui.

La normalizzazione in batch funziona meglio dopo la funzione di attivazione e qui o qui è il motivo: è stata sviluppata per prevenire lo spostamento della covariata interna. Lo spostamento della covariata interna si verifica quando la distribuzione delle attivazionidi uno strato cambia significativamente durante l'allenamento. La normalizzazione in batch viene utilizzata in modo che la distribuzione degli input (e questi input siano letteralmente il risultato di una funzione di attivazione) su uno strato specifico non cambi nel tempo a causa degli aggiornamenti dei parametri da ciascun batch (o almeno, gli consente di cambiare in modo vantaggioso). Utilizza le statistiche batch per eseguire la normalizzazione, quindi utilizza i parametri di normalizzazione batch (gamma e beta nel documento originale) "per assicurarsi che la trasformazione inserita nella rete possa rappresentare la trasformazione dell'identità" (citazione dal documento originale). Ma il punto è che stiamo provando a normalizzare gli input in un layer, quindi dovrebbe sempre andare immediatamente prima del layer successivo nella rete. Sia che


27
Ho appena visto nella classe deeplearning.ai che Andrew Ng afferma che c'è un dibattito al riguardo nella comunità del Deep Learning. Preferisce applicare la normalizzazione batch prima della non linearità.
Shahensha,

3
@kRazzyR Volevo dire che il Prof. Andrew Ng ha parlato di questo argomento nelle sue lezioni di deep learning su deeplearning.ai. Ha detto che la comunità è divisa sul modo giusto di fare le cose e che ha preferito applicare la normalizzazione in batch prima di applicare la non linearità.
Shahensha,

3
@jmancuso, BN viene applicato prima dell'attivazione. Dal documento stesso, equazione è g(BN(Wx + b)), dov'è gla funzione di attivazione.
yashgarg1232,

43

Questa discussione ha avuto un notevole dibattito sull'opportunità di applicare BN prima della non linearità del livello corrente o alle attivazioni del livello precedente.

Sebbene non vi sia una risposta corretta, gli autori della normalizzazione in lotti affermano che dovrebbe essere applicato immediatamente prima della non linearità del livello corrente. Il motivo (citato dalla carta originale) -

"Aggiungiamo la trasformazione BN immediatamente prima della non linearità, normalizzando x = Wu + b. Avremmo potuto anche normalizzare gli input di layer u, ma poiché è probabile che tu produca un'altra non linearità, è probabile che la forma della sua distribuzione cambi durante l'addestramento e il vincolo del suo primo e secondo momento non eliminerebbero il cambiamento di covariata, al contrario, è più probabile che Wu + b abbia una distribuzione simmetrica e non sparsa, che è "più gaussiana" (Hyv¨arinen & Oja, 2000) ; la normalizzazione probabilmente produrrà attivazioni con una distribuzione stabile. "


3
Nella mia esperienza personale, non fa una grande differenza, ma a parità di condizioni, ho sempre visto BN funzionare leggermente meglio quando si applica la normalizzazione batch prima della non linearità (prima della funzione di attivazione).
Brad Hesse,

31

Keras ora supporta l' use_bias=Falseopzione, quindi possiamo salvare alcuni calcoli scrivendo come

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

o

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

come model.add(BatchNormalization())diverso damodel.add(BatchNormalization(axis=bn_axis))
kRazzy R

@kRazzR non è diverso se si utilizza tensorflowcome backend. È scritto qui perché lo ha copiato dal keras.applicationsmodulo, dove bn_axisdeve essere specificato per supportare sia i formati channels_firstche i channels_lastformati.
ldavid,

9
Qualcuno può, per favore, elaborare come questo si collega alla domanda PO? (Sono piuttosto alle prime armi con gli NN, quindi forse mi manca qualcosa.)
Pepacz,

30

Ora è quasi diventato una tendenza avere un Conv2Dseguito da un ReLuseguito da un BatchNormalizationlivello. Così ho inventato una piccola funzione per chiamarli tutti in una volta. Rende la definizione del modello molto più pulita e più facile da leggere.

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
forse spingere questo a Keras?
sabato

6

È un altro tipo di livello, quindi è necessario aggiungerlo come livello in un punto appropriato del modello

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

Guarda un esempio qui: https://github.com/fchollet/keras/blob/master/examples/kaggle_otto_nn.py


1
Dopo aver aggiunto BatchNormalization, val_acc ha smesso di aumentare ogni epoca. Il val_acc è rimasto stagnante allo stesso numero dopo ogni epoca dopo l'aggiunta di BatchNormalization. Ho pensato che la normalizzazione in lotti avrebbe dovuto aumentare il val_acc. Come faccio a sapere se funziona correttamente? Sai cosa potrebbe aver causato questo?
pr338

sfortunatamente il link non è più valido :(
user2324712

Esistono copie di questo esempio nelle forcelle di Keras (ad esempio github.com/WenchenLi/kaggle/blob/master/otto/keras/… ), ma non so perché sia ​​stato rimosso dal repository originale di Keras e se il il codice è compatibile con le ultime versioni di Keras.
Pavel Surmenok,

4

La normalizzazione batch viene utilizzata per normalizzare il livello di input e i livelli nascosti regolando la media e il ridimensionamento delle attivazioni. A causa di questo effetto normalizzante con un livello aggiuntivo nelle reti neurali profonde, la rete può utilizzare un tasso di apprendimento più elevato senza sfumare o esplodere. Inoltre, la normalizzazione batch regolarizza la rete in modo che sia più facile generalizzare ed è quindi superfluo utilizzare il dropout per mitigare il sovradimensionamento.

Subito dopo aver calcolato la funzione lineare usando dire, il Dense () o Conv2D () in Keras, usiamo BatchNormalization () che calcola la funzione lineare in un livello e quindi aggiungiamo la non linearità al livello usando 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)

Come viene applicata la normalizzazione batch?

Supponiamo di aver inserito a [l-1] in un livello l. Inoltre abbiamo pesi W [l] e unità di polarizzazione b [l] per lo strato l. Sia un [l] il vettore di attivazione calcolato (cioè dopo aver aggiunto la non linearità) per lo strato l e z [l] sia il vettore prima di aggiungere la non linearità

  1. Usando un [l-1] e W [l] possiamo calcolare z [l] per il livello l
  2. Di solito nella propagazione feed-forward aggiungeremo unità di polarizzazione a z [l] in questa fase come questa z [l] + b [l], ma nella normalizzazione batch questo passaggio di aggiunta di b [l] non è richiesto e no b Viene utilizzato il parametro [l].
  3. Calcola z [l] significa e sottralo da ciascun elemento
  4. Dividi (z [l] - media) usando la deviazione standard. Chiamalo Z_temp [l]
  5. Ora definisci i nuovi parametri γ e β che cambieranno la scala del livello nascosto come segue:

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

In questo estratto di codice, Dense () prende a [l-1], usa W [l] e calcola z [l]. Quindi il BatchNormalization immediato () eseguirà i passaggi precedenti per dare z_norm [l]. E quindi l'attivazione immediata () calcolerà tanh (z_norm [l]) per dare un [l] cioè

a[l] = tanh(z_norm[l])
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.