La capa de normalización por lotes de Keras está rota PlatoBlockchain Data Intelligence. Búsqueda vertical. Ai.

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

ACTUALIZACIÓN: Desafortunadamente, mi solicitud de extracción a Keras que cambió el comportamiento de la capa de Normalización de lote no fue aceptada. Puedes leer los detalles esta página. Para aquellos de ustedes que son lo suficientemente valientes como para meterse con implementaciones personalizadas, pueden encontrar el código en mi rama. 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 uso, pero sin promesas.

La mayoría de las personas que trabajan en Deep Learning han usado o escuchado sobre Keras. Para aquellos de ustedes que no lo han hecho, es una gran biblioteca que abstrae los marcos subyacentes de Deep Learning, como TensorFlow, Theano y CNTK, y proporciona un API de alto nivel para entrenar ANNs. Es fácil de usar, permite la creación rápida de prototipos y tiene una comunidad activa amigable. Lo he estado usando mucho y contribuí 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 mordido el extraño comportamiento de la capa de Normalización de 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é desarrollar un caso sobre por qué la capa Bormalización de lotes de Keras no funciona bien con Transfer Learning, proporcionaré el código que soluciona el problema y daré ejemplos con los resultados de parche.

En las subsecciones a continuación, proporciono una introducción sobre cómo se usa Transfer Learning en Deep Learning, qué es la capa Batch Normalization, cómo funciona learnining_phase y cómo Keras cambió el comportamiento de BN con el tiempo. Si ya los conoce, puede saltar directamente a la sección 2 de manera segura.

1.1 El uso de Transfer Learning es crucial para Deep Learning

Una de las razones por las cuales Deep Learning fue criticado 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 el aprendizaje de transferencia.

Suponga que está trabajando en una aplicación de Visión por computadora y que desea crear un clasificador que distinga a los gatos de los perros. En realidad, no necesitas millones de imágenes de perros / gatos para entrenar a la modelo. En su lugar, puede usar un clasificador previamente entrenado y ajustar las circunvoluciones principales con menos datos. La idea detrás de esto es que, dado que el modelo previamente entrenado se ajustaba 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 reentrenar parcialmente la red con sus datos .
La capa de normalización por lotes de Keras está rota PlatoBlockchain Data Intelligence. Búsqueda vertical. Ai.
Keras viene con varios modelos previamente entrenados y ejemplos fáciles de usar sobre cómo ajustar los modelos. Puedes leer más sobre el documentación.

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

La capa de normalización por 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 que lea el papel original. Una explicación demasiado simplificada es que reescala la entrada restando su media y dividiéndola con su desviación estándar; También puede aprender a deshacer la transformación si es necesario.
La capa de normalización por lotes de Keras está rota PlatoBlockchain Data Intelligence. Búsqueda vertical. Ai.

1.3 ¿Cuál es la fase de aprendizaje en Keras?

Algunas capas funcionan de manera diferente durante el entrenamiento y el modo de inferencia. Los ejemplos más notables son las capas de Normalización de lote y Deserción. 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 el promedio 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 tren o de prueba. Si el usuario no lo configura manualmente, durante el ajuste () la red se ejecuta con learning_phase = 1 (modo de tren). Al producir predicciones (por ejemplo, cuando llamamos a los métodos predict () & Evaluation () o en el paso de validación del ajuste ()), 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 que se agregue cualquier modelo o tensor en el gráfico. Si learning_phase se establece estáticamente, Keras se bloqueará en cualquier modo que el usuario haya seleccionado.

1.4 ¿Cómo implementó Keras la Normalización de lotes con el tiempo?

Keras ha cambiado el comportamiento de la Normalización de lotes varias veces, pero la actualización significativa más reciente ocurrió en Keras 2.1.3. Antes de v2.1.3, cuando la capa BN estaba congelada (entrenable = Falso), seguía actualizando sus estadísticas de lotes, algo que causó 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ían ocurrirle cambios. Si actualizamos parcialmente sus pesos y las siguientes capas también están congeladas, nunca tendrán la oportunidad de ajustarse a las actualizaciones de las estadísticas de mini lotes que conducen a un error mayor. Afortunadamente, a partir de la versión 2.1.3, cuando una capa BN está congelada, 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 del 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 está congelada, 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 cuales las estadísticas de mini lotes no deben actualizarse cuando la capa está congelada: puede dar resultados pobres porque las siguientes capas no están entrenadas adecuadamente.

Suponga que está construyendo un modelo de Visión por Computadora pero que no tiene suficientes datos, por lo que decide usar una de las CNN pre-entrenadas de Keras y afinarla. 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 serán similares a las del conjunto de datos original. Recuerde que en este momento, durante el entrenamiento, su red siempre utilizará 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 aprendidas previamente de las capas BN congeladas. Como resultado, si ajusta las capas superiores, sus pesos se ajustarán a la media / varianza de nueva conjunto de datos Sin embargo, durante la inferencia recibirán datos que se escalan diferentemente porque la media / varianza de la reconocida por Se utilizará el conjunto de datos.
La capa de normalización por lotes de Keras está rota PlatoBlockchain Data Intelligence. Búsqueda vertical. Ai.
Arriba proporciono una arquitectura simplista (y poco realista) para fines de demostración. Supongamos que ajustamos el modelo desde la 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 utilizarán la media / varianza de sus datos de entrenamiento. Esto tendrá efectos negativos en las ReLU congeladas si la media y la varianza en cada BN no son cercanas a las aprendidas durante el entrenamiento previo. También hará que el resto de la red (desde CONV k + 1 y posterior) 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 cambie 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 y dará lugar a malos resultados.

2.2 ¿Cómo puede detectar si está 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. Vale la pena señalar que, debido a la forma en que se implementa el mecanismo learning_phase en Keras, generalmente 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 utilizados; Como puede ver en los ejemplos en las siguientes subsecciones, la mejor manera de hacerlo es comenzar con una sesión limpia y cambiar la fase de aprendizaje antes de definir cualquier tensor en el gráfico.

Otra forma de detectar el problema mientras se trabaja con clasificadores binarios es verificar la precisión y el AUC. Si la precisión es cercana al 50% pero el AUC está cerca de 1 (y también observa diferencias entre el modo de tren / 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. Del mismo modo, para la regresión, puede usar MSE y la correlación de Spearman para detectarlo.

2.3 ¿Cómo podemos solucionarlo?

Creo que el problema se puede solucionar si las capas de BN congeladas son solo eso: permanentemente bloqueadas en modo de prueba. En cuanto a la implementación, el indicador 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 corrección anterior, cuando una capa BN está congelada, 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 que conducen a una mayor precisión. Obviamente, cuando la capa BN no está congelada, continuará utilizando las estadísticas de mini lotes durante el entrenamiento.

2.4 Evaluar los efectos del parche

A pesar de que escribí la implementación anterior recientemente, la idea detrás de esto 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 no congelada) y realizando capacitación en caché (pasando datos a través del modelo congelado una vez y luego usándolos para entrenar la red no congelada). Sin embargo, debido a que "confía en mí, 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 de validación / tren.
  2. Si durante la validación obtengo una precisión significativamente menor en el mismo conjunto de datos, tendré una clara indicación de que la política actual de BN afecta negativamente el rendimiento del modelo durante la inferencia.
  3. Cualquier preprocesamiento tendrá lugar fuera de los generadores. Esto se hace para evitar un error que se introdujo en v2.1.5 (actualmente corregido en la próxima v2.1.6 y la última versión maestra).
  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 en el conjunto de entrenamiento una precisión casi perfecta. Aún al final de cada iteración, mientras evaluamos el modelo en el mismo conjunto de datos, obtenemos diferencias significativas en pérdida y precisión. Tenga en cuenta que no deberíamos estar recibiendo esto; Hemos sobreajustado intencionalmente el modelo en el conjunto de datos específico y los conjuntos de datos de capacitación / validación son idénticos.

Una vez completado el entrenamiento, evaluamos el modelo usando 3 configuraciones diferentes de la fase de aprendizaje: Dinámico, Estático = 0 (modo de prueba) y Estático = 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 (mejora). ¿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 se congelaron, estas estadísticas nunca se actualizaron. Esta discrepancia entre los valores de las estadísticas de 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 una 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 pre-entrenado de Keras (originalmente instalado en imagenet), elimine la capa de clasificación superior y ajústela con y sin el parche y compare los resultados. Para los datos, utilizaremos CIFAR10 (la división estándar de tren / prueba proporcionada por Keras) y redimensionaremos 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 ajustar todo después de la capa 139 usando SGD (lr = 1e-4, momento = 0.9). Sin el parche, nuestro modelo logra 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 tren y prueba. La deserción 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 tu opinión sobre esto). La razón es que Dropout se usa para evitar el sobreajuste, por lo que bloquearlo permanentemente al modo de predicción durante el entrenamiento sería contrario a su propósito. ¿Qué piensas?

Creo firmemente que esta discrepancia debe resolverse en Keras. He visto efectos aún más profundos (desde 100% hasta 50% de precisión) en aplicaciones del mundo real causadas por este problema. yo planea enviar ya envió un PR a Keras con la solución y con suerte será aceptado.

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

Sello de tiempo:

Mas de Caja de datos