Cette page a été traduite par l'API Cloud Translation.
Switch to English

Formation et évaluation avec les méthodes intégrées

Voir sur TensorFlow.org Exécuter dans Google Colab Afficher la source sur GitHub Télécharger le carnet

Installer

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

introduction

Ce guide couvre les modèles de formation, d'évaluation et de prédiction (inférence) lors de l'utilisation d'API intégrées pour la formation et la validation (telles que model.fit() , model.evaluate() , model.predict() ).

Si vous souhaitez tirer parti de fit() tout en spécifiant votre propre fonction d'étape d'entraînement, consultez le guide «Personnalisation de ce qui se passe dans fit() » .

Si vous souhaitez rédiger vos propres boucles de formation et d'évaluation à partir de zéro, consultez le guide «Écrire une boucle de formation à partir de zéro» .

En général, que vous utilisiez des boucles intégrées ou que vous écriviez les vôtres, la formation et l'évaluation des modèles fonctionnent strictement de la même manière pour tous les types de modèles Keras - modèles séquentiels, modèles construits avec l'API fonctionnelle et modèles écrits à partir de zéro via sous-classement du modèle.

Ce guide ne couvre pas la formation distribuée. Pour la formation distribuée, consultez notre guide sur la formation multi-gpu et distribuée .

Présentation de l'API: un premier exemple de bout en bout

Lorsque vous transmettez des données aux boucles d'apprentissage intégrées d'un modèle, vous devez utiliser des tableaux NumPy (si vos données sont petites et tf.data Dataset en mémoire) ou des objets tf.data Dataset . Dans les prochains paragraphes, nous utiliserons l'ensemble de données MNIST en tant que tableaux NumPy, afin de montrer comment utiliser les optimiseurs, les pertes et les métriques.

Considérons le modèle suivant (ici, nous construisons avec l'API fonctionnelle, mais il peut également s'agir d'un modèle séquentiel ou d'un modèle sous-classé):

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)

Voici à quoi ressemble le flux de travail typique de bout en bout, composé de:

  • Entraînement
  • Validation sur un jeu d'exclusion généré à partir des données d'entraînement d'origine
  • Évaluation sur les données de test

Nous utiliserons les données MNIST pour cet exemple.

(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]

Nous spécifions la configuration de la formation (optimiseur, perte, métriques):

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

Nous appelons fit() , qui entraînera le modèle en découpant les données en "lots" de taille "batch_size", et en effectuant des itérations répétées sur l'ensemble de données pour un nombre donné "d'époques".

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

L'objet "historique" renvoyé contient un enregistrement des valeurs de perte et des valeurs de métrique pendant l'entraînement:

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]}

Nous évaluons le modèle sur les données de test via 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)

Passons maintenant en revue chaque élément de ce flux de travail en détail.

La méthode compile() : spécifier une perte, des métriques et un optimiseur

Pour entraîner un modèle avec fit() , vous devez spécifier une fonction de perte, un optimiseur et, éventuellement, des métriques à surveiller.

Vous les transmettez au modèle en tant qu'arguments de la méthode compile() :

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

L'argument metrics doit être une liste - votre modèle peut avoir n'importe quel nombre de métriques.

Si votre modèle a plusieurs sorties, vous pouvez spécifier différentes pertes et mesures pour chaque sortie, et vous pouvez moduler la contribution de chaque sortie à la perte totale du modèle. Vous trouverez plus de détails à ce sujet dans la section "Transmission de données aux modèles multi-entrées et multi-sorties" .

Notez que si vous êtes satisfait des paramètres par défaut, dans de nombreux cas, l'optimiseur, la perte et les mesures peuvent être spécifiés via des identificateurs de chaîne comme raccourci:

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

Pour une réutilisation ultérieure, mettons notre définition de modèle et notre étape de compilation dans les fonctions; nous les appellerons plusieurs fois à travers différents exemples de ce guide.

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

De nombreux optimiseurs, pertes et métriques intégrés sont disponibles

En général, vous n'aurez pas à créer à partir de zéro vos propres pertes, métriques ou optimiseurs, car ce dont vous avez besoin fait probablement déjà partie de l'API Keras:

Optimiseurs:

  • SGD() (avec ou sans momentum)
  • RMSprop()
  • Adam()
  • etc.

Pertes:

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

Métrique:

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

Pertes personnalisées

Il existe deux façons de fournir des pertes personnalisées avec Keras. Le premier exemple crée une fonction qui accepte les entrées y_true et y_pred . L'exemple suivant montre une fonction de perte qui calcule l'erreur quadratique moyenne entre les données réelles et les prédictions:

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 vous avez besoin d'une fonction de perte qui prend des paramètres à côté de y_true et y_pred , vous pouvez sous- tf.keras.losses.Loss classe tf.keras.losses.Loss et implémenter les deux méthodes suivantes:

  • __init__(self) : acceptez les paramètres à passer lors de l'appel de votre fonction de perte
  • call(self, y_true, y_pred) : utilisez les cibles (y_true) et les prédictions du modèle (y_pred) pour calculer la perte du modèle

Supposons que vous souhaitiez utiliser l'erreur quadratique moyenne, mais avec un terme supplémentaire qui découragera les valeurs de prédiction loin de 0,5 (nous supposons que les cibles catégorielles sont encodées à chaud et prennent des valeurs comprises entre 0 et 1). Cela incite le modèle à ne pas être trop confiant, ce qui peut aider à réduire le surajustement (nous ne saurons pas si cela fonctionne avant d'essayer!).

Voici comment procéder:

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étriques personnalisées

Si vous avez besoin d'une métrique qui ne fait pas partie de l'API, vous pouvez facilement créer des métriques personnalisées en sous- tf.keras.metrics.Metric classe tf.keras.metrics.Metric . Vous devrez implémenter 4 méthodes:

  • __init__(self) , dans lequel vous allez créer des variables d'état pour votre métrique.
  • update_state(self, y_true, y_pred, sample_weight=None) , qui utilise les cibles y_true et les prédictions du modèle y_pred pour mettre à jour les variables d'état.
  • result(self) , qui utilise les variables d'état pour calculer les résultats finaux.
  • reset_states(self) , qui réinitialise l'état de la métrique.

La mise à jour de l'état et le calcul des résultats sont séparés (dans update_state() et result() , respectivement) car dans certains cas, le calcul des résultats peut être très coûteux et ne serait effectué que périodiquement.

Voici un exemple simple montrant comment implémenter une métrique CategoricalTruePositives , qui compte le nombre d'échantillons correctement classés comme appartenant à une classe donnée:

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>

Gestion des pertes et des métriques qui ne correspondent pas à la signature standard

L'écrasante majorité des pertes et des métriques peut être calculée à partir de y_true et y_pred , où y_pred est une sortie de votre modèle. Mais pas tous. Par exemple, une perte de régularisation peut nécessiter uniquement l'activation d'une couche (il n'y a pas de cibles dans ce cas), et cette activation peut ne pas être une sortie de modèle.

Dans ce cas, vous pouvez appeler self.add_loss(loss_value) depuis la méthode d'appel d'une couche personnalisée. Les pertes ajoutées de cette manière sont ajoutées à la perte "principale" pendant l'entraînement (celle passée à compile() ). Voici un exemple simple qui ajoute la régularisation des activités (notez que la régularisation des activités est intégrée dans toutes les couches Keras - cette couche est juste pour donner un exemple concret):

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>

Vous pouvez faire de même pour la journalisation des valeurs de métrique, en utilisant 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>

Dans l' API fonctionnelle , vous pouvez également appeler model.add_loss(loss_tensor) ou model.add_metric(metric_tensor, name, aggregation) .

Voici un exemple simple:

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>

Notez que lorsque vous passez des pertes via add_loss() , il devient possible d'appeler compile() sans fonction de perte, puisque le modèle a déjà une perte à minimiser.

Considérez la couche LogisticEndpoint suivante: elle prend comme entrées des cibles et des logits, et elle suit une perte de add_loss() via add_loss() . Il suit également la précision de la classification via 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)

Vous pouvez l'utiliser dans un modèle avec deux entrées (données d'entrée et cibles), compilé sans argument de loss , comme ceci:

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>

Pour plus d'informations sur la formation de modèles à entrées multiples, reportez-vous à la section Transmission de données à des modèles à entrées et sorties multiples .

Mise à part automatique d'un jeu d'exclusion de validation

Dans le premier exemple de bout en bout que vous avez vu, nous avons utilisé l'argument validation_data pour passer un tuple de tableaux NumPy (x_val, y_val) au modèle pour évaluer une perte de validation et des métriques de validation à la fin de chaque époque.

Voici une autre option: l'argument validation_split vous permet de réserver automatiquement une partie de vos données d'entraînement pour validation. La valeur de l'argument représente la fraction des données à réserver pour la validation, elle doit donc être définie sur un nombre supérieur à 0 et inférieur à 1. Par exemple, validation_split=0.2 signifie "utiliser 20% des données pour la validation", et validation_split=0.6 signifie "utiliser 60% des données pour la validation".

La façon dont la validation est calculée est de prendre les derniers échantillons x% des tableaux reçus par l'appel d'ajustement, avant tout brassage.

Notez que vous ne pouvez utiliser validation_split lors de l'entraînement avec des données 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>

Formation et évaluation à partir des ensembles de données tf.data

Dans les derniers paragraphes, vous avez vu comment gérer les pertes, les métriques et les optimiseurs, et vous avez vu comment utiliser les arguments validation_data et validation_split en forme, lorsque vos données sont transmises sous forme de tableaux NumPy.

Examinons maintenant le cas où vos données se présentent sous la forme d'un objet tf.data.Dataset .

L'API tf.data est un ensemble d'utilitaires dans TensorFlow 2.0 pour charger et prétraiter les données de manière rapide et évolutive.

Pour obtenir un guide complet sur la création de Datasets , consultez la documentation tf.data .

Vous pouvez transmettre une instance de Dataset directement aux méthodes fit() , evaluate() et 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}

Notez que l'ensemble de données est réinitialisé à la fin de chaque époque, de sorte qu'il peut être réutilisé à l'époque suivante.

Si vous souhaitez exécuter l'entraînement uniquement sur un nombre spécifique de lots de cet ensemble de données, vous pouvez transmettre l'argument steps_per_epoch , qui spécifie le nombre d'étapes d'entraînement que le modèle doit exécuter à l'aide de cet ensemble de données avant de passer à l'époque suivante.

Si vous faites cela, le jeu de données n'est pas réinitialisé à la fin de chaque époque, au lieu de cela, nous continuons simplement à dessiner les lots suivants. L'ensemble de données finira par manquer de données (à moins qu'il ne s'agisse d'un ensemble de données en boucle infinie).

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>

Utilisation d'un ensemble de données de validation

Vous pouvez passer une instance de Dataset comme argument validation_data dans 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>

À la fin de chaque époque, le modèle effectuera une itération sur l'ensemble de données de validation et calculera la perte de validation et les métriques de validation.

Si vous souhaitez exécuter la validation uniquement sur un nombre spécifique de lots de cet ensemble de données, vous pouvez passer l'argument validation_steps , qui spécifie le nombre d'étapes de validation que le modèle doit exécuter avec l'ensemble de données de validation avant d'interrompre la validation et de passer à l'époque suivante:

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>

Notez que l'ensemble de données de validation sera réinitialisé après chaque utilisation (de sorte que vous évaluerez toujours sur les mêmes échantillons d'époque en époque).

L'argument validation_split (générant un ensemble d'exclusion à partir des données d'entraînement) n'est pas pris en charge lors de l'apprentissage à partir d'objets Dataset , car cette fonctionnalité nécessite la possibilité d'indexer les échantillons des ensembles de données, ce qui n'est généralement pas possible avec l'API Dataset .

Autres formats d'entrée pris en charge

Outre les tableaux NumPy, les tenseurs désireux et les Datasets TensorFlow, il est possible d'entraîner un modèle Keras à l'aide de cadres de données Pandas ou de générateurs Python qui génèrent des lots de données et d'étiquettes.

En particulier, la classe keras.utils.Sequence offre une interface simple pour créer des générateurs de données Python qui prennent en charge le multitraitement et peuvent être mélangés.

En général, nous vous recommandons d'utiliser:

  • Données d'entrée NumPy si vos données sont petites et tiennent en mémoire
  • Objets de jeu de Dataset si vous avez des jeux de données volumineux et que vous devez effectuer une formation distribuée
  • Objets de Sequence si vous avez de grands ensembles de données et que vous devez faire beaucoup de traitements personnalisés côté Python qui ne peuvent pas être effectués dans TensorFlow (par exemple, si vous comptez sur des bibliothèques externes pour le chargement ou le prétraitement des données).

Utilisation d'un objet keras.utils.Sequence comme entrée

keras.utils.Sequence est un utilitaire que vous pouvez sous- keras.utils.Sequence pour obtenir un générateur Python avec deux propriétés importantes:

  • Cela fonctionne bien avec le multitraitement.
  • Il peut être mélangé (par exemple en passant shuffle=True dans fit() ).

Une Sequence doit implémenter deux méthodes:

  • __getitem__
  • __len__

La méthode __getitem__ doit renvoyer un lot complet. Si vous souhaitez modifier votre ensemble de données entre les époques, vous pouvez implémenter on_epoch_end .

Voici un exemple rapide:

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)

Utilisation de la pondération des échantillons et de la pondération des classes

Avec les paramètres par défaut, le poids d'un échantillon est déterminé par sa fréquence dans l'ensemble de données. Il existe deux méthodes pour pondérer les données, indépendamment de la fréquence d'échantillonnage:

  • Poids de classe
  • Exemples de poids

Poids de classe

Il est fixé par le passage d' un dictionnaire à l' class_weight argument Model.fit() . Ce dictionnaire mappe les indices de classe au poids qui doit être utilisé pour les échantillons appartenant à cette classe.

Cela peut être utilisé pour équilibrer les classes sans rééchantillonnage, ou pour entraîner un modèle qui donne plus d'importance à une classe particulière.

Par exemple, si la classe "0" est deux fois moins représentée que la classe "1" dans vos données, vous pouvez utiliser Model.fit(..., class_weight={0: 1., 1: 0.5}) .

Voici un exemple NumPy où nous utilisons des pondérations de classe ou des pondérations d'échantillons pour donner plus d'importance à la classification correcte de la classe n ° 5 (qui est le chiffre «5» dans l'ensemble de données 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>

Exemples de poids

Pour un contrôle fin, ou si vous ne construisez pas de classificateur, vous pouvez utiliser des "poids d'échantillons".

  • Lors de l'entraînement à partir de données NumPy: sample_weight argument Model.fit() à Model.fit() .
  • Lors de l'entraînement à partir de tf.data ou de tout autre type d'itérateur: (input_batch, label_batch, sample_weight_batch) rendement (input_batch, label_batch, sample_weight_batch) .

Un tableau de "poids d'échantillon" est un tableau de nombres qui spécifient le poids que chaque échantillon d'un lot doit avoir dans le calcul de la perte totale. Il est couramment utilisé dans les problèmes de classification déséquilibrés (l'idée étant de donner plus de poids à des classes rarement vues).

Lorsque les poids utilisés sont des uns et des zéros, le tableau peut être utilisé comme masque pour la fonction de perte (en supprimant entièrement la contribution de certains échantillons à la perte totale).

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>

Voici un exemple d'ensemble de Dataset correspondant:

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>

Transmission de données à des modèles multi-entrées et multi-sorties

Dans les exemples précédents, nous considérions un modèle avec une seule entrée (un tenseur de forme (764,) ) et une seule sortie (un tenseur de prédiction de forme (10,) ). Mais qu'en est-il des modèles qui ont plusieurs entrées ou sorties?

Considérez le modèle suivant, qui a une entrée d'image de forme (32, 32, 3) (c'est-à-dire (height, width, channels) ) et une entrée de série temporelle de forme (None, 10) (c'est (timesteps, features) ). Notre modèle aura deux sorties calculées à partir de la combinaison de ces entrées: un «score» (de forme (1,) ) et une distribution de probabilité sur cinq classes (de forme (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]
)

Tracons ce modèle afin que vous puissiez clairement voir ce que nous faisons ici (notez que les formes affichées dans le tracé sont des formes par lots, plutôt que des formes par échantillon).

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

png

Au moment de la compilation, nous pouvons spécifier différentes pertes sur différentes sorties, en passant les fonctions de perte sous forme de liste:

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

Si nous ne transmettions qu'une seule fonction de perte au modèle, la même fonction de perte serait appliquée à chaque sortie (ce qui n'est pas approprié ici).

De même pour les métriques:

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()],
    ],
)

Puisque nous avons donné des noms à nos couches de sortie, nous pourrions également spécifier des pertes et des métriques par sortie via 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()],
    },
)

Nous vous recommandons d'utiliser des noms et dictionnaires explicites si vous avez plus de 2 sorties.

Il est possible de donner des poids différents à différentes pertes spécifiques à la sortie (par exemple, on peut souhaiter privilégier la perte "score" dans notre exemple, en donnant à 2x l'importance de la perte de classe), en utilisant l'argument 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},
)

Vous pouvez également choisir de ne pas calculer une perte pour certaines sorties, si ces sorties sont destinées à la prédiction mais pas à la formation:

# 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()},
)

La transmission de données à un modèle multi-entrées ou multi-sorties en ajustement fonctionne de la même manière que la spécification d'une fonction de perte lors de la compilation: vous pouvez transmettre des listes de tableaux NumPy (avec un mappage 1: 1 vers les sorties qui ont reçu une fonction de perte) ou dicts le mappage des noms de sortie aux tableaux 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>

Voici le cas d'utilisation du jeu de Dataset : de la même manière que ce que nous avons fait pour les tableaux NumPy, le jeu de Dataset doit renvoyer un tuple de dictionnaires.

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>

Utilisation des rappels

Les callbacks dans Keras sont des objets qui sont appelés à différents moments pendant l'apprentissage (au début d'une époque, à la fin d'un batch, à la fin d'une époque, etc.) et qui peuvent être utilisés pour implémenter des comportements tels que:

  • Faire la validation à différents moments de la formation (au-delà de la validation intégrée par époque)
  • Contrôle du modèle à intervalles réguliers ou lorsqu'il dépasse un certain seuil de précision
  • Changer le taux d'apprentissage du modèle lorsque la formation semble plafonner
  • Ajuster les couches supérieures lorsque l'entraînement semble plafonner
  • Envoi de notifications par e-mail ou par messagerie instantanée à la fin de l'entraînement ou lorsqu'un certain seuil de performance est dépassé
  • Etc.

Les rappels peuvent être passés sous forme de liste à votre appel à 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>

De nombreux rappels intégrés sont disponibles

  • ModelCheckpoint : enregistrez périodiquement le modèle.
  • EarlyStopping : EarlyStopping entraînement lorsque l'entraînement n'améliore plus les métriques de validation.
  • TensorBoard : TensorBoard périodiquement des logs de modèles qui peuvent être visualisés dans TensorBoard (plus de détails dans la section "Visualisation").
  • CSVLogger : diffuse les données de perte et de métrique dans un fichier CSV.
  • etc.

Voir la documentation des rappels pour la liste complète.

Rédaction de votre propre rappel

Vous pouvez créer un rappel personnalisé en étendant la classe de base keras.callbacks.Callback . Un rappel a accès à son modèle associé via la propriété de classe self.model .

Assurez-vous de lire le guide complet sur l'écriture de rappels personnalisés .

Voici un exemple simple d'enregistrement d'une liste de valeurs de perte par lot pendant l'entraînement:

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"))

Modèles de point de contrôle

Lorsque vous entraînez un modèle sur des ensembles de données relativement volumineux, il est essentiel d'enregistrer les points de contrôle de votre modèle à intervalles fréquents.

Le moyen le plus simple d'y parvenir est d' ModelCheckpoint rappel 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>

Le rappel ModelCheckpoint peut être utilisé pour implémenter la tolérance aux pannes: la possibilité de redémarrer l'entraînement à partir du dernier état enregistré du modèle au cas où l'entraînement serait interrompu de manière aléatoire. Voici un exemple de base:

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>

Vous appelez également écrire votre propre rappel pour enregistrer et restaurer les modèles.

Pour un guide complet sur la sérialisation et l'enregistrement, consultez le guide d'enregistrement et de sérialisation des modèles .

Utilisation des grilles de taux d'apprentissage

Un modèle courant lors de la formation de modèles d'apprentissage profond consiste à réduire progressivement l'apprentissage au fur et à mesure que la formation progresse. Ceci est généralement connu sous le nom de «décroissance du taux d'apprentissage».

Le calendrier de décroissance d'apprentissage peut être statique (fixé à l'avance, en fonction de l'époque courante ou de l'indice de lot courant), ou dynamique (répondant au comportement actuel du modèle, en particulier la perte de validation).

Passer un planning à un optimiseur

Vous pouvez facilement utiliser un calendrier de décroissance du taux d'apprentissage statique en passant un objet de planification comme argument learning_rate dans votre optimiseur:

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)

Plusieurs planifications intégrées sont disponibles: ExponentialDecay , PiecewiseConstantDecay , PolynomialDecay et InverseTimeDecay .

Utilisation des rappels pour mettre en œuvre un calendrier de taux d'apprentissage dynamique

Un programme de taux d'apprentissage dynamique (par exemple, la diminution du taux d'apprentissage lorsque la perte de validation ne s'améliore plus) ne peut pas être obtenu avec ces objets de planification car l'optimiseur n'a pas accès aux métriques de validation.

Cependant, les rappels ont accès à toutes les métriques, y compris les métriques de validation! Vous pouvez ainsi réaliser ce modèle en utilisant un callback qui modifie le taux d'apprentissage actuel sur l'optimiseur. En fait, cela est même intégré au rappel ReduceLROnPlateau .

Visualiser les pertes et les métriques pendant l'entraînement

La meilleure façon de garder un œil sur votre modèle pendant l'entraînement est d'utiliser TensorBoard , une application basée sur un navigateur que vous pouvez exécuter localement et qui vous fournit:

  • Graphiques en direct de la perte et métriques pour la formation et l'évaluation
  • (en option) Visualisations des histogrammes de vos activations de calques
  • (en option) visualisations 3D des espaces d'incorporation appris par vos calques d' Embedding

Si vous avez installé TensorFlow avec pip, vous devriez pouvoir lancer TensorBoard à partir de la ligne de commande:

tensorboard --logdir=/full_path_to_your_logs

Utilisation du rappel TensorBoard

Le moyen le plus simple d'utiliser TensorBoard avec un modèle Keras et la méthode fit est le rappel TensorBoard .

Dans le cas le plus simple, spécifiez simplement où vous voulez que le rappel écrive les journaux, et vous êtes prêt à partir:

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>

Pour plus d'informations, consultez la documentation du rappel TensorBoard .