Ayuda a proteger la Gran Barrera de Coral con TensorFlow en Kaggle Únete Challenge

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

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

Configuración

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

Introducción

Esta guía cubre la formación, evaluación y predicción (inferencia) modelos cuando se utiliza una función de API para el entrenamiento y validación (como Model.fit() , Model.evaluate() y Model.predict() ).

Si usted está interesado en el aprovechamiento de fit() especificando su propia función de paso de formación, consulte el Personalización de lo que sucede en el fit() guía .

Si está interesado en escribir sus propios bucles de formación y de evaluación a partir de cero, consulte la guía de "escribir un bucle de formación a partir de cero" .

En general, ya sea que esté utilizando bucles integrados o escribiendo 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 a través de subclases de modelos.

Esta guía no cubre la formación distribuida, que está cubierto en nuestra guía de multi-GPU y la formación distribuida .

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

Al pasar los datos a la incorporada en la formación de bucles de un modelo, debe utilizar matrices NumPy (si sus datos es pequeño y cabe en memoria) o tf.data Dataset objetos. En los siguientes 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:

  • Capacitación
  • Validación en un conjunto de reserva 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()],
)

Hacemos un llamado fit() , que formará el modelo por corte de los datos en "lotes" de tamaño batch_size , y repetidamente interactuando sobre todo el conjunto de datos para un determinado número de epochs .

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 [==============================] - 3s 3ms/step - loss: 0.3387 - sparse_categorical_accuracy: 0.9050 - val_loss: 0.1957 - val_sparse_categorical_accuracy: 0.9426
Epoch 2/2
782/782 [==============================] - 2s 3ms/step - loss: 0.1543 - sparse_categorical_accuracy: 0.9548 - val_loss: 0.1425 - val_sparse_categorical_accuracy: 0.9593

La regresado history objeto contiene un registro de los valores de pérdida y los valores del indicador durante el entrenamiento:

history.history
{'loss': [0.3386789858341217, 0.1543138176202774],
 'sparse_categorical_accuracy': [0.9050400257110596, 0.9548400044441223],
 'val_loss': [0.19569723308086395, 0.14253544807434082],
 'val_sparse_categorical_accuracy': [0.9426000118255615, 0.9592999815940857]}

Evaluamos el modelo de 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 2ms/step - loss: 0.1414 - sparse_categorical_accuracy: 0.9569
test loss, test acc: [0.14140386879444122, 0.9569000005722046]
Generate predictions for 3 samples
predictions shape: (3, 10)

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

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

Para entrenar un modelo con fit() , es necesario especificar una función de pérdida, un optimizador, y, opcionalmente, algunas métricas a monitor.

Se pasa éstos al modelo como argumentos para la compile() método:

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

El metrics argumento 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 sobre esto en los datos que pasan a multi-entrada, sección de modelos 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

Se encuentran 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 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

Si necesita crear una pérdida personalizada, Keras ofrece dos formas de hacerlo.

El primer método implica la creación de una función que acepta entradas y_true y 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 [==============================] - 2s 2ms/step - loss: 0.0162
<keras.callbacks.History at 0x7ff8881ba250>

Si necesita una función de pérdida que se lleva en los parámetros lado y_true y y_pred , puede subclase el tf.keras.losses.Loss clase y poner en práctica los dos métodos siguientes:

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

Supongamos que desea usar 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 [==============================] - 2s 2ms/step - loss: 0.0388
<keras.callbacks.History at 0x7ff8882130d0>

Métricas personalizadas

Si necesita una métrica que no forma parte de la API, puede crear fácilmente métricas personalizadas subclasificando la tf.keras.metrics.Metric clase. Deberá implementar 4 métodos:

  • __init__(self) , en el que se va a 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.

Actualización de estado y los resultados de cálculo se mantienen separados (en update_state() y el result() , respectivamente) debido a que en algunos casos, el cálculo de los resultados puede ser muy costoso y sólo se llevaría a cabo de forma periódica.

He aquí un ejemplo simple que muestra cómo implementar un CategoricalTruePositives métrica que cuenta cuántas muestras fueron correctamente clasificados 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_state(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 [==============================] - 2s 3ms/step - loss: 0.3404 - categorical_true_positives: 45217.0000
Epoch 2/3
782/782 [==============================] - 2s 3ms/step - loss: 0.1588 - categorical_true_positives: 47606.0000
Epoch 3/3
782/782 [==============================] - 2s 3ms/step - loss: 0.1168 - categorical_true_positives: 48278.0000
<keras.callbacks.History at 0x7ff8880a3610>

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 las métricas puede calcularse a partir 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 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 self.add_loss(loss_value) desde el interior del método llamado de una capa personalizada. Las pérdidas añadidas de esta manera se añaden a la pérdida de "principal" durante el entrenamiento (la aprobada para compile() ). Aquí hay un ejemplo simple que agrega regularización de actividad (tenga en cuenta que la regularización de actividad está incorporada en todas las capas de Keras; esta capa es solo para 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 [==============================] - 2s 2ms/step - loss: 2.4545
<keras.callbacks.History at 0x7ff87c53f310>

Puede hacer lo mismo para el registro de valores de indicadores, utilizando 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 [==============================] - 2s 2ms/step - loss: 0.3461 - std_of_activation: 0.9929
<keras.callbacks.History at 0x7ff87c3d5bd0>

En el API funcional , también puede llamar a 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 [==============================] - 2s 3ms/step - loss: 2.4647 - std_of_activation: 0.0017
<keras.callbacks.History at 0x7ff87c216f90>

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

Consideremos el siguiente LogisticEndpoint capa: toma como entradas objetivos y logits, y hace un seguimiento de una pérdida crossentropy través add_loss() . También sigue la precisión de 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)

Se puede utilizar en un modelo con dos entradas (datos de entrada y metas), compilado sin loss argumento, 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 414ms/step - loss: 0.9889 - binary_accuracy: 0.0000e+00
<keras.callbacks.History at 0x7ff87c0848d0>

Para obtener más información sobre el entrenamiento de los modelos multi-entrada, consulte la sección de pasar datos a múltiples modelos de entrada, de salida múltiple.

Separación automática de un conjunto de exclusión de validación

En el primer ejemplo de extremo a extremo que viste, se utilizó el validation_data argumento para pasar una tupla de matrices NumPy (x_val, y_val) en el modelo para evaluar una pérdida de validación y las métricas de validación al final de cada época.

Aquí hay otra opción: el argumento validation_split le permite automáticamente parte de reserva de sus datos de entrenamiento para su validación. El valor del argumento representa la fracción de los datos a ser reservados para la validación, por lo que se debe establecer en un número mayor que 0 y menor que 1. Por ejemplo, validation_split=0.2 medios de "uso 20% de los datos para la validación", y validation_split=0.6 medios de "uso 60% de los datos para la validación".

La forma en que se calcula la validación es a través de los últimos x% de las muestras de las matrices recibidos por el fit() llamada, antes de cualquier arrastrando los pies.

Tenga en cuenta que sólo se puede utilizar validation_split cuando el entrenamiento con los datos NumPy.

model = get_compiled_model()
model.fit(x_train, y_train, batch_size=64, validation_split=0.2, epochs=1)
625/625 [==============================] - 2s 3ms/step - loss: 0.3682 - sparse_categorical_accuracy: 0.8957 - val_loss: 0.2276 - val_sparse_categorical_accuracy: 0.9301
<keras.callbacks.History at 0x7ff81c680890>

Capacitación y evaluación de los conjuntos de datos de tf.data

En los últimos párrafos, que ha visto cómo manejar las pérdidas, métricas y optimizadores, y que ha visto cómo utilizar los validation_data y validation_split argumentos de fit() , cuando los datos se pasa como matrices NumPy.

Ahora vamos a echar un vistazo al caso de que sus datos se presenta en forma de un tf.data.Dataset objeto.

El tf.data API es un conjunto de utilidades en TensorFlow 2.0 para la carga y los datos de preprocesamiento de un modo que es rápido y escalable.

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

Puede pasar un Dataset instancia 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 3ms/step - loss: 0.3372 - sparse_categorical_accuracy: 0.9047
Epoch 2/3
782/782 [==============================] - 2s 3ms/step - loss: 0.1596 - sparse_categorical_accuracy: 0.9523
Epoch 3/3
782/782 [==============================] - 2s 3ms/step - loss: 0.1171 - sparse_categorical_accuracy: 0.9655
Evaluate
157/157 [==============================] - 0s 2ms/step - loss: 0.1211 - sparse_categorical_accuracy: 0.9648
{'loss': 0.12107347697019577,
 'sparse_categorical_accuracy': 0.9648000001907349}

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

Si desea ejecutar el entrenamiento sólo en un determinado número de lotes a partir de este conjunto de datos, se puede pasar el steps_per_epoch argumento, que especifica el número de pasos de formación del modelo se debe ejecutar utilizando 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 [==============================] - 1s 3ms/step - loss: 0.7937 - sparse_categorical_accuracy: 0.7894
Epoch 2/3
100/100 [==============================] - 0s 3ms/step - loss: 0.3699 - sparse_categorical_accuracy: 0.8938
Epoch 3/3
100/100 [==============================] - 0s 3ms/step - loss: 0.3155 - sparse_categorical_accuracy: 0.9061
<keras.callbacks.History at 0x7ff81c587e90>

Usando un conjunto de datos de validación

Puede pasar un Dataset de instancia que el validation_data argumento de 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 [==============================] - 3s 3ms/step - loss: 0.3380 - sparse_categorical_accuracy: 0.9035 - val_loss: 0.2015 - val_sparse_categorical_accuracy: 0.9405
<keras.callbacks.History at 0x7ff81c30e450>

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 sólo en un determinado número de lotes a partir de este conjunto de datos, se puede pasar el validation_steps argumento, que especifica el número de pasos de validación del modelo se debe ejecutar con el conjunto de datos de validación antes de interrumpir la validación y de 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 [==============================] - 3s 3ms/step - loss: 0.3369 - sparse_categorical_accuracy: 0.9036 - val_loss: 0.2953 - val_sparse_categorical_accuracy: 0.9187
<keras.callbacks.History at 0x7ff81c30e310>

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 (generación de un conjunto holdout de los datos de entrenamiento) no se admite cuando la formación de Dataset de objetos, ya que esta característica requiere la capacidad de índice de las muestras de los conjuntos de datos, que no es posible en general con el Dataset API.

Otros formatos de entrada compatibles

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

En particular, los keras.utils.Sequence ofertas de clase una interfaz sencilla para construir generadores de datos de Python que se multiprocesamiento-conscientes y pueden ser mezcladas.

En general, le recomendamos que utilice:

  • Ingrese datos NumPy si sus datos son pequeños y caben en la memoria
  • Dataset objetos si tiene grandes conjuntos de datos y que tiene que hacer la formación distribuida
  • Sequence objetos si tiene grandes conjuntos de datos y que tiene que hacer una gran cantidad de procesamiento del lado de Python personalizado que no se puede hacer en TensorFlow (por ejemplo, si se basan en las bibliotecas externas para la carga de datos o el procesamiento previo).

El uso de un keras.utils.Sequence objeto como entrada

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

  • Funciona bien con multiprocesamiento.
  • Se puede arrastrando los pies (por ejemplo, al pasar shuffle=True en fit() ).

Una Sequence debe implementar dos métodos:

  • __getitem__
  • __len__

El método __getitem__ debe devolver un lote completo. Si desea modificar el conjunto de datos entre las épocas, es posible aplicar 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 debe usarse 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 la clase representada como "1" en sus datos, puede utilizar 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 3ms/step - loss: 0.3708 - sparse_categorical_accuracy: 0.9032
<keras.callbacks.History at 0x7ff80c7ddd10>

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() .
  • Cuando la formación de tf.data o cualquier otro tipo de iterador: Rendimiento (input_batch, label_batch, sample_weight_batch) tuplas.

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 completamente 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 3ms/step - loss: 0.3806 - sparse_categorical_accuracy: 0.9000
<keras.callbacks.History at 0x7ff80c650350>

He aquí un juego Dataset ejemplo:

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 [==============================] - 3s 3ms/step - loss: 0.3588 - sparse_categorical_accuracy: 0.9070
<keras.callbacks.History at 0x7ff80c51cb50>

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 sola salida (un tensor 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) (que es (height, width, channels) ) y una entrada de serie de tiempo de forma (None, 10) (que 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 dict:

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 de producción específicos (por ejemplo, uno podría desear privilegiar la pérdida de "puntuación" en nuestro ejemplo, al dar a 2x la importancia de la pérdida de clases), utilizando el loss_weights argumento:

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 multi-entrada o modelo de múltiples salidas de fit() funciona de una manera similar a la especificación de una función de pérdida de compilación: se puede pasar listas de matrices NumPy (con 1: 1 asignación a las salidas que recibieron una función de pérdida ) o dicts mapeo de nombres de salida de 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 [==============================] - 2s 9ms/step - loss: 5.6917 - score_output_loss: 0.1031 - class_output_loss: 5.5886
4/4 [==============================] - 0s 6ms/step - loss: 4.4108 - score_output_loss: 0.0999 - class_output_loss: 4.3109
<keras.callbacks.History at 0x7ff80c3b4110>

Aquí está el Dataset de casos de uso: de manera similar a lo que hicimos para las matrices NumPy, el Dataset debe devolver una tupla de dicts.

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 21ms/step - loss: 4.2451 - score_output_loss: 0.0993 - class_output_loss: 4.1458
<keras.callbacks.History at 0x7ff80c3ed450>

Usar devoluciones de llamada

Las devoluciones de llamada en Keras son objetos que se llaman en diferentes puntos durante el entrenamiento (al comienzo de una época, al final de un lote, al final de una época, etc.). Se pueden usar para implementar ciertos 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.

Devoluciones de llamada se pueden pasar como una lista a su llamada a la 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 [==============================] - 2s 3ms/step - loss: 0.3725 - sparse_categorical_accuracy: 0.8939 - val_loss: 0.2314 - val_sparse_categorical_accuracy: 0.9321
Epoch 2/20
625/625 [==============================] - 2s 3ms/step - loss: 0.1805 - sparse_categorical_accuracy: 0.9471 - val_loss: 0.2012 - val_sparse_categorical_accuracy: 0.9379
Epoch 3/20
625/625 [==============================] - 2s 3ms/step - loss: 0.1346 - sparse_categorical_accuracy: 0.9603 - val_loss: 0.1651 - val_sparse_categorical_accuracy: 0.9505
Epoch 4/20
625/625 [==============================] - 2s 3ms/step - loss: 0.1065 - sparse_categorical_accuracy: 0.9684 - val_loss: 0.1510 - val_sparse_categorical_accuracy: 0.9571
Epoch 5/20
625/625 [==============================] - 2s 3ms/step - loss: 0.0884 - sparse_categorical_accuracy: 0.9734 - val_loss: 0.1505 - val_sparse_categorical_accuracy: 0.9538
Epoch 6/20
625/625 [==============================] - 2s 3ms/step - loss: 0.0746 - sparse_categorical_accuracy: 0.9778 - val_loss: 0.1508 - val_sparse_categorical_accuracy: 0.9575
Epoch 00006: early stopping
<keras.callbacks.History at 0x7ff80c64cad0>

Hay muchas devoluciones de llamada integradas disponibles

Hay muchas devoluciones de llamada integradas que ya están disponibles en Keras, como:

  • ModelCheckpoint : Periódicamente guardar el modelo.
  • EarlyStopping : la formación de detención cuando la formación ya no es mejorar las métricas de validación.
  • TensorBoard : troncos modelo periódicamente de escritura que se pueden visualizar en TensorBoard (más detalles en el "Visualización" sección).
  • CSVLogger : Secuencias de pérdida de datos y métricas en un archivo CSV.
  • etc.

Consulte la documentación de las devoluciones de llamada para la lista completa.

Escribiendo su propia devolución de llamada

Puede crear una devolución de llamada personalizados mediante la extensión de 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 personalizados .

Aquí hay un ejemplo simple 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 sencilla de lograr esto es con el ModelCheckpoint devolución de llamada:

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
613/625 [============================>.] - ETA: 0s - loss: 0.3693 - sparse_categorical_accuracy: 0.8972
Epoch 00001: val_loss improved from inf to 0.23508, saving model to mymodel_1
2021-11-12 20:11:50.182298: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: mymodel_1/assets
625/625 [==============================] - 3s 4ms/step - loss: 0.3660 - sparse_categorical_accuracy: 0.8979 - val_loss: 0.2351 - val_sparse_categorical_accuracy: 0.9273
Epoch 2/2
620/625 [============================>.] - ETA: 0s - loss: 0.1659 - sparse_categorical_accuracy: 0.9507
Epoch 00002: val_loss improved from 0.23508 to 0.16898, saving model to mymodel_2
INFO:tensorflow:Assets written to: mymodel_2/assets
625/625 [==============================] - 2s 3ms/step - loss: 0.1657 - sparse_categorical_accuracy: 0.9507 - val_loss: 0.1690 - val_sparse_categorical_accuracy: 0.9482
<keras.callbacks.History at 0x7ff8b577cc90>

El ModelCheckpoint devolución de llamada se puede utilizar para poner en práctica la tolerancia a fallos: la capacidad de formación de reinicio desde el último estado guardado del modelo en el entrenamiento caso se interrumpe al azar. 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
  88/1563 [>.............................] - ETA: 3s - loss: 1.1203 - sparse_categorical_accuracy: 0.6911INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=1.04/assets
 185/1563 [==>...........................] - ETA: 6s - loss: 0.7768 - sparse_categorical_accuracy: 0.7858INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.75/assets
 286/1563 [====>.........................] - ETA: 6s - loss: 0.6382 - sparse_categorical_accuracy: 0.8211INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.63/assets
 383/1563 [======>.......................] - ETA: 6s - loss: 0.5584 - sparse_categorical_accuracy: 0.8433INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.55/assets
 484/1563 [========>.....................] - ETA: 6s - loss: 0.5032 - sparse_categorical_accuracy: 0.8578INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.50/assets
 586/1563 [==========>...................] - ETA: 5s - loss: 0.4644 - sparse_categorical_accuracy: 0.8684INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.46/assets
 685/1563 [============>.................] - ETA: 5s - loss: 0.4356 - sparse_categorical_accuracy: 0.8762INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.43/assets
 783/1563 [==============>...............] - ETA: 5s - loss: 0.4127 - sparse_categorical_accuracy: 0.8825INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.41/assets
 883/1563 [===============>..............] - ETA: 4s - loss: 0.3958 - sparse_categorical_accuracy: 0.8868INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.39/assets
 985/1563 [=================>............] - ETA: 3s - loss: 0.3766 - sparse_categorical_accuracy: 0.8918INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.38/assets
1086/1563 [===================>..........] - ETA: 3s - loss: 0.3624 - sparse_categorical_accuracy: 0.8958INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.36/assets
1184/1563 [=====================>........] - ETA: 2s - loss: 0.3498 - sparse_categorical_accuracy: 0.8994INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.35/assets
1283/1563 [=======================>......] - ETA: 1s - loss: 0.3383 - sparse_categorical_accuracy: 0.9029INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.34/assets
1386/1563 [=========================>....] - ETA: 1s - loss: 0.3265 - sparse_categorical_accuracy: 0.9058INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.33/assets
1485/1563 [===========================>..] - ETA: 0s - loss: 0.3184 - sparse_categorical_accuracy: 0.9081INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.32/assets
1563/1563 [==============================] - 11s 7ms/step - loss: 0.3122 - sparse_categorical_accuracy: 0.9097
<keras.callbacks.History at 0x7ff8b53e1dd0>

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

Para una guía completa en la serialización y el ahorro, consulte la guía para el ahorro y la serialización de los modelos .

Usar horarios de tasas 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

Usted puede utilizar fácilmente un horario descomposición tasa de aprendizaje estática pasando un objeto horario que el learning_rate argumento 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)

Varios programas internos están disponibles: ExponentialDecay , PiecewiseConstantDecay , PolynomialDecay y 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 es aún incorporada como el ReduceLROnPlateau de devolución de llamada.

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 navegador que se puede ejecutar de forma local que le proporciona:

  • Gráficos en vivo de la pérdida y métricas para capacitación y evaluación.
  • (opcionalmente) Visualizaciones de los histogramas de sus activaciones de capa
  • (opcionalmente) y diseño 3D de los espacios de incrustación memorizada por el Embedding capas

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 Keras y el fit() método es el TensorBoard devolución de llamada.

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)
<keras.callbacks.TensorBoard at 0x7ff88c8c04d0>

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