In [ ]:
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Note: Nuestra comunidad de Tensorflow ha traducido estos documentos. Como las traducciones de la comunidad son basados en el "mejor esfuerzo", no hay ninguna garantia que esta sea un reflejo preciso y actual de la Documentacion Oficial en Ingles. Si tienen sugerencias sobre como mejorar esta traduccion, por favor envian un "Pull request" al siguiente repositorio tensorflow/docs. Para ofrecerse como voluntario o hacer revision de las traducciones de la Comunidad por favor contacten al siguiente grupo docs@tensorflow.org list.
Un callback personalizado es una herramienta poderosa para personalizar el comportamiento de un modelo de Keras durante el entrenamiento, evaluacion o inferencia, incluyendo la lectura/cambio del modelo de Keras. Ejemplos incluyen tf.keras.callbacks.TensorBoard, donde se pueden exportar y visualizar el progreso del entrenamiento y los resultados con TensorBoard, o tf.keras.callbacks.ModelCheckpoint donde el modelo es automaticamente guardado durante el entrenamiento, entre otros. En esta guia aprenderas que es un callback de Keras, cuando se llama, que puede hacer y como puedes construir una propia. Al final de la guia habra demos para la creacion de aplicaciones simples de callback para ayudarte a empezar tu propio callback personalizados.
In [ ]:
import tensorflow as tf
En Keras 'Callback' es una clase de python destinada a ser subclase para proporcionar una funcionalidad específica, con un conjunto de métodos llamados en varias etapas de entrenamiento (incluyendo el inicio y fin de los batch/epoch), pruebas y predicciones. Los Callbacks son útiles para tener visibilidad de los estados internos y las estadísticas del modelo durante el entrenamiento. Puedes pasar una lista de callbacks (como argumento de palabra clave callbacks) a cualquiera de los siguientes metodos tf.keras.Model.fit (),tf.keras.Model.evaluate ()ytf.keras.Model .predict (). Los metodos de los callbacks se llamaran en diferentes etapas del entrenamiento/evaluación/inferencia.
Para comenzar, importemos TensorDlow y definamos un modelo secuencial sencillo en Keras:
In [ ]:
# Definir el modelo de Keras model al que se le agregaran los callbacks
def get_model():
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(1, activation = 'linear', input_dim = 784))
model.compile(optimizer=tf.keras.optimizers.RMSprop(lr=0.1), loss='mean_squared_error', metrics=['mae'])
return model
Luego, cara el dataset de MNIST para entrenamiento y pruebas de la APLI de datasetws de Keras:
In [ ]:
# Cargar los datos de ejemplo de MNIST data y preprocesarlos
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
x_train = x_train.reshape(60000, 784).astype('float32') / 255
x_test = x_test.reshape(10000, 784).astype('float32') / 255
Ahora, define un callback simple y personalizado para rastrear el inicio y fin de cada batch de datos. Durante esas llamadas, imprime el indice del batch actual.
In [ ]:
import datetime
class MyCustomCallback(tf.keras.callbacks.Callback):
def on_train_batch_begin(self, batch, logs=None):
print('Entrenamiento: batch {} comienza en {}'.format(batch, datetime.datetime.now().time()))
def on_train_batch_end(self, batch, logs=None):
print('Entrenamiento: batch {} termina en {}'.format(batch, datetime.datetime.now().time()))
def on_test_batch_begin(self, batch, logs=None):
print('Evaluacion: batch {} comienza en {}'.format(batch, datetime.datetime.now().time()))
def on_test_batch_end(self, batch, logs=None):
print('Evaluacion: batch {} termina en {}'.format(batch, datetime.datetime.now().time()))
Dar un callback mara los metodos del modelo tales como tf.keras.Model.fit() aseguran que los metodos son llamados en dichas etapas:
In [ ]:
model = get_model()
_ = model.fit(x_train, y_train,
batch_size=64,
epochs=1,
steps_per_epoch=5,
verbose=0,
callbacks=[MyCustomCallback()])
Los usuarios pueden dar una lista de callbacks para los siguientes metodos de tf.keras.Model:
fit(), fit_generator()Entrena el modelo por una cantidad determinada de epochs (iteraciones en un dataset, o para los datos determinados por un generador de Python que va batch-por-batch).
evaluate(), evaluate_generator()Evalua el modelo para determinados datos o generador de datos. Regresa la perdida (loss) y valores metricos para la evaluacion.
predict(), predict_generator()Genera las predicciones a regresar para los datos ingresados o el generador de datos. NOTA: Toda la documentacion esta en ingles.
In [ ]:
_ = model.evaluate(x_test, y_test, batch_size=128, verbose=0, steps=5,
callbacks=[MyCustomCallback()])
Para entrenamiento, pruebas y prediccion, los siguientes metodos se han previsto para ser sobreescritos.
on_(train|test|predict)_begin(self, logs=None)Llamado al inicio de fit/evaluate/predict.
on_(train|test|predict)_end(self, logs=None)Llamado al fin de fit/evaluate/predict.
on_(train|test|predict)_batch_begin(self, batch, logs=None)Llamado justo antes de procesar un batch durante entrenamiento/pruebas/prediccion. Dentro de este metodo, logs es un diccionario con las llaves batch y size disponibles, representando el numero de batch actual y las dimensiones del mismo.
on_(train|test|predict)_batch_end(self, batch, logs=None)Llamado al final del entrenamiento/pruebas/prediccion de un batch. dentro de este metodo, logs es un diccionario que contiene resultados metricos con estado.
Adicionalmente, para el entrenamiento, los siguientes metodos son provistos.
Llamado al inicio de una epoch durante el entrenamiento.
Llamado al final de una epoch durante el entrenamiento.
In [ ]:
class LossAndErrorPrintingCallback(tf.keras.callbacks.Callback):
def on_train_batch_end(self, batch, logs=None):
print('Para el batch {}, la perdida (loss) es {:7.2f}.'.format(batch, logs['loss']))
def on_test_batch_end(self, batch, logs=None):
print('Para el batch {}, la perdida (loss) es {:7.2f}.'.format(batch, logs['loss']))
def on_epoch_end(self, epoch, logs=None):
print('La perdida promedio para la epoch {} es {:7.2f} y el MAE es {:7.2f}.'.format(epoch, logs['loss'], logs['mae']))
model = get_model()
_ = model.fit(x_train, y_train,
batch_size=64,
steps_per_epoch=5,
epochs=3,
verbose=0,
callbacks=[LossAndErrorPrintingCallback()])
De manera similar, uno puede proveer callbacks en las llamadas a evaluate().
In [ ]:
_ = model.evaluate(x_test, y_test, batch_size=128, verbose=0, steps=20,
callbacks=[LossAndErrorPrintingCallback()])
El primer ejemplo muestra la creacion de un Callback que detiene el entrenamiento de Keras cuando se alcanza el minimo de perdida mutando el atributomodel.stop_training (boolean). Opcionalmente, el usuario puede proporcionar el argumento patience para especificar cuantas epochs debe esperar el entrenamiento antes de detenerse.
tf.keras.callbacks.EarlyStopping proporciona una implementación mas completa y general.
In [ ]:
import numpy as np
class EarlyStoppingAtMinLoss(tf.keras.callbacks.Callback):
"""Detener el entrenamiento cuando la perdida (loss) esta en su minimo, i.e. la perdida (loss) deja de disminuir.
Arguments:
patience: Numero de epochs a esperar despues de que el min ha sido alcanzaado. Despues de este numero
de no mejoras, el entrenamiento para.
"""
def __init__(self, patience=0):
super(EarlyStoppingAtMinLoss, self).__init__()
self.patience = patience
# best_weights para almacenar los pesos en los cuales ocurre la perdida minima.
self.best_weights = None
def on_train_begin(self, logs=None):
# El numero de epoch que ha esperado cuando la perdida ya no es minima.
self.wait = 0
# El epoch en el que en entrenamiento se detiene.
self.stopped_epoch = 0
# Initialize el best como infinito.
self.best = np.Inf
def on_epoch_end(self, epoch, logs=None):
current = logs.get('loss')
if np.less(current, self.best):
self.best = current
self.wait = 0
# Guardar los mejores pesos si el resultado actual es mejor (menos).
self.best_weights = self.model.get_weights()
else:
self.wait += 1
if self.wait >= self.patience:
self.stopped_epoch = epoch
self.model.stop_training = True
print('Restaurando los pesos del modelo del final de la mejor epoch.')
self.model.set_weights(self.best_weights)
def on_train_end(self, logs=None):
if self.stopped_epoch > 0:
print('Epoch %05d: Detencion anticipada' % (self.stopped_epoch + 1))
In [ ]:
model = get_model()
_ = model.fit(x_train, y_train,
batch_size=64,
steps_per_epoch=5,
epochs=30,
verbose=0,
callbacks=[LossAndErrorPrintingCallback(), EarlyStoppingAtMinLoss()])
Algo que es hecho comunmente en el entrenamiento de un modelo es cambiar el learning rate conforme pasan mas epochs. El backend de Keras expone la API get_value la cual puede ser usada para definir las variables. En este ejemplo estamos mostrando como un Callback personalizado puede ser usado para cambiar dinamicamente el learning rate.
Nota: este es solo una implementacion de ejemplo, callbacks.LearningRateScheduler y keras.optimizers.schedules contienen implementaciones mas generales.
In [ ]:
class LearningRateScheduler(tf.keras.callbacks.Callback):
"""Planificador de Learning rate que define el learning rate deacuerdo a lo programado.
Arguments:
schedule: una funcion que toma el indice del epoch
(entero, indexado desde 0) y el learning rate actual
como entradas y regresa un nuevo learning rate como salida (float).
"""
def __init__(self, schedule):
super(LearningRateScheduler, self).__init__()
self.schedule = schedule
def on_epoch_begin(self, epoch, logs=None):
if not hasattr(self.model.optimizer, 'lr'):
raise ValueError('Optimizer must have a "lr" attribute.')
# Obtener el learning rate actua del optimizer del modelo.
lr = float(tf.keras.backend.get_value(self.model.optimizer.lr))
# Llamar la funcion schedule para obtener el learning rate programado.
scheduled_lr = self.schedule(epoch, lr)
# Definir el valor en el optimized antes de que la epoch comience
tf.keras.backend.set_value(self.model.optimizer.lr, scheduled_lr)
print('\nEpoch %05d: Learning rate is %6.4f.' % (epoch, scheduled_lr))
In [ ]:
LR_SCHEDULE = [
# (epoch a comenzar, learning rate) tupla
(3, 0.05), (6, 0.01), (9, 0.005), (12, 0.001)
]
def lr_schedule(epoch, lr):
"""Funcion de ayuda para recuperar el learning rate programado basado en la epoch."""
if epoch < LR_SCHEDULE[0][0] or epoch > LR_SCHEDULE[-1][0]:
return lr
for i in range(len(LR_SCHEDULE)):
if epoch == LR_SCHEDULE[i][0]:
return LR_SCHEDULE[i][1]
return lr
model = get_model()
_ = model.fit(x_train, y_train,
batch_size=64,
steps_per_epoch=5,
epochs=15,
verbose=0,
callbacks=[LossAndErrorPrintingCallback(), LearningRateScheduler(lr_schedule)])
Asegurate de revisar los callbacks de Keras preexistentes visitando la documentacion de la api. Las aplicaciones incluyen el registro a CSV, guardar el modelo, visualizar en TensorBoard y mucho mas.
NOTA: La documentacion aun esta en ingles