Path: blob/master/site/es-419/tutorials/keras/overfit_and_underfit.ipynb
25118 views
Copyright 2018 The TensorFlow Authors.
Sobreajuste y subajuste
Como de costumbre, el código de este ejemplo usará la API tf.keras
, de la que puede obtener más información en la guía Keras de TensorFlow.
En ambos ejemplos anteriores, clasificación de texto y predicción de la eficiencia del combustible, la precisión de los modelos en los datos de validación alcanzaba su pico tras entrenar durante un determinado número de épocas y luego
se estancaba o comenzaba a disminuir.
En otras palabras, el modelo tendía a sobreajustarse a los datos de entrenamiento. Es importante aprender a lidiar con el sobreajuste. Si bien a menudo es posible alcanzar altos niveles de precisión en el conjunto de entrenamiento, lo que realmente querrá es desarrollar modelos que generalicen bien en un conjunto de prueba (o datos que no hayan visto previamente).
Lo contrario al sobreajuste es el subajuste. El subajuste se presenta cuando todavía se puede mejorar el rendimiento de los datos de entrenamiento. Son varios los motivos por los que puede suceder esto: si el modelo no es lo suficientemente potente, si está excesivamente regularizado o si sencillamente no se ha entrenado lo suficiente. Esto significa que la red no ha aprendido los patrones relevantes de los datos de entrenamiento.
No obstante, si entrena durante demasiado tiempo, el modelo comenzará a sobreajustarse y aprenderá patrones de los datos de entrenamiento que no podrán generalizarse a los datos de prueba. Es necesario encontrar el equilibrio. Comprender cómo entrenar durante un número adecuado de épocas, como veremos a continuación, es una habilidad muy útil.
Para evitar el sobreajuste, la mejor solución es usar datos de entrenamiento más completos. Los conjuntos de datos deberían abarcar el rango completo de entradas que se espera que maneje el modelo. Los datos adicionales solo serán útiles si cubren casos nuevos o interesantes.
Un modelo entrenado con datos más completos naturalmente generalizará mejor. Cuando esto ya no sea posible, la siguiente mejor solución será utilizar técnicas como la regularización. Estas técnicas limitan la cantidad y el tipo de información que el modelo puede almacenar. Si una red puede memorizar solo un pequeño número de patrones, el proceso de optimización la obligará a centrarse en los patrones más destacados, que tienen más posibilidades de generalizar bien.
En este documento, exploraremos varias técnicas comunes de regularización y las utilizaremos para mejorar un modelo de clasificación.
Preparar
Antes de comenzar, importe los paquetes necesarios:
El conjunto de datos Higgs
El objetivo de este tutorial no es el de hacer física de partículas, así que no se detenga en los detalles del conjunto de datos. Contiene 11 000 000 ejemplos, cada uno con 28 características y una etiqueta de clase binaria.
La clase tf.data.experimental.CsvDataset
se puede usar para leer registros csv directamente desde un archivo gzip sin necesidad de implementar el paso intermedio de descompresión.
Esa clase de lector de csv devuelve una lista de escalares para cada registro. La siguiente función vuelve a empaquetar esa lista de escalares en un par (feature_vector, label).
TensorFlow es más eficiente cuando opera con grandes lotes de datos.
Entonces, en vez de volver a empaquetar individualmente cada fila, cree un nuevo tf.data.Dataset
que tome lotes de 10 000 ejemplos, aplique la función pack_row
a cada lote y luego divida la copia de seguridad de los lotes en registros individuales:
Inspeccione algunos de los archivos de este nuevo packed_ds
.
Las características no están perfectamente normalizadas, pero es suficiente para este tutorial.
Para que este tutorial sea relativamente breve, use solo las primeras 1000 muestras para validación y las siguientes 10 000 para entrenamiento:
Los métodos Dataset.skip
y Dataset.take
facilitan esta tarea.
Al mismo tiempo, use el método Dataset.cache
para asegurarse de que el cargador no necesite volver a leer los datos del archivo en cada época:
Estos conjuntos de datos devuelven ejemplos individuales. Use el método Dataset.batch
para crear lotes del tamaño adecuado para entrenamiento. Antes de separar en lotes, recuerde también usar Dataset.shuffle
y Dataset.repeat
en el conjunto de entrenamiento.
Demostrar sobreajuste
La forma más sencilla de evitar el sobreajuste es comenzar con un modelo pequeño: un modelo con un pequeño número de parámetros que se pueden aprender (que está determinado por la cantidad de capas y la cantidad de unidades por capa). En el aprendizaje profundo, el número de parámetros que se pueden aprender en un modelo suele denominarse "capacidad" del modelo.
Se puede deducir que un modelo con más parámetros tendrá más "capacidad de memorización" y, por lo tanto, será capaz de aprender fácilmente una asignación perfecta similar a un diccionario entre las muestras de entrenamiento y sus objetivos, una asignación sin ningún poder de generalización, pero esto sería inútil a la hora de hacer predicciones sobre datos que no se hayan visto previamente.
No olvide esto: los modelos de aprendizaje profundo tienden a ajustarse bien a los datos de entrenamiento, pero el verdadero reto no consiste en realizar el ajuste, sino en lograr la generalización.
Por otro lado, si la red tiene recursos de memorización limitados, no será capaz de aprender la asignación tan fácilmente. Para minimizar su pérdida, deberá aprender representaciones comprimidas que tengan mayor poder predictivo. Al mismo tiempo, si crea un modelo demasiado pequeño, tendrá dificultad para ajustarse a los datos de entrenamiento. Existe un equilibrio entre "demasiada capacidad" y "sin suficiente capacidad".
Desafortunadamente, no existe una fórmula mágica para determinar el tamaño o la arquitectura adecuados para un modelo (en lo que respecta al número de capas o al tamaño adecuado de cada capa). Deberá experimentar con una serie de arquitecturas diferentes.
Para encontrar un tamaño de modelo adecuado, lo mejor es empezar con una cantidad relativamente pequeña de capas y parámetros, y luego ir aumentando el tamaño de las capas o añadiendo nuevas capas hasta que vea que disminuye la pérdida de validación.
Comience con un modelo simple que use solo capas densamente conectadas (tf.keras.layers.Dense
) como línea de base, luego, cree modelos más grandes y compárelos.
Procedimiento de entrenamiento
Muchos modelos se entrenan mejor si reduce gradualmente la tasa de aprendizaje durante el entrenamiento. Use tf.keras.optimizers.schedules
para reducir la tasa de aprendizaje a lo largo del tiempo:
El código anterior configura tf.keras.optimizers.schedules.InverseTimeDecay
para que disminuya hiperbólicamente la tasa de aprendizaje a la mitad de la tasa inicial en 1000 épocas, a 1/3 en 2000 épocas, y así sucesivamente.
Cada modelo de este tutorial usará la misma configuración de entrenamiento. Por lo que es recomendable que se configuren de forma reutilizable, empezando por la lista de retrollamadas.
El entrenamiento para este tutorial se ejecuta durante varias épocas cortas. Para reducir el ruido de registro, use tfdocs.EpochDots
que simplemente imprime un .
para cada época, y un conjunto completo de métricas cada 100 épocas.
Luego, incluya tf.keras.callbacks.EarlyStopping
para evitar tiempos de entrenamiento largos e innecesarios. Tenga en cuenta que esta retrollamada se configura para monitorear val_binary_crossentropy
, no val_loss
. Esta diferencia resultará importante más adelante.
Use callbacks.TensorBoard
para generar registros de TensorBoard para el entrenamiento.
De forma similar, cada modelo usará las mismas configuraciones Model.compile
y Model.fit
:
Modelo Tiny
Comience por entrenar un modelo:
Ahora, compruebe el desempeño del modelo:
Modelo Small
Para comprobar si puede superar el rendimiento del modelo pequeño, entrene modelos más grandes de forma progresiva.
Pruebe dos capas ocultas con 16 unidades cada una:
Modelo Medium
Ahora, pruebe tres capas ocultas con 64 unidades cada una:
Y entrene el modelo con los mismos datos:
Modelo Large
A modo de ejercicio práctico, puede crear un modelo aún más grande y comprobar con qué rapidez empieza a sobreajustarse. A continuación, añada a este modelo de referencia una red que tenga mucha más capacidad, mucho más de la que el problema justificaría:
Y, nuevamente, entrene el modelo con los mismos datos:
Trazar las pérdidas de entrenamiento y de validación
Las líneas continuas muestran la pérdida de entrenamiento y las líneas discontinuas muestran la pérdida de validación (recuerde que una pérdida de validación menor corresponde a un mejor modelo).
Si bien generar un modelo más grande le da más potencia, si no se limita de algún modo esta potencia, puede sobreajustarse fácilmente al conjunto de entrenamiento.
En este ejemplo, generalmente, solo el modelo "Tiny"
logra evitar por completo el sobreajuste, y cada uno de los modelos más grandes se sobreajusta a los datos con mayor rapidez. Esto afecta tanto al modelo "large"
que, para saber realmente qué está sucediendo, deberá cambiar el trazado a una escala logarítmica.
Esto resulta evidente si traza y compara las métricas de validación con las métricas de entrenamiento.
Es normal que haya una pequeña diferencia.
Si ambas métricas se mueven en la misma dirección, todo está bien.
Si la métrica de validación comienza a estancarse mientras que la métrica de entrenamiento continúa mejorando, probablemente esté a punto de sobreajustarse.
Si la métrica de validación se mueve en la dirección equivocada, es claro que el modelo se está sobreajustando.
Nota: En todas las ejecuciones de entrenamiento anteriores se usó callbacks.EarlyStopping
para finalizar el entrenamiento una vez que sea claro que el modelo ya no está haciendo avances.
Ver en TensorBoard
Todos estos modelos escribieron registros de TensorBoard durante el entrenamiento.
Abra un visor de TensorBoard incorporado dentro de un bloc de notas (Lo sentimos, esto no se puede ver en tensorflow.org):
Puede ver los resultados de una ejecución previa de este bloc de notas en TensorBoard.dev.
Estrategias para evitar el sobreajuste
Antes de comenzar a ver el contenido de esta sección, copie los registros de entrenamiento del modelo "Tiny"
que vimos más arriba para que los pueda usar como línea de base para una comparación.
Añadir regularización de pesos
Probablemente conozca el principio de la navaja de Ockham: frente a dos explicaciones de algo, lo más probable es que la explicación correcta sea la "más simple", la que genera menor cantidad de hipótesis. Esto también se puede aplicar a los modelos que aprenden las redes neuronales: ante una serie de datos de entrenamiento y una arquitectura de red, existen múltiples conjuntos de valores de pesos (múltiples modelos) que podrían explicar los datos, y lo más probable es que los modelos más complejos tengan mayor tendencia a sobreajustarse que los modelos más simples.
En este contexto, un "modelo simple" es un modelo donde la distribución de valores de parámetros tenga menor entropía (o un modelo con menor cantidad de parámetros en total, como se demostró anteriormente). Por lo tanto, una forma común de reducir el sobreajuste es establecer límites a la complejidad de una red al forzar sus pesos para que solo tengan en cuenta los valores más bajos, lo que a su vez hace que la distribución de los valores de pesos sea más "regular". A este proceso se lo denomina "regularización de pesos", y se lleva a cabo mediante la incorporación de un costo asociado con mayores pesos a la función de pérdida de la red. Existen dos tipos de costos:
Regularización L1, donde el costo añadido es proporcional al valor absoluto de los coeficientes de los pesos (es decir, lo que se conoce como "Norma L1" de los pesos).
Regularización L2, donde el costo añadido es proporcional al cuadrado del valor de los coeficientes de los pesos (es decir, lo que se conoce como la "Norma L2" al cuadrado de los pesos). La regularización L2 también se conoce como caída del peso en el contexto de las redes neuronales. No deje que los nombres lo confundan: en términos matemáticos, la caída del peso es exactamente lo mismo que la regularización L2.
La regularización L1 lleva los pesos a exactamente cero, lo que fomenta un modelo disperso. La regularización L2 penalizará los parámetros de pesos sin volverlos dispersos, ya que la penalización va a cero para los pesos más bajos; este es uno de los motivos por los que L2 es más común.
En tf.keras
, la regularización de pesos se agrega pasando instancias regularizadoras de pesos en las capas a modo de argumentos de palabra clave. Agregue regularización de pesos L2:
l2(0.001)
significa que cada coeficiente de matriz de pesos de la capa agregará 0.001 * weight_coefficient_value**2
a la pérdida total de la red.
Es por eso que monitoreamos binary_crossentropy
de forma directa. Porque no incluye ese componente de regularización.
Entonces, ese mismo modelo "Large"
con una penalización de regularización L2
tiene un mejor rendimiento:
Como se demuestra en el diagrama de arriba, el modelo de regularización "L2"
ahora es mucho más competitivo con el modelo "Tiny"
. Este modelo "L2"
también es mucho más resistente al sobreajuste que el modelo "Large"
en el que se basó, a pesar de tener la misma cantidad de parámetros.
Más información
Hay dos cosas importantes que se deben tener en cuenta sobre este tipo de regularización:
Si está escribiendo su propio bucle de entrenamiento, debe asegurarse de pedirle al modelo que indique sus pérdidas de regularización.
Esta implementación funciona mediante la incorporación de penalizaciones de peso a la pérdida del modelo, para luego aplicar un procedimiento de optimización estándar.
Hay un segundo enfoque que directamente ejecuta el optimizador sobre la perdida bruta y, luego, mientras aplica el paso calculado, el optimizador también aplica cierto grado de caída de pesos. Esta "caída de pesos desacoplada" se usa en optimizadores como tf.keras.optimizers.Ftrl
y tfa.optimizers.AdamW
.
Añadir abandono
El abandono es una de las técnicas de regularización más efectivas y más comunes para las redes neuronales, desarrollada por Hinton y sus estudiantes en la Universidad de Toronto.
La explicación intuitiva del abandono es que, dado que los nodos individuales en la red no pueden depender de los resultados de los demás, cada nodo debe producir características útiles por sí mismo.
El abandono, aplicado a una capa, consiste en "descartar" aleatoriamente (es decir, establecer en cero) una cantidad determinada de características de la capa durante el entrenamiento. Por ejemplo, una capa dada normalmente tendría como resultado un vector [0.2, 0.5, 1.3, 0.8, 1.1]
para una muestra de entrada dada durante el entrenamiento; luego de aplicar el abandono, este vector tendrá algunas entradas cero distribuidas aleatoriamente, por ejemplo, [0, 0.5, 1.3, 0, 1.1]
.
La "tasa de abandono" es la fracción de las características que se llevan a cero; generalmente se establece entre 0.2 y 0.5. Al momento de la prueba, no se descarta ninguna unidad, sino que los valores de salida de la capa se reducen por un factor equivalente a la tasa de abandono, para compensar el hecho de que durante el entrenamiento hay más unidades activas.
En Keras, puede introducir abandono en una red a través de la capa tf.keras.layers.Dropout
, que se aplica a la salida de la capa anterior.
Agregue dos capas de abandono a su red para comprobar qué tan eficientes son a la hora de reducir el sobreajuste:
En este trazado podemos ver que ambos enfoques de regularización mejoran el comportamiento del modelo "Large"
. Pero, aun así, no supera la línea de base del modelo "Tiny"
.
A continuación, pruébelos juntos para ver si eso mejora los resultados.
Combinación de L2 y abandono
Resulta evidente que este modelo con regularización "Combined"
es el mejor hasta el momento.
Ver en TensorBoard
Estos modelos también se registran en registros de TensorBoard.
Para abrir un visor incorporado, ejecute lo siguiente dentro de una celda de código (Lo sentimos, esto no se puede ver en tensorflow.org):
Puede ver los resultados de una ejecución previa de este bloc de notas en TensorBoard.dev.
Conclusiones
En resumen, estas son las formas más comunes de evitar el sobreajuste en redes neuronales:
Conseguir más datos de entrenamiento
Reducir la capacidad de la red
Añadir regularización de pesos
Añadir abandono
Hay dos enfoques importantes que no se incluyen en esta guía:
Normalización de lotes (
tf.keras.layers.BatchNormalization
)
Recuerde que cada método puede ser útil por sí solo, pero a menudo combinarlos resulta aún más eficaz.