La capa de normalización por lotes de Keras está rota

  • 17 de abril de 2018
  • Vasilis Vryniotis
  • . 31 comentarios

La capa de normalizacion por lotes de Keras esta rota
ACTUALIZACIÓN: Lamentablemente, no se aceptó mi solicitud de extracción a Keras que cambió el comportamiento de la capa de Normalización por lotes. Puedes leer los detalles aquí. Para aquellos de ustedes que son lo suficientemente valientes como para meterse con implementaciones personalizadas, pueden encontrar el código en mi sucursal. Podría mantenerlo y fusionarlo con la última versión estable de Keras (2.1.6, 2.2.2 y 2.2.4) durante el tiempo que lo use, pero sin promesas.

La mayoría de las personas que trabajan en Deep Learning han usado o han oído hablar de Keras. Para aquellos de ustedes que no lo han hecho, es una gran biblioteca que abstrae los marcos de aprendizaje profundo subyacentes, como TensorFlow, Theano y CNTK, y proporciona una API de alto nivel para entrenar ANN. Es fácil de usar, permite la creación rápida de prototipos y tiene una comunidad amigable y activa. Lo he estado usando mucho y contribuyendo al proyecto periódicamente durante bastante tiempo y definitivamente lo recomiendo a cualquiera que quiera trabajar en Deep Learning.

Aunque Keras me hizo la vida más fácil, muchas veces me ha molestado el comportamiento extraño de la capa de normalización por lotes. Su comportamiento predeterminado ha cambiado con el tiempo, sin embargo, todavía causa problemas a muchos usuarios y, como resultado, hay varios relacionados. problemas abiertos en Github. En esta publicación de blog, intentaré explicar por qué la capa BatchNormalization de Keras no funciona bien con Transfer Learning, proporcionaré el código que soluciona el problema y daré ejemplos con los resultados de la parche.

En las subsecciones a continuación, brindo una introducción sobre cómo se usa Transfer Learning en Deep Learning, qué es la capa de normalización por lotes, cómo funciona learnining_phase y cómo Keras cambió el comportamiento de BN con el tiempo. Si ya los conoce, puede pasar con seguridad directamente a la sección 2.

1.1 Usar Transfer Learning es crucial para Deep Learning

Una de las razones por las que se criticó el aprendizaje profundo en el pasado es que requiere demasiados datos. Esto no siempre es cierto; existen varias técnicas para abordar esta limitación, una de las cuales es Transfer Learning.

Suponga que está trabajando en una aplicación de visión artificial y desea crear un clasificador que distinga a los gatos de los perros. En realidad, no necesita millones de imágenes de gatos/perros para entrenar el modelo. En su lugar, puede usar un clasificador previamente entrenado y ajustar las circunvoluciones superiores con menos datos. La idea detrás de esto es que, dado que el modelo preentrenado se ajustó a las imágenes, las circunvoluciones inferiores pueden reconocer características como líneas, bordes y otros patrones útiles, lo que significa que puede usar sus pesos como buenos valores de inicialización o volver a entrenar parcialmente la red con sus datos. .
1685087480 947 La capa de normalizacion por lotes de Keras esta rota
Keras viene con varios modelos previamente entrenados y ejemplos fáciles de usar sobre cómo ajustar los modelos. Puedes leer más en el documentación.

1.2 ¿Qué es la capa de normalización por lotes?

La capa de normalización de lotes fue introducida en 2014 por Ioffe y Szegedy. Aborda el problema del gradiente de fuga al estandarizar la salida de la capa anterior, acelera el entrenamiento al reducir el número de iteraciones requeridas y permite el entrenamiento de redes neuronales más profundas. Explicar exactamente cómo funciona está más allá del alcance de esta publicación, pero le recomiendo encarecidamente que lea el papel original. Una explicación demasiado simplificada es que vuelve a escalar la entrada restando su media y dividiéndola por su desviación estándar; también puede aprender a deshacer la transformación si es necesario.
La capa de normalizacion por lotes de Keras esta rota

1.3 ¿Qué es la fase de aprendizaje en Keras?

Algunas capas funcionan de manera diferente durante el modo de entrenamiento e inferencia. Los ejemplos más notables son las capas de normalización por lotes y abandono. En el caso de BN, durante el entrenamiento usamos la media y la varianza del mini-lote para reescalar la entrada. Por otro lado, durante la inferencia usamos la media móvil y la varianza que se estimó durante el entrenamiento.

Keras sabe en qué modo ejecutar porque tiene un mecanismo incorporado llamado fase_de_aprendizaje. La fase de aprendizaje controla si la red está en modo de entrenamiento o de prueba. Si el usuario no lo configura manualmente, durante fit() la red se ejecuta con learning_phase=1 (modo de entrenamiento). Mientras se producen predicciones (por ejemplo, cuando llamamos a los métodos predecir() y evaluar() o en el paso de validación de fit()), la red se ejecuta con learning_phase=0 (modo de prueba). Aunque no se recomienda, el usuario también puede cambiar estáticamente la fase_de_aprendizaje a un valor específico, pero esto debe suceder antes de agregar cualquier modelo o tensor en el gráfico. Si la fase_de_aprendizaje se establece de forma estática, Keras se bloqueará en el modo que haya seleccionado el usuario.

1.4 ¿Cómo implementó Keras la normalización por lotes a lo largo del tiempo?

Keras ha cambiado el comportamiento de la normalización por lotes varias veces, pero la actualización importante más reciente se produjo en Keras 2.1.3. Antes de la versión 2.1.3, cuando la capa BN estaba congelada (entrenable = Falso), seguía actualizando sus estadísticas por lotes, algo que causaba dolores de cabeza épicos a sus usuarios.

Esta no era solo una política extraña, en realidad estaba mal. Imagine que existe una capa BN entre convoluciones; si la capa está congelada, no debería ocurrirle ningún cambio. Si actualizamos parcialmente sus pesos y las siguientes capas también se congelan, nunca tendrán la oportunidad de ajustarse a las actualizaciones de las estadísticas de los mini lotes, lo que generará un mayor error. Afortunadamente, a partir de la versión 2.1.3, cuando una capa BN se congela, ya no actualiza sus estadísticas. ¿Pero es eso suficiente? No si está utilizando Transfer Learning.

A continuación, describo exactamente cuál es el problema y esbozo la implementación técnica para resolverlo. También proporciono algunos ejemplos para mostrar los efectos sobre la precisión del modelo antes y después de la parche Está aplicado.

2.1 Descripción técnica del problema

El problema con la implementación actual de Keras es que cuando una capa BN se congela, continúa usando las estadísticas de mini lotes durante el entrenamiento. Creo que un mejor enfoque cuando el BN está congelado es usar la media móvil y la varianza que aprendió durante el entrenamiento. ¿Por qué? Por las mismas razones por las que las estadísticas de minilotes no deben actualizarse cuando la capa está congelada: puede dar lugar a resultados deficientes porque las siguientes capas no se entrenan correctamente.

Suponga que está construyendo un modelo de visión por computadora pero no tiene suficientes datos, por lo que decide usar una de las CNN preentrenadas de Keras y ajustarla. Desafortunadamente, al hacerlo, no obtiene garantías de que la media y la varianza de su nuevo conjunto de datos dentro de las capas BN sean similares a las del conjunto de datos original. Recuerde que por el momento, durante el entrenamiento su red siempre usará las estadísticas de mini lotes ya sea que la capa BN esté congelada o no; también durante la inferencia utilizará las estadísticas previamente aprendidas de las capas BN congeladas. Como resultado, si ajusta las capas superiores, sus pesos se ajustarán a la media/varianza de la nuevo conjunto de datos Sin embargo, durante la inferencia recibirán datos que están escalados diferentemente porque la media/varianza de la original se utilizará el conjunto de datos.
1685087480 547 La capa de normalizacion por lotes de Keras esta rota
Arriba proporciono una arquitectura simplista (y poco realista) con fines de demostración. Supongamos que ajustamos el modelo desde Convolución k+1 hasta la parte superior de la red (lado derecho) y mantenemos congelado el fondo (lado izquierdo). Durante el entrenamiento, todas las capas BN de 1 a k usarán la media/varianza de sus datos de entrenamiento. Esto tendrá efectos negativos en las ReLU congeladas si la media y la varianza de cada BN no se acercan a las aprendidas durante el entrenamiento previo. También hará que el resto de la red (desde CONV k+1 y posteriores) se entrene con entradas que tienen diferentes escalas en comparación con lo que recibirá durante la inferencia. Durante el entrenamiento, su red puede adaptarse a estos cambios, sin embargo, en el momento en que cambia al modo de predicción, Keras utilizará diferentes estadísticas de estandarización, algo que acelerará la distribución de las entradas de las siguientes capas, lo que conducirá a resultados deficientes.

2.2 ¿Cómo puedes detectar si estás afectado?

Una forma de detectarlo es establecer estáticamente la fase de aprendizaje de Keras en 1 (modo de entrenamiento) y en 0 (modo de prueba) y evaluar su modelo en cada caso. Si hay una diferencia significativa en la precisión en el mismo conjunto de datos, el problema lo está afectando a usted. Vale la pena señalar que, debido a la forma en que se implementa el mecanismo learning_phase en Keras, normalmente no se recomienda meterse con él. Los cambios en la fase_de_aprendizaje no tendrán efecto en los modelos que ya están compilados y usados; como puede ver en los ejemplos de las siguientes subsecciones, la mejor manera de hacerlo es comenzar con una sesión limpia y cambiar la fase_de_aprendizaje antes de que se defina cualquier tensor en el gráfico.

Otra forma de detectar el problema mientras trabajar con clasificadores binarios es verificar la precisión y el AUC. Si la precisión está cerca del 50% pero el AUC está cerca de 1 (y también observa diferencias entre el modo de entrenamiento/prueba en el mismo conjunto de datos), podría ser que las probabilidades estén fuera de escala debido a las estadísticas de BN. De manera similar, para la regresión puede usar MSE y la correlación de Spearman para detectarla.

2.3 ¿Cómo podemos solucionarlo?

Creo que el problema se puede solucionar si las capas BN congeladas son en realidad solo eso: permanentemente bloqueadas en modo de prueba. En cuanto a la implementación, la bandera entrenable debe ser parte del gráfico computacional y el comportamiento del BN debe depender no solo de la fase de aprendizaje sino también del valor de la propiedad entrenable. Puede encontrar los detalles de mi implementación en Github.

Al aplicar la solución anterior, cuando una capa BN se congela, ya no usará las estadísticas de mini lotes, sino que usará las aprendidas durante el entrenamiento. Como resultado, no habrá discrepancias entre los modos de entrenamiento y prueba, lo que conduce a una mayor precisión. Obviamente, cuando la capa BN no está congelada, continuará usando las estadísticas de mini lotes durante el entrenamiento.

2.4 Evaluación de los efectos del parche

Aunque escribí la implementación anterior recientemente, la idea detrás de ella está muy probada en problemas del mundo real utilizando varias soluciones que tienen el mismo efecto. Por ejemplo, la discrepancia entre los modos de entrenamiento y prueba se puede evitar dividiendo la red en dos partes (congelada y descongelada) y realizando un entrenamiento en caché (pasando datos a través del modelo congelado una vez y luego usándolos para entrenar la red descongelada). Sin embargo, debido a que el “créanme, ya he hecho esto antes” generalmente no tiene peso, a continuación proporciono algunos ejemplos que muestran los efectos de la nueva implementación en la práctica.

Aquí hay algunos puntos importantes sobre el experimento:

  1. Usaré una pequeña cantidad de datos para sobreajustar intencionalmente el modelo y entrenaré y validaré el modelo en el mismo conjunto de datos. Al hacerlo, espero una precisión casi perfecta y un rendimiento idéntico en el conjunto de datos del tren/validación.
  2. Si durante la validación obtengo una precisión significativamente menor en el mismo conjunto de datos, tendré una indicación clara de que la política actual de BN afecta negativamente el rendimiento del modelo durante la inferencia.
  3. Cualquier preprocesamiento tendrá lugar fuera de Generators. Esto se hace para solucionar un error que se introdujo en la versión 2.1.5 (actualmente solucionado en la próxima versión 2.1.6 y la versión maestra más reciente).
  4. Obligaremos a Keras a utilizar diferentes fases de aprendizaje durante la evaluación. Si detectamos diferencias entre la precisión informada, sabremos que estamos afectados por la política actual de BN.

El código para el experimento se muestra a continuación:

import numpy as np
from keras.datasets import cifar10
from scipy.misc import imresize

from keras.preprocessing.image import ImageDataGenerator
from keras.applications.resnet50 import ResNet50, preprocess_input
from keras.models import Model, load_model
from keras.layers import Dense, Flatten
from keras import backend as K


seed = 42
epochs = 10
records_per_class = 100

# We take only 2 classes from CIFAR10 and a very small sample to intentionally overfit the model.
# We will also use the same data for train/test and expect that Keras will give the same accuracy.
(x, y), _ = cifar10.load_data()

def filter_resize(category):
   # We do the preprocessing here instead in the Generator to get around a bug on Keras 2.1.5.
   return [preprocess_input(imresize(img, (224,224)).astype('float')) for img in x[y.flatten()==category][:records_per_class]]

x = np.stack(filter_resize(3)+filter_resize(5))
records_per_class = x.shape[0] // 2
y = np.array([[1,0]]*records_per_class + [[0,1]]*records_per_class)


# We will use a pre-trained model and finetune the top layers.
np.random.seed(seed)
base_model = ResNet50(weights="imagenet", include_top=False, input_shape=(224, 224, 3))
l = Flatten()(base_model.output)
predictions = Dense(2, activation='softmax')(l)
model = Model(inputs=base_model.input, outputs=predictions)

for layer in model.layers[:140]:
   layer.trainable = False

for layer in model.layers[140:]:
   layer.trainable = True

model.compile(optimizer="sgd", loss="categorical_crossentropy", metrics=['accuracy'])
model.fit_generator(ImageDataGenerator().flow(x, y, seed=42), epochs=epochs, validation_data=ImageDataGenerator().flow(x, y, seed=42))

# Store the model on disk
model.save('tmp.h5')


# In every test we will clear the session and reload the model to force Learning_Phase values to change.
print('DYNAMIC LEARNING_PHASE')
K.clear_session()
model = load_model('tmp.h5')
# This accuracy should match exactly the one of the validation set on the last iteration.
print(model.evaluate_generator(ImageDataGenerator().flow(x, y, seed=42)))


print('STATIC LEARNING_PHASE = 0')
K.clear_session()
K.set_learning_phase(0)
model = load_model('tmp.h5')
# Again the accuracy should match the above.
print(model.evaluate_generator(ImageDataGenerator().flow(x, y, seed=42)))


print('STATIC LEARNING_PHASE = 1')
K.clear_session()
K.set_learning_phase(1)
model = load_model('tmp.h5')
# The accuracy will be close to the one of the training set on the last iteration.
print(model.evaluate_generator(ImageDataGenerator().flow(x, y, seed=42)))

Veamos los resultados en Keras v2.1.5:

Epoch 1/10
1/7 [===>..........................] - ETA: 25s - loss: 0.8751 - acc: 0.5312
2/7 [=======>......................] - ETA: 11s - loss: 0.8594 - acc: 0.4531
3/7 [===========>..................] - ETA: 7s - loss: 0.8398 - acc: 0.4688 
4/7 [================>.............] - ETA: 4s - loss: 0.8467 - acc: 0.4844
5/7 [====================>.........] - ETA: 2s - loss: 0.7904 - acc: 0.5437
6/7 [========================>.....] - ETA: 1s - loss: 0.7593 - acc: 0.5625
7/7 [==============================] - 12s 2s/step - loss: 0.7536 - acc: 0.5744 - val_loss: 0.6526 - val_acc: 0.6650

Epoch 2/10
1/7 [===>..........................] - ETA: 4s - loss: 0.3881 - acc: 0.8125
2/7 [=======>......................] - ETA: 3s - loss: 0.3945 - acc: 0.7812
3/7 [===========>..................] - ETA: 2s - loss: 0.3956 - acc: 0.8229
4/7 [================>.............] - ETA: 1s - loss: 0.4223 - acc: 0.8047
5/7 [====================>.........] - ETA: 1s - loss: 0.4483 - acc: 0.7812
6/7 [========================>.....] - ETA: 0s - loss: 0.4325 - acc: 0.7917
7/7 [==============================] - 8s 1s/step - loss: 0.4095 - acc: 0.8089 - val_loss: 0.4722 - val_acc: 0.7700

Epoch 3/10
1/7 [===>..........................] - ETA: 4s - loss: 0.2246 - acc: 0.9375
2/7 [=======>......................] - ETA: 3s - loss: 0.2167 - acc: 0.9375
3/7 [===========>..................] - ETA: 2s - loss: 0.2260 - acc: 0.9479
4/7 [================>.............] - ETA: 2s - loss: 0.2179 - acc: 0.9375
5/7 [====================>.........] - ETA: 1s - loss: 0.2356 - acc: 0.9313
6/7 [========================>.....] - ETA: 0s - loss: 0.2392 - acc: 0.9427
7/7 [==============================] - 8s 1s/step - loss: 0.2288 - acc: 0.9456 - val_loss: 0.4282 - val_acc: 0.7800

Epoch 4/10
1/7 [===>..........................] - ETA: 4s - loss: 0.2183 - acc: 0.9688
2/7 [=======>......................] - ETA: 3s - loss: 0.1899 - acc: 0.9844
3/7 [===========>..................] - ETA: 2s - loss: 0.1887 - acc: 0.9792
4/7 [================>.............] - ETA: 1s - loss: 0.1995 - acc: 0.9531
5/7 [====================>.........] - ETA: 1s - loss: 0.1932 - acc: 0.9625
6/7 [========================>.....] - ETA: 0s - loss: 0.1819 - acc: 0.9688
7/7 [==============================] - 8s 1s/step - loss: 0.1743 - acc: 0.9747 - val_loss: 0.3778 - val_acc: 0.8400

Epoch 5/10
1/7 [===>..........................] - ETA: 3s - loss: 0.0973 - acc: 1.0000
2/7 [=======>......................] - ETA: 3s - loss: 0.0828 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0851 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0897 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0928 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0936 - acc: 1.0000
7/7 [==============================] - 8s 1s/step - loss: 0.1337 - acc: 0.9838 - val_loss: 0.3916 - val_acc: 0.8100

Epoch 6/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0747 - acc: 1.0000
2/7 [=======>......................] - ETA: 3s - loss: 0.0852 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0812 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0831 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0779 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0766 - acc: 1.0000
7/7 [==============================] - 8s 1s/step - loss: 0.0813 - acc: 1.0000 - val_loss: 0.3637 - val_acc: 0.8550

Epoch 7/10
1/7 [===>..........................] - ETA: 1s - loss: 0.2478 - acc: 0.8750
2/7 [=======>......................] - ETA: 2s - loss: 0.1966 - acc: 0.9375
3/7 [===========>..................] - ETA: 2s - loss: 0.1528 - acc: 0.9583
4/7 [================>.............] - ETA: 1s - loss: 0.1300 - acc: 0.9688
5/7 [====================>.........] - ETA: 1s - loss: 0.1193 - acc: 0.9750
6/7 [========================>.....] - ETA: 0s - loss: 0.1196 - acc: 0.9792
7/7 [==============================] - 8s 1s/step - loss: 0.1084 - acc: 0.9838 - val_loss: 0.3546 - val_acc: 0.8600

Epoch 8/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0539 - acc: 1.0000
2/7 [=======>......................] - ETA: 2s - loss: 0.0900 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0815 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0740 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0700 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0701 - acc: 1.0000
7/7 [==============================] - 8s 1s/step - loss: 0.0695 - acc: 1.0000 - val_loss: 0.3269 - val_acc: 0.8600

Epoch 9/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0306 - acc: 1.0000
2/7 [=======>......................] - ETA: 3s - loss: 0.0377 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0898 - acc: 0.9583
4/7 [================>.............] - ETA: 1s - loss: 0.0773 - acc: 0.9688
5/7 [====================>.........] - ETA: 1s - loss: 0.0742 - acc: 0.9750
6/7 [========================>.....] - ETA: 0s - loss: 0.0708 - acc: 0.9792
7/7 [==============================] - 8s 1s/step - loss: 0.0659 - acc: 0.9838 - val_loss: 0.3604 - val_acc: 0.8600

Epoch 10/10
1/7 [===>..........................] - ETA: 3s - loss: 0.0354 - acc: 1.0000
2/7 [=======>......................] - ETA: 3s - loss: 0.0381 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0354 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0828 - acc: 0.9688
5/7 [====================>.........] - ETA: 1s - loss: 0.0791 - acc: 0.9750
6/7 [========================>.....] - ETA: 0s - loss: 0.0794 - acc: 0.9792
7/7 [==============================] - 8s 1s/step - loss: 0.0704 - acc: 0.9838 - val_loss: 0.3615 - val_acc: 0.8600

DYNAMIC LEARNING_PHASE
[0.3614931714534759, 0.86]

STATIC LEARNING_PHASE = 0
[0.3614931714534759, 0.86]

STATIC LEARNING_PHASE = 1
[0.025861846953630446, 1.0]

Como podemos ver arriba, durante el entrenamiento, el modelo aprende muy bien los datos y logra una precisión casi perfecta en el conjunto de entrenamiento. Aún al final de cada iteración, al evaluar el modelo en el mismo conjunto de datos, obtenemos diferencias significativas en la pérdida y la precisión. Tenga en cuenta que no deberíamos obtener esto; hemos sobreajustado intencionalmente el modelo en el conjunto de datos específico y los conjuntos de datos de entrenamiento/validación son idénticos.

Una vez que se completa el entrenamiento, evaluamos el modelo usando 3 configuraciones diferentes de fase de aprendizaje: dinámica, estática = 0 (modo de prueba) y estática = 1 (modo de entrenamiento). Como podemos ver, las dos primeras configuraciones proporcionarán resultados idénticos en términos de pérdida y precisión, y su valor coincide con la precisión informada del modelo en el conjunto de validación en la última iteración. Sin embargo, una vez que cambiamos al modo de entrenamiento, observamos una gran discrepancia (mejoría). ¿Por qué es eso? Como dijimos anteriormente, los pesos de la red se ajustan esperando recibir datos escalados con la media/varianza de los datos de entrenamiento. Desafortunadamente, esas estadísticas son diferentes de las almacenadas en las capas BN. Dado que las capas BN estaban congeladas, estas estadísticas nunca se actualizaron. Esta discrepancia entre los valores de las estadísticas BN conduce al deterioro de la precisión durante la inferencia.

Veamos qué sucede una vez que aplicamos el parche:

Epoch 1/10
1/7 [===>..........................] - ETA: 26s - loss: 0.9992 - acc: 0.4375
2/7 [=======>......................] - ETA: 12s - loss: 1.0534 - acc: 0.4375
3/7 [===========>..................] - ETA: 7s - loss: 1.0592 - acc: 0.4479 
4/7 [================>.............] - ETA: 4s - loss: 0.9618 - acc: 0.5000
5/7 [====================>.........] - ETA: 2s - loss: 0.8933 - acc: 0.5250
6/7 [========================>.....] - ETA: 1s - loss: 0.8638 - acc: 0.5417
7/7 [==============================] - 13s 2s/step - loss: 0.8357 - acc: 0.5570 - val_loss: 0.2414 - val_acc: 0.9450

Epoch 2/10
1/7 [===>..........................] - ETA: 4s - loss: 0.2331 - acc: 0.9688
2/7 [=======>......................] - ETA: 2s - loss: 0.3308 - acc: 0.8594
3/7 [===========>..................] - ETA: 2s - loss: 0.3986 - acc: 0.8125
4/7 [================>.............] - ETA: 1s - loss: 0.3721 - acc: 0.8281
5/7 [====================>.........] - ETA: 1s - loss: 0.3449 - acc: 0.8438
6/7 [========================>.....] - ETA: 0s - loss: 0.3168 - acc: 0.8646
7/7 [==============================] - 9s 1s/step - loss: 0.3165 - acc: 0.8633 - val_loss: 0.1167 - val_acc: 0.9950

Epoch 3/10
1/7 [===>..........................] - ETA: 1s - loss: 0.2457 - acc: 1.0000
2/7 [=======>......................] - ETA: 2s - loss: 0.2592 - acc: 0.9688
3/7 [===========>..................] - ETA: 2s - loss: 0.2173 - acc: 0.9688
4/7 [================>.............] - ETA: 1s - loss: 0.2122 - acc: 0.9688
5/7 [====================>.........] - ETA: 1s - loss: 0.2003 - acc: 0.9688
6/7 [========================>.....] - ETA: 0s - loss: 0.1896 - acc: 0.9740
7/7 [==============================] - 9s 1s/step - loss: 0.1835 - acc: 0.9773 - val_loss: 0.0678 - val_acc: 1.0000

Epoch 4/10
1/7 [===>..........................] - ETA: 1s - loss: 0.2051 - acc: 1.0000
2/7 [=======>......................] - ETA: 2s - loss: 0.1652 - acc: 0.9844
3/7 [===========>..................] - ETA: 2s - loss: 0.1423 - acc: 0.9896
4/7 [================>.............] - ETA: 1s - loss: 0.1289 - acc: 0.9922
5/7 [====================>.........] - ETA: 1s - loss: 0.1225 - acc: 0.9938
6/7 [========================>.....] - ETA: 0s - loss: 0.1149 - acc: 0.9948
7/7 [==============================] - 9s 1s/step - loss: 0.1060 - acc: 0.9955 - val_loss: 0.0455 - val_acc: 1.0000

Epoch 5/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0769 - acc: 1.0000
2/7 [=======>......................] - ETA: 2s - loss: 0.0846 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0797 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0736 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0914 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0858 - acc: 1.0000
7/7 [==============================] - 9s 1s/step - loss: 0.0808 - acc: 1.0000 - val_loss: 0.0346 - val_acc: 1.0000

Epoch 6/10
1/7 [===>..........................] - ETA: 1s - loss: 0.1267 - acc: 1.0000
2/7 [=======>......................] - ETA: 2s - loss: 0.1039 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0893 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0780 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0758 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0789 - acc: 1.0000
7/7 [==============================] - 9s 1s/step - loss: 0.0738 - acc: 1.0000 - val_loss: 0.0248 - val_acc: 1.0000

Epoch 7/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0344 - acc: 1.0000
2/7 [=======>......................] - ETA: 3s - loss: 0.0385 - acc: 1.0000
3/7 [===========>..................] - ETA: 3s - loss: 0.0467 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0445 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0446 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0429 - acc: 1.0000
7/7 [==============================] - 9s 1s/step - loss: 0.0421 - acc: 1.0000 - val_loss: 0.0202 - val_acc: 1.0000

Epoch 8/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0319 - acc: 1.0000
2/7 [=======>......................] - ETA: 3s - loss: 0.0300 - acc: 1.0000
3/7 [===========>..................] - ETA: 3s - loss: 0.0320 - acc: 1.0000
4/7 [================>.............] - ETA: 2s - loss: 0.0307 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0303 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0291 - acc: 1.0000
7/7 [==============================] - 9s 1s/step - loss: 0.0358 - acc: 1.0000 - val_loss: 0.0167 - val_acc: 1.0000

Epoch 9/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0246 - acc: 1.0000
2/7 [=======>......................] - ETA: 3s - loss: 0.0255 - acc: 1.0000
3/7 [===========>..................] - ETA: 3s - loss: 0.0258 - acc: 1.0000
4/7 [================>.............] - ETA: 2s - loss: 0.0250 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0252 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0260 - acc: 1.0000
7/7 [==============================] - 9s 1s/step - loss: 0.0327 - acc: 1.0000 - val_loss: 0.0143 - val_acc: 1.0000

Epoch 10/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0251 - acc: 1.0000
2/7 [=======>......................] - ETA: 2s - loss: 0.0228 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0217 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0249 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0244 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0239 - acc: 1.0000
7/7 [==============================] - 9s 1s/step - loss: 0.0290 - acc: 1.0000 - val_loss: 0.0127 - val_acc: 1.0000

DYNAMIC LEARNING_PHASE
[0.012697912137955427, 1.0]

STATIC LEARNING_PHASE = 0
[0.012697912137955427, 1.0]

STATIC LEARNING_PHASE = 1
[0.01744014158844948, 1.0]

En primer lugar, observamos que la red converge significativamente más rápido y logra una precisión perfecta. También vemos que ya no hay discrepancia en términos de precisión cuando cambiamos entre diferentes valores de fase de aprendizaje.

2.5 ¿Cómo funciona el parche en un conjunto de datos real?

Entonces, ¿cómo funciona el parche en un experimento más realista? Usemos el ResNet50 preentrenado de Keras (que originalmente encajaba en imagenet), eliminemos la capa de clasificación superior y la ajustemos con y sin el parche y comparemos los resultados. Para los datos, utilizaremos CIFAR10 (la división estándar de tren/prueba proporcionada por Keras) y cambiaremos el tamaño de las imágenes a 224 × 224 para que sean compatibles con el tamaño de entrada de ResNet50.

Haremos 10 épocas para entrenar la capa de clasificación superior usando RSMprop y luego haremos otras 5 para afinar todo después de la capa 139 usando SGD (lr=1e-4, impulso=0.9). Sin el parche nuestro modelo alcanza una precisión del 87,44%. Usando el parche, obtenemos una precisión del 92,36%, casi 5 puntos más.

2.6 ¿Deberíamos aplicar la misma corrección a otras capas como Dropout?

La normalización por lotes no es la única capa que funciona de manera diferente entre los modos de entrenamiento y prueba. El abandono y sus variantes también tienen el mismo efecto. ¿Deberíamos aplicar la misma política a todas estas capas? Creo que no (aunque me encantaría escuchar sus pensamientos sobre esto). La razón es que Dropout se usa para evitar el sobreajuste, por lo que bloquearlo permanentemente en el modo de predicción durante el entrenamiento anularía su propósito. ¿Qué opinas?

Creo firmemente que esta discrepancia debe resolverse en Keras. He visto efectos aún más profundos (del 100 % al 50 % de precisión) en aplicaciones del mundo real causados ​​por este problema. I planea enviar ya envié un relaciones públicas a Keras con la solución y, con suerte, será aceptada.

Si te gustó esta publicación de blog, tómate un momento para compartirla en Facebook o Twitter. 🙂

Fuente del artículo

Deja un comentario