Path: blob/master/site/es-419/guide/keras/train_and_evaluate.ipynb
25118 views
Copyright 2020 The TensorFlow Authors.
Entrenamiento y evaluación con los métodos integrados
Preparación
Introducción
Esta guía cubre los modelos de entrenamiento, evaluación y predicción (inferencia) cuando se utilizan las API incorporadas para el entrenamiento y la validación (como Model.fit()
, Model.evaluate()
y Model.predict()
).
Si está interesado en aprovechar fit()
mientras especifica su propia función de pasos de entrenamiento, consulte la guía Personalización de lo que ocurre en fit()
.
Si está interesado en escribir sus propios bucles de entrenamiento y evaluación desde cero, consulte la guía "escribir un bucle de entrenamiento desde cero".
En general, tanto si utiliza bucles incorporados como si escribe los suyos propios, el entrenamiento y la evaluación de modelos funcionan estrictamente de la misma manera en todos los tipos de modelos Keras: modelos secuenciales, modelos construidos con la API funcional y modelos escritos desde cero mediante subclases de modelos.
Esta guía no cubre el entrenamiento distribuido, que está cubierto en nuestra guía de multi-GPU & entrenamiento distribuido.
Visión general de la API: un primer ejemplo de extremo a extremo
Cuando pase datos a los bucles de entrenamiento incorporados de un modelo, debería utilizar matrices NumPy (si sus datos son pequeños y caben en la memoria) u objetos tf.data Dataset
. En los próximos párrafos, utilizaremos el conjunto de datos MNIST como matrices NumPy, con el fin de demostrar cómo utilizar optimizadores, pérdidas y métricas.
Consideremos el siguiente modelo (aquí, construimos con la API Funcional, pero podría ser un modelo Secuencial o un modelo subclaseado también):
Este es el flujo de trabajo típico de principio a fin:
Entrenamiento
Validación en un conjunto de retención generado a partir de los datos de entrenamiento originales
Evaluación de los datos de las pruebas
Para este ejemplo utilizaremos datos MNIST.
Especificamos la configuración de entrenamiento (optimizador, pérdida, métrica):
Llamamos a fit()
, que entrenará el modelo cortando los datos en "lotes" de tamaño batch_size
, e iterando repetidamente sobre todo el conjunto de datos para obtener un número determinado de epochs
.
El objeto history
devuelto contiene un registro de los valores de pérdida y los valores métricos durante el entrenamiento:
Evaluamos el modelo en los datos de prueba mediante evaluate()
:
Ahora, revisemos cada pieza de este flujo de trabajo en detalle.
El método compile()
: especifica una pérdida, métricas y un optimizador
Para entrenar un modelo con fit()
, necesita especificar una función de pérdida, un optimizador y, de forma opcional, algunas métricas que monitorear.
Se pasan al modelo como argumentos del método compile()
:
El argumento metrics
debe ser una lista -- su modelo puede tener cualquier número de métricas.
Si su modelo tiene múltiples salidas, puede especificar diferentes pérdidas y métricas para cada salida, y puede modular la contribución de cada salida a la pérdida total del modelo. Encontrará más detalles al respecto en la sección Paso de datos a modelos con múltiples entradas y salidas.
Tenga en cuenta que si está satisfecho con la configuración predeterminada, en muchos casos el optimizador, la pérdida y las métricas se pueden especificar mediante identificadores de cadena como un acceso directo:
Para su posterior re-uso, pongamos nuestra definición del modelo y el paso de compilación en funciones; las llamaremos varias veces por medio de diferentes ejemplos en esta guía.
Hay disponibles muchos optimizadores, pérdidas y métricas integrados.
En general, no tendrá que crear sus propias pérdidas, métricas u optimizadores desde cero, porque es probable que lo que necesite ya forme parte de la API de Keras:
Optimizadores:
SGD()
(con o sin momentum)RMSprop()
Adam()
etc.
Pérdidas:
MeanSquaredError()
KLDivergence()
CosineSimilarity()
etc.
Métricas:
AUC()
Precision()
Recall()
etc.
Pérdidas personalizadas
Si necesita crear una pérdida personalizada, Keras proporciona dos formas de hacerlo.
El primer método consiste en crear una función que acepte las entradas y_true
y y_pred
. El siguiente ejemplo muestra una función de pérdida que calcula el error cuadrático promedio entre los datos reales y las predicciones:
Si necesita una función de pérdida que tome parámetros además de y_true
y y_pred
, puede subclasificar la clase tf.keras.losses.Loss
e implementar los dos siguientes métodos:
__init__(self)
: aceptar parámetros para pasar durante la llamada de su función de pérdidacall(self, y_true, y_pred)
: utilizar los objetivos (y_true) y las predicciones del modelo (y_pred) para calcular la pérdida del modelo
Digamos que desea utilizar el error cuadrático promedio, pero con un término adicional que desincentivará los valores de predicción alejados de 0.5 (suponemos que los objetivos categóricos se codifican con un solo disparo y toman valores entre 0 y 1). Esto crea un incentivo para que el modelo no se confíe demasiado, lo que puede ayudar a reducir el sobreajuste (¡no sabremos si funciona hasta que lo probemos!).
Así es como debe hacerlo:
Métricas personalizadas
Si necesita una métrica que no forma parte de la API, puede crear fácilmente métricas personalizadas subclasificando la clase tf.keras.metrics.Metric
. Necesitará implementar 4 métodos:
__init__(self)
, en el que creará variables de estado para su métrica.update_state(self, y_true, y_pred, sample_weight=None)
, que utiliza los objetivos y_true y las predicciones del modelo y_pred para actualizar las variables de estado.result(self)
, que utiliza las variables de estado para calcular los resultados finales.reset_state(self)
, que reinicializa el estado de la métrica.
La actualización del estado y el cálculo de resultados se mantienen separados (en update_state()
y result()
, respectivamente) porque en algunos casos, el cálculo de resultados puede ser muy costoso y solo se realizaría periódicamente.
A continuación se muestra un ejemplo sencillo de cómo implementar una métrica CategoricalTruePositives
que cuenta cuántas muestras se clasificaron correctamente como si pertenecieran a una clase determinada:
Manejo de pérdidas y métricas que no se ajustan a la firma estándar
La inmensa mayoría de las pérdidas y métricas pueden calcularse a partir de y_true
y y_pred
, donde y_pred
es una salida del modelo, pero no todas. Por ejemplo, una pérdida de regularización puede requerir solo la activación de una capa (no hay objetivos en este caso), y esta activación puede no ser una salida del modelo.
En tales casos, puede llamar a self.add_loss(loss_value)
desde dentro del método de llamada de una capa personalizada. Las pérdidas agregadas de esta manera se suman a la pérdida "principal" durante el entrenamiento (la que se pasa a compile()
). Aquí hay un ejemplo simple que agrega regularización de la actividad (tenga en cuenta que la regularización de la actividad está incorporada en todas las capas de Keras - esta capa es solo para proporcionar un ejemplo concreto):
Puede hacer lo mismo para registrar valores métricos, utilizando add_metric()
:
En la API funcional, también puede llamar a model.add_loss(loss_tensor)
, o a model.add_metric(metric_tensor, name, aggregation)
.
Este es un ejemplo sencillo:
Tenga en cuenta que cuando se pasan las pérdidas mediante add_loss()
, se hace posible llamar a compile()
sin una función de pérdida, ya que el modelo ya tiene una pérdida que minimizar.
Considere la siguiente capa LogisticEndpoint
: toma como entradas objetivos y logits, y rastrea una pérdida de entropía cruzada mediante add_loss()
. También realiza un seguimiento de la precisión de la clasificación mediante add_metric()
.
Puede utilizarlo en un modelo con dos entradas (datos de entrada y objetivos), compilado sin un argumento loss
, así:
Para obtener más información sobre el entrenamiento de modelos multientrada, consulte la sección Paso de datos a modelos multientrada y multisalida.
Apartar automáticamente un conjunto de retención de validación
En el primer ejemplo de extremo a extremo que vio, usamos el argumento validation_data
para pasar una tupla de matrices NumPy (x_val, y_val)
al modelo para evaluar una pérdida de validación y métricas de validación al final de cada época.
Aquí hay otra opción: el argumento validation_split
permite reservar automáticamente parte de los datos de entrenamiento para realizar la validación. El valor del argumento representa la fracción de los datos que se reservará para la validación, por lo que debe establecerse en un número superior a 0 e inferior a 1. Por ejemplo, validation_split=0.2
significa "utilizar el 20% de los datos para la validación", y validation_split=0.6
significa "utilizar el 60% de los datos para la validación".
La forma en que se calcula la validación es tomar las últimas muestras x% de las matrices recibidas por la llamada fit()
, antes de mezclar.
Tenga en cuenta que solo puede utilizar validation_split
cuando entrene con datos NumPy.
Entrenamiento y evaluación a partir de conjuntos de datos tf.data
En los últimos párrafos, habrá visto cómo manejar pérdidas, métricas y optimizadores, y habrá visto cómo usar los argumentos validation_data
y validation_split
en fit()
, cuando sus datos se pasan como matrices NumPy.
Veamos ahora el caso en el que los datos se presentan en forma de objeto tf.data.Dataset
.
La API tf.data
es un conjunto de utilidades de TensorFlow 2.0 para cargar y preprocesar datos de forma rápida y escalable.
Para obtener una guía completa sobre la creación de Datasets
, consulte la documentación tf.data.
Puede pasar una instancia Dataset
directamente a los métodos fit()
, evaluate()
y predict()
:
Tenga en cuenta que el conjunto de datos se restablece al final de cada época, por lo que puede volver a utilizarse en la siguiente.
Si desea ejecutar el entrenamiento solo en un número específico de lotes de este conjunto de datos, puede pasar el argumento steps_per_epoch
, que especifica cuántos pasos de entrenamiento debe ejecutar el modelo utilizando este conjunto de datos antes de pasar a la siguiente época.
Si se hace esto, el conjunto de datos no se reinicia al final de cada época, sino que se siguen dibujando los siguientes lotes. El conjunto de datos eventualmente se quedará sin datos (a menos que sea un conjunto de datos de bucle infinito).
Utilizar un conjunto de datos de validación
Puede pasar una instancia de Dataset
como argumento de validation_data
en fit()
:
Al final de cada época, el modelo iterará sobre el conjunto de datos de validación y calculará la pérdida de validación y las métricas de validación.
Si desea ejecutar la validación solo en un número específico de lotes de este conjunto de datos, puede pasar el argumento validation_steps
, que especifica cuántos pasos de validación debe ejecutar el modelo con el conjunto de datos de validación antes de interrumpir la validación y pasar a la siguiente época:
Tenga en cuenta que el conjunto de datos de validación se restablecerá después de cada uso (de modo que siempre evaluará las mismas muestras de una época a otra).
El argumento validation_split
(generar un conjunto de retención a partir de los datos de entrenamiento) no es compatible cuando se entrena a partir de objetos Dataset
, ya que esta función requiere la capacidad de indexar las muestras de los conjuntos de datos, lo que no es posible en general con la API Dataset
.
Otros formatos de entrada compatibles
Además de las matrices NumPy, los tensores eager y los Datasets
de TensorFlow, es posible entrenar un modelo Keras usando dataframes Pandas, o desde generadores Python que producen lotes de datos y etiquetas.
En particular, la clase keras.utils.Sequence
ofrece una interfaz sencilla para construir generadores de datos Python compatibles con el multiprocesamiento y que se pueden mezclar.
En general, le recomendamos que utilice:
Datos de entrada NumPy si sus datos son pequeños y caben en la memoria
Dataset
objetos si tiene grandes conjuntos de datos y necesita realizar un entrenamiento distribuido.Sequence
si tiene grandes conjuntos de datos y necesita hacer mucho procesamiento personalizado en Python que no se puede hacer en TensorFlow (por ejemplo, si depende de bibliotecas externas para cargar o preprocesar datos).
Utilizando un objeto keras.utils.Sequence
como entrada
keras.utils.Sequence
es una utilidad que podrá subclasificar para obtener un generador de Python con dos propiedades importantes:
Funciona bien con el multiprocesamiento.
Se puede mezclar (por ejemplo, al pasar
shuffle=True
enfit()
).
Un Sequence
debe implementar dos métodos:
__getitem__
__len__
El método __getitem__
debe devolver un lote completo. Si desea modificar su conjunto de datos entre épocas, puede implementar on_epoch_end
.
Este es un ejemplo rápido:
Cómo utilizar la ponderación de muestras y la ponderación de clases
Con la configuración predeterminada, el peso de una muestra se decide por su frecuencia en el conjunto de datos. Existen dos métodos para ponderar los datos, independientes de la frecuencia de las muestras:
Pesos de la clase
Pesos de la muestra
Pesos de la clase
Se establece pasando un diccionario al argumento class_weight
de Model.fit()
. Este diccionario asigna índices de clase al peso que debe utilizarse para las muestras que pertenecen a esta clase.
Esto se puede utilizar para equilibrar las clases sin remuestreo, o para entrenar un modelo que dé más importancia a una clase en particular.
Por ejemplo, si la clase "0" tiene la mitad de representación que la clase "1" en sus datos, podría utilizar Model.fit(..., class_weight={0: 1., 1: 0.5})
.
Este es un ejemplo de NumPy en el que utilizamos pesos de la clase o pesos de la muestra para dar más importancia a la clasificación correcta de la clase #5 (que es el dígito "5" en el conjunto de datos MNIST).
Pesos de la muestra
Para un control más preciso, o si no está construyendo un clasificador, puede utilizar "pesos de la muestra".
Cuando se entrena a partir de datos NumPy: Pase el argumento
sample_weight
aModel.fit()
.Cuando se entrena a partir de
tf.data
o cualquier otro tipo de iterador: Produce tuplas(input_batch, label_batch, sample_weight_batch)
.
Un arreglo de "pesos de la muestra" es un arreglo de números que especifica cuánto peso debe tener cada muestra de un lote en el cálculo de la pérdida total. Se suele utilizar en problemas de clasificación desequilibrada (la idea es dar más peso a las clases poco frecuentes).
Cuando los pesos utilizados son unos y ceros, el arreglo puede utilizarse como una máscara para la función de pérdida (se descarta por completo la contribución de ciertas muestras en la pérdida total).
A continuación se muestra un ejemplo de Dataset
:
Pasar datos a modelos multientrada y multisalida
En los ejemplos anteriores, considerábamos un modelo con una única entrada (un tensor de forma (764,)
) y una única salida (un tensor de predicción de forma (10,)
). Pero, ¿qué ocurre con los modelos que tienen varias entradas o salidas?
Consideremos el siguiente modelo, que tiene una entrada de imagen de forma (32, 32, 3)
(es decir, (height, width, channels)
) y una entrada de serie temporal de forma (None, 10)
(es decir, (timesteps, features)
). Nuestro modelo tendrá dos salidas calculadas a partir de la combinación de estas entradas: una "puntuación" (de forma (1,)
) y una distribución de probabilidad sobre cinco clases (de forma (5,)
).
Vamos a trazar este modelo, para que pueda ver claramente lo que estamos haciendo aquí (tenga en cuenta que las formas que se muestran en el gráfico son formas de lote, en vez de formas por muestra).
En el momento de la compilación, podemos especificar diferentes pérdidas para diferentes salidas, pasando las funciones de pérdida como una lista:
Si solo pasamos una única función de pérdida al modelo, se aplicará la misma función de pérdida a cada salida (lo que no es apropiado en este caso).
Lo mismo sucede con las métricas:
Como dimos nombres a nuestras capas de salida, también podríamos especificar pérdidas y métricas por salida mediante un dict:
Recomendamos el uso de nombres explícitos y dicts si tiene más de 2 salidas.
Es posible dar diferentes pesos a diferentes pérdidas específicas de la salida (por ejemplo, uno podría desear privilegiar la pérdida de "puntuación" en nuestro ejemplo, dando a 2x la importancia de la pérdida de la clase), utilizando el argumento loss_weights
:
También puede elegir no calcular una pérdida para ciertas salidas, si estas salidas están destinadas a la predicción pero no al entrenamiento:
Pasar datos a un modelo multientrada o multisalida en fit()
funciona de forma similar a especificar una función de pérdida en compilación: puede pasar listas de matrices NumPy (con mapeo 1:1 a las salidas que recibieron una función de pérdida) o dictos que mapean nombres de salida a matrices NumPy.
Este es el caso de uso de Dataset
: de forma similar a lo que hicimos para las matrices de NumPy, Dataset
debería devolver una tupla de dicts.
Cómo utilizar las retrollamadas
Las retrollamadas en Keras son objetos que se llaman en diferentes puntos durante el entrenamiento (al inicio de una época, al final de un lote, al final de una época, etc.). Pueden ser utilizados para implementar ciertos comportamientos, tales como:
Realizar la validación en diferentes puntos durante el entrenamiento (más allá de la validación incorporada por época).
Verificación del modelo a intervalos regulares o cuando supera un determinado umbral de precisión.
Modificación del ritmo de aprendizaje del modelo cuando el entrenamiento parece estancarse
Realizar un ajuste fino de las capas superiores cuando el entrenamiento parece estancarse.
Envío de notificaciones por correo electrónico o mensaje instantáneo cuando finalice el entrenamiento o se supere un determinado umbral de rendimiento.
Etc.
Las retrollamadas pueden pasarse como una lista a su llamada a fit()
:
Dispone de muchas retrollamadas integradas
Hay muchas retrollamadas incorporadas ya disponibles en Keras, tales como:
ModelCheckpoint
: Guarda periódicamente el modelo.Detención temprana
: Detiene el entrenamiento cuando éste ya no mejora las métricas de validación.TensorBoard
: escribe periódicamente registros del modelo que pueden visualizarse en TensorBoard (más detalles en la sección "Visualización").CSVLogger
: transmite datos de pérdidas y métricas a un archivo CSV.etc.
Consulte la documentación sobre retrollamadas para ver la lista completa.
Cómo escribir su propia retrollamada
Puede crear una retrollamada personalizada ampliando la clase base keras.callbacks.Callback
. Una retrollamada tiene acceso a su modelo asociado mediante la propiedad de la clase self.model
.
Asegúrese de leer la guía completa para escribir retrollamadas personalizadas.
Este es un ejemplo sencillo en el que se guarda una lista de valores de pérdida por lote durante el entrenamiento:
Modelos de punto de verificación
Cuando se entrena un modelo en conjuntos de datos relativamente grandes, es crucial guardar puntos de verificación del modelo a intervalos frecuentes.
La forma más sencilla de conseguirlo es con la retrollamada ModelCheckpoint
:
La retrollamada ModelCheckpoint
puede utilizarse para implementar la tolerancia ante errores: la capacidad de reiniciar el entrenamiento desde el último estado guardado del modelo en caso de que el entrenamiento se interrumpa aleatoriamente. Este es un ejemplo básico:
También puede escribir su propia retrollamada para guardar y restaurar modelos.
Para obtener una guía completa sobre serialización y guardado, consulte la guía para guardar y serializar Modelos.
Cómo utilizar los programas de aprendizaje
Un patrón común cuando se entrenan modelos de aprendizaje profundo es reducir gradualmente el aprendizaje conforme avanza el entrenamiento. Esto se conoce generalmente como "decaimiento de la tasa de aprendizaje".
El programa de decaimiento del aprendizaje puede ser estático (fijado por adelantado, en función de la época actual o del índice del lote actual), o dinámico (que responde al comportamiento actual del modelo, en particular a la pérdida de validación).
Cómo pasar un programa a un optimizador
Puede utilizar fácilmente un programa estático de decaimiento de la tasa de aprendizaje pasando un objeto del programa como argumento learning_rate
en su optimizador:
Se dispone de varias programaciones incorporadas: ExponentialDecay
, PiecewiseConstantDecay
, PolynomialDecay
, y InverseTimeDecay
.
Uso de retrollamadas para aplicar una programación dinámica de la tasa de aprendizaje
Una programación dinámica de la tasa de aprendizaje (por ejemplo, la disminución de la tasa de aprendizaje cuando la pérdida de validación ya no está mejorando) no se puede lograr con estos objetos de programación, ya que el optimizador no tiene acceso a las métricas de validación.
Sin embargo, las retrollamadas tienen acceso a todas las métricas, ¡incluidas las de validación! Por lo tanto, puede lograr este patrón mediante el uso de una retrollamada que modifica la tasa de aprendizaje actual en el optimizador. De hecho, esto incluso está incorporado como la retrollamada ReduceLROnPlateau
.
Visualización de pérdidas y métricas durante el entrenamiento
La mejor manera de mantener un ojo en su modelo durante el entrenamiento es utilizar TensorBoard -- una aplicación basada en el navegador que puede ejecutar localmente y le proporciona:
Gráficos en vivo de la pérdida y métricas para el entrenamiento y la evaluación
(opcionalmente) Visualizaciones de los histogramas de las activaciones de sus capas
(opcionalmente) visualizaciones 3D de los espacios de incorporación aprendidos por sus capas
Embedding
Si instaló TensorFlow con la herramienta pip, debería poder iniciar TensorBoard desde la línea de comandos:
Cómo utilizar la retrollamada de TensorBoard
La forma más sencilla de utilizar TensorBoard con un modelo Keras y el método fit()
es la retrollamada TensorBoard
.
En el caso más sencillo, basta con especificar dónde desea que la retrollamada escriba los registros, y listo:
Para obtener más información, consulte la documentación para la retrollamada TensorBoard
.