Zapisz datę! Google I / O powraca w dniach 18-20 maja Zarejestruj się teraz
Ta strona została przetłumaczona przez Cloud Translation API.
Switch to English

Szkolenie i ewaluacja za pomocą wbudowanych metod

Zobacz na TensorFlow.org Uruchom w Google Colab Wyświetl źródło w serwisie GitHub Pobierz notatnik

Ustawiać

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

Wprowadzenie

Ten przewodnik obejmuje modele szkolenia, oceny i przewidywania (wnioskowania) w przypadku korzystania z wbudowanych interfejsów API do szkolenia i walidacji (takich jak Model.fit() , Model.evaluate() i Model.predict() ).

Jeśli jesteś zainteresowany wykorzystaniem funkcji fit() podczas określania własnej funkcji kroku szkoleniowego, zapoznaj się z przewodnikiem Dostosowywanie tego, co dzieje się w fit() .

Jeśli jesteś zainteresowany pisaniem własnych pętli szkoleniowych i ocen od zera, zapoznaj się z przewodnikiem „Pisanie pętli szkoleniowej od zera” .

Ogólnie rzecz biorąc, niezależnie od tego, czy korzystasz z wbudowanych pętli, czy piszesz własne, szkolenie i ocena modeli działają dokładnie w ten sam sposób w przypadku każdego rodzaju modelu Keras - modele sekwencyjne, modele zbudowane za pomocą funkcjonalnego interfejsu API i modele napisane od podstaw za podklasy modelu.

Ten przewodnik nie obejmuje szkolenia rozproszonego, które jest omówione w naszym przewodniku po wielu GPU i szkoleniach rozproszonych .

Omówienie interfejsu API: pierwszy kompleksowy przykład

Podczas przekazywania danych do wbudowanych pętli szkoleniowych modelu należy użyć tablic NumPy (jeśli dane są małe i tf.data Dataset w pamięci) lub obiektów tf.data Dataset . W następnych kilku akapitach użyjemy zestawu danych MNIST jako tablic NumPy, aby zademonstrować, jak używać optymalizatorów, strat i metryk.

Rozważmy następujący model (tutaj budujemy za pomocą funkcjonalnego interfejsu API, ale może to być również model sekwencyjny lub model podklasy):

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)

Oto jak wygląda typowy kompleksowy przepływ pracy, na który składają się:

  • Trening
  • Walidacja zestawu wstrzymanego wygenerowanego na podstawie oryginalnych danych szkoleniowych
  • Ocena na danych testowych

W tym przykładzie użyjemy danych MNIST.

(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

Określamy konfigurację treningu (optymalizator, strata, metryki):

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

batch_size fit() , która batch_size model przez batch_size danych na „partie” o rozmiarze batch_size i wielokrotne iterowanie po całym zestawie danych dla określonej liczby epochs .

print("Fit model on training data")
history = model.fit(
    x_train,
    y_train,
    batch_size=64,
    epochs=2,
    # We pass some validation for
    # monitoring validation loss and metrics
    # at the end of each epoch
    validation_data=(x_val, y_val),
)
Fit model on training data
Epoch 1/2
782/782 [==============================] - 3s 3ms/step - loss: 0.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

Zwrócony obiekt history zawiera zapis wartości strat i wartości metryki podczas uczenia:

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

Oceniamy model na danych testowych za pomocą 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)

Przyjrzyjmy się teraz szczegółowo każdemu elementowi tego przepływu pracy.

Metoda compile() : określanie straty, metryki i optymalizatora

Aby wytrenować model za pomocą fit() , musisz określić funkcję straty, optymalizator i opcjonalnie niektóre metryki do monitorowania.

Przekazujesz je do modelu jako argumenty do metody compile() :

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

Argument metrics powinien być listą - Twój model może mieć dowolną liczbę metryk.

Jeśli model ma wiele wyników, możesz określić różne straty i metryki dla każdego wyniku, a także modulować udział każdego wyniku w całkowitej utracie modelu. Więcej informacji na ten temat znajdziesz w sekcji Przekazywanie danych do modeli z wieloma wejściami i wieloma wyjściami .

Zwróć uwagę, że jeśli jesteś zadowolony z ustawień domyślnych, w wielu przypadkach optymalizator, straty i metryki można określić za pomocą identyfikatorów ciągów jako skrótu:

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

W celu późniejszego ponownego wykorzystania umieśćmy definicję modelu i krok kompilacji w funkcjach; będziemy je nazywać kilkakrotnie w różnych przykładach w tym przewodniku.

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

Dostępnych jest wiele wbudowanych optymalizatorów, strat i metryk

Ogólnie rzecz biorąc, nie będziesz musiał tworzyć własnych strat, wskaźników ani optymalizatorów od zera, ponieważ to, czego potrzebujesz, prawdopodobnie będzie już częścią interfejsu API Keras:

Optymalizatory:

  • SGD() (z momentem lub bez)
  • RMSprop()
  • Adam()
  • itp.

Straty:

  • MeanSquaredError()
  • KLDivergence()
  • CosineSimilarity()
  • itp.

Metryka:

  • AUC()
  • Precision()
  • Recall()
  • itp.

Straty niestandardowe

Jeśli chcesz stworzyć niestandardową stratę, Keras oferuje dwa sposoby, aby to zrobić.

Pierwsza metoda polega na utworzeniu funkcji, która akceptuje dane wejściowe y_true i y_pred . Poniższy przykład przedstawia funkcję straty, która oblicza średni kwadrat błędu między rzeczywistymi danymi a prognozami:

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>

Jeśli potrzebujesz funkcji strat, która przyjmuje parametry oprócz y_true i y_pred , możesz tf.keras.losses.Loss klasę tf.keras.losses.Loss i zaimplementować następujące dwie metody:

  • __init__(self) : zaakceptuj parametry, które zostaną przekazane podczas wywołania funkcji utraty
  • call(self, y_true, y_pred) : użyj celów (y_true) i prognoz modelu (y_pred), aby obliczyć stratę modelu

Powiedzmy, że chcesz użyć błędu średniokwadratowego, ale z dodanym terminem, który zmniejszy motywację do wartości predykcji daleko od 0,5 (zakładamy, że cele kategorialne są zakodowane na gorąco i przyjmują wartości od 0 do 1). Stwarza to zachętę do tego, aby model nie był zbyt pewny siebie, co może pomóc zmniejszyć nadmierne dopasowanie (nie będziemy wiedzieć, czy zadziała, dopóki nie spróbujemy!).

Oto jak byś to zrobił:

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>

Dane niestandardowe

Jeśli potrzebujesz metryki, która nie jest częścią interfejsu API, możesz łatwo utworzyć metryki niestandardowe, tworząc podklasy klasy tf.keras.metrics.Metric . Będziesz musiał zaimplementować 4 metody:

  • __init__(self) , w którym utworzysz zmienne stanu dla swojej metryki.
  • update_state(self, y_true, y_pred, sample_weight=None) , który wykorzystuje wartości docelowe y_true i przewidywania modelu y_pred do aktualizacji zmiennych stanu.
  • result(self) , który używa zmiennych stanu do obliczenia ostatecznych wyników.
  • reset_states(self) , który ponownie inicjuje stan metryki.

Aktualizacja stanu i obliczenia wyników są przechowywane oddzielnie (odpowiednio w update_state() i result() , ponieważ w niektórych przypadkach obliczenia wyników mogą być bardzo kosztowne i byłyby wykonywane tylko okresowo.

Oto prosty przykład pokazujący, jak zaimplementować metrykę CategoricalTruePositives która zlicza, ile próbek zostało poprawnie sklasyfikowanych jako należące do danej klasy:

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>

Obsługa strat i metryk, które nie pasują do standardowego podpisu

Przeważająca większość strat i metryk można obliczyć na podstawie y_true i y_pred , gdzie y_pred to wynik twojego modelu - ale nie wszystkie z nich. Na przykład utrata regularyzacji może wymagać jedynie aktywacji warstwy (w tym przypadku nie ma celów), a ta aktywacja może nie być wynikiem modelowym.

W takich przypadkach możesz wywołać self.add_loss(loss_value) z wnętrza metody wywołania warstwy niestandardowej. Straty dodane w ten sposób są dodawane do „głównej” straty podczas treningu (tej przekazanej do compile() ). Oto prosty przykład, który dodaje regularyzację działań (zwróć uwagę, że regularyzacja działań jest wbudowana we wszystkie warstwy Keras - ta warstwa ma na celu zapewnienie konkretnego przykładu):

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>

Możesz zrobić to samo w przypadku rejestrowania wartości metryk, używając 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>

W funkcjonalnym interfejsie API można również wywołać model.add_loss(loss_tensor) lub model.add_metric(metric_tensor, name, aggregation) .

Oto prosty przykład:

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>

Zauważ, że kiedy przekazujesz straty za pomocą add_loss() , staje się możliwe wywołanie compile() bez funkcji strat, ponieważ model ma już straty do zminimalizowania.

Rozważmy następującą warstwę LogisticEndpoint : przyjmuje jako dane wejściowe cele i logi i śledzi stratę add_loss() za pomocą add_loss() . Śledzi również dokładność klasyfikacji za pomocą 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)

Możesz go użyć w modelu z dwoma wejściami (danymi wejściowymi i celami), skompilowanymi bez argumentu loss , na przykład:

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>

Aby uzyskać więcej informacji na temat uczenia modeli z wieloma wejściami, zobacz sekcję Przekazywanie danych do modeli z wieloma wejściami i wieloma wyjściami .

Automatyczne wyodrębnianie zestawu wstrzymania walidacji

W pierwszym (x_val, y_val) Ciebie przykładzie od końca do końca użyliśmy argumentu validation_data aby przekazać krotkę tablic NumPy (x_val, y_val) do modelu w celu oceny utraty walidacji i metryk walidacji na końcu każdej epoki.

Oto inna opcja: argument validation_split umożliwia automatyczne zarezerwowanie części danych szkoleniowych do walidacji. Wartość argumentu reprezentuje ułamek danych, które mają być zarezerwowane do walidacji, więc powinna być ustawiona na liczbę większą niż 0 i mniejszą niż 1. Na przykład validation_split=0.2 oznacza „użyj 20% danych do walidacji”, a validation_split=0.6 oznacza "użyj 60% danych do walidacji".

Sposób obliczania walidacji polega na pobraniu ostatnich x% próbek tablic odebranych przez wywołanie fit() przed jakimkolwiek tasowaniem.

Pamiętaj, że możesz używać validation_split tylko podczas uczenia z danymi NumPy.

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>

Szkolenie i ocena z tf.data Datasets

W kilku ostatnich akapitach widzieliśmy, jak radzić sobie ze stratami, metrykami i optymalizatorami, a także jak używać argumentów validation_data i validation_split w fit() , gdy dane są przekazywane jako tablice NumPy.

Przyjrzyjmy się teraz przypadkowi, w którym Twoje dane mają postać obiektutf.data.Dataset .

tf.data API tf.data to zestaw narzędzi w TensorFlow 2.0 do ładowania i wstępnego przetwarzania danych w sposób szybki i skalowalny.

Pełny przewodnik dotyczący tworzenia Datasets znajduje się w dokumentacji tf.data .

Możesz przekazać instancję Dataset bezpośrednio do metod fit() , evaluate() i 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}

Zwróć uwagę, że zestaw danych jest resetowany na koniec każdej epoki, dzięki czemu można go ponownie wykorzystać w następnej epoce.

Jeśli chcesz uruchomić szkolenie tylko na określonej liczbie partii z tego zestawu danych, możesz przekazać argument steps_per_epoch , który określa, ile kroków szkoleniowych model powinien uruchomić przy użyciu tego zestawu danych przed przejściem do następnej epoki.

Jeśli to zrobisz, zestaw danych nie zostanie zresetowany na koniec każdej epoki, zamiast tego po prostu rysujemy kolejne partie. W zbiorze danych w końcu zabraknie danych (chyba że jest to zbiór danych o nieskończonej pętli).

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>

Korzystanie ze zbioru danych do walidacji

Możesz przekazać instancję Dataset jako argument validation_data w 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>

Pod koniec każdej epoki model dokona iteracji po zbiorze danych walidacyjnych i obliczy utratę walidacji i metryki walidacji.

Jeśli chcesz uruchomić walidację tylko na określonej liczbie partii z tego zestawu danych, możesz przekazać argument validation_steps , który określa, ile kroków walidacji model powinien wykonać z zestawem danych walidacyjnych, zanim przerwie walidację i przejdzie do następnej epoki:

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>

Zwróć uwagę, że zestaw danych walidacyjnych zostanie zresetowany po każdym użyciu (tak, że zawsze będziesz oceniać te same próbki od epoki do epoki).

Argument validation_split (generowanie zestawu wstrzymania z danych uczących) nie jest obsługiwany podczas uczenia z obiektów Dataset , ponieważ ta funkcja wymaga możliwości indeksowania próbek zestawów danych, co jest ogólnie niemożliwe w przypadku interfejsu API Dataset .

Obsługiwane są inne formaty wejściowe

Oprócz tablic NumPy, chętnych tensorów i Datasets TensorFlow, możliwe jest trenowanie modelu Keras przy użyciu ramek danych Pandas lub z generatorów Pythona, które generują partie danych i etykiet.

W szczególności klasa keras.utils.Sequence oferuje prosty interfejs do tworzenia generatorów danych Pythona, które obsługują wieloprocesorowość i mogą być przetasowywane.

Ogólnie zalecamy użycie:

  • NumPy wprowadź dane, jeśli dane są małe i mieszczą się w pamięci
  • Obiekty Dataset jeśli masz duże zestawy danych i musisz przeprowadzić rozproszone szkolenie
  • Sequence obiekty, jeśli masz duże zbiory danych i musisz wykonać wiele niestandardowych operacji przetwarzania po stronie Pythona, których nie można wykonać w TensorFlow (np. Jeśli polegasz na zewnętrznych bibliotekach do ładowania lub przetwarzania wstępnego danych).

Użycie obiektu keras.utils.Sequence jako danych wejściowych

keras.utils.Sequence to narzędzie, które można keras.utils.Sequence , aby uzyskać generator keras.utils.Sequence Python z dwiema ważnymi właściwościami:

  • Działa dobrze w przypadku przetwarzania wieloprocesowego.
  • Można go przetasować (np. Przy podawaniu shuffle=True in fit() ).

Sequence musi implementować dwie metody:

  • __getitem__
  • __len__

Metoda __getitem__ powinna zwrócić całą wiązkę. Jeśli chcesz zmodyfikować swój zestaw danych między epokami, możesz zaimplementować on_epoch_end .

Oto krótki przykład:

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)

Korzystanie z ważenia próbek i ważenia klas

Przy ustawieniach domyślnych o wadze próbki decyduje częstotliwość w zbiorze danych. Istnieją dwie metody ważenia danych, niezależnie od częstotliwości próbkowania:

  • Wagi klas
  • Przykładowe wagi

Wagi klas

Jest to ustawiane przez przekazanie słownika do argumentu class_weight do Model.fit() . Ten słownik odwzorowuje indeksy klas na wagę, która powinna być używana dla próbek należących do tej klasy.

Może to służyć do równoważenia klas bez ponownego próbkowania lub do trenowania modelu, który nadaje większe znaczenie określonej klasie.

Na przykład, jeśli klasa „0” jest w połowie reprezentowana jako klasa „1” w Twoich danych, możesz użyć Model.fit(..., class_weight={0: 1., 1: 0.5}) .

Oto przykład NumPy, w którym używamy wag klas lub wag przykładowych, aby nadać większą wagę poprawnej klasyfikacji klasy # 5 (która jest cyfrą „5” w zbiorze danych 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.6269 - sparse_categorical_accuracy: 0.8396
<tensorflow.python.keras.callbacks.History at 0x7fb6ca2479b0>

Przykładowe wagi

Aby uzyskać precyzyjną kontrolę lub jeśli nie tworzysz klasyfikatora, możesz użyć „wag próbki”.

  • Podczas uczenia z danych NumPy: Przekaż argument sample_weight do Model.fit() .
  • Podczas uczenia z tf.data lub innego rodzaju iteratora: (input_batch, label_batch, sample_weight_batch) Yield (input_batch, label_batch, sample_weight_batch) .

Tablica „wag próbek” to tablica liczb, które określają, jaką wagę każda próbka w partii powinna mieć przy obliczaniu całkowitej straty. Jest powszechnie stosowany w niezrównoważonych problemach klasyfikacyjnych (chodzi o nadanie większej wagi rzadko spotykanym klasom).

Gdy używane wagi to jedynki i zera, tablica może służyć jako maska funkcji straty (całkowicie odrzucając udział niektórych próbek w całkowitej utracie).

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>

Oto pasujący przykład Dataset :

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>

Przekazywanie danych do modeli z wieloma wejściami i wieloma wyjściami

W poprzednich przykładach rozważaliśmy model z jednym wejściem (tensor kształtu (764,) ) i jednym wyjściem (tensor predykcji kształtu (10,) ). Ale co z modelami, które mają wiele wejść lub wyjść?

Rozważmy następujący model, który zawiera dane wejściowe obrazu o kształcie (32, 32, 3) (to jest (height, width, channels) ) i dane wejściowe kształtu szeregów czasowych (None, 10) (to jest (timesteps, features) ). Nasz model będzie miał dwa wyniki obliczone z kombinacji tych danych wejściowych: „wynik” (o kształcie (1,) ) i rozkład prawdopodobieństwa w pięciu klasach (o kształcie (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]
)

Narysujmy ten model, abyś mógł wyraźnie zobaczyć, co tutaj robimy (zwróć uwagę, że kształty pokazane na wykresie są kształtami wsadowymi, a nie kształtami na próbkę).

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

png

W czasie kompilacji możemy określić różne straty dla różnych wyjść, przekazując funkcje strat jako listę:

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

Gdybyśmy przekazali do modelu tylko jedną funkcję straty, ta sama funkcja straty byłaby zastosowana do każdego wyniku (co nie jest tutaj właściwe).

Podobnie w przypadku danych:

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

Ponieważ nadaliśmy nazwy naszym warstwom wyjściowym, możemy również określić straty na wyjście i metryki za pomocą dyktowania:

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

Zalecamy użycie jawnych nazw i nakazów, jeśli masz więcej niż 2 wyjścia.

Możliwe jest przypisanie różnych wag różnym stratom specyficznym dla produkcji (na przykład można chcieć uprzywilejować stratę „wyniku” w naszym przykładzie, nadając dwukrotnie loss_weights znaczenie niż strata klasy), używając argumentu 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},
)

Możesz również zdecydować, aby nie obliczać strat dla niektórych wyników, jeśli te dane wyjściowe są przeznaczone do przewidywania, ale nie do uczenia:

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

Przekazywanie danych do modelu z wieloma wejściami lub wieloma wyjściami w fit() działa w podobny sposób, jak określanie funkcji straty w kompilacji: możesz przekazać listy tablic NumPy (z mapowaniem 1: 1 do wyjść, które otrzymały funkcję utraty ) lub dyktuje mapowanie nazw wyjściowych na tablice 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 [==============================] - 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>

Oto przypadek użycia Dataset : podobnie jak w przypadku tablic NumPy, Dataset powinien zwrócić krotkę dykt.

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>

Korzystanie z wywołań zwrotnych

Wywołania zwrotne w Keras to obiekty wywoływane w różnych punktach podczas uczenia (na początku epoki, na końcu serii, na końcu epoki itp.). Można je wykorzystać do realizacji określonych zachowań, takich jak:

  • Przeprowadzanie walidacji w różnych punktach podczas szkolenia (poza wbudowaną walidacją na epokę)
  • Sprawdzanie modelu w regularnych odstępach czasu lub gdy przekracza on określony próg dokładności
  • Zmiana wskaźnika uczenia się modelu, gdy szkolenie wydaje się być plateau
  • Dokonywanie dostrajania górnych warstw podczas treningu wydaje się być plateau
  • Wysyłanie powiadomień e-mail lub wiadomości błyskawicznych po zakończeniu szkolenia lub przekroczeniu określonego progu wydajności
  • Itp.

Wywołania zwrotne można przekazać jako listę do wywołania 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>

Dostępnych jest wiele wbudowanych wywołań zwrotnych

W Keras jest już dostępnych wiele wbudowanych wywołań zwrotnych, takich jak:

  • ModelCheckpoint : Okresowo zapisuj model.
  • EarlyStopping : Zatrzymaj trenowanie, gdy szkolenie nie poprawia już wskaźników walidacji.
  • TensorBoard : okresowo zapisuj dzienniki modeli, które można wizualizować w TensorBoard (więcej szczegółów w sekcji „Wizualizacja”).
  • CSVLogger : przesyła dane dotyczące strat i metryk do pliku CSV.
  • itp.

Pełną listę znajdziesz w dokumentacji wywołań zwrotnych .

Pisanie własnego oddzwonienia

Możesz utworzyć niestandardowe wywołanie zwrotne, rozszerzając klasę bazową keras.callbacks.Callback . self.model zwrotne ma dostęp do skojarzonego z nim modelu za pośrednictwem właściwości klasy self.model .

Przeczytaj pełny przewodnik dotyczący pisania niestandardowych wywołań zwrotnych .

Oto prosty przykład zapisywania listy wartości strat na partię podczas uczenia:

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

Modele kontrolne

Kiedy trenujesz model na stosunkowo dużych zestawach danych, ważne jest, aby zapisywać punkty kontrolne modelu w częstych odstępach czasu.

Najłatwiej to osiągnąć za pomocą wywołania zwrotnego 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
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>

ModelCheckpoint zwrotne ModelCheckpoint może służyć do implementacji odporności na błędy: możliwość ponownego uruchomienia uczenia od ostatniego zapisanego stanu modelu w przypadku losowego przerwania uczenia. Oto podstawowy przykład:

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>

Dzwonisz również napisz własne wywołanie zwrotne do zapisywania i przywracania modeli.

Aby uzyskać pełny przewodnik po serializacji i zapisywaniu, zobacz przewodnik dotyczący zapisywania i serializacji modeli .

Korzystanie z harmonogramów kursów nauki

Powszechnym wzorcem podczas trenowania modeli uczenia głębokiego jest stopniowe ograniczanie uczenia się w miarę postępu szkolenia. Jest to ogólnie znane jako „spadek szybkości uczenia się”.

Harmonogram zaniku uczenia się może być statyczny (ustalony z góry, jako funkcja bieżącej epoki lub bieżącego indeksu wsadu) lub dynamiczny (odpowiadający bieżącemu zachowaniu modelu, w szczególności utracie walidacji).

Przekazywanie harmonogramu optymalizatorowi

Możesz łatwo użyć harmonogramu spadku statycznej szybkości uczenia się, przekazując obiekt harmonogramu jako argument learning_rate w swoim optymalizatorze:

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)

Dostępnych jest kilka wbudowanych harmonogramów: ExponentialDecay , PiecewiseConstantDecay , PolynomialDecay i InverseTimeDecay .

Korzystanie z wywołań zwrotnych w celu wdrożenia harmonogramu dynamicznego uczenia się

Harmonogram dynamicznego współczynnika uczenia się (na przykład zmniejszenie współczynnika uczenia się, gdy utrata walidacji już nie poprawia się) nie może zostać osiągnięty za pomocą tych obiektów harmonogramu, ponieważ optymalizator nie ma dostępu do metryk walidacji.

Jednak wywołania zwrotne mają dostęp do wszystkich metryk, w tym metryk walidacji! W ten sposób można osiągnąć ten wzorzec, używając wywołania zwrotnego, które modyfikuje bieżący współczynnik uczenia się w optymalizatorze. W rzeczywistości jest to nawet wbudowane jako wywołanie zwrotne ReduceLROnPlateau .

Wizualizacja strat i metryk podczas treningu

Najlepszym sposobem na obserwowanie modelu podczas treningu jest użycie TensorBoard - aplikacji opartej na przeglądarce, którą można uruchamiać lokalnie i która zapewnia:

  • Wykresy na żywo strat i metryki do szkolenia i oceny
  • (opcjonalnie) Wizualizacje histogramów aktywacji warstw
  • (opcjonalnie) wizualizacje 3D przestrzeni osadzania poznane przez warstwy Embedding

Jeśli zainstalowałeś TensorFlow z pip, powinieneś być w stanie uruchomić TensorBoard z wiersza poleceń:

tensorboard --logdir=/full_path_to_your_logs

Korzystanie z wywołania zwrotnego TensorBoard

Najłatwiejszym sposobem użycia TensorBoard z modelem Keras i metodą fit() jest wywołanie zwrotne TensorBoard .

W najprostszym przypadku wystarczy określić, gdzie wywołanie zwrotne ma zapisywać dzienniki i gotowe:

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>

Więcej informacji można znaleźć w dokumentacji wywołania zwrotnego TensorBoard .