Se usó la API de Cloud Translation para traducir esta página.
Switch to English

Capacitación y evaluación con los métodos incorporados

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar cuaderno

Preparar

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

Introducción

Esta guía cubre modelos de entrenamiento, evaluación y predicción (inferencia) cuando se utilizan API integradas para entrenamiento y validación (como model.fit() , model.evaluate() , model.predict() ).

Si está interesado en aprovechar el fit() mientras especifica su propia función de pasos de entrenamiento, consulte la guía "Personalización de lo que sucede en el fit() " .

Si está interesado en escribir sus propios ciclos de formación y evaluación desde cero, consulte la guía "Cómo escribir un ciclo de formación desde cero" .

En general, ya sea que utilice bucles integrados o escriba los suyos propios, el entrenamiento y la evaluación de modelos funcionan estrictamente de la misma manera en todos los tipos de modelos de Keras: modelos secuenciales, modelos creados con la API funcional y modelos escritos desde cero subclases de modelos.

Esta guía no cubre la formación distribuida. Para obtener capacitación distribuida, consulte nuestra guía de capacitación distribuida y de múltiples gpu .

Descripción general de la API: un primer ejemplo de un extremo a otro

Al pasar datos a los bucles de entrenamiento integrados de un modelo, debe usar matrices NumPy (si sus datos son pequeños y tf.data Dataset en la memoria) u objetos tf.data Dataset . En los próximos párrafos, usaremos el conjunto de datos MNIST como matrices NumPy, para demostrar cómo usar optimizadores, pérdidas y métricas.

Consideremos el siguiente modelo (aquí, lo construimos con la API funcional, pero podría ser un modelo secuencial o un modelo de subclases también):

inputs = keras.Input(shape=(784,), name="digits")
x = layers.Dense(64, activation="relu", name="dense_1")(inputs)
x = layers.Dense(64, activation="relu", name="dense_2")(x)
outputs = layers.Dense(10, activation="softmax", name="predictions")(x)

model = keras.Model(inputs=inputs, outputs=outputs)

Así es como se ve el típico flujo de trabajo de un extremo a otro, que consiste en:

  • Formación
  • Validación de un conjunto reservado generado a partir de los datos de entrenamiento originales
  • Evaluación de los datos de prueba

Usaremos datos MNIST para este ejemplo.

(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()

# Preprocess the data (these are NumPy arrays)
x_train = x_train.reshape(60000, 784).astype("float32") / 255
x_test = x_test.reshape(10000, 784).astype("float32") / 255

y_train = y_train.astype("float32")
y_test = y_test.astype("float32")

# Reserve 10,000 samples for validation
x_val = x_train[-10000:]
y_val = y_train[-10000:]
x_train = x_train[:-10000]
y_train = y_train[:-10000]

Especificamos la configuración de entrenamiento (optimizador, pérdida, métricas):

model.compile(
    optimizer=keras.optimizers.RMSprop(),  # Optimizer
    # Loss function to minimize
    loss=keras.losses.SparseCategoricalCrossentropy(),
    # List of metrics to monitor
    metrics=[keras.metrics.SparseCategoricalAccuracy()],
)

Llamamos a fit() , que entrenará el modelo dividiendo los datos en "lotes" de tamaño "batch_size", e iterando repetidamente sobre todo el conjunto de datos para un número determinado de "épocas".

print("Fit model on training data")
history = model.fit(
    x_train,
    y_train,
    batch_size=64,
    epochs=2,
    # We pass some validation for
    # monitoring validation loss and metrics
    # at the end of each epoch
    validation_data=(x_val, y_val),
)
Fit model on training data
Epoch 1/2
782/782 [==============================] - 2s 2ms/step - loss: 0.3425 - sparse_categorical_accuracy: 0.9034 - val_loss: 0.1827 - val_sparse_categorical_accuracy: 0.9478
Epoch 2/2
782/782 [==============================] - 2s 2ms/step - loss: 0.1618 - sparse_categorical_accuracy: 0.9513 - val_loss: 0.1282 - val_sparse_categorical_accuracy: 0.9651

El objeto "historial" devuelto contiene un registro de los valores de pérdida y los valores métricos durante el entrenamiento:

history.history
{'loss': [0.3424801528453827, 0.16180744767189026],
 'sparse_categorical_accuracy': [0.903439998626709, 0.9512799978256226],
 'val_loss': [0.18268445134162903, 0.12816601991653442],
 'val_sparse_categorical_accuracy': [0.9477999806404114, 0.9650999903678894]}

Evaluamos el modelo en los datos de prueba a través de evaluate() :

# Evaluate the model on the test data using `evaluate`
print("Evaluate on test data")
results = model.evaluate(x_test, y_test, batch_size=128)
print("test loss, test acc:", results)

# Generate predictions (probabilities -- the output of the last layer)
# on new data using `predict`
print("Generate predictions for 3 samples")
predictions = model.predict(x_test[:3])
print("predictions shape:", predictions.shape)
Evaluate on test data
79/79 [==============================] - 0s 1ms/step - loss: 0.1310 - sparse_categorical_accuracy: 0.9637
test loss, test acc: [0.1309928148984909, 0.963699996471405]
Generate predictions for 3 samples
predictions shape: (3, 10)

Ahora, revisemos cada parte de este flujo de trabajo en detalle.

El método compile() : especificar una pérdida, métricas y un optimizador

Para entrenar un modelo con fit() , debe especificar una función de pérdida, un optimizador y, opcionalmente, algunas métricas para monitorear.

Los pasa al modelo como argumentos para el método compile() :

model.compile(
    optimizer=keras.optimizers.RMSprop(learning_rate=1e-3),
    loss=keras.losses.SparseCategoricalCrossentropy(),
    metrics=[keras.metrics.SparseCategoricalAccuracy()],
)

El argumento de las metrics debe ser una lista; su modelo puede tener cualquier cantidad 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 sobre esto en la sección "Pasar datos a modelos de múltiples entradas y múltiples 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 atajo:

model.compile(
    optimizer="rmsprop",
    loss="sparse_categorical_crossentropy",
    metrics=["sparse_categorical_accuracy"],
)

Para su posterior reutilización, pongamos la definición de nuestro modelo y compilemos el paso en funciones; los llamaremos varias veces a través de diferentes ejemplos en esta guía.

def get_uncompiled_model():
    inputs = keras.Input(shape=(784,), name="digits")
    x = layers.Dense(64, activation="relu", name="dense_1")(inputs)
    x = layers.Dense(64, activation="relu", name="dense_2")(x)
    outputs = layers.Dense(10, activation="softmax", name="predictions")(x)
    model = keras.Model(inputs=inputs, outputs=outputs)
    return model


def get_compiled_model():
    model = get_uncompiled_model()
    model.compile(
        optimizer="rmsprop",
        loss="sparse_categorical_crossentropy",
        metrics=["sparse_categorical_accuracy"],
    )
    return model

Están disponibles muchos optimizadores, pérdidas y métricas integrados

En general, no tendrá que crear desde cero sus propias pérdidas, métricas u optimizadores, porque lo que necesita probablemente ya sea parte de la API de Keras:

Optimizadores:

  • SGD() (con o sin impulso)
  • RMSprop()
  • Adam()
  • etc.

Pérdidas:

  • MeanSquaredError()
  • KLDivergence()
  • CosineSimilarity()
  • etc.

Métrica:

  • AUC()
  • Precision()
  • Recall()
  • etc.

Pérdidas personalizadas

Hay dos formas de proporcionar pérdidas personalizadas con Keras. El primer ejemplo crea una función que acepta entradas y_true e y_pred . El siguiente ejemplo muestra una función de pérdida que calcula el error cuadrático medio entre los datos reales y las predicciones:

def custom_mean_squared_error(y_true, y_pred):
    return tf.math.reduce_mean(tf.square(y_true - y_pred))


model = get_uncompiled_model()
model.compile(optimizer=keras.optimizers.Adam(), loss=custom_mean_squared_error)

# We need to one-hot encode the labels to use MSE
y_train_one_hot = tf.one_hot(y_train, depth=10)
model.fit(x_train, y_train_one_hot, batch_size=64, epochs=1)
782/782 [==============================] - 1s 1ms/step - loss: 0.0168

<tensorflow.python.keras.callbacks.History at 0x7f75581d56a0>

Si necesita una función de pérdida que tome parámetros además de y_true e y_pred , puede subclasificar la clase tf.keras.losses.Loss e implementar los siguientes dos métodos:

  • __init__(self) : acepta parámetros para pasar durante la llamada de tu función de pérdida
  • call(self, y_true, y_pred) : use los objetivos (y_true) y las predicciones del modelo (y_pred) para calcular la pérdida del modelo

Supongamos que desea utilizar el error cuadrático medio, pero con un término agregado que desincentivará los valores de predicción lejos de 0.5 (asumimos que los objetivos categóricos están codificados de forma directa y toman valores entre 0 y 1). Esto crea un incentivo para que el modelo no tenga demasiada confianza, lo que puede ayudar a reducir el sobreajuste (¡no sabremos si funciona hasta que lo intentemos!).

Así es como lo haría:

class CustomMSE(keras.losses.Loss):
    def __init__(self, regularization_factor=0.1, name="custom_mse"):
        super().__init__(name=name)
        self.regularization_factor = regularization_factor

    def call(self, y_true, y_pred):
        mse = tf.math.reduce_mean(tf.square(y_true - y_pred))
        reg = tf.math.reduce_mean(tf.square(0.5 - y_pred))
        return mse + reg * self.regularization_factor


model = get_uncompiled_model()
model.compile(optimizer=keras.optimizers.Adam(), loss=CustomMSE())

y_train_one_hot = tf.one_hot(y_train, depth=10)
model.fit(x_train, y_train_one_hot, batch_size=64, epochs=1)
782/782 [==============================] - 1s 2ms/step - loss: 0.0390

<tensorflow.python.keras.callbacks.History at 0x7f7558184c88>

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 . Deberá 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_states(self) , que reinicia el estado de la métrica.

La actualización del estado y el cálculo de los resultados se mantienen separados (en update_state() y result() , respectivamente) porque en algunos casos, el cálculo de los resultados puede ser muy costoso y solo se realizará periódicamente.

Aquí hay un ejemplo simple que muestra cómo implementar una métrica CategoricalTruePositives , que cuenta cuántas muestras se clasificaron correctamente como pertenecientes a una clase determinada:

class CategoricalTruePositives(keras.metrics.Metric):
    def __init__(self, name="categorical_true_positives", **kwargs):
        super(CategoricalTruePositives, self).__init__(name=name, **kwargs)
        self.true_positives = self.add_weight(name="ctp", initializer="zeros")

    def update_state(self, y_true, y_pred, sample_weight=None):
        y_pred = tf.reshape(tf.argmax(y_pred, axis=1), shape=(-1, 1))
        values = tf.cast(y_true, "int32") == tf.cast(y_pred, "int32")
        values = tf.cast(values, "float32")
        if sample_weight is not None:
            sample_weight = tf.cast(sample_weight, "float32")
            values = tf.multiply(values, sample_weight)
        self.true_positives.assign_add(tf.reduce_sum(values))

    def result(self):
        return self.true_positives

    def reset_states(self):
        # The state of the metric will be reset at the start of each epoch.
        self.true_positives.assign(0.0)


model = get_uncompiled_model()
model.compile(
    optimizer=keras.optimizers.RMSprop(learning_rate=1e-3),
    loss=keras.losses.SparseCategoricalCrossentropy(),
    metrics=[CategoricalTruePositives()],
)
model.fit(x_train, y_train, batch_size=64, epochs=3)
Epoch 1/3
782/782 [==============================] - 1s 2ms/step - loss: 0.3429 - categorical_true_positives: 45146.0000
Epoch 2/3
782/782 [==============================] - 1s 2ms/step - loss: 0.1560 - categorical_true_positives: 47637.0000
Epoch 3/3
782/782 [==============================] - 1s 2ms/step - loss: 0.1155 - categorical_true_positives: 48237.0000

<tensorflow.python.keras.callbacks.History at 0x7f755801bfd0>

Manejo de pérdidas y métricas que no se ajustan a la firma estándar

La gran mayoría de pérdidas y métricas se pueden calcular a partir de y_true y y_pred , donde y_pred es una salida de su modelo. Pero no todos ellos. Por ejemplo, una pérdida de regularización solo puede requerir 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 agregan a la pérdida "principal" durante el entrenamiento (la que se pasa a compile() ). Aquí hay un ejemplo simple que agrega regularización de actividades (tenga en cuenta que la regularización de actividades está incorporada en todas las capas de Keras; esta capa es solo por el simple hecho de proporcionar un ejemplo concreto):

class ActivityRegularizationLayer(layers.Layer):
    def call(self, inputs):
        self.add_loss(tf.reduce_sum(inputs) * 0.1)
        return inputs  # Pass-through layer.


inputs = keras.Input(shape=(784,), name="digits")
x = layers.Dense(64, activation="relu", name="dense_1")(inputs)

# Insert activity regularization as a layer
x = ActivityRegularizationLayer()(x)

x = layers.Dense(64, activation="relu", name="dense_2")(x)
outputs = layers.Dense(10, name="predictions")(x)

model = keras.Model(inputs=inputs, outputs=outputs)
model.compile(
    optimizer=keras.optimizers.RMSprop(learning_rate=1e-3),
    loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
)

# The displayed loss will be much higher than before
# due to the regularization component.
model.fit(x_train, y_train, batch_size=64, epochs=1)
782/782 [==============================] - 1s 2ms/step - loss: 2.4756

<tensorflow.python.keras.callbacks.History at 0x7f75501e1f98>

Puede hacer lo mismo para registrar valores de métricas, usando add_metric() :

class MetricLoggingLayer(layers.Layer):
    def call(self, inputs):
        # The `aggregation` argument defines
        # how to aggregate the per-batch values
        # over each epoch:
        # in this case we simply average them.
        self.add_metric(
            keras.backend.std(inputs), name="std_of_activation", aggregation="mean"
        )
        return inputs  # Pass-through layer.


inputs = keras.Input(shape=(784,), name="digits")
x = layers.Dense(64, activation="relu", name="dense_1")(inputs)

# Insert std logging as a layer.
x = MetricLoggingLayer()(x)

x = layers.Dense(64, activation="relu", name="dense_2")(x)
outputs = layers.Dense(10, name="predictions")(x)

model = keras.Model(inputs=inputs, outputs=outputs)
model.compile(
    optimizer=keras.optimizers.RMSprop(learning_rate=1e-3),
    loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
)
model.fit(x_train, y_train, batch_size=64, epochs=1)
782/782 [==============================] - 1s 2ms/step - loss: 0.3493 - std_of_activation: 0.9813

<tensorflow.python.keras.callbacks.History at 0x7f75500321d0>

En la API funcional , también puede llamar model.add_loss(loss_tensor) o model.add_metric(metric_tensor, name, aggregation) .

He aquí un ejemplo sencillo:

inputs = keras.Input(shape=(784,), name="digits")
x1 = layers.Dense(64, activation="relu", name="dense_1")(inputs)
x2 = layers.Dense(64, activation="relu", name="dense_2")(x1)
outputs = layers.Dense(10, name="predictions")(x2)
model = keras.Model(inputs=inputs, outputs=outputs)

model.add_loss(tf.reduce_sum(x1) * 0.1)

model.add_metric(keras.backend.std(x1), name="std_of_activation", aggregation="mean")

model.compile(
    optimizer=keras.optimizers.RMSprop(1e-3),
    loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
)
model.fit(x_train, y_train, batch_size=64, epochs=1)
782/782 [==============================] - 1s 2ms/step - loss: 2.5230 - std_of_activation: 0.0020

<tensorflow.python.keras.callbacks.History at 0x7f74ec71d828>

Tenga en cuenta que cuando pasa las pérdidas a través de add_loss() , es posible llamar a compile() sin una función de pérdida, ya que el modelo ya tiene una pérdida para minimizar.

Considere la siguiente capa LogisticEndpoint : toma como entradas objetivos y logits, y rastrea una pérdida de add_loss() través de add_loss() . También rastrea la precisión de la clasificación a través de add_metric() .

class LogisticEndpoint(keras.layers.Layer):
    def __init__(self, name=None):
        super(LogisticEndpoint, self).__init__(name=name)
        self.loss_fn = keras.losses.BinaryCrossentropy(from_logits=True)
        self.accuracy_fn = keras.metrics.BinaryAccuracy()

    def call(self, targets, logits, sample_weights=None):
        # Compute the training-time loss value and add it
        # to the layer using `self.add_loss()`.
        loss = self.loss_fn(targets, logits, sample_weights)
        self.add_loss(loss)

        # Log accuracy as a metric and add it
        # to the layer using `self.add_metric()`.
        acc = self.accuracy_fn(targets, logits, sample_weights)
        self.add_metric(acc, name="accuracy")

        # Return the inference-time prediction tensor (for `.predict()`).
        return tf.nn.softmax(logits)

Puede usarlo en un modelo con dos entradas (datos de entrada y objetivos), compilado sin un argumento de loss , como este:

import numpy as np

inputs = keras.Input(shape=(3,), name="inputs")
targets = keras.Input(shape=(10,), name="targets")
logits = keras.layers.Dense(10)(inputs)
predictions = LogisticEndpoint(name="predictions")(logits, targets)

model = keras.Model(inputs=[inputs, targets], outputs=predictions)
model.compile(optimizer="adam")  # No loss argument!

data = {
    "inputs": np.random.random((3, 3)),
    "targets": np.random.random((3, 10)),
}
model.fit(data)
1/1 [==============================] - 0s 1ms/step - loss: 0.9344 - binary_accuracy: 0.0000e+00

<tensorflow.python.keras.callbacks.History at 0x7f7558339f28>

Para obtener más información sobre cómo entrenar modelos de múltiples entradas, consulte la sección Pasar datos a modelos de múltiples entradas y múltiples salidas .

Separación automática de un conjunto de exclusió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 sus datos de entrenamiento para la validación. El valor del argumento representa la fracción de los datos que se reservarán 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 tomando el último x% de las muestras de las matrices recibidas por la llamada de ajuste, antes de cualquier mezcla.

Tenga en cuenta que solo puede usar validation_split cuando entrena con datos NumPy.

model = get_compiled_model()
model.fit(x_train, y_train, batch_size=64, validation_split=0.2, epochs=1)
625/625 [==============================] - 1s 2ms/step - loss: 0.3753 - sparse_categorical_accuracy: 0.8927 - val_loss: 0.2252 - val_sparse_categorical_accuracy: 0.9344

<tensorflow.python.keras.callbacks.History at 0x7f755826f160>

Capacitación y evaluación de tf.data Datasets

En los últimos párrafos, ha visto cómo manejar pérdidas, métricas y optimizadores, y cómo usar los argumentos validation_data y validation_split en forma, cuando sus datos se pasan como matrices NumPy.

Ahora tf.data.Dataset un vistazo al caso en el que sus datos vienen en forma de un objeto tf.data.Dataset .

La API tf.data es un conjunto de utilidades en TensorFlow 2.0 para cargar y preprocesar datos de una manera rápida y escalable.

Para obtener una guía completa sobre la creación de Datasets , consulte la documentación de tf.data .

Puede pasar una instancia de Dataset directamente a los métodos fit() , evaluate() y predict() :

model = get_compiled_model()

# First, let's create a training Dataset instance.
# For the sake of our example, we'll use the same MNIST data as before.
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
# Shuffle and slice the dataset.
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64)

# Now we get a test dataset.
test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test))
test_dataset = test_dataset.batch(64)

# Since the dataset already takes care of batching,
# we don't pass a `batch_size` argument.
model.fit(train_dataset, epochs=3)

# You can also evaluate or predict on a dataset.
print("Evaluate")
result = model.evaluate(test_dataset)
dict(zip(model.metrics_names, result))
Epoch 1/3
782/782 [==============================] - 2s 2ms/step - loss: 0.3404 - sparse_categorical_accuracy: 0.9048
Epoch 2/3
782/782 [==============================] - 2s 2ms/step - loss: 0.1596 - sparse_categorical_accuracy: 0.9529
Epoch 3/3
782/782 [==============================] - 2s 2ms/step - loss: 0.1165 - sparse_categorical_accuracy: 0.9658
Evaluate
157/157 [==============================] - 0s 1ms/step - loss: 0.1147 - sparse_categorical_accuracy: 0.9659

{'loss': 0.11471886932849884,
 'sparse_categorical_accuracy': 0.9659000039100647}

Tenga en cuenta que el conjunto de datos se restablece al final de cada época, por lo que puede reutilizarse en la siguiente época.

Si desea ejecutar el entrenamiento solo en una cantidad específica 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 con este conjunto de datos antes de pasar a la siguiente época.

Si hace esto, el conjunto de datos no se restablece al final de cada época, sino que seguimos dibujando los siguientes lotes. El conjunto de datos eventualmente se quedará sin datos (a menos que sea un conjunto de datos de bucle infinito).

model = get_compiled_model()

# Prepare the training dataset
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64)

# Only use the 100 batches per epoch (that's 64 * 100 samples)
model.fit(train_dataset, epochs=3, steps_per_epoch=100)
Epoch 1/3
100/100 [==============================] - 0s 2ms/step - loss: 0.8448 - sparse_categorical_accuracy: 0.7734
Epoch 2/3
100/100 [==============================] - 0s 2ms/step - loss: 0.3912 - sparse_categorical_accuracy: 0.8922
Epoch 3/3
100/100 [==============================] - 0s 2ms/step - loss: 0.3399 - sparse_categorical_accuracy: 0.9011

<tensorflow.python.keras.callbacks.History at 0x7f74ec5cf7f0>

Usar un conjunto de datos de validación

Puede pasar una instancia de Dataset como el argumento validation_data en fit() :

model = get_compiled_model()

# Prepare the training dataset
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64)

# Prepare the validation dataset
val_dataset = tf.data.Dataset.from_tensor_slices((x_val, y_val))
val_dataset = val_dataset.batch(64)

model.fit(train_dataset, epochs=1, validation_data=val_dataset)
782/782 [==============================] - 2s 2ms/step - loss: 0.3384 - sparse_categorical_accuracy: 0.9032 - val_loss: 0.1752 - val_sparse_categorical_accuracy: 0.9518

<tensorflow.python.keras.callbacks.History at 0x7f74ec4d2ba8>

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:

model = get_compiled_model()

# Prepare the training dataset
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64)

# Prepare the validation dataset
val_dataset = tf.data.Dataset.from_tensor_slices((x_val, y_val))
val_dataset = val_dataset.batch(64)

model.fit(
    train_dataset,
    epochs=1,
    # Only run validation using the first 10 batches of the dataset
    # using the `validation_steps` argument
    validation_data=val_dataset,
    validation_steps=10,
)
782/782 [==============================] - 2s 2ms/step - loss: 0.3503 - sparse_categorical_accuracy: 0.9021 - val_loss: 0.3226 - val_sparse_categorical_accuracy: 0.9156

<tensorflow.python.keras.callbacks.History at 0x7f74ec4caa58>

Tenga en cuenta que el conjunto de datos de validación se restablecerá después de cada uso (de modo que siempre estará evaluando las mismas muestras de una época a otra).

El argumento validation_split (que genera un conjunto de exclusión a partir de los datos de entrenamiento) no se admite cuando se entrena desde objetos de Dataset de 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 de Dataset .

Otros formatos de entrada compatibles

Además de las matrices NumPy, los tensores ansiosos y los Datasets TensorFlow, es posible entrenar un modelo Keras utilizando marcos de datos Pandas o generadores de Python que producen lotes de datos y etiquetas.

En particular, la clase keras.utils.Sequence ofrece una interfaz simple para construir generadores de datos Python que son compatibles con el multiprocesamiento y se pueden barajar.

En general, le recomendamos que utilice:

  • Ingrese datos NumPy si sus datos son pequeños y caben en la memoria
  • Objetos de Dataset si tiene grandes conjuntos de datos y necesita realizar un entrenamiento distribuido
  • Sequence objetos si tiene grandes conjuntos de datos y necesita hacer mucho procesamiento personalizado del lado de Python que no se puede realizar en TensorFlow (por ejemplo, si depende de bibliotecas externas para la carga de datos o el preprocesamiento).

Usando un objeto keras.utils.Sequence como entrada

keras.utils.Sequence es una utilidad que puede subclasificar para obtener un generador de Python con dos propiedades importantes:

  • Funciona bien con multiprocesamiento.
  • Se puede shuffle=True (por ejemplo, cuando se pasa shuffle=True en fit() ).

Una Sequence debe implementar dos métodos:

  • __getitem__
  • __len__

El método __getitem__ debería devolver un lote completo. Si desea modificar su conjunto de datos entre épocas, puede implementar on_epoch_end .

He aquí un ejemplo rápido:

from skimage.io import imread
from skimage.transform import resize
import numpy as np

# Here, `filenames` is list of path to the images
# and `labels` are the associated labels.

class CIFAR10Sequence(Sequence):
    def __init__(self, filenames, labels, batch_size):
        self.filenames, self.labels = filenames, labels
        self.batch_size = batch_size

    def __len__(self):
        return int(np.ceil(len(self.filenames) / float(self.batch_size)))

    def __getitem__(self, idx):
        batch_x = self.filenames[idx * self.batch_size:(idx + 1) * self.batch_size]
        batch_y = self.labels[idx * self.batch_size:(idx + 1) * self.batch_size]
        return np.array([
            resize(imread(filename), (200, 200))
               for filename in batch_x]), np.array(batch_y)

sequence = CIFAR10Sequence(filenames, labels, batch_size)
model.fit(sequence, epochs=10)

Usar ponderación de muestra y ponderación de clase

Con la configuración predeterminada, el peso de una muestra se decide por su frecuencia en el conjunto de datos. Hay dos métodos para ponderar los datos, independientemente de la frecuencia de muestreo:

  • Pesos de clase
  • Pesos de muestra

Pesos de clase

Esto se establece mediante el paso de un diccionario a la class_weight argumento para Model.fit() . Este diccionario asigna índices de clase al peso que se debe utilizar para las muestras que pertenecen a esta clase.

Esto se puede utilizar para equilibrar clases sin volver a muestrear o para entrenar un modelo que dé más importancia a una clase en particular.

Por ejemplo, si la clase "0" es la mitad de lo que representa la clase "1" en sus datos, puede usar Model.fit(..., class_weight={0: 1., 1: 0.5}) .

Aquí hay un ejemplo de NumPy donde usamos pesos de clase o pesos de 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).

import numpy as np

class_weight = {
    0: 1.0,
    1: 1.0,
    2: 1.0,
    3: 1.0,
    4: 1.0,
    # Set weight "2" for class "5",
    # making this class 2x more important
    5: 2.0,
    6: 1.0,
    7: 1.0,
    8: 1.0,
    9: 1.0,
}

print("Fit with class weight")
model = get_compiled_model()
model.fit(x_train, y_train, class_weight=class_weight, batch_size=64, epochs=1)
Fit with class weight
782/782 [==============================] - 2s 2ms/step - loss: 0.3729 - sparse_categorical_accuracy: 0.9025

<tensorflow.python.keras.callbacks.History at 0x7f74ec265358>

Pesos de muestra

Para un control detallado, o si no está construyendo un clasificador, puede usar "pesos de muestra".

  • Cuando el entrenamiento de los datos NumPy: Pasar el sample_weight argumento para Model.fit() .
  • Al entrenar desde tf.data o cualquier otro tipo de iterador: (input_batch, label_batch, sample_weight_batch) rendimiento (input_batch, label_batch, sample_weight_batch) .

Una matriz de "pesos de muestra" es una matriz de números que especifican cuánto peso debe tener cada muestra en un lote para calcular la pérdida total. Se usa comúnmente en problemas de clasificación desequilibrada (la idea es dar más peso a las clases que rara vez se ven).

Cuando los pesos utilizados son unos y ceros, la matriz se puede utilizar como una máscara para la función de pérdida (descartando por completo la contribución de ciertas muestras a la pérdida total).

sample_weight = np.ones(shape=(len(y_train),))
sample_weight[y_train == 5] = 2.0

print("Fit with sample weight")
model = get_compiled_model()
model.fit(x_train, y_train, sample_weight=sample_weight, batch_size=64, epochs=1)
Fit with sample weight
782/782 [==============================] - 2s 2ms/step - loss: 0.3837 - sparse_categorical_accuracy: 0.8984

<tensorflow.python.keras.callbacks.History at 0x7f74ec11afd0>

Aquí hay un ejemplo de Dataset coincidente:

sample_weight = np.ones(shape=(len(y_train),))
sample_weight[y_train == 5] = 2.0

# Create a Dataset that includes sample weights
# (3rd element in the return tuple).
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train, sample_weight))

# Shuffle and slice the dataset.
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64)

model = get_compiled_model()
model.fit(train_dataset, epochs=1)
782/782 [==============================] - 2s 2ms/step - loss: 0.3792 - sparse_categorical_accuracy: 0.9030

<tensorflow.python.keras.callbacks.History at 0x7f74d47f2208>

Pasar datos a modelos de múltiples entradas y múltiples salidas

En los ejemplos anteriores, estábamos considerando un modelo con una sola entrada (un tensor de forma (764,) ) y una única salida (un tensor de predicción de forma (10,) ). Pero, ¿qué pasa con los modelos que tienen múltiples entradas o salidas?

Considere el siguiente modelo, que tiene una entrada de imagen de forma (32, 32, 3) (eso es (height, width, channels) ) y una entrada de serie temporal de forma (None, 10) (eso es (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,) ).

image_input = keras.Input(shape=(32, 32, 3), name="img_input")
timeseries_input = keras.Input(shape=(None, 10), name="ts_input")

x1 = layers.Conv2D(3, 3)(image_input)
x1 = layers.GlobalMaxPooling2D()(x1)

x2 = layers.Conv1D(3, 3)(timeseries_input)
x2 = layers.GlobalMaxPooling1D()(x2)

x = layers.concatenate([x1, x2])

score_output = layers.Dense(1, name="score_output")(x)
class_output = layers.Dense(5, name="class_output")(x)

model = keras.Model(
    inputs=[image_input, timeseries_input], outputs=[score_output, class_output]
)

Grafiquemos este modelo para que pueda ver claramente lo que estamos haciendo aquí (tenga en cuenta que las formas que se muestran en la gráfica son formas por lotes, en lugar de formas por muestra).

keras.utils.plot_model(model, "multi_input_and_output_model.png", show_shapes=True)

png

En el momento de la compilación, podemos especificar diferentes pérdidas a diferentes salidas, pasando las funciones de pérdida como una lista:

model.compile(
    optimizer=keras.optimizers.RMSprop(1e-3),
    loss=[keras.losses.MeanSquaredError(), keras.losses.CategoricalCrossentropy()],
)

Si solo pasáramos una única función de pérdida al modelo, la misma función de pérdida se aplicaría a cada salida (lo cual no es apropiado aquí).

Lo mismo ocurre con las métricas:

model.compile(
    optimizer=keras.optimizers.RMSprop(1e-3),
    loss=[keras.losses.MeanSquaredError(), keras.losses.CategoricalCrossentropy()],
    metrics=[
        [
            keras.metrics.MeanAbsolutePercentageError(),
            keras.metrics.MeanAbsoluteError(),
        ],
        [keras.metrics.CategoricalAccuracy()],
    ],
)

Dado que le dimos nombres a nuestras capas de salida, también podríamos especificar pérdidas por salida y métricas a través de un dictado:

model.compile(
    optimizer=keras.optimizers.RMSprop(1e-3),
    loss={
        "score_output": keras.losses.MeanSquaredError(),
        "class_output": keras.losses.CategoricalCrossentropy(),
    },
    metrics={
        "score_output": [
            keras.metrics.MeanAbsolutePercentageError(),
            keras.metrics.MeanAbsoluteError(),
        ],
        "class_output": [keras.metrics.CategoricalAccuracy()],
    },
)

Recomendamos el uso de nombres y dictados explícitos si tiene más de 2 salidas.

Es posible dar diferentes pesos a diferentes pérdidas específicas de 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 clase), usando el argumento loss_weights :

model.compile(
    optimizer=keras.optimizers.RMSprop(1e-3),
    loss={
        "score_output": keras.losses.MeanSquaredError(),
        "class_output": keras.losses.CategoricalCrossentropy(),
    },
    metrics={
        "score_output": [
            keras.metrics.MeanAbsolutePercentageError(),
            keras.metrics.MeanAbsoluteError(),
        ],
        "class_output": [keras.metrics.CategoricalAccuracy()],
    },
    loss_weights={"score_output": 2.0, "class_output": 1.0},
)

También puede optar por no calcular una pérdida para ciertas salidas, si estas salidas están destinadas a la predicción pero no al entrenamiento:

# List loss version
model.compile(
    optimizer=keras.optimizers.RMSprop(1e-3),
    loss=[None, keras.losses.CategoricalCrossentropy()],
)

# Or dict loss version
model.compile(
    optimizer=keras.optimizers.RMSprop(1e-3),
    loss={"class_output": keras.losses.CategoricalCrossentropy()},
)

Pasar datos a un modelo de múltiples entradas o múltiples salidas en ajuste funciona de manera similar a la especificación de una función de pérdida en la compilación: puede pasar listas de matrices NumPy (con mapeo 1: 1 a las salidas que recibieron una función de pérdida) o dicta la asignación de nombres de salida a matrices NumPy .

model.compile(
    optimizer=keras.optimizers.RMSprop(1e-3),
    loss=[keras.losses.MeanSquaredError(), keras.losses.CategoricalCrossentropy()],
)

# Generate dummy NumPy data
img_data = np.random.random_sample(size=(100, 32, 32, 3))
ts_data = np.random.random_sample(size=(100, 20, 10))
score_targets = np.random.random_sample(size=(100, 1))
class_targets = np.random.random_sample(size=(100, 5))

# Fit on lists
model.fit([img_data, ts_data], [score_targets, class_targets], batch_size=32, epochs=1)

# Alternatively, fit on dicts
model.fit(
    {"img_input": img_data, "ts_input": ts_data},
    {"score_output": score_targets, "class_output": class_targets},
    batch_size=32,
    epochs=1,
)
4/4 [==============================] - 0s 6ms/step - loss: 20.0184 - score_output_loss: 0.5383 - class_output_loss: 19.4800
4/4 [==============================] - 0s 4ms/step - loss: 17.7266 - score_output_loss: 0.3122 - class_output_loss: 17.4145

<tensorflow.python.keras.callbacks.History at 0x7f755022feb8>

Aquí está el caso de uso del Dataset : de manera similar a lo que hicimos para las matrices NumPy, el Dataset debería devolver una tupla de dictados.

train_dataset = tf.data.Dataset.from_tensor_slices(
    (
        {"img_input": img_data, "ts_input": ts_data},
        {"score_output": score_targets, "class_output": class_targets},
    )
)
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64)

model.fit(train_dataset, epochs=1)
2/2 [==============================] - 0s 8ms/step - loss: 17.2156 - score_output_loss: 0.2522 - class_output_loss: 16.9634

<tensorflow.python.keras.callbacks.History at 0x7f75c56c1128>

Usar devoluciones de llamada

Las devoluciones de llamada 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.) y que se pueden usar para implementar comportamientos como:

  • Realización de validación en diferentes puntos durante el entrenamiento (más allá de la validación incorporada por época)
  • Señalar el modelo a intervalos regulares o cuando exceda un cierto umbral de precisión
  • Cambiar la tasa de aprendizaje del modelo cuando el entrenamiento parece estancarse
  • Hacer un ajuste fino de las capas superiores cuando el entrenamiento parece estancarse
  • Envío de notificaciones por correo electrónico o mensajes instantáneos cuando finaliza el entrenamiento o cuando se excede un determinado umbral de rendimiento
  • Etc.

Las devoluciones de llamada se pueden pasar como una lista a su llamada a fit() :

model = get_compiled_model()

callbacks = [
    keras.callbacks.EarlyStopping(
        # Stop training when `val_loss` is no longer improving
        monitor="val_loss",
        # "no longer improving" being defined as "no better than 1e-2 less"
        min_delta=1e-2,
        # "no longer improving" being further defined as "for at least 2 epochs"
        patience=2,
        verbose=1,
    )
]
model.fit(
    x_train,
    y_train,
    epochs=20,
    batch_size=64,
    callbacks=callbacks,
    validation_split=0.2,
)
Epoch 1/20
625/625 [==============================] - 1s 2ms/step - loss: 0.3816 - sparse_categorical_accuracy: 0.8913 - val_loss: 0.2325 - val_sparse_categorical_accuracy: 0.9304
Epoch 2/20
625/625 [==============================] - 1s 2ms/step - loss: 0.1773 - sparse_categorical_accuracy: 0.9477 - val_loss: 0.2088 - val_sparse_categorical_accuracy: 0.9343
Epoch 3/20
625/625 [==============================] - 1s 2ms/step - loss: 0.1293 - sparse_categorical_accuracy: 0.9606 - val_loss: 0.1515 - val_sparse_categorical_accuracy: 0.9568
Epoch 4/20
625/625 [==============================] - 1s 2ms/step - loss: 0.1009 - sparse_categorical_accuracy: 0.9700 - val_loss: 0.1376 - val_sparse_categorical_accuracy: 0.9607
Epoch 5/20
625/625 [==============================] - 1s 2ms/step - loss: 0.0821 - sparse_categorical_accuracy: 0.9747 - val_loss: 0.1533 - val_sparse_categorical_accuracy: 0.9545
Epoch 6/20
625/625 [==============================] - 1s 2ms/step - loss: 0.0704 - sparse_categorical_accuracy: 0.9794 - val_loss: 0.1319 - val_sparse_categorical_accuracy: 0.9616
Epoch 00006: early stopping

<tensorflow.python.keras.callbacks.History at 0x7f74d46abdd8>

Hay muchas devoluciones de llamada integradas disponibles

  • ModelCheckpoint : guarde periódicamente el modelo.
  • EarlyStopping : Detenga el entrenamiento cuando el entrenamiento ya no mejore las métricas de validación.
  • TensorBoard : escribe periódicamente registros de modelos que se pueden visualizar 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 de devoluciones de llamada para obtener la lista completa.

Escribiendo su propia devolución de llamada

Puede crear una devolución de llamada personalizada ampliando la clase base keras.callbacks.Callback . Una devolución de llamada tiene acceso a su modelo asociado a través de la propiedad de clase self.model .

Asegúrese de leer la guía completa para escribir devoluciones de llamada personalizadas .

A continuación, se muestra un ejemplo sencillo que guarda una lista de valores de pérdida por lote durante el entrenamiento:

class LossHistory(keras.callbacks.Callback):
    def on_train_begin(self, logs):
        self.per_batch_losses = []

    def on_batch_end(self, batch, logs):
        self.per_batch_losses.append(logs.get("loss"))

Modelos de puntos de control

Cuando entrena el modelo en conjuntos de datos relativamente grandes, es fundamental guardar los puntos de control de su modelo a intervalos frecuentes.

La forma más fácil de lograr esto es con la ModelCheckpoint llamada ModelCheckpoint :

model = get_compiled_model()

callbacks = [
    keras.callbacks.ModelCheckpoint(
        # Path where to save the model
        # The two parameters below mean that we will overwrite
        # the current checkpoint if and only if
        # the `val_loss` score has improved.
        # The saved model name will include the current epoch.
        filepath="mymodel_{epoch}",
        save_best_only=True,  # Only save a model if `val_loss` has improved.
        monitor="val_loss",
        verbose=1,
    )
]
model.fit(
    x_train, y_train, epochs=2, batch_size=64, callbacks=callbacks, validation_split=0.2
)
Epoch 1/2
608/625 [============================>.] - ETA: 0s - loss: 0.3797 - sparse_categorical_accuracy: 0.8940
Epoch 00001: val_loss improved from inf to 0.23986, saving model to mymodel_1
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.
INFO:tensorflow:Assets written to: mymodel_1/assets
625/625 [==============================] - 2s 3ms/step - loss: 0.3765 - sparse_categorical_accuracy: 0.8949 - val_loss: 0.2399 - val_sparse_categorical_accuracy: 0.9276
Epoch 2/2
606/625 [============================>.] - ETA: 0s - loss: 0.1758 - sparse_categorical_accuracy: 0.9474
Epoch 00002: val_loss improved from 0.23986 to 0.19765, saving model to mymodel_2
INFO:tensorflow:Assets written to: mymodel_2/assets
625/625 [==============================] - 2s 3ms/step - loss: 0.1751 - sparse_categorical_accuracy: 0.9477 - val_loss: 0.1976 - val_sparse_categorical_accuracy: 0.9409

<tensorflow.python.keras.callbacks.History at 0x7f7550171f28>

La ModelCheckpoint llamada ModelCheckpoint se puede utilizar para implementar la tolerancia a fallos: la capacidad de reiniciar el entrenamiento desde el último estado guardado del modelo en caso de que el entrenamiento se interrumpa aleatoriamente. Aquí tienes un ejemplo básico:

import os

# Prepare a directory to store all the checkpoints.
checkpoint_dir = "./ckpt"
if not os.path.exists(checkpoint_dir):
    os.makedirs(checkpoint_dir)


def make_or_restore_model():
    # Either restore the latest model, or create a fresh one
    # if there is no checkpoint available.
    checkpoints = [checkpoint_dir + "/" + name for name in os.listdir(checkpoint_dir)]
    if checkpoints:
        latest_checkpoint = max(checkpoints, key=os.path.getctime)
        print("Restoring from", latest_checkpoint)
        return keras.models.load_model(latest_checkpoint)
    print("Creating a new model")
    return get_compiled_model()


model = make_or_restore_model()
callbacks = [
    # This callback saves a SavedModel every 100 batches.
    # We include the training loss in the saved model name.
    keras.callbacks.ModelCheckpoint(
        filepath=checkpoint_dir + "/ckpt-loss={loss:.2f}", save_freq=100
    )
]
model.fit(x_train, y_train, epochs=1, callbacks=callbacks)
Creating a new model
  94/1563 [>.............................] - ETA: 3s - loss: 0.9261 - sparse_categorical_accuracy: 0.7420INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.90/assets
 192/1563 [==>...........................] - ETA: 6s - loss: 0.6734 - sparse_categorical_accuracy: 0.8097INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.66/assets
 292/1563 [====>.........................] - ETA: 6s - loss: 0.5676 - sparse_categorical_accuracy: 0.8390INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.56/assets
 393/1563 [======>.......................] - ETA: 6s - loss: 0.5077 - sparse_categorical_accuracy: 0.8543INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.51/assets
 490/1563 [========>.....................] - ETA: 5s - loss: 0.4665 - sparse_categorical_accuracy: 0.8652INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.46/assets
 589/1563 [==========>...................] - ETA: 5s - loss: 0.4356 - sparse_categorical_accuracy: 0.8735INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.43/assets
 690/1563 [============>.................] - ETA: 4s - loss: 0.4077 - sparse_categorical_accuracy: 0.8813INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.41/assets
 791/1563 [==============>...............] - ETA: 4s - loss: 0.3883 - sparse_categorical_accuracy: 0.8873INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.39/assets
 892/1563 [================>.............] - ETA: 3s - loss: 0.3715 - sparse_categorical_accuracy: 0.8921INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.37/assets
 992/1563 [==================>...........] - ETA: 3s - loss: 0.3569 - sparse_categorical_accuracy: 0.8964INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.36/assets
1092/1563 [===================>..........] - ETA: 2s - loss: 0.3444 - sparse_categorical_accuracy: 0.8994INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.34/assets
1194/1563 [=====================>........] - ETA: 2s - loss: 0.3315 - sparse_categorical_accuracy: 0.9025INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.33/assets
1293/1563 [=======================>......] - ETA: 1s - loss: 0.3217 - sparse_categorical_accuracy: 0.9056INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.32/assets
1383/1563 [=========================>....] - ETA: 1s - loss: 0.3145 - sparse_categorical_accuracy: 0.9077INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.31/assets
1478/1563 [===========================>..] - ETA: 0s - loss: 0.3057 - sparse_categorical_accuracy: 0.9102INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.30/assets
1563/1563 [==============================] - 9s 6ms/step - loss: 0.2996 - sparse_categorical_accuracy: 0.9119

<tensorflow.python.keras.callbacks.History at 0x7f74ec20d668>

También llama a escribir su propia devolución de llamada para guardar y restaurar modelos.

Para obtener una guía completa sobre serialización y almacenamiento, consulte la guía para guardar y serializar modelos .

Usar programas de ritmo de aprendizaje

Un patrón común al entrenar modelos de aprendizaje profundo es reducir gradualmente el aprendizaje a medida que avanza el entrenamiento. Esto se conoce generalmente como "disminución de la tasa de aprendizaje".

El programa de deterioro del aprendizaje podría ser estático (fijado de antemano, en función de la época actual o del índice de lote actual) o dinámico (respondiendo al comportamiento actual del modelo, en particular la pérdida de validación).

Pasar una programación a un optimizador

Puede usar fácilmente un programa de disminución de la tasa de aprendizaje estático pasando un objeto de programación como argumento learning_rate en su optimizador:

initial_learning_rate = 0.1
lr_schedule = keras.optimizers.schedules.ExponentialDecay(
    initial_learning_rate, decay_steps=100000, decay_rate=0.96, staircase=True
)

optimizer = keras.optimizers.RMSprop(learning_rate=lr_schedule)

Hay varios programas integrados disponibles: ExponentialDecay , PiecewiseConstantDecay , PolynomialDecay e InverseTimeDecay .

Usar devoluciones de llamada para implementar un programa de ritmo de aprendizaje dinámico

No se puede lograr un programa de tasa de aprendizaje dinámico (por ejemplo, disminuir la tasa de aprendizaje cuando la pérdida de validación ya no mejora) con estos objetos de programación ya que el optimizador no tiene acceso a las métricas de validación.

Sin embargo, las devoluciones de llamada tienen acceso a todas las métricas, ¡incluidas las métricas de validación! Por lo tanto, puede lograr este patrón utilizando una devolución de llamada que modifica la tasa de aprendizaje actual en el optimizador. De hecho, esto incluso está integrado como devolución de llamada ReduceLROnPlateau .

Visualización de pérdidas y métricas durante el entrenamiento

La mejor manera de vigilar su modelo durante el entrenamiento es usar TensorBoard , una aplicación basada en navegador que puede ejecutar localmente y que le brinda:

  • Gráficos en vivo de la pérdida y métricas para entrenamiento y evaluación
  • (opcionalmente) Visualizaciones de los histogramas de sus activaciones de capa
  • (opcionalmente) visualizaciones 3D de los espacios de incrustación aprendidos por sus capas de Embedding

Si instaló TensorFlow con pip, debería poder iniciar TensorBoard desde la línea de comandos:

tensorboard --logdir=/full_path_to_your_logs

Usar la devolución de llamada de TensorBoard

La forma más fácil de usar TensorBoard con un modelo de Keras y el método de ajuste es la TensorBoard llamada de TensorBoard .

En el caso más simple, simplemente especifique dónde desea que la devolución de llamada escriba los registros, y estará listo:

keras.callbacks.TensorBoard(
    log_dir="/full_path_to_your_logs",
    histogram_freq=0,  # How often to log histogram visualizations
    embeddings_freq=0,  # How often to log embedding visualizations
    update_freq="epoch",
)  # How often to write logs (default: once per epoch)
<tensorflow.python.keras.callbacks.TensorBoard at 0x7f74ec5179e8>

Para obtener más información, consulte la documentación de la TensorBoard llamada de TensorBoard .