¿Dónde llamo a la función BatchNormalization en Keras?

11 minutos de lectura

avatar de usuario
pr338

Si quiero usar la función BatchNormalization en Keras, ¿tengo que llamarla una sola vez al principio?

Leí esta documentación para ello: http://keras.io/layers/normalization/

No veo dónde se supone que debo llamarlo. A continuación se muestra mi código tratando de usarlo:

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)

Pregunto porque si ejecuto el código con la segunda línea, incluida la normalización por lotes, y si ejecuto el código sin la segunda línea, obtengo resultados similares. Entonces, o no estoy llamando a la función en el lugar correcto, o supongo que no hace mucha diferencia.

Solo para responder esta pregunta con un poco más de detalle, y como dijo Pavel, la Normalización por lotes es solo otra capa, por lo que puede usarla como tal para crear la arquitectura de red que desee.

El caso de uso general es usar BN entre las capas lineales y no lineales en su red, porque normaliza la entrada a su función de activación, para que esté centrado en la sección lineal de la función de activación (como Sigmoid). Hay una pequeña discusión al respecto. aquí

En su caso anterior, esto podría verse así:


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

Espero que esto aclare las cosas un poco más.

  • FYI aparentemente la normalización por lotes funciona mejor en la práctica después de la función de activación

    – claudio

    5 de octubre de 2016 a las 9:39

  • Hola @Claudiu, ¿te importaría ampliar este tema para tu información? Parece contradecir directamente la respuesta anterior.

    – Ben Ogorek

    06/10/2016 a las 12:51

  • @benogorek: claro, básicamente lo basé completamente en los resultados aquí donde colocar la norma del lote después del relu funcionó mejor. FWIW No he tenido éxito aplicándolo de una forma u otra en la única red que he probado

    – claudio

    06/10/2016 a las 13:41

  • Interesante. Solo para dar seguimiento, si continúa leyendo en ese resumen, dice que su mejor modelo [GoogLeNet128_BN_lim0606] en realidad tiene la capa BN ANTES del ReLU. Entonces, si bien BN después de la activación podría mejorar la precisión en un caso aislado, cuando se construye todo el modelo, antes funciona mejor. Es probable que colocar BN después de la Activación pueda mejorar la precisión, pero es probable que dependa del problema.

    – Lucas Ramadán

    06/10/2016 a las 20:55


  • @CarlThomé más o menos. Ver este reddit comentario de ReginaldIII, por ejemplo. Afirman: “BN está normalizando la distribución de características que salen de una convolución, algunas [of] estas características pueden ser negativas [and] truncado por una no linealidad como ReLU. Si normaliza antes de la activación, está incluyendo estos valores negativos en la normalización inmediatamente antes de eliminarlos del espacio de funciones. BN después de la activación normalizará las características positivas sin sesgarlas estadísticamente con características que no pasan a la siguiente capa convolucional”.

    – mab

    29 de agosto de 2017 a las 8:26


Este hilo es engañoso. Intenté comentar la respuesta de Lucas Ramadan, pero aún no tengo los privilegios correctos, así que solo pondré esto aquí.

La normalización por lotes funciona mejor después de la función de activación, y aquí o aquí es por eso: fue desarrollado para prevenir el cambio de covariable interno. El cambio de covariable interna ocurre cuando la distribución de la activaciones de una capa cambia significativamente a lo largo del entrenamiento. La normalización por lotes se usa para que la distribución de las entradas (y estas entradas son literalmente el resultado de una función de activación) a una capa específica no cambie con el tiempo debido a las actualizaciones de parámetros de cada lote (o al menos, permite que cambie). de manera ventajosa). Utiliza estadísticas por lotes para realizar la normalización y luego usa los parámetros de normalización por lotes (gamma y beta en el artículo original) “para asegurarse de que la transformación insertada en la red pueda representar la transformación de identidad” (cita del artículo original). Pero el punto es que estamos tratando de normalizar las entradas a una capa, por lo que siempre debe ir inmediatamente antes de la siguiente capa en la red. Si eso es o no después de una función de activación depende de la arquitectura en cuestión.

  • Acabo de ver en la clase de deeplearning.ai que Andrew Ng dice que hay un debate sobre esto en la comunidad de aprendizaje profundo. Prefiere aplicar la normalización por lotes antes que la no linealidad.

    – Shahensha

    1 de noviembre de 2017 a las 5:24

  • @kRazzyR Quise decir que el Prof. Andrew Ng habló sobre este tema en sus clases de aprendizaje profundo en aprendizajeprofundo.ai Dijo que la comunidad está dividida sobre la forma correcta de hacer las cosas y que prefería aplicar la normalización por lotes antes que aplicar la no linealidad.

    – Shahensha

    02/04/2018 a las 20:48


  • @jmancuso, BN se aplica antes de la activación. Del papel mismo, la ecuación es g(BN(Wx + b)) dónde g es la función de activación.

    – o12d10

    15 de enero de 2019 a las 18:54

  • Antes son después es apropiado para probar. Nadie sabe de antemano cuál es mejor en la práctica. Pero teóricamente sí, antes la no linealidad tiene más sentido.

    – Serguéi Bushmanov

    9 sep 2021 a las 18:30

avatar de usuario
usuario12340

Este hilo tiene un debate considerable sobre si BN debe aplicarse antes de la no linealidad de la capa actual o para las activaciones de la capa anterior.

Aunque no hay una respuesta correcta, los autores de Batch Normalization dicen que
Debe aplicarse inmediatamente antes de la no linealidad de la capa actual. La razón (citado del artículo original) –

“Agregamos la transformada BN inmediatamente antes de la no linealidad, al normalizar x = Wu+b. También podríamos haber normalizado las entradas de la capa u, pero dado que u es probablemente la salida de otra no linealidad, es probable que la forma de su distribución cambie durante entrenamiento, y restringir su primer y segundo momento no eliminaría el cambio de covariable. Por el contrario, es más probable que Wu + b tenga una distribución simétrica, no dispersa, que es “más gaussiana” (Hyv¨arinen & Oja, 2000) ; normalizarlo es probable que produzca activaciones con una distribución estable”.

  • En mi propia experiencia personal, no hace una gran diferencia, pero en igualdad de condiciones, siempre he visto que BN funciona un poco mejor cuando se aplica la normalización por lotes antes que la no linealidad (antes de la función de activación).

    – Brad Hesse

    02/10/2017 a las 19:24

avatar de usuario
no loo

Keras ahora admite la use_bias=False opción, por lo que podemos ahorrar algunos cálculos escribiendo como

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

Ahora casi se ha convertido en una tendencia tener una Conv2D seguido de un ReLu seguido de un BatchNormalization capa. Así que inventé una pequeña función para llamarlos a todos a la vez. Hace que la definición del modelo se vea mucho más limpia y fácil de leer.

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

  • tal vez empujar esto a keras?

    – sachinruk

    22 de marzo de 2017 a las 23:06

avatar de usuario
Aishwarya Radhakrishnan

La normalización por lotes se utiliza para normalizar la capa de entrada, así como las capas ocultas, ajustando la media y la escala de las activaciones. Debido a este efecto de normalización con una capa adicional en las redes neuronales profundas, la red puede usar una tasa de aprendizaje más alta sin gradientes que desaparezcan o exploten. Además, la normalización por lotes regulariza la red de manera que es más fácil de generalizar y, por lo tanto, no es necesario utilizar el abandono para mitigar el sobreajuste.

Inmediatamente después de calcular la función lineal usando Dense() o Conv2D() en Keras, usamos BatchNormalization() que calcula la función lineal en una capa y luego agregamos la no linealidad a la capa 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)

¿Cómo se aplica la normalización por lotes?

Supongamos que hemos introducido un[l-1] a una capa l. También tenemos pesos W[l] y unidad de polarización b[l] para la capa l. Deja un[l] sea ​​el vector de activación calculado (es decir, después de agregar la no linealidad) para la capa l y z[l] ser el vector antes de agregar la no linealidad

  1. Usando un[l-1] y W[l] podemos calcular z[l] para la capa l
  2. Por lo general, en la propagación de alimentación hacia adelante, agregaremos una unidad de polarización a la z[l] en esta etapa como esta z[l]+b[l]pero en la normalización por lotes este paso de adición de b[l] no se requiere y no b[l] se utiliza el parámetro.
  3. Calcular z[l] significa y restarlo de cada elemento
  4. Dividir (z[l] – media) utilizando la desviación estándar. Llámalo Z_temp[l]
  5. Ahora defina nuevos parámetros γ y β que cambiarán la escala de la capa oculta de la siguiente manera:

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

En este extracto de código, Dense() toma el a[l-1]utiliza W[l] y calcula z[l]. Luego, el BatchNormalization() inmediato realizará los pasos anteriores para dar z_norm[l]. Y luego la activación inmediata () calculará tanh (z_norm[l]) para dar un[l] es decir

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

  • tal vez empujar esto a keras?

    – sachinruk

    22 de marzo de 2017 a las 23:06

avatar de usuario
Pavel Surmenok

Es otro tipo de capa, por lo que debe agregarla como una capa en un lugar apropiado de su modelo.

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

Vea un ejemplo aquí: https://github.com/fchollet/keras/blob/master/examples/kaggle_otto_nn.py

  • Después de agregar BatchNormalization, val_acc dejó de aumentar cada época. El val_acc permaneció estancado en el mismo número después de cada época después de que agregué BatchNormalization. Pensé que se suponía que la Normalización por lotes aumentaría el valor de val_acc. ¿Cómo puedo saber si está funcionando correctamente? ¿Sabes qué puede haber causado esto?

    – pr338

    14 de enero de 2016 a las 6:12

  • lamentablemente el enlace ya no es valido 🙁

    – usuario2324712

    21 de mayo de 2016 a las 13:58

  • Hay copias de ese ejemplo en forks de Keras (por ejemplo github.com/WenchenLi/kaggle/blob/master/otto/keras/…), pero no sé por qué se eliminó del repositorio original de Keras y si el código es compatible con las últimas versiones de Keras.

    – Pavel Surmenok

    23/09/2016 a las 16:15

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad