Pomoc chronić Wielkiej Rafy Koralowej z TensorFlow na Kaggle Dołącz Wyzwanie

Szkolenie i ocena metodami wbudowanymi

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

Ustawiać

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

Wstęp

Obejmuje prowadzące szkolenia, oceny i przewidywania (wnioskowanie) modele podczas korzystania z wbudowanej API do szkolenia i walidacji (takich jak Model.fit() , Model.evaluate() i Model.predict() ).

Jeśli jesteś zainteresowany w wykorzystaniu fit() , określając swoją funkcję krok szkolenie, zobacz Dostosowywanie co dzieje się w fit() przewodnika .

Jeśli jesteś zainteresowany pisania własnych pętli szkoleniowe i oceny od podstaw, można znaleźć w podręczniku „Zapis pętlę szkolenia od podstaw” .

Ogólnie rzecz biorąc, niezależnie od tego, czy używasz wbudowanych pętli, czy piszesz własne, uczenie i ocena modeli działa dokładnie w ten sam sposób we wszystkich modelach Keras — modele sekwencyjne, modele zbudowane za pomocą interfejsu API funkcjonalnego i modele napisane od podstaw za pomocą podklasy modeli.

Podręcznik ten nie obejmuje rozproszoną szkolenie, które zostało opisane w naszym przewodniku do multi-GPU i rozproszonej szkolenia .

Przegląd API: pierwszy kompleksowy przykład

Podczas przekazywania danych do wbudowanej w szkoleniu pętle modelu, należy użyć tablic numpy (jeśli dane jest mały i zmieści się w pamięci) lub tf.data Dataset obiektów. 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 wbudowujemy w Functional API, ale może to być również model sekwencyjny lub model podklasowy):

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 przepływ pracy typu end-to-end, składający się z:

  • Trening
  • Walidacja na zestawie wstrzymania wygenerowanym z oryginalnych danych treningowych
  • 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]

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

Nazywamy fit() , która będzie szkolić modelu przez cięcie dane do „partii” o rozmiarze batch_size i wielokrotnie iteracji przez cały zbiór danych dla danej 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.3387 - sparse_categorical_accuracy: 0.9050 - val_loss: 0.1957 - val_sparse_categorical_accuracy: 0.9426
Epoch 2/2
782/782 [==============================] - 2s 3ms/step - loss: 0.1543 - sparse_categorical_accuracy: 0.9548 - val_loss: 0.1425 - val_sparse_categorical_accuracy: 0.9593

Zwracany history obiekt posiada zapis wartości strat i wartości metrycznych podczas treningu:

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

Oceniamy modelu 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.1414 - sparse_categorical_accuracy: 0.9569
test loss, test acc: [0.14140386879444122, 0.9569000005722046]
Generate predictions for 3 samples
predictions shape: (3, 10)

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

compile() Sposób: Określanie straty, dane i optymalizator

Trenować model z fit() , trzeba określić funkcję strat, optymalizator i ewentualnie jakieś metryki monitorować.

Przekazać je do modelu jako argumentów do compile() metody:

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

metrics argument powinien być lista - model może mieć dowolną liczbę metryk.

Jeśli Twój model ma wiele wyników, możesz określić różne straty i metryki dla każdego wyniku, a także możesz modulować udział każdego wyniku w całkowitej stracie modelu. Znajdziesz więcej szczegółów na ten temat w przekazywanie danych do wielu wejść, multi-wyjścia sekcji modeli.

Zwróć uwagę, że jeśli jesteś zadowolony z ustawień domyślnych, w wielu przypadkach optymalizator, stratę 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"],
)

Do późniejszego ponownego wykorzystania, umieśćmy naszą definicję modelu i krok kompilacji w funkcjach; nazwiemy je kilka razy 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ć od podstaw własnych strat, metryk lub optymalizatorów, ponieważ to, czego potrzebujesz, prawdopodobnie jest już częścią API Keras:

Optymalizatory:

  • SGD() (z lub bez pędu)
  • RMSprop()
  • Adam()
  • itp.

Straty:

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

Metryka:

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

Straty niestandardowe

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

Pierwsza metoda polega na tworzeniu się funkcję, która przyjmuje wejścia y_true i y_pred . Poniższy przykład przedstawia funkcję straty, która oblicza błąd średniokwadratowy między danymi rzeczywistymi a przewidywaniami:

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


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

# We need to one-hot encode the labels to use MSE
y_train_one_hot = tf.one_hot(y_train, depth=10)
model.fit(x_train, y_train_one_hot, batch_size=64, epochs=1)
782/782 [==============================] - 2s 2ms/step - loss: 0.0162
<keras.callbacks.History at 0x7ff8881ba250>

Jeśli potrzebujesz funkcji straty, które odbywają się w parametrach obok y_true i y_pred można podklasy tf.keras.losses.Loss klasę i wdrożenie następujących dwóch metod:

  • __init__(self) : akceptować parametry przekazać podczas rozmowy swojej funkcji straty
  • call(self, y_true, y_pred) : użyj cele (y_true) oraz model przewidywania (y_pred) obliczyć straty modelki

Załóżmy, że chcesz użyć błędu średniokwadratowego, ale z dodanym terminem, który zmniejszy predykcję na wartości dalekie od 0,5 (zakładamy, że cele jakościowe są zakodowane jednorazowo 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 w zmniejszeniu nadmiernego dopasowania (nie będziemy wiedzieć, czy to dział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.0388
<keras.callbacks.History at 0x7ff8882130d0>

Dane niestandardowe

Jeśli potrzebujesz metryki, które nie jest częścią interfejsu API, można łatwo tworzyć niestandardowe dane przez instacji tf.keras.metrics.Metric klasę. Będziesz musiał zaimplementować 4 metody:

  • __init__(self) , w którym można tworzyć zmienne stanu na swoją metrykę.
  • update_state(self, y_true, y_pred, sample_weight=None) , który wykorzystuje cele y_true i model przewidywania y_pred aktualizację zmiennych stanu.
  • result(self) , która wykorzystuje zmienne stanu, aby obliczyć wyniki końcowe.
  • reset_state(self) , który reinicjalizuje stanu metrykę.

Aktualizacja stanu i wyniki obliczeń są przechowywane oddzielnie (w update_state() i result() , odpowiednio), ponieważ w niektórych przypadkach obliczanie wyników może być bardzo kosztowne i będzie okresowo wykonywane tylko.

Oto prosty przykład pokazujący jak zaimplementować CategoricalTruePositives metryczny, że liczy, ile Próbki prawidłowo 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_state(self):
        # The state of the metric will be reset at the start of each epoch.
        self.true_positives.assign(0.0)


model = get_uncompiled_model()
model.compile(
    optimizer=keras.optimizers.RMSprop(learning_rate=1e-3),
    loss=keras.losses.SparseCategoricalCrossentropy(),
    metrics=[CategoricalTruePositives()],
)
model.fit(x_train, y_train, batch_size=64, epochs=3)
Epoch 1/3
782/782 [==============================] - 2s 3ms/step - loss: 0.3404 - categorical_true_positives: 45217.0000
Epoch 2/3
782/782 [==============================] - 2s 3ms/step - loss: 0.1588 - categorical_true_positives: 47606.0000
Epoch 3/3
782/782 [==============================] - 2s 3ms/step - loss: 0.1168 - categorical_true_positives: 48278.0000
<keras.callbacks.History at 0x7ff8880a3610>

Obsługa strat i wskaźników, które nie pasują do standardowego podpisu

Zdecydowana większość strat i metryk można obliczyć z y_true i y_pred , gdzie y_pred jest sygnałem wyjściowym 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 modelu.

W takich przypadkach można nazwać self.add_loss(loss_value) od wewnątrz metody połączenia warstwy niestandardowej. Straty dodane w ten sposób dodane do „głównego” straty podczas treningu (jeden przeszedł do compile() ). Oto prosty przykład, który dodaje regularyzację aktywności (zauważ, że regularyzacja aktywności jest wbudowana we wszystkie warstwy Keras — ta warstwa służy tylko do dostarczenia 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: 2.4545
<keras.callbacks.History at 0x7ff87c53f310>

Można zrobić to samo dla zalogowaniu wartości metryki, 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.3461 - std_of_activation: 0.9929
<keras.callbacks.History at 0x7ff87c3d5bd0>

W API Funkcjonalnej , można również zadzwonić 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 3ms/step - loss: 2.4647 - std_of_activation: 0.0017
<keras.callbacks.History at 0x7ff87c216f90>

Zauważ, że kiedy przechodzą straty poprzez add_loss() , staje się możliwe, aby zadzwonić do compile() bez funkcji strat, ponieważ model ma już stratę do minimalizowania.

Rozważmy następujący LogisticEndpoint warstwy: trwa jako wejścia celów i logits, i śledzi crossentropy straty poprzez add_loss() . Śledzi również dokładność klasyfikacji poprzez 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żna go używać w modelu z dwoma wejściami i cele (dane wejściowe), zestawionych bez loss argumentu, 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 414ms/step - loss: 0.9889 - binary_accuracy: 0.0000e+00
<keras.callbacks.History at 0x7ff87c0848d0>

Aby uzyskać więcej informacji na temat szkolenia modeli multi-wejściowe, patrz sekcja Przekazywanie danych do multi-wejściowych modeli wielo-wyjściowych.

Automatyczne rozdzielenie zestawu wstrzymania walidacji

W pierwszym przykładzie end-to-end widziałeś, użyliśmy validation_data argument przekazać krotki tablic numpy (x_val, y_val) do modelu oceny utraty walidacji i weryfikacji wskaźników na koniec każdej epoki.

Oto kolejna opcja: argument validation_split pozwala automatycznie rezerwowy część danych treningowych do walidacji. Wartość argumentów reprezentuje część danych, które są zarezerwowane dla walidacji, więc powinien on być ustawiony na wartość wyższą niż 0 i mniejszy niż 1. Na przykład, validation_split=0.2 oznacza „stosowanie 20% danych walidacji” i validation_split=0.6 oznacza „stosowanie 60% danych walidacji”.

Sposób walidacja jest obliczany jest poprzez ostatniej x% próbek tablic otrzymanych przez fit() połączenia, zanim jakiekolwiek tasowanie.

Należy pamiętać, że można używać tylko validation_split gdy szkolenie 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 3ms/step - loss: 0.3682 - sparse_categorical_accuracy: 0.8957 - val_loss: 0.2276 - val_sparse_categorical_accuracy: 0.9301
<keras.callbacks.History at 0x7ff81c680890>

Szkolenie i ocena z zestawów danych tf.data

W ciągu ostatnich kilku akapitach, widziałeś, jak radzić sobie straty, metryk i optymalizujące i widziałem, jak korzystać z validation_data i validation_split argumentów w fit() , gdy dane są przekazywane w postaci tablic numpy.

Załóżmy teraz przyjrzeć się w przypadku, gdy dane jest w postaci tf.data.Dataset obiektu.

tf.data API to zestaw narzędzi w TensorFlow 2,0 do załadunku i przerób danych w sposób, który jest szybki i skalowalne.

Na kompletny przewodnik na temat tworzenia Datasets , zobacz dokumentację tf.data .

Można przekazać Dataset instancji bezpośrednio do metody fit() , evaluate() , a predict() :

model = get_compiled_model()

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

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

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

# You can also evaluate or predict on a dataset.
print("Evaluate")
result = model.evaluate(test_dataset)
dict(zip(model.metrics_names, result))
Epoch 1/3
782/782 [==============================] - 2s 3ms/step - loss: 0.3372 - sparse_categorical_accuracy: 0.9047
Epoch 2/3
782/782 [==============================] - 2s 3ms/step - loss: 0.1596 - sparse_categorical_accuracy: 0.9523
Epoch 3/3
782/782 [==============================] - 2s 3ms/step - loss: 0.1171 - sparse_categorical_accuracy: 0.9655
Evaluate
157/157 [==============================] - 0s 2ms/step - loss: 0.1211 - sparse_categorical_accuracy: 0.9648
{'loss': 0.12107347697019577,
 'sparse_categorical_accuracy': 0.9648000001907349}

Zwróć uwagę, że zestaw danych jest resetowany na koniec każdej epoki, więc można go ponownie użyć w następnej epoce.

Jeśli chcesz uruchomić szkolenie tylko na liczbie określonej partii ze zbioru danych, można zdać steps_per_epoch argument, który określa ile szkolenie kroki model powinien być uruchomiony za pomocą zbioru danych przed przejściem do następnej epoki.

Jeśli to zrobisz, zestaw danych nie zostanie zresetowany pod koniec każdej epoki, zamiast tego po prostu rysujemy kolejne partie. W zestawie danych w końcu zabraknie danych (chyba że jest to zestaw danych zapętlony w nieskończoność).

model = get_compiled_model()

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

# Only use the 100 batches per epoch (that's 64 * 100 samples)
model.fit(train_dataset, epochs=3, steps_per_epoch=100)
Epoch 1/3
100/100 [==============================] - 1s 3ms/step - loss: 0.7937 - sparse_categorical_accuracy: 0.7894
Epoch 2/3
100/100 [==============================] - 0s 3ms/step - loss: 0.3699 - sparse_categorical_accuracy: 0.8938
Epoch 3/3
100/100 [==============================] - 0s 3ms/step - loss: 0.3155 - sparse_categorical_accuracy: 0.9061
<keras.callbacks.History at 0x7ff81c587e90>

Korzystanie ze zbioru danych walidacyjnych

Można przekazać Dataset instancji jako validation_data argument fit() :

model = get_compiled_model()

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

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

model.fit(train_dataset, epochs=1, validation_data=val_dataset)
782/782 [==============================] - 3s 3ms/step - loss: 0.3380 - sparse_categorical_accuracy: 0.9035 - val_loss: 0.2015 - val_sparse_categorical_accuracy: 0.9405
<keras.callbacks.History at 0x7ff81c30e450>

Pod koniec każdej epoki model będzie iterować po zbiorze danych walidacyjnych i obliczy metryki utraty walidacji i walidacji.

Jeśli chcesz uruchomić sprawdzanie tylko w liczbie określonej partii z tego zestawu danych, można zdać validation_steps argument, który określa ile walidacja kroki model powinien uruchomić przy zbiorze walidacji przed przerywania walidacji i przejściem 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 [==============================] - 3s 3ms/step - loss: 0.3369 - sparse_categorical_accuracy: 0.9036 - val_loss: 0.2953 - val_sparse_categorical_accuracy: 0.9187
<keras.callbacks.History at 0x7ff81c30e310>

Należy pamiętać, że zestaw danych walidacyjnych zostanie zresetowany po każdym użyciu (aby zawsze dokonywać oceny na tych samych próbkach od epoki do epoki).

Argument validation_split (generowanie wstrzymanie zestaw danych z treningu) nie jest obsługiwana, gdy szkolenie z Dataset obiektów, ponieważ ta funkcja wymaga zdolności do indeksu próbek zestawów danych, co nie jest możliwe w ogóle z Dataset API.

Obsługiwane inne formaty wejściowe

Poza tym, macierze NumPy żądnych tensorów i TensorFlow Datasets , to możliwe do trenowania modelu Keras pomocą dataframes PANDAS lub z generatorów Pythona że partie wydajność danych i etykiet.

W szczególności, keras.utils.Sequence Class oferuje prosty interfejs Pythona zbudować generatory danych, które są Multiprocessing świadomy i może być tasuje.

Ogólnie zalecamy używanie:

  • Dane wejściowe NumPy, jeśli dane są małe i mieszczą się w pamięci
  • Dataset obiektów, jeśli masz duże zbiory danych i trzeba zrobić rozproszoną szkolenia
  • Sequence obiektów jeśli masz duże zbiory danych i trzeba zrobić wiele niestandardowego przetwarzania Python-bocznej, które nie mogą być wykonane w TensorFlow (np jeśli opierają się na zewnętrznych bibliotek do załadunku danych lub przerób).

Korzystanie z keras.utils.Sequence obiekt jako wejście

keras.utils.Sequence to narzędzie, które można podklasy, aby uzyskać generator Pythona z dwóch istotnych właściwości:

  • Działa dobrze z przetwarzaniem wieloprocesowym.
  • Może być tasuje (np podczas przechodzenia shuffle=True w fit() ).

Sequence musi realizować na dwa sposoby:

  • __getitem__
  • __len__

Metoda __getitem__ powinien zwrócić kompletną partię. Jeśli chcesz zmodyfikować zbiór danych między epokami, można wdrożyć 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 jej częstotliwość w zbiorze danych. Istnieją dwie metody ważenia danych, niezależnie od częstotliwości próbkowania:

  • Wagi klas
  • Odważniki próbek

Wagi klas

To jest ustalana przez przechodzącą słownika do class_weight argument Model.fit() . Słownik ten odwzorowuje indeksy klas na wagi, które powinny być używane dla próbek należących do tej klasy.

Można to wykorzystać do zrównoważenia klas bez ponownego próbkowania lub do trenowania modelu, który nadaje większą wagę określonej klasie.

Na przykład, jeśli klasa "0" jest w połowie tak reprezentowane klasy "1" w swoich danych, można użyć Model.fit(..., class_weight={0: 1., 1: 0.5}) .

Oto przykład NumPy, w którym używamy wag klas lub wag próbek, aby nadać większą wagę prawidłowej klasyfikacji klasy nr 5 (która jest cyfrą „5” w zestawie 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 3ms/step - loss: 0.3708 - sparse_categorical_accuracy: 0.9032
<keras.callbacks.History at 0x7ff80c7ddd10>

Odważniki próbek

Aby uzyskać drobnoziarnistą kontrolę lub jeśli nie budujesz klasyfikatora, możesz użyć „wagi próbek”.

  • Podczas szkolenia z danych NumPy: Przełóż sample_weight argument Model.fit() .
  • Podczas szkolenia z tf.data lub innego rodzaju iteracyjnej: Wydajność (input_batch, label_batch, sample_weight_batch) krotki.

Tablica „wagi próbek” to tablica liczb, które określają, jaką wagę powinna mieć każda próbka w partii przy obliczaniu całkowitej straty. Jest powszechnie stosowany w problemach z niezrównoważoną klasyfikacją (pomysł polega na tym, aby nadać większą wagę rzadko spotykanym klasom).

Gdy wagi będą zer i jedynek, tablica może być stosowany jako maska dla funkcji strat (całkowicie wyrzucaniu wkład niektórych próbek do całkowitej utraty).

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

print("Fit with sample weight")
model = get_compiled_model()
model.fit(x_train, y_train, sample_weight=sample_weight, batch_size=64, epochs=1)
Fit with sample weight
782/782 [==============================] - 2s 3ms/step - loss: 0.3806 - sparse_categorical_accuracy: 0.9000
<keras.callbacks.History at 0x7ff80c650350>

Oto dopasowanie Dataset Przykład:

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

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

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

model = get_compiled_model()
model.fit(train_dataset, epochs=1)
782/782 [==============================] - 3s 3ms/step - loss: 0.3588 - sparse_categorical_accuracy: 0.9070
<keras.callbacks.History at 0x7ff80c51cb50>

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

W poprzednich przykładach, my za model z jednego wejścia (tensora kształt (764,) ) i jednym wyjściem (tensora przewidywania kształtu (10,) ). Ale co z modelami, które mają wiele wejść lub wyjść?

Rozważmy następujący wzór, który ma wejście obrazu kształcie (32, 32, 3) (to jest (height, width, channels) ) i wejście serii czas kształtu (None, 10) (to jest (timesteps, features) ). Nasz model mają dwa wyjścia obliczone z kombinacji tych wejść: „punktów” (kształt (1,) ), a rozkład prawdopodobieństwa dla pięciu grup (kształtu (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 wyraźnie zobaczyć, co tutaj robimy (zwróć uwagę, że kształty pokazane na wykresie są kształtami wsadowymi, a nie kształtami przypadającymi 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 na różnych wyjściach, 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 zostałaby zastosowana do każdego wyniku (co nie jest właściwe w tym przypadku).

Podobnie dla metryk:

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, mogliśmy również określić straty i metryki na dane wyjściowe za pomocą dyktatu:

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żywanie wyraźnych nazw i podpowiedzi, jeśli masz więcej niż 2 wyjścia.

Jest to możliwe, aby dać różne wagi do różnych specyficznych strat wyjście (na przykład, może sobie życzyć, aby przywilej „Wynik” stratę w naszym przykładzie, dając do 2x znaczenie utraty klasy), stosując loss_weights argumentu:

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ć straty dla niektórych wyników, jeśli te wyniki 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 multi-input lub modelu multi-wyjścia w fit() działa w podobny sposób, jak określenie funkcji straty w kompilacji: można przekazać list tablic numpy (1: 1 mapowanie do wyjść, które otrzymały funkcję strat ) lub dicts odwzorowujące nazwy wyjściowe tablic numPy.

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

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

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

# Alternatively, fit on dicts
model.fit(
    {"img_input": img_data, "ts_input": ts_data},
    {"score_output": score_targets, "class_output": class_targets},
    batch_size=32,
    epochs=1,
)
4/4 [==============================] - 2s 9ms/step - loss: 5.6917 - score_output_loss: 0.1031 - class_output_loss: 5.5886
4/4 [==============================] - 0s 6ms/step - loss: 4.4108 - score_output_loss: 0.0999 - class_output_loss: 4.3109
<keras.callbacks.History at 0x7ff80c3b4110>

Oto Dataset przypadek użycia: podobnie jak to, co zrobiliśmy dla tablic numpy The Dataset powinien wrócić krotka dicts.

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

model.fit(train_dataset, epochs=1)
2/2 [==============================] - 0s 21ms/step - loss: 4.2451 - score_output_loss: 0.0993 - class_output_loss: 4.1458
<keras.callbacks.History at 0x7ff80c3ed450>

Korzystanie z wywołań zwrotnych

Wywołania zwrotne w Keras to obiekty, które są wywoływane w różnych punktach uczenia się (na początku epoki, na końcu wsadu, na końcu epoki itp.). Mogą służyć do realizacji określonych zachowań, takich jak:

  • Wykonywanie walidacji w różnych punktach podczas treningu (poza wbudowaną walidacją na epokę)
  • Sprawdzanie modelu w regularnych odstępach czasu lub gdy przekracza określony próg dokładności
  • Zmiana szybkości uczenia się modelu, gdy trening wydaje się stabilizować
  • Dostrajanie górnych warstw, gdy trening wydaje się stabilizować
  • 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 mogą być przekazywane w formie listy na wezwanie do fit() :

model = get_compiled_model()

callbacks = [
    keras.callbacks.EarlyStopping(
        # Stop training when `val_loss` is no longer improving
        monitor="val_loss",
        # "no longer improving" being defined as "no better than 1e-2 less"
        min_delta=1e-2,
        # "no longer improving" being further defined as "for at least 2 epochs"
        patience=2,
        verbose=1,
    )
]
model.fit(
    x_train,
    y_train,
    epochs=20,
    batch_size=64,
    callbacks=callbacks,
    validation_split=0.2,
)
Epoch 1/20
625/625 [==============================] - 2s 3ms/step - loss: 0.3725 - sparse_categorical_accuracy: 0.8939 - val_loss: 0.2314 - val_sparse_categorical_accuracy: 0.9321
Epoch 2/20
625/625 [==============================] - 2s 3ms/step - loss: 0.1805 - sparse_categorical_accuracy: 0.9471 - val_loss: 0.2012 - val_sparse_categorical_accuracy: 0.9379
Epoch 3/20
625/625 [==============================] - 2s 3ms/step - loss: 0.1346 - sparse_categorical_accuracy: 0.9603 - val_loss: 0.1651 - val_sparse_categorical_accuracy: 0.9505
Epoch 4/20
625/625 [==============================] - 2s 3ms/step - loss: 0.1065 - sparse_categorical_accuracy: 0.9684 - val_loss: 0.1510 - val_sparse_categorical_accuracy: 0.9571
Epoch 5/20
625/625 [==============================] - 2s 3ms/step - loss: 0.0884 - sparse_categorical_accuracy: 0.9734 - val_loss: 0.1505 - val_sparse_categorical_accuracy: 0.9538
Epoch 6/20
625/625 [==============================] - 2s 3ms/step - loss: 0.0746 - sparse_categorical_accuracy: 0.9778 - val_loss: 0.1508 - val_sparse_categorical_accuracy: 0.9575
Epoch 00006: early stopping
<keras.callbacks.History at 0x7ff80c64cad0>

Dostępnych jest wiele wbudowanych wywołań zwrotnych

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

  • ModelCheckpoint : Okresowo zapisać model.
  • EarlyStopping : szkolenia zatrzyma się, gdy szkolenie nie jest już poprawa wskaźników walidacji.
  • TensorBoard : okresowo zapisu modelu dzienniki, które mogą być wizualizowane w TensorBoard (więcej szczegółów w sekcji „Wizualizacja”).
  • CSVLogger : utrata lub dane strumieni danych do pliku CSV.
  • itp.

Zobacz dokumentację wywołań zwrotnych dla kompletnej listy.

Pisanie własnego oddzwaniania

Można tworzyć niestandardowe zwrotnego poprzez rozszerzenie klasy bazowej keras.callbacks.Callback . Zwrotna ma dostęp do jego powiązanego modelu poprzez właściwość klasa self.model .

Upewnij się, aby przeczytać kompletny podręcznik do pisania niestandardowych wywołań zwrotnych .

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

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

Podczas uczenia modelu na stosunkowo dużych zestawach danych bardzo ważne jest zapisywanie punktów kontrolnych modelu w częstych odstępach czasu.

Najprostszym sposobem osiągnięcia tego celu jest z ModelCheckpoint zwrotnego:

model = get_compiled_model()

callbacks = [
    keras.callbacks.ModelCheckpoint(
        # Path where to save the model
        # The two parameters below mean that we will overwrite
        # the current checkpoint if and only if
        # the `val_loss` score has improved.
        # The saved model name will include the current epoch.
        filepath="mymodel_{epoch}",
        save_best_only=True,  # Only save a model if `val_loss` has improved.
        monitor="val_loss",
        verbose=1,
    )
]
model.fit(
    x_train, y_train, epochs=2, batch_size=64, callbacks=callbacks, validation_split=0.2
)
Epoch 1/2
613/625 [============================>.] - ETA: 0s - loss: 0.3693 - sparse_categorical_accuracy: 0.8972
Epoch 00001: val_loss improved from inf to 0.23508, saving model to mymodel_1
2021-11-12 20:11:50.182298: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: mymodel_1/assets
625/625 [==============================] - 3s 4ms/step - loss: 0.3660 - sparse_categorical_accuracy: 0.8979 - val_loss: 0.2351 - val_sparse_categorical_accuracy: 0.9273
Epoch 2/2
620/625 [============================>.] - ETA: 0s - loss: 0.1659 - sparse_categorical_accuracy: 0.9507
Epoch 00002: val_loss improved from 0.23508 to 0.16898, saving model to mymodel_2
INFO:tensorflow:Assets written to: mymodel_2/assets
625/625 [==============================] - 2s 3ms/step - loss: 0.1657 - sparse_categorical_accuracy: 0.9507 - val_loss: 0.1690 - val_sparse_categorical_accuracy: 0.9482
<keras.callbacks.History at 0x7ff8b577cc90>

ModelCheckpoint zwrotna może być używany do realizacji odporności na uszkodzenia: zdolność do treningu restartu od ostatniego zapisanego stanu modelu w przypadku szkolenia zostanie przypadkowo przerwany. 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
  88/1563 [>.............................] - ETA: 3s - loss: 1.1203 - sparse_categorical_accuracy: 0.6911INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=1.04/assets
 185/1563 [==>...........................] - ETA: 6s - loss: 0.7768 - sparse_categorical_accuracy: 0.7858INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.75/assets
 286/1563 [====>.........................] - ETA: 6s - loss: 0.6382 - sparse_categorical_accuracy: 0.8211INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.63/assets
 383/1563 [======>.......................] - ETA: 6s - loss: 0.5584 - sparse_categorical_accuracy: 0.8433INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.55/assets
 484/1563 [========>.....................] - ETA: 6s - loss: 0.5032 - sparse_categorical_accuracy: 0.8578INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.50/assets
 586/1563 [==========>...................] - ETA: 5s - loss: 0.4644 - sparse_categorical_accuracy: 0.8684INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.46/assets
 685/1563 [============>.................] - ETA: 5s - loss: 0.4356 - sparse_categorical_accuracy: 0.8762INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.43/assets
 783/1563 [==============>...............] - ETA: 5s - loss: 0.4127 - sparse_categorical_accuracy: 0.8825INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.41/assets
 883/1563 [===============>..............] - ETA: 4s - loss: 0.3958 - sparse_categorical_accuracy: 0.8868INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.39/assets
 985/1563 [=================>............] - ETA: 3s - loss: 0.3766 - sparse_categorical_accuracy: 0.8918INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.38/assets
1086/1563 [===================>..........] - ETA: 3s - loss: 0.3624 - sparse_categorical_accuracy: 0.8958INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.36/assets
1184/1563 [=====================>........] - ETA: 2s - loss: 0.3498 - sparse_categorical_accuracy: 0.8994INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.35/assets
1283/1563 [=======================>......] - ETA: 1s - loss: 0.3383 - sparse_categorical_accuracy: 0.9029INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.34/assets
1386/1563 [=========================>....] - ETA: 1s - loss: 0.3265 - sparse_categorical_accuracy: 0.9058INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.33/assets
1485/1563 [===========================>..] - ETA: 0s - loss: 0.3184 - sparse_categorical_accuracy: 0.9081INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.32/assets
1563/1563 [==============================] - 11s 7ms/step - loss: 0.3122 - sparse_categorical_accuracy: 0.9097
<keras.callbacks.History at 0x7ff8b53e1dd0>

Zadzwoń również napisz swój własny callback do zapisywania i przywracania modeli.

Dla kompletnego przewodnika po serializacji i oszczędności można znaleźć w instrukcji do zapisywania i szeregowania modele .

Korzystanie z harmonogramów nauki

Typowym wzorcem podczas uczenia modeli głębokiego uczenia się jest stopniowe zmniejszanie uczenia się w miarę postępu uczenia. Jest to ogólnie znane jako „zanikanie szybkości uczenia się”.

Harmonogram zaniku uczenia może być statyczny (z góry ustalony jako funkcja bieżącej epoki lub bieżącego indeksu partii) lub dynamiczny (odpowiadający na bieżące zachowanie modelu, w szczególności na utratę walidacji).

Przekazywanie harmonogramu do optymalizatora

Można łatwo korzystać z harmonogramu szybkość uczenia zaniku statyczne przekazując obiekt harmonogramu jako learning_rate argument w swojej optymalizatora:

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)

Kilka wbudowanych harmonogramów są dostępne: ExponentialDecay , PiecewiseConstantDecay , PolynomialDecay i InverseTimeDecay .

Wykorzystanie połączeń zwrotnych do wdrożenia harmonogramu dynamicznego tempa nauki

Dynamiczny harmonogram szybkości uczenia się (na przykład zmniejszenie szybkości uczenia się, gdy utrata walidacji już się nie poprawia) 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 za pomocą wywołania zwrotnego, które modyfikuje bieżącą szybkość uczenia się w optymalizatorze. W rzeczywistości, to jest nawet wbudowany jako ReduceLROnPlateau zwrotnego.

Wizualizacja strat i metryk podczas treningu

Najlepszym sposobem, aby mieć oko na modelu podczas treningu jest wykorzystanie TensorBoard - aplikacji opartych na przeglądarce, który można uruchomić lokalnie, które oferuje:

  • Żywe wykresy strat i metryki do szkolenia i oceny
  • (opcjonalnie) Wizualizacje histogramów aktywacji warstw
  • (opcjonalnie) 3D wizualizacje zatapiania przestrzeniach nauczyć swoich Embedding warstw

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

tensorboard --logdir=/full_path_to_your_logs

Korzystanie z funkcji zwrotnej TensorBoard

Najprostszym sposobem użycia TensorBoard z modelem Keras i fit() metody jest TensorBoard zwrotna.

W najprostszym przypadku po prostu określ, gdzie wywołanie zwrotne ma zapisywać logi i możesz już iść:

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

Aby uzyskać więcej informacji, zapoznaj się z dokumentacją TensorBoard zwrotnego .