web-dev-qa-db-fra.com

Où est-ce que j'appelle la fonction BatchNormalization dans Keras?

Si je veux utiliser la fonction BatchNormalization dans Keras, dois-je l'appeler une fois seulement au début?

J'ai lu cette documentation pour cela: http://keras.io/layers/normalization/

Je ne vois pas où je suis censé l'appeler. Ci-dessous, mon code essayant de l'utiliser:

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)

Je demande parce que si je lance le code avec la deuxième ligne, y compris la normalisation par lots et si je lance le code sans la deuxième ligne, j'obtiens des résultats similaires. Donc soit je n’appelle pas la fonction au bon endroit, soit je suppose que cela ne fait pas une grande différence.

134
pr338

Pour répondre à cette question un peu plus en détail, et comme Pavel l’a dit, la normalisation par lots n’est qu’une couche supplémentaire; vous pouvez donc vous en servir pour créer l’architecture réseau de votre choix.

Le cas d'utilisation général consiste à utiliser un BN entre les couches linéaires et non linéaires de votre réseau, car il normalise l'entrée dans votre fonction d'activation, de sorte que vous êtes centré sur la section linéaire de la fonction d'activation (telle que Sigmoid). Il y a une petite discussion à ce sujet ici

Dans votre cas ci-dessus, cela pourrait ressembler à:


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

J'espère que cela clarifie un peu les choses.

184
Lucas Ramadan

Ce fil est trompeur. J'ai essayé de commenter la réponse de Lucas Ramadan, mais comme je n'ai pas encore les bons privilèges, je vais simplement mettre ceci ici.

La normalisation par lots fonctionne mieux après la fonction d'activation, et ici ou ici c'est pourquoi: elle a été développée pour empêcher le changement de covariable interne. Un changement de covariable interne se produit lorsque la distribution des activations d'une couche se déplace de manière significative tout au long de la formation. La normalisation des lots est utilisée pour que la distribution des entrées (et ces entrées soient littéralement le résultat d'une fonction d'activation) vers une couche spécifique ne change pas au fil du temps en raison des mises à jour des paramètres de chaque lot (ou au moins, lui permet de changer de manière avantageuse). Il utilise les statistiques de lot pour effectuer la normalisation, puis utilise les paramètres de normalisation de lot (gamma et bêta dans le document d'origine) "pour s'assurer que la transformation insérée dans le réseau peut représenter la transformation d'identité" (citation du document d'origine). Mais le fait est que nous essayons de normaliser les entrées dans une couche, elle doit donc toujours être placée juste avant la couche suivante du réseau. Que ce soit ou non après une fonction d'activation dépend de l'architecture en question.

47
jmancuso

Ce fil de discussion suscite un débat considérable sur le point de savoir si le BN doit être appliqué avant la non-linéarité du calque actuel ou pour les activations du calque précédent.

Bien qu'il n'y ait pas de réponse correcte, les auteurs de Batch Normalization disent que Il convient de l'appliquer immédiatement avant la non-linéarité du calque actuel. La raison (citée dans l'article d'origine) -

"Nous ajoutons la transformée de BN immédiatement avant la non-linéarité, en normalisant x = Wu + b. Nous aurions aussi normalisé les entrées de la couche u, mais comme u est probablement la sortie d'une autre non-linéarité, la forme de sa distribution est susceptible de changer au cours de la conversion. l’entraînement, et contraindre ses premier et deuxième moments n’éliminerait pas le changement de covariable, contrairement à Wu + b. ; normaliser est susceptible de produire des activations avec une distribution stable. "

36
user12340

Keras supporte maintenant l’option use_bias=False, nous pouvons donc sauvegarder des calculs en écrivant comme

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

ou

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

C'est presque devenu une tendance maintenant d'avoir un Conv2D suivi d'un ReLu suivi d'un BatchNormalization couche. J'ai donc composé une petite fonction pour les appeler tous en même temps. Donne à la définition du modèle un aspect beaucoup plus propre et plus facile à lire.

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

C'est un autre type de calque, vous devez donc l'ajouter en tant que calque à un emplacement approprié de votre modèle.

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

Voir un exemple ici: https://github.com/fchollet/keras/blob/master/examples/kaggle_otto_nn.py

4
Pavel Surmenok

La normalisation par lots est utilisée pour normaliser la couche d'entrée ainsi que les couches masquées en ajustant la moyenne et la mise à l'échelle des activations. En raison de cet effet normalisant associé à une couche supplémentaire dans les réseaux de neurones profonds, le réseau peut utiliser un taux d’apprentissage plus élevé sans disparaître ni exploser. De plus, la normalisation par lots régularise le réseau de manière à ce qu'il soit plus facile de généraliser et qu'il n'est donc pas nécessaire d'utiliser le décrochage pour limiter les surajustements.

Juste après le calcul de la fonction linéaire à l'aide de say, Dense () ou Conv2D () dans Keras, nous utilisons BatchNormalization () qui calcule la fonction linéaire dans une couche, puis nous ajoutons la non-linéarité à la couche à l'aide de 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)

Comment la normalisation par lots est-elle appliquée?

Supposons que nous ayons une entrée [l-1] dans une couche l. Nous avons aussi les poids W [l] et l'unité de polarisation b [l] pour la couche l. Soit a [l] le vecteur d’activation calculé (c’est-à-dire après l’ajout de la non-linéarité) pour la couche l et z [l] le vecteur avant l’ajout de la non-linéarité

  1. En utilisant [l-1] et W [l], nous pouvons calculer z [l] pour le calque l
  2. Habituellement, dans la propagation par anticipation, nous ajouterons l'unité de biais au z [l] à ce stade, comme ceci z [l] + b [l], mais dans la normalisation par lots, cette étape d'ajout de b [l] n'est pas obligatoire et non. Le paramètre b [l] est utilisé.
  3. Calculez z [l] signifie et soustrayez-le de chaque élément
  4. Divisez (z [l] - moyenne) en utilisant l’écart type. Appelez ça Z_temp [l]
  5. Définissez maintenant les nouveaux paramètres γ et β qui modifieront l’échelle de la couche masquée comme suit:

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

Dans cet extrait de code, Dense () prend a [l-1], utilise W [l] et calcule z [l]. Ensuite, la méthode BatchNormalization () immédiate effectuera les étapes ci-dessus pour donner z_norm [l]. Ensuite, l'activation immédiate () calculera tanh (z_norm [l]) pour donner un [l], à savoir.

a[l] = tanh(z_norm[l])