Eine Frage haben? Verbinden Sie sich mit der Community im TensorFlow Forum Visit Forum

Schulung und Bewertung mit den eingebauten Methoden

Ansicht auf TensorFlow.org In Google Colab ausführen Quelle auf GitHub anzeigen Notizbuch herunterladen

Einrichten

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

Einführung

Dieses Handbuch behandelt Trainings-, Evaluierungs- und Vorhersagemodelle (Inferenzmodelle), wenn integrierte APIs für Training und Validierung verwendet werden (z. B. Model.fit() , Model.evaluate() und Model.predict() ).

Wenn Sie fit() nutzen möchten, während Sie Ihre eigene Trainingsschrittfunktion angeben, lesen Sie die Anleitung Anpassen, was in fit() geschieht .

Wenn Sie daran interessiert sind, Ihre eigenen Trainings- und Bewertungsschleifen von Grund auf neu zu schreiben , lesen Sie die Anleitung "Schreiben einer Trainingsschleife von Grund auf neu" .

Unabhängig davon, ob Sie integrierte Schleifen verwenden oder eigene schreiben, funktioniert die Modellschulung und -bewertung für alle Arten von Keras-Modellen streng gleich - sequentielle Modelle, Modelle, die mit der Funktions-API erstellt wurden, und Modelle, die von Grund auf neu geschrieben wurden Modellunterklassen.

Dieses Handbuch behandelt keine verteilten Schulungen, die in unserem Handbuch zu Multi-GPU- und verteilten Schulungen behandelt werden .

API-Übersicht: Ein erstes End-to-End-Beispiel

Wenn Sie Daten an die integrierten Trainingsschleifen eines Modells übergeben, sollten Sie entweder NumPy-Arrays (wenn Ihre Daten klein sind und in den Speicher tf.data Dataset ) oder tf.data Dataset Objekte verwenden . In den nächsten Absätzen verwenden wir das MNIST-Dataset als NumPy-Arrays, um die Verwendung von Optimierern, Verlusten und Metriken zu demonstrieren.

Betrachten wir das folgende Modell (hier bauen wir die funktionale API ein, es kann sich aber auch um ein sequentielles Modell oder ein untergeordnetes Modell handeln):

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)

So sieht der typische End-to-End-Workflow aus: Bestehend aus:

  • Ausbildung
  • Validierung eines Holdout-Sets, das aus den ursprünglichen Trainingsdaten generiert wurde
  • Auswertung der Testdaten

In diesem Beispiel werden MNIST-Daten verwendet.

(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]
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step

Wir geben die Trainingskonfiguration an (Optimierer, Verlust, Metriken):

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

Wir rufen fit() , das das Modell trainiert, indem die Daten in " batch_size " der Größe batch_size und für eine bestimmte Anzahl von epochs wiederholt über den gesamten Datensatz iteriert werden.

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.5769 - sparse_categorical_accuracy: 0.8386 - val_loss: 0.1833 - val_sparse_categorical_accuracy: 0.9464
Epoch 2/2
782/782 [==============================] - 2s 2ms/step - loss: 0.1621 - sparse_categorical_accuracy: 0.9518 - val_loss: 0.1467 - val_sparse_categorical_accuracy: 0.9579

Das zurückgegebene history enthält eine Aufzeichnung der Verlustwerte und Metrikwerte während des Trainings:

history.history
{'loss': [0.3323673903942108, 0.15159013867378235],
 'sparse_categorical_accuracy': [0.9050800204277039, 0.9542400240898132],
 'val_loss': [0.18328842520713806, 0.14667865633964539],
 'val_sparse_categorical_accuracy': [0.946399986743927, 0.9578999876976013]}

Wir bewerten das Modell anhand der Testdaten über 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.1449 - sparse_categorical_accuracy: 0.9539
test loss, test acc: [0.14493884146213531, 0.9538999795913696]
Generate predictions for 3 samples
predictions shape: (3, 10)

Lassen Sie uns nun jeden Teil dieses Workflows im Detail überprüfen.

Die compile() -Methode: Angabe eines Verlusts, von Metriken und eines Optimierers

Um ein Modell mit fit() zu trainieren, müssen Sie eine Verlustfunktion, einen Optimierer und optional einige zu überwachende Metriken angeben.

Sie übergeben diese als Argumente an die compile() -Methode an das Modell:

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

Das metrics sollte eine Liste sein - Ihr Modell kann eine beliebige Anzahl von Metriken enthalten.

Wenn Ihr Modell mehrere Ausgaben hat, können Sie für jede Ausgabe unterschiedliche Verluste und Metriken angeben und den Beitrag jeder Ausgabe zum Gesamtverlust des Modells modulieren. Weitere Informationen hierzu finden Sie im Abschnitt Übergeben von Daten an Modelle mit mehreren Eingängen und Ausgängen .

Beachten Sie, dass, wenn Sie mit den Standardeinstellungen zufrieden sind, in vielen Fällen der Optimierer, der Verlust und die Metriken über Zeichenfolgenkennungen als Verknüpfung angegeben werden können:

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

Lassen Sie uns zur späteren Wiederverwendung unsere Modelldefinition und den Kompilierungsschritt in Funktionen einfügen. Wir werden sie in diesem Handbuch mehrmals anhand verschiedener Beispiele aufrufen.

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

Viele integrierte Optimierer, Verluste und Metriken sind verfügbar

Im Allgemeinen müssen Sie keine eigenen Verluste, Metriken oder Optimierer von Grund auf neu erstellen, da das, was Sie benötigen, wahrscheinlich bereits Teil der Keras-API ist:

Optimierer:

  • SGD() (mit oder ohne Impuls)
  • RMSprop()
  • Adam()
  • usw.

Verluste:

  • MeanSquaredError()
  • KLDivergence()
  • CosineSimilarity()
  • usw.

Metriken:

  • AUC()
  • Precision()
  • Recall()
  • usw.

Zollverluste

Wenn Sie einen benutzerdefinierten Verlust erstellen müssen, bietet Keras zwei Möglichkeiten, dies zu tun.

Die erste Methode besteht darin, eine Funktion zu erstellen, die die Eingaben y_true und y_pred akzeptiert. Das folgende Beispiel zeigt eine Verlustfunktion, die den mittleren quadratischen Fehler zwischen den realen Daten und den Vorhersagen berechnet:

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.0272
<tensorflow.python.keras.callbacks.History at 0x7fb6b01c09e8>

Wenn Sie eine Verlustfunktion benötigen, die neben y_true und y_pred Parameter y_pred , können Sie die Klasse tf.keras.losses.Loss und die folgenden zwei Methoden implementieren:

  • __init__(self) : Akzeptiert Parameter, die während des Aufrufs Ihrer Verlustfunktion übergeben werden sollen
  • call(self, y_true, y_pred) : Verwenden Sie die Ziele (y_true) und die Modellvorhersagen (y_pred), um den Verlust des Modells zu berechnen

Angenommen, Sie möchten den mittleren quadratischen Fehler verwenden, jedoch mit einem zusätzlichen Begriff, der die Vorhersagewerte weit von 0,5 entfernt (wir gehen davon aus, dass die kategorialen Ziele One-Hot-codiert sind und Werte zwischen 0 und 1 annehmen). Dies schafft einen Anreiz für das Modell, nicht zu sicher zu sein, was dazu beitragen kann, die Überanpassung zu reduzieren (wir werden nicht wissen, ob es funktioniert, bis wir es versuchen!).

So würden Sie es machen:

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.0489
<tensorflow.python.keras.callbacks.History at 0x7fb6b00725f8>

Benutzerdefinierte Metriken

Wenn Sie eine Metrik benötigen, die nicht Teil der API ist, können Sie einfach benutzerdefinierte Metriken erstellen, indem Sie die Klasse tf.keras.metrics.Metric . Sie müssen 4 Methoden implementieren:

  • __init__(self) , in dem Sie Statusvariablen für Ihre Metrik erstellen.
  • update_state(self, y_true, y_pred, sample_weight=None) , das die Ziele y_true und die Modellvorhersagen y_pred verwendet, um die Statusvariablen zu aktualisieren.
  • result(self) , das die Statusvariablen verwendet, um die Endergebnisse zu berechnen.
  • reset_states(self) , das den Status der Metrik neu reset_states(self) .

update_state() und Ergebnisberechnung werden getrennt gehalten (in update_state() bzw. result() ), da in einigen Fällen die Ergebnisberechnung sehr teuer sein kann und nur in regelmäßigen Abständen durchgeführt wird.

Hier ist ein einfaches Beispiel, das zeigt, wie eine CategoricalTruePositives Metrik implementiert wird, die zählt, wie viele Stichproben korrekt als zu einer bestimmten Klasse gehörend klassifiziert wurden:

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 [==============================] - 2s 2ms/step - loss: 0.5782 - categorical_true_positives: 22110.9323
Epoch 2/3
782/782 [==============================] - 2s 2ms/step - loss: 0.1737 - categorical_true_positives: 23825.8212
Epoch 3/3
782/782 [==============================] - 2s 2ms/step - loss: 0.1254 - categorical_true_positives: 24152.4547
<tensorflow.python.keras.callbacks.History at 0x7fb6a42a55f8>

Umgang mit Verlusten und Metriken, die nicht zur Standardsignatur passen

Die überwiegende Mehrheit der Verluste und Metriken kann aus y_true und y_pred berechnet werden, wobei y_pred eine Ausgabe Ihres Modells ist - aber nicht alle. Beispielsweise erfordert ein Regularisierungsverlust möglicherweise nur die Aktivierung einer Ebene (in diesem Fall gibt es keine Ziele), und diese Aktivierung ist möglicherweise keine Modellausgabe.

In solchen Fällen können Sie self.add_loss(loss_value) innerhalb der self.add_loss(loss_value) einer benutzerdefinierten Ebene aufrufen. Auf diese Weise hinzugefügte Verluste werden zum "Hauptverlust" während des Trainings addiert (derjenige, der an compile() ). Hier ist ein einfaches Beispiel, das die Regularisierung von Aktivitäten hinzufügt (beachten Sie, dass die Regularisierung von Aktivitäten in allen Keras-Ebenen integriert ist - diese Ebene dient nur dazu, ein konkretes Beispiel bereitzustellen):

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: 3.4140
<tensorflow.python.keras.callbacks.History at 0x7fb6a4233748>

Sie können dasselbe für die Protokollierung von add_metric() mit 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.5646 - std_of_activation: 0.9702
<tensorflow.python.keras.callbacks.History at 0x7fb6a40cf6a0>

In der Funktions-API können Sie auch model.add_loss(loss_tensor) oder model.add_metric(metric_tensor, name, aggregation) .

Hier ist ein einfaches Beispiel:

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 2ms/step - loss: 3.6195 - std_of_activation: 0.0020
<tensorflow.python.keras.callbacks.History at 0x7fb6a07d42b0>

Beachten Sie, dass beim add_loss() Verlusten über add_loss() compile() ohne Verlustfunktion aufgerufen werden kann, da das Modell bereits einen zu minimierenden Verlust aufweist.

Betrachten Sie die folgende LogisticEndpoint Ebene: Sie verwendet Ziele und Protokolle als Eingabe und verfolgt einen Crossentropieverlust über add_loss() . Es verfolgt auch die Klassifizierungsgenauigkeit über 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)

Sie können es in einem Modell mit zwei Eingaben (Eingabedaten und Zielen) verwenden, die ohne loss wie folgt kompiliert wurden:

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 222ms/step - loss: 0.9652 - binary_accuracy: 0.0000e+00
<tensorflow.python.keras.callbacks.History at 0x7fb6a05e01d0>

Weitere Informationen zum Trainieren von Multi-Input-Modellen finden Sie im Abschnitt Übergeben von Daten an Multi-Input- und Multi-Output-Modelle .

Automatisches Auseinstellen eines Validierungs-Holdout-Sets

Im ersten End-to-End-Beispiel, das Sie gesehen haben, haben wir das Argument validation_data , um ein Tupel von NumPy-Arrays (x_val, y_val) an das Modell zu übergeben, um am Ende jeder Epoche einen Validierungsverlust und Validierungsmetriken auszuwerten.

Hier ist eine weitere Option: Mit dem Argument validation_split können Sie einen Teil Ihrer Trainingsdaten automatisch für die Validierung reservieren. Der Argumentwert stellt den Bruchteil der Daten dar, die für die Validierung reserviert werden sollen. Daher sollte er auf eine Zahl höher als 0 und niedriger als 1 gesetzt werden. validation_split=0.2 bedeutet beispielsweise "20% der Daten für die Validierung verwenden" validation_split=0.6 bedeutet "60% der Daten zur Validierung verwenden".

Die Art und Weise, wie die Validierung berechnet wird, besteht darin, vor dem Mischen die letzten x% Abtastwerte der vom Aufruf fit() empfangenen Arrays zu entnehmen.

Beachten Sie, dass Sie validation_split beim Training mit NumPy-Daten verwenden können.

model = get_compiled_model()
model.fit(x_train, y_train, batch_size=64, validation_split=0.2, epochs=1)
625/625 [==============================] - 2s 2ms/step - loss: 0.6075 - sparse_categorical_accuracy: 0.8389 - val_loss: 0.2291 - val_sparse_categorical_accuracy: 0.9322
<tensorflow.python.keras.callbacks.History at 0x7fb6a0504240>

Schulung & Auswertung aus tf.data-Datensätzen

In den letzten paar Absätze, haben Sie gesehen , wie Verluste, Metriken und Optimizern zu handhaben , und Sie haben gesehen , wie die verwenden validation_data und validation_split Argumente fit() , wenn Sie Ihre Daten als NumPy Arrays übergeben wird.

Schauen wir uns nun den Fall an, in dem Ihre Daten in Form einestf.data.Dataset Objektstf.data.Dataset .

Die tf.data API ist eine Reihe von Dienstprogrammen in TensorFlow 2.0, mit denen Daten schnell und skalierbar tf.data und vorverarbeitet werden können.

Für eine komplette Anleitung zum Erstellen von Datasets finden Sie in der tf.data Dokumentation .

Sie können eine Dataset Instanz direkt an die Methoden fit() , evaluate() und 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.5652 - sparse_categorical_accuracy: 0.8404
Epoch 2/3
782/782 [==============================] - 2s 2ms/step - loss: 0.1721 - sparse_categorical_accuracy: 0.9497
Epoch 3/3
782/782 [==============================] - 2s 2ms/step - loss: 0.1170 - sparse_categorical_accuracy: 0.9645
Evaluate
157/157 [==============================] - 0s 2ms/step - loss: 0.1308 - sparse_categorical_accuracy: 0.9602
{'loss': 0.13075917959213257,
 'sparse_categorical_accuracy': 0.9602000117301941}

Beachten Sie, dass der Datensatz am Ende jeder Epoche zurückgesetzt wird, damit er für die nächste Epoche wiederverwendet werden kann.

Wenn Sie das Training nur für eine bestimmte Anzahl von Stapeln aus diesem steps_per_epoch , können Sie das Argument steps_per_epoch , das angibt, wie viele Trainingsschritte das Modell mit diesem steps_per_epoch ausführen soll, bevor Sie mit der nächsten Epoche steps_per_epoch .

Wenn Sie dies tun, wird der Datensatz nicht am Ende jeder Epoche zurückgesetzt, sondern wir zeichnen einfach die nächsten Stapel weiter. Dem Datensatz gehen möglicherweise die Daten aus (es sei denn, es handelt sich um einen Datensatz mit Endlosschleifen).

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 2ms/step - loss: 1.2664 - sparse_categorical_accuracy: 0.6389
Epoch 2/3
100/100 [==============================] - 0s 2ms/step - loss: 0.3868 - sparse_categorical_accuracy: 0.8875
Epoch 3/3
100/100 [==============================] - 0s 2ms/step - loss: 0.3578 - sparse_categorical_accuracy: 0.8981
<tensorflow.python.keras.callbacks.History at 0x7fb6a02a5358>

Verwenden eines Validierungsdatensatzes

Sie können eine Dataset Instanz als validation_data Argument in 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 3ms/step - loss: 0.5754 - sparse_categorical_accuracy: 0.8384 - val_loss: 0.1829 - val_sparse_categorical_accuracy: 0.9465
<tensorflow.python.keras.callbacks.History at 0x7fb6a01651d0>

Am Ende jeder Epoche durchläuft das Modell den Validierungsdatensatz und berechnet die Validierungsverlust- und Validierungsmetriken.

Wenn Sie die Validierung nur für eine bestimmte Anzahl von Stapeln aus diesem Datensatz ausführen möchten, können Sie das Argument validation_steps , das angibt, wie viele Validierungsschritte das Modell mit dem Validierungsdatensatz ausführen soll, bevor die Validierung unterbrochen und mit der nächsten Epoche fortgefahren wird:

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.5503 - sparse_categorical_accuracy: 0.8507 - val_loss: 0.3296 - val_sparse_categorical_accuracy: 0.9062
<tensorflow.python.keras.callbacks.History at 0x7fb6a02e4630>

Beachten Sie, dass der Validierungsdatensatz nach jeder Verwendung zurückgesetzt wird (sodass Sie von Epoche zu Epoche immer dieselben Proben bewerten).

Das Argument validation_split (Generieren eines Holdout-Sets aus den Trainingsdaten) wird beim Training aus Dataset Objekten nicht unterstützt, da für diese Funktion die Indizierung der Stichproben der Datasets erforderlich ist, was mit der Dataset API im Allgemeinen nicht möglich ist.

Andere Eingabeformate werden unterstützt

Neben NumPy-Arrays, eifrigen Tensoren und TensorFlow- Datasets ist es möglich, ein Keras-Modell mithilfe von Pandas-Datenrahmen oder von Python-Generatoren zu trainieren, die Stapel von Daten und Beschriftungen liefern.

Insbesondere bietet die Klasse keras.utils.Sequence eine einfache Schnittstelle zum Erstellen von Python-Datengeneratoren, die Multiprozessor- keras.utils.Sequence sind und gemischt werden können.

Im Allgemeinen empfehlen wir die Verwendung von:

  • NumPy-Eingabedaten, wenn Ihre Daten klein sind und in den Speicher passen
  • Dataset , wenn Sie über große Dataset verfügen und verteiltes Training durchführen müssen
  • Sequence , wenn Sie über große Datenmengen verfügen und viele benutzerdefinierte Python-seitige Verarbeitungen durchführen müssen, die in TensorFlow nicht möglich sind (z. B. wenn Sie zum Laden oder Vorverarbeiten von Daten auf externe Bibliotheken angewiesen sind).

Verwenden eines keras.utils.Sequence Objekts als Eingabe

keras.utils.Sequence ist ein Dienstprogramm, das Sie in Unterklassen unterteilen können, um einen Python-Generator mit zwei wichtigen Eigenschaften zu erhalten:

  • Es funktioniert gut mit Multiprocessing.
  • Es kann gemischt werden (z. B. beim Übergeben von shuffle=True in fit() ).

Eine Sequence muss zwei Methoden implementieren:

  • __getitem__
  • __len__

Die Methode __getitem__ sollte einen vollständigen Stapel zurückgeben. Wenn Sie Ihr Dataset zwischen Epochen ändern möchten, können Sie on_epoch_end implementieren.

Hier ist ein kurzes Beispiel:

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)

Verwenden der Stichprobengewichtung und der Klassengewichtung

Mit den Standardeinstellungen wird das Gewicht einer Probe durch ihre Häufigkeit im Datensatz bestimmt. Es gibt zwei Methoden, um die Daten unabhängig von der Probenfrequenz zu gewichten:

  • Klassengewichte
  • Probengewichte

Klassengewichte

Dies wird durch einen Wörterbuch zum vorbei class_weight Argumente Model.fit() . Dieses Wörterbuch ordnet Klassenindizes dem Gewicht zu, das für Stichproben dieser Klasse verwendet werden soll.

Dies kann verwendet werden, um Klassen ohne erneutes Abtasten auszugleichen oder um ein Modell zu trainieren, das einer bestimmten Klasse mehr Bedeutung beimisst.

Wenn beispielsweise die Klasse "0" in Ihren Daten halb so Model.fit(..., class_weight={0: 1., 1: 0.5}) ist wie die Klasse "1", können Sie Model.fit(..., class_weight={0: 1., 1: 0.5}) .

Hier ist ein NumPy-Beispiel, in dem wir Klassengewichte oder Stichprobengewichte verwenden, um der korrekten Klassifizierung der Klasse 5 (die die Ziffer "5" im MNIST-Datensatz ist) mehr Bedeutung zu verleihen.

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.6269 - sparse_categorical_accuracy: 0.8396
<tensorflow.python.keras.callbacks.History at 0x7fb6ca2479b0>

Probengewichte

Für eine feinkörnige Kontrolle oder wenn Sie keinen Klassifikator erstellen, können Sie "Stichprobengewichte" verwenden.

  • Beim Training aus NumPy-Daten: sample_weight Argument Model.fit() an Model.fit() .
  • Beim Training mit tf.data oder einer anderen Art von Iterator: (input_batch, label_batch, sample_weight_batch) .

Ein Array "Probengewichte" ist ein Array von Zahlen, die angeben, wie viel Gewicht jede Probe in einer Charge bei der Berechnung des Gesamtverlusts haben soll. Es wird häufig bei unausgeglichenen Klassifizierungsproblemen verwendet (die Idee ist, selten gesehenen Klassen mehr Gewicht zu verleihen).

Wenn die verwendeten Gewichte Einsen und Nullen sind, kann das Array als Maske für die Verlustfunktion verwendet werden (wobei der Beitrag bestimmter Stichproben zum Gesamtverlust vollständig verworfen wird).

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.6540 - sparse_categorical_accuracy: 0.8302
<tensorflow.python.keras.callbacks.History at 0x7fb6b03db128>

Hier ist ein passendes Dataset Beispiel:

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.6052 - sparse_categorical_accuracy: 0.8477
<tensorflow.python.keras.callbacks.History at 0x7fb6a40cc908>

Übergabe von Daten an Modelle mit mehreren Eingängen und Ausgängen

In den vorherigen Beispielen haben wir ein Modell mit einer einzelnen Eingabe (einem Tensor der Form (764,) ) und einer einzelnen Ausgabe (einem Vorhersage-Tensor der Form (10,) ) betrachtet. Aber was ist mit Modellen mit mehreren Ein- oder Ausgängen?

Stellen Sie sich das folgende Modell vor, das eine Bildeingabe der Form (32, 32, 3) (das ist (height, width, channels) ) und eine Zeitreiheneingabe der Form (None, 10) (das ist (timesteps, features) ) hat. Unser Modell wird zwei Ausgaben haben, die aus der Kombination dieser Eingaben berechnet werden: eine "Punktzahl" (der Form (1,) ) und eine Wahrscheinlichkeitsverteilung über fünf Klassen (der Form (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]
)

Lassen Sie uns dieses Modell zeichnen, damit Sie klar sehen können, was wir hier tun (beachten Sie, dass die im Diagramm gezeigten Formen Stapelformen sind und keine Formen pro Stichprobe).

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

png

Zur Kompilierungszeit können wir unterschiedliche Verluste für unterschiedliche Ausgaben angeben, indem wir die Verlustfunktionen als Liste übergeben:

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

Wenn wir nur eine einzige Verlustfunktion an das Modell übergeben würden, würde dieselbe Verlustfunktion auf jede Ausgabe angewendet (was hier nicht angemessen ist).

Ebenso für Metriken:

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

Da wir unseren Ausgabeebenen Namen gegeben haben, können wir auch Verluste und Metriken pro Ausgabe über ein Diktat angeben:

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

Wir empfehlen die Verwendung expliziter Namen und Diktate, wenn Sie mehr als 2 Ausgänge haben.

Es ist möglich, verschiedenen ausgabespezifischen Verlusten unterschiedliche Gewichte zuzuweisen (zum Beispiel möchte man in unserem Beispiel den "Score" -Verlust privilegieren, indem man 2x die Wichtigkeit des Klassenverlusts loss_weights ), indem man das 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},
)

Sie können auch festlegen, dass für bestimmte Ausgaben kein Verlust berechnet wird, wenn diese Ausgaben für die Vorhersage, nicht jedoch für das Training bestimmt sind:

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

Das Übergeben von Daten an ein Multi-Input- oder Multi-Output-Modell in fit() funktioniert ähnlich wie das Angeben einer Verlustfunktion beim Kompilieren: Sie können Listen von NumPy-Arrays übergeben (mit 1: 1-Zuordnung zu den Ausgaben, die eine Verlustfunktion erhalten haben) ) oder diktiert die Zuordnung von Ausgabenamen zu NumPy-Arrays .

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 [==============================] - 10s 10ms/step - loss: 12.4255 - score_output_loss: 0.7638 - class_output_loss: 11.6617
4/4 [==============================] - 0s 5ms/step - loss: 11.1176 - score_output_loss: 0.6303 - class_output_loss: 10.4873
<tensorflow.python.keras.callbacks.History at 0x7fb6a02ed828>

Hier ist der Anwendungsfall für den Dataset : Ähnlich wie bei NumPy-Arrays sollte der Dataset ein Tupel von Diktaten zurückgeben.

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 27ms/step - loss: 10.9011 - score_output_loss: 0.4919 - class_output_loss: 10.4092
<tensorflow.python.keras.callbacks.History at 0x7fb6b00ae9e8>

Rückrufe verwenden

Rückrufe in Keras sind Objekte, die während des Trainings an verschiedenen Punkten aufgerufen werden (zu Beginn einer Epoche, am Ende eines Stapels, am Ende einer Epoche usw.). Sie können verwendet werden, um bestimmte Verhaltensweisen zu implementieren, z.

  • Validierung an verschiedenen Punkten während des Trainings durchführen (über die integrierte Validierung pro Epoche hinaus)
  • Überprüfen Sie das Modell in regelmäßigen Abständen oder wenn es einen bestimmten Genauigkeitsschwellenwert überschreitet
  • Das Ändern der Lernrate des Modells während des Trainings scheint ein Plateau zu erreichen
  • Die Feinabstimmung der obersten Schichten während des Trainings scheint ein Plateau zu sein
  • Senden von E-Mail- oder Sofortnachrichtenbenachrichtigungen, wenn das Training endet oder wenn ein bestimmter Leistungsschwellenwert überschritten wird
  • Usw.

Rückrufe können als Liste an Ihren Anruf übergeben werden, fit() zu 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.6076 - sparse_categorical_accuracy: 0.8350 - val_loss: 0.2323 - val_sparse_categorical_accuracy: 0.9306
Epoch 2/20
625/625 [==============================] - 1s 2ms/step - loss: 0.1925 - sparse_categorical_accuracy: 0.9436 - val_loss: 0.1828 - val_sparse_categorical_accuracy: 0.9446
Epoch 3/20
625/625 [==============================] - 1s 2ms/step - loss: 0.1310 - sparse_categorical_accuracy: 0.9616 - val_loss: 0.1580 - val_sparse_categorical_accuracy: 0.9510
Epoch 4/20
625/625 [==============================] - 1s 2ms/step - loss: 0.0967 - sparse_categorical_accuracy: 0.9700 - val_loss: 0.1681 - val_sparse_categorical_accuracy: 0.9490
Epoch 5/20
625/625 [==============================] - 1s 2ms/step - loss: 0.0841 - sparse_categorical_accuracy: 0.9742 - val_loss: 0.1482 - val_sparse_categorical_accuracy: 0.9568
Epoch 00005: early stopping
<tensorflow.python.keras.callbacks.History at 0x7fb63c5945c0>

Viele integrierte Rückrufe sind verfügbar

In Keras sind bereits viele integrierte Rückrufe verfügbar, z.

  • ModelCheckpoint : Speichern Sie das Modell regelmäßig.
  • EarlyStopping : EarlyStopping Sie das Training, wenn das Training die Validierungsmetriken nicht mehr verbessert.
  • TensorBoard : Schreiben TensorBoard regelmäßig Modellprotokolle, die in TensorBoard visualisiert werden können (weitere Details im Abschnitt "Visualisierung").
  • CSVLogger : CSVLogger Verlust- und CSVLogger in eine CSV-Datei.
  • usw.

Die vollständige Liste finden Sie in der Dokumentation zu Rückrufen .

Schreiben Sie Ihren eigenen Rückruf

Sie können einen benutzerdefinierten Rückruf erstellen, indem Sie die Basisklasse keras.callbacks.Callback . Ein Rückruf hat über die Klasseneigenschaft self.model Zugriff auf das zugehörige Modell.

Lesen Sie unbedingt die vollständige Anleitung zum Schreiben von benutzerdefinierten Rückrufen .

Hier ist ein einfaches Beispiel zum Speichern einer Liste von Verlustwerten pro Charge während des Trainings:

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

Checkpointing-Modelle

Wenn Sie ein Modell mit relativ großen Datenmengen trainieren, ist es wichtig, die Prüfpunkte Ihres Modells in regelmäßigen Abständen zu speichern.

Der einfachste Weg, dies zu erreichen, ist der ModelCheckpoint Rückruf:

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
625/625 [==============================] - 2s 2ms/step - loss: 0.6397 - sparse_categorical_accuracy: 0.8210 - val_loss: 0.2310 - val_sparse_categorical_accuracy: 0.9326

Epoch 00001: val_loss improved from inf to 0.23098, saving model to mymodel_1
INFO:tensorflow:Assets written to: mymodel_1/assets
Epoch 2/2
625/625 [==============================] - 1s 2ms/step - loss: 0.1885 - sparse_categorical_accuracy: 0.9454 - val_loss: 0.1851 - val_sparse_categorical_accuracy: 0.9435

Epoch 00002: val_loss improved from 0.23098 to 0.18510, saving model to mymodel_2
INFO:tensorflow:Assets written to: mymodel_2/assets
<tensorflow.python.keras.callbacks.History at 0x7fb6a04271d0>

Der ModelCheckpoint Rückruf kann verwendet werden, um Fehlertoleranz zu implementieren: Die Möglichkeit, das Training ab dem zuletzt gespeicherten Status des Modells neu zu starten, falls das Training zufällig unterbrochen wird. Hier ist ein einfaches Beispiel:

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
  85/1563 [>.............................] - ETA: 2s - loss: 1.4465 - sparse_categorical_accuracy: 0.5717INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.93/assets
 185/1563 [==>...........................] - ETA: 5s - loss: 1.1118 - sparse_categorical_accuracy: 0.6784INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.69/assets
 284/1563 [====>.........................] - ETA: 5s - loss: 0.9495 - sparse_categorical_accuracy: 0.7266INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.58/assets
 385/1563 [======>.......................] - ETA: 5s - loss: 0.8464 - sparse_categorical_accuracy: 0.7569INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.52/assets
 485/1563 [========>.....................] - ETA: 5s - loss: 0.7749 - sparse_categorical_accuracy: 0.7776INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.47/assets
 585/1563 [==========>...................] - ETA: 4s - loss: 0.7210 - sparse_categorical_accuracy: 0.7930INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.44/assets
 685/1563 [============>.................] - ETA: 4s - loss: 0.6788 - sparse_categorical_accuracy: 0.8050INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.42/assets
 785/1563 [==============>...............] - ETA: 4s - loss: 0.6445 - sparse_categorical_accuracy: 0.8149INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.40/assets
 883/1563 [===============>..............] - ETA: 3s - loss: 0.6165 - sparse_categorical_accuracy: 0.8229INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.38/assets
 984/1563 [=================>............] - ETA: 3s - loss: 0.5917 - sparse_categorical_accuracy: 0.8299INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.37/assets
1082/1563 [===================>..........] - ETA: 2s - loss: 0.5709 - sparse_categorical_accuracy: 0.8358INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.35/assets
1185/1563 [=====================>........] - ETA: 1s - loss: 0.5517 - sparse_categorical_accuracy: 0.8413INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.34/assets
1282/1563 [=======================>......] - ETA: 1s - loss: 0.5356 - sparse_categorical_accuracy: 0.8459INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.33/assets
1384/1563 [=========================>....] - ETA: 0s - loss: 0.5202 - sparse_categorical_accuracy: 0.8503INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.32/assets
1484/1563 [===========================>..] - ETA: 0s - loss: 0.5065 - sparse_categorical_accuracy: 0.8542INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.31/assets
1563/1563 [==============================] - 9s 5ms/step - loss: 0.4965 - sparse_categorical_accuracy: 0.8570
<tensorflow.python.keras.callbacks.History at 0x7fb6a036f5c0>

Sie rufen auch Ihren eigenen Rückruf zum Speichern und Wiederherstellen von Modellen an.

Eine vollständige Anleitung zum Serialisieren und Speichern finden Sie in der Anleitung zum Speichern und Serialisieren von Modellen .

Verwenden von Lernratenplänen

Ein gängiges Muster beim Training von Deep-Learning-Modellen besteht darin, das Lernen im Verlauf des Trainings schrittweise zu reduzieren. Dies ist allgemein als "Lernratenabfall" bekannt.

Der Zeitplan für den Lernabfall kann statisch (im Voraus in Abhängigkeit von der aktuellen Epoche oder dem aktuellen Batch-Index festgelegt) oder dynamisch (entsprechend dem aktuellen Verhalten des Modells, insbesondere dem Validierungsverlust) sein.

Übergeben eines Zeitplans an einen Optimierer

Sie können einen statischen Zeitplan für den Zerfall der learning_rate einfach verwenden, indem Sie ein Zeitplanobjekt als Argument für learning_rate in Ihrem Optimierer übergeben:

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)

Es stehen mehrere integrierte Zeitpläne zur Verfügung: ExponentialDecay , PiecewiseConstantDecay , PolynomialDecay und InverseTimeDecay .

Verwenden von Rückrufen zum Implementieren eines dynamischen Lernratenplans

Ein dynamischer Lernratenplan (z. B. Verringern der Lernrate, wenn sich der Validierungsverlust nicht mehr verbessert) kann mit diesen Zeitplanobjekten nicht erreicht werden, da der Optimierer keinen Zugriff auf Validierungsmetriken hat.

Rückrufe haben jedoch Zugriff auf alle Metriken, einschließlich Validierungsmetriken! Sie können dieses Muster also erreichen, indem Sie einen Rückruf verwenden, der die aktuelle Lernrate im Optimierer ändert. Dies ist sogar als ReduceLROnPlateau Rückruf integriert.

Visualisierung von Verlusten und Metriken während des Trainings

Der beste Weg, um Ihr Modell während des Trainings im Auge zu behalten, ist die Verwendung von TensorBoard - einer browserbasierten Anwendung, die Sie lokal ausführen können und die Ihnen Folgendes bietet:

  • Live-Diagramme der Verluste und Metriken für Training und Bewertung
  • (optional) Visualisierungen der Histogramme Ihrer Ebenenaktivierungen
  • (optional) 3D-Visualisierungen der Einbettungsräume, die von Ihren Embedding gelernt wurden

Wenn Sie TensorFlow mit pip installiert haben, sollten Sie TensorBoard über die Befehlszeile starten können:

tensorboard --logdir=/full_path_to_your_logs

Verwenden des TensorBoard-Rückrufs

Der einfachste Weg, TensorBoard mit einem Keras-Modell und der fit() -Methode zu verwenden, ist der TensorBoard Rückruf.

Geben Sie im einfachsten Fall einfach an, wo der Rückruf Protokolle schreiben soll, und los geht's:

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 0x7fb6a422a748>

Weitere Informationen finden Sie in der Dokumentation zum TensorBoard Rückruf .