Treinamento e avaliação com os métodos integrados

Ver no TensorFlow.org Executar no Google Colab Ver fonte no GitHub Baixar caderno

Configurar

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

Introdução

Este guia cobre modelos de treinamento, avaliação e predição (inferência) ao usar APIs integradas para treinamento e validação (como Model.fit() , Model.evaluate() e Model.predict() ).

Se você estiver interessado em aproveitar fit() ao especificar sua própria função de etapa de treinamento, consulte o guia Personalizando o que acontece em fit() .

Se você estiver interessado em escrever seus próprios loops de treinamento e avaliação do zero, consulte o guia "escrevendo um loop de treinamento do zero" .

Em geral, esteja você usando loops integrados ou escrevendo seus próprios, o treinamento e a avaliação do modelo funcionam estritamente da mesma maneira em todos os tipos de modelo Keras - modelos sequenciais, modelos construídos com a API Funcional e modelos escritos do zero via subclasse de modelo.

Este guia não cobre o treinamento distribuído, que é abordado em nosso guia para treinamento distribuído e multi-GPU .

Visão geral da API: um primeiro exemplo de ponta a ponta

Ao passar dados para os loops de treinamento integrados de um modelo, você deve usar matrizes NumPy (se seus dados forem pequenos e tf.data Dataset na memória) ou objetos tf.data Dataset . Nos próximos parágrafos, usaremos o conjunto de dados MNIST como matrizes NumPy, a fim de demonstrar como usar otimizadores, perdas e métricas.

Vamos considerar o seguinte modelo (aqui, construímos com a API Funcional, mas também pode ser um modelo Sequencial ou um modelo de subclasse):

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)

Esta é a aparência de um fluxo de trabalho ponta a ponta típico, consistindo em:

  • Treinamento
  • Validação em um conjunto de validação gerado a partir dos dados de treinamento originais
  • Avaliação dos dados de teste

Usaremos dados MNIST para este exemplo.

(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

Especificamos a configuração do treinamento (otimizador, perda, métricas):

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

Chamamos fit() , que treinará o modelo batch_size os dados em "lotes" de tamanho batch_size e repetidamente iterando em todo o conjunto de dados por um determinado número de epochs .

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

O objeto de history retornado mantém um registro dos valores de perda e valores de métrica durante o treinamento:

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

Avaliamos o modelo nos dados de teste por meio de evaluate() :

# Evaluate the model on the test data using `evaluate`
print("Evaluate on test data")
results = model.evaluate(x_test, y_test, batch_size=128)
print("test loss, test acc:", results)

# Generate predictions (probabilities -- the output of the last layer)
# on new data using `predict`
print("Generate predictions for 3 samples")
predictions = model.predict(x_test[:3])
print("predictions shape:", predictions.shape)
Evaluate on test data
79/79 [==============================] - 0s 2ms/step - loss: 0.1449 - sparse_categorical_accuracy: 0.9539
test loss, test acc: [0.14493884146213531, 0.9538999795913696]
Generate predictions for 3 samples
predictions shape: (3, 10)

Agora, vamos revisar cada parte desse fluxo de trabalho em detalhes.

O método compile() : especificando uma perda, métricas e um otimizador

Para treinar um modelo com fit() , você precisa especificar uma função de perda, um otimizador e, opcionalmente, algumas métricas para monitorar.

Você os passa para o modelo como argumentos para o método compile() :

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

O argumento metrics deve ser uma lista - seu modelo pode ter qualquer número de métricas.

Se o seu modelo tem várias saídas, você pode especificar diferentes perdas e métricas para cada saída e pode modular a contribuição de cada saída para a perda total do modelo. Você encontrará mais detalhes sobre isso na seção Passando dados para modelos de múltiplas entradas e saídas .

Observe que se você estiver satisfeito com as configurações padrão, em muitos casos, o otimizador, a perda e as métricas podem ser especificados por meio de identificadores de string como um atalho:

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

Para reutilização posterior, vamos colocar nossa definição de modelo e etapa de compilação em funções; vamos chamá-los várias vezes em diferentes exemplos neste guia.

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

Muitos otimizadores, perdas e métricas integrados estão disponíveis

Em geral, você não terá que criar suas próprias perdas, métricas ou otimizadores do zero, porque o que você precisa provavelmente já faz parte da API Keras:

Otimizadores:

  • SGD() (com ou sem impulso)
  • RMSprop()
  • Adam()
  • etc.

Perdas:

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

Métricas:

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

Perdas personalizadas

Se você precisar criar uma perda personalizada, Keras oferece duas maneiras de fazer isso.

O primeiro método envolve a criação de uma função que aceita as entradas y_true e y_pred . O exemplo a seguir mostra uma função de perda que calcula o erro quadrático médio entre os dados reais e as previsões:

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>

Se precisar de uma função de perda que y_true parâmetros ao lado de y_true e y_pred , você pode tf.keras.losses.Loss subclasse da classe tf.keras.losses.Loss e implementar os dois métodos a seguir:

  • __init__(self) : aceita parâmetros para passar durante a chamada de sua função de perda
  • call(self, y_true, y_pred) : use os alvos (y_true) e as previsões do modelo (y_pred) para calcular a perda do modelo

Digamos que você queira usar o erro quadrático médio, mas com um termo adicionado que diminuirá os valores de predição longe de 0,5 (assumimos que os alvos categóricos são codificados em um ponto e assumem valores entre 0 e 1). Isso cria um incentivo para que o modelo não fique muito confiante, o que pode ajudar a reduzir o sobreajuste (não saberemos se funciona até tentarmos!).

Veja como você faria isso:

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>

Métricas personalizadas

Se você precisa de uma métrica que não faz parte da API, pode criar facilmente métricas personalizadas criando uma subclasse da classe tf.keras.metrics.Metric . Você precisará implementar 4 métodos:

  • __init__(self) , em que você criará variáveis ​​de estado para sua métrica.
  • update_state(self, y_true, y_pred, sample_weight=None) , que usa os destinos y_true e as previsões do modelo y_pred para atualizar as variáveis ​​de estado.
  • result(self) , que usa as variáveis ​​de estado para calcular os resultados finais.
  • reset_states(self) , que reinicializa o estado da métrica.

A atualização do estado e o cálculo dos resultados são mantidos separados (em update_state() e result() , respectivamente) porque em alguns casos, o cálculo dos resultados pode ser muito caro e só seria feito periodicamente.

Aqui está um exemplo simples que mostra como implementar uma métrica CategoricalTruePositives que conta quantas amostras foram classificadas corretamente como pertencentes a uma determinada classe:

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>

Lidar com perdas e métricas que não se enquadram na assinatura padrão

A grande maioria das perdas e métricas pode ser calculada a partir de y_true e y_pred , em que y_pred é uma saída de seu modelo - mas não de todos eles. Por exemplo, uma perda de regularização pode exigir apenas a ativação de uma camada (não há alvos neste caso), e essa ativação pode não ser uma saída do modelo.

Nesses casos, você pode chamar self.add_loss(loss_value) de dentro do método de chamada de uma camada personalizada. As perdas adicionadas desta forma são adicionadas à perda "principal" durante o treinamento (aquela que foi passada para compile() ). Aqui está um exemplo simples que adiciona regularização de atividade (observe que a regularização de atividade é integrada em todas as camadas Keras - esta camada é apenas para fornecer um exemplo concreto):

class ActivityRegularizationLayer(layers.Layer):
    def call(self, inputs):
        self.add_loss(tf.reduce_sum(inputs) * 0.1)
        return inputs  # Pass-through layer.


inputs = keras.Input(shape=(784,), name="digits")
x = layers.Dense(64, activation="relu", name="dense_1")(inputs)

# Insert activity regularization as a layer
x = ActivityRegularizationLayer()(x)

x = layers.Dense(64, activation="relu", name="dense_2")(x)
outputs = layers.Dense(10, name="predictions")(x)

model = keras.Model(inputs=inputs, outputs=outputs)
model.compile(
    optimizer=keras.optimizers.RMSprop(learning_rate=1e-3),
    loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
)

# The displayed loss will be much higher than before
# due to the regularization component.
model.fit(x_train, y_train, batch_size=64, epochs=1)
782/782 [==============================] - 2s 2ms/step - loss: 3.4140
<tensorflow.python.keras.callbacks.History at 0x7fb6a4233748>

Você pode fazer o mesmo para registrar valores métricos, usando 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>

Na API Funcional , você também pode chamar model.add_loss(loss_tensor) ou model.add_metric(metric_tensor, name, aggregation) .

Aqui está um exemplo simples:

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>

Note que quando você passa perdas via add_loss() , torna-se possível chamar compile() sem uma função de perda, uma vez que o modelo já tem uma perda para minimizar.

Considere a seguinte camada LogisticEndpoint : ela toma como entradas alvos e logits e rastreia uma perda de entrecropia cruzada por meio de add_loss() . Ele também rastreia a precisão da classificação por meio de add_metric() .

class LogisticEndpoint(keras.layers.Layer):
    def __init__(self, name=None):
        super(LogisticEndpoint, self).__init__(name=name)
        self.loss_fn = keras.losses.BinaryCrossentropy(from_logits=True)
        self.accuracy_fn = keras.metrics.BinaryAccuracy()

    def call(self, targets, logits, sample_weights=None):
        # Compute the training-time loss value and add it
        # to the layer using `self.add_loss()`.
        loss = self.loss_fn(targets, logits, sample_weights)
        self.add_loss(loss)

        # Log accuracy as a metric and add it
        # to the layer using `self.add_metric()`.
        acc = self.accuracy_fn(targets, logits, sample_weights)
        self.add_metric(acc, name="accuracy")

        # Return the inference-time prediction tensor (for `.predict()`).
        return tf.nn.softmax(logits)

Você pode usá-lo em um modelo com duas entradas (dados de entrada e alvos), compilado sem um argumento de loss , como este:

import numpy as np

inputs = keras.Input(shape=(3,), name="inputs")
targets = keras.Input(shape=(10,), name="targets")
logits = keras.layers.Dense(10)(inputs)
predictions = LogisticEndpoint(name="predictions")(logits, targets)

model = keras.Model(inputs=[inputs, targets], outputs=predictions)
model.compile(optimizer="adam")  # No loss argument!

data = {
    "inputs": np.random.random((3, 3)),
    "targets": np.random.random((3, 10)),
}
model.fit(data)
1/1 [==============================] - 0s 222ms/step - loss: 0.9652 - binary_accuracy: 0.0000e+00
<tensorflow.python.keras.callbacks.History at 0x7fb6a05e01d0>

Para obter mais informações sobre o treinamento de modelos de múltiplas entradas, consulte a seção Passando dados para modelos de múltiplas entradas e saídas .

Separar automaticamente um conjunto de validação de validação

No primeiro exemplo de ponta a ponta que você viu, usamos o argumento validation_data para passar uma tupla de matrizes NumPy (x_val, y_val) para o modelo para avaliar uma perda de validação e métricas de validação no final de cada época.

Aqui está outra opção: o argumento validation_split permite que você reserve automaticamente parte de seus dados de treinamento para validação. O valor do argumento representa a fração dos dados a serem reservados para validação, portanto, deve ser definido como um número maior que 0 e menor que 1. Por exemplo, validation_split=0.2 significa "use 20% dos dados para validação", e validation_split=0.6 significa "usar 60% dos dados para validação".

A forma como a validação é calculada é pegando as últimas x% amostras dos arrays recebidos pela chamada fit() , antes de qualquer embaralhamento.

Observe que você só pode usar validation_split ao treinar com dados 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>

Treinamento e avaliação de conjuntos de dados tf.data

Nos últimos parágrafos, você viu como lidar com perdas, métricas e otimizadores, e você viu como usar os validation_data e validation_split argumentos no fit() , quando os dados são passados como matrizes Numpy.

Vamos agora dar uma olhada no caso em que seus dados vêm na forma de um objetotf.data.Dataset .

A API tf.data é um conjunto de utilitários no TensorFlow 2.0 para carregar e pré-processar dados de maneira rápida e escalonável.

Para obter um guia completo sobre a criação de Datasets , consulte a documentação tf.data .

Você pode passar uma instância de Dataset diretamente para os métodos fit() , evaluate() e 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}

Observe que o conjunto de dados é redefinido no final de cada época, para que possa ser reutilizado na próxima época.

Se você deseja executar o treinamento apenas em um número específico de lotes desse conjunto de dados, pode passar o argumento steps_per_epoch , que especifica quantas etapas de treinamento o modelo deve executar usando este conjunto de dados antes de passar para a próxima época.

Se você fizer isso, o conjunto de dados não será redefinido no final de cada época, em vez disso, continuaremos desenhando os próximos lotes. O conjunto de dados acabará ficando sem dados (a menos que seja um conjunto de dados em loop infinito).

model = get_compiled_model()

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

# Only use the 100 batches per epoch (that's 64 * 100 samples)
model.fit(train_dataset, epochs=3, steps_per_epoch=100)
Epoch 1/3
100/100 [==============================] - 1s 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>

Usando um conjunto de dados de validação

Você pode passar uma instância do Dataset como o argumento validation_data em 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>

No final de cada época, o modelo irá iterar sobre o conjunto de dados de validação e calcular a perda de validação e as métricas de validação.

Se você deseja executar a validação apenas em um número específico de lotes deste conjunto de dados, pode passar o argumento validation_steps , que especifica quantas etapas de validação o modelo deve executar com o conjunto de dados de validação antes de interromper a validação e passar para a próxima época:

model = get_compiled_model()

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

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

model.fit(
    train_dataset,
    epochs=1,
    # Only run validation using the first 10 batches of the dataset
    # using the `validation_steps` argument
    validation_data=val_dataset,
    validation_steps=10,
)
782/782 [==============================] - 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>

Observe que o conjunto de dados de validação será redefinido após cada uso (de modo que você sempre estará avaliando nas mesmas amostras de época para época).

O argumento validation_split (gerando um conjunto de validação dos dados de treinamento) não é compatível com o treinamento de objetos Dataset , pois esse recurso requer a capacidade de indexar as amostras dos conjuntos de dados, o que não é possível em geral com a API Dataset .

Outros formatos de entrada suportados

Além de matrizes NumPy, tensores ansiosos e Datasets TensorFlow, é possível treinar um modelo Keras usando dataframes Pandas ou geradores Python que geram lotes de dados e rótulos.

Em particular, a classe keras.utils.Sequence oferece uma interface simples para construir geradores de dados Python que são compatíveis com multiprocessamento e podem ser embaralhados.

Em geral, recomendamos que você use:

  • Dados de entrada NumPy se seus dados forem pequenos e couberem na memória
  • Objetos de Dataset se você tiver grandes conjuntos de dados e precisar fazer treinamento distribuído
  • Objetos de Sequence se você tiver grandes conjuntos de dados e precisar fazer muito processamento personalizado do lado do Python que não pode ser feito no TensorFlow (por exemplo, se você depende de bibliotecas externas para carregamento ou pré-processamento de dados).

Usando um objeto keras.utils.Sequence como entrada

keras.utils.Sequence é um utilitário que você pode criar em subclasses para obter um gerador Python com duas propriedades importantes:

  • Funciona bem com multiprocessamento.
  • Pode ser embaralhado (por exemplo, ao passar shuffle=True in fit() ).

Uma Sequence deve implementar dois métodos:

  • __getitem__
  • __len__

O método __getitem__ deve retornar um lote completo. Se você quiser modificar seu conjunto de dados entre épocas, você pode implementar on_epoch_end .

Aqui está um exemplo rápido:

from skimage.io import imread
from skimage.transform import resize
import numpy as np

# Here, `filenames` is list of path to the images
# and `labels` are the associated labels.

class CIFAR10Sequence(Sequence):
    def __init__(self, filenames, labels, batch_size):
        self.filenames, self.labels = filenames, labels
        self.batch_size = batch_size

    def __len__(self):
        return int(np.ceil(len(self.filenames) / float(self.batch_size)))

    def __getitem__(self, idx):
        batch_x = self.filenames[idx * self.batch_size:(idx + 1) * self.batch_size]
        batch_y = self.labels[idx * self.batch_size:(idx + 1) * self.batch_size]
        return np.array([
            resize(imread(filename), (200, 200))
               for filename in batch_x]), np.array(batch_y)

sequence = CIFAR10Sequence(filenames, labels, batch_size)
model.fit(sequence, epochs=10)

Usando ponderação de amostra e ponderação de classe

Com as configurações padrão, o peso de uma amostra é decidido por sua frequência no conjunto de dados. Existem dois métodos para ponderar os dados, independentemente da frequência da amostra:

  • Pesos de classe
  • Pesos de amostra

Pesos de classe

Isso é definido pela passagem de um dicionário para o class_weight argumento para Model.fit() . Este dicionário mapeia índices de classe para o peso que deve ser usado para amostras pertencentes a esta classe.

Isso pode ser usado para equilibrar classes sem reamostrar ou para treinar um modelo que dê mais importância a uma classe específica.

Por exemplo, se a classe "0" é representada pela metade como classe "1" em seus dados, você pode usar Model.fit(..., class_weight={0: 1., 1: 0.5}) .

Aqui está um exemplo NumPy onde usamos pesos de classe ou pesos de amostra para dar mais importância à classificação correta da classe # 5 (que é o dígito "5" no conjunto de dados 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>

Pesos de amostra

Para um controle refinado, ou se você não estiver construindo um classificador, você pode usar "pesos de amostra".

  • Quando o treinamento a partir de dados Numpy: Passe o sample_weight argumento para Model.fit() .
  • Ao treinar a partir de tf.data ou qualquer outro tipo de iterador: tuplas de rendimento (input_batch, label_batch, sample_weight_batch) .

Uma matriz de "pesos de amostra" é uma matriz de números que especifica quanto peso cada amostra em um lote deve ter no cálculo da perda total. É comumente usado em problemas de classificação desequilibrada (a ideia é dar mais peso a classes raramente vistas).

Quando os pesos usados ​​são uns e zeros, a matriz pode ser usada como uma máscara para a função de perda (descartando totalmente a contribuição de certas amostras para a perda total).

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

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

Aqui está um exemplo de Dataset correspondente:

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>

Passando dados para modelos de múltiplas entradas e saídas

Nos exemplos anteriores, estávamos considerando um modelo com uma única entrada (um tensor de forma (764,) ) e uma única saída (um tensor de predição de forma (10,) ). Mas e quanto aos modelos que têm várias entradas ou saídas?

Considere o modelo a seguir, que tem uma entrada de imagem de forma (32, 32, 3) (isto é (height, width, channels) ) e uma entrada de série temporal de forma (None, 10) (isto é (timesteps, features) ). Nosso modelo terá duas saídas calculadas a partir da combinação dessas entradas: uma "pontuação" (de forma (1,) ) e uma distribuição de probabilidade em cinco classes (de forma (5,) ).

image_input = keras.Input(shape=(32, 32, 3), name="img_input")
timeseries_input = keras.Input(shape=(None, 10), name="ts_input")

x1 = layers.Conv2D(3, 3)(image_input)
x1 = layers.GlobalMaxPooling2D()(x1)

x2 = layers.Conv1D(3, 3)(timeseries_input)
x2 = layers.GlobalMaxPooling1D()(x2)

x = layers.concatenate([x1, x2])

score_output = layers.Dense(1, name="score_output")(x)
class_output = layers.Dense(5, name="class_output")(x)

model = keras.Model(
    inputs=[image_input, timeseries_input], outputs=[score_output, class_output]
)

Vamos plotar este modelo, para que você possa ver claramente o que estamos fazendo aqui (observe que as formas mostradas no gráfico são formas de lote, em vez de formas por amostra).

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

png

No momento da compilação, podemos especificar diferentes perdas para diferentes saídas, passando as funções de perda como uma lista:

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

Se passássemos apenas uma única função de perda para o modelo, a mesma função de perda seria aplicada a todas as saídas (o que não é apropriado aqui).

Da mesma forma para métricas:

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

Como demos nomes às nossas camadas de saída, também podemos especificar perdas por saída e métricas por meio de um dict:

model.compile(
    optimizer=keras.optimizers.RMSprop(1e-3),
    loss={
        "score_output": keras.losses.MeanSquaredError(),
        "class_output": keras.losses.CategoricalCrossentropy(),
    },
    metrics={
        "score_output": [
            keras.metrics.MeanAbsolutePercentageError(),
            keras.metrics.MeanAbsoluteError(),
        ],
        "class_output": [keras.metrics.CategoricalAccuracy()],
    },
)

Recomendamos o uso de nomes e dictos explícitos se você tiver mais de 2 saídas.

É possível atribuir pesos diferentes para perdas específicas de saída diferentes (por exemplo, pode-se desejar privilegiar a perda de "pontuação" em nosso exemplo, atribuindo a 2x a importância da perda de classe), usando o argumento 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},
)

Você também pode optar por não calcular uma perda para determinadas saídas, se essas saídas forem destinadas para previsão, mas não para treinamento:

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

Passar dados para um modelo de múltiplas entradas ou saídas em fit() funciona de maneira semelhante à especificação de uma função de perda na compilação: você pode passar listas de matrizes NumPy (com mapeamento 1: 1 para as saídas que receberam uma função de perda ) ou dicts mapeando nomes de saída para matrizes 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>

Este é o caso de uso do Dataset : de forma semelhante ao que fizemos para os arrays NumPy, o Dataset deve retornar uma tupla de dicts.

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

model.fit(train_dataset, epochs=1)
2/2 [==============================] - 0s 27ms/step - loss: 10.9011 - score_output_loss: 0.4919 - class_output_loss: 10.4092
<tensorflow.python.keras.callbacks.History at 0x7fb6b00ae9e8>

Usando callbacks

Callbacks no Keras são objetos que são chamados em diferentes pontos durante o treinamento (no início de uma época, no final de um lote, no final de uma época, etc.). Eles podem ser usados ​​para implementar certos comportamentos, como:

  • Fazer a validação em diferentes pontos durante o treinamento (além da validação integrada por época)
  • Verificar o modelo em intervalos regulares ou quando ele exceder um certo limite de precisão
  • Alterar a taxa de aprendizado do modelo quando o treinamento parece estar em um patamar
  • Fazer o ajuste fino das camadas superiores quando o treinamento parece estar em um patamar
  • Envio de notificações por e-mail ou mensagem instantânea quando o treinamento termina ou quando um determinado limite de desempenho é excedido
  • Etc.

Os retornos de chamada podem ser passados ​​como uma lista para sua chamada para 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>

Muitos retornos de chamada integrados estão disponíveis

Existem muitos retornos de chamada integrados já disponíveis no Keras, como:

  • ModelCheckpoint : Salve o modelo periodicamente.
  • EarlyStopping : EarlyStopping treinamento quando o treinamento não estiver mais melhorando as métricas de validação.
  • TensorBoard : escreva periodicamente logs de modelo que podem ser visualizados no TensorBoard (mais detalhes na seção "Visualização").
  • CSVLogger : transmite dados de perda e métricas para um arquivo CSV.
  • etc.

Consulte a documentação de callbacks para a lista completa.

Escrevendo seu próprio retorno de chamada

Você pode criar um retorno de chamada personalizado estendendo a classe base keras.callbacks.Callback . Um retorno de chamada tem acesso ao seu modelo associado por meio da propriedade de classe self.model .

Certifique-se de ler o guia completo para escrever retornos de chamada personalizados .

Aqui está um exemplo simples salvando uma lista de valores de perda por lote durante o treinamento:

class LossHistory(keras.callbacks.Callback):
    def on_train_begin(self, logs):
        self.per_batch_losses = []

    def on_batch_end(self, batch, logs):
        self.per_batch_losses.append(logs.get("loss"))

Modelos de checkpoint

Quando você está treinando o modelo em conjuntos de dados relativamente grandes, é crucial salvar os pontos de verificação do seu modelo em intervalos frequentes.

A maneira mais fácil de fazer isso é com o retorno de chamada 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>

O retorno de chamada ModelCheckpoint pode ser usado para implementar tolerância a falhas: a capacidade de reiniciar o treinamento a partir do último estado salvo do modelo, caso o treinamento seja interrompido aleatoriamente. Aqui está um exemplo básico:

import os

# Prepare a directory to store all the checkpoints.
checkpoint_dir = "./ckpt"
if not os.path.exists(checkpoint_dir):
    os.makedirs(checkpoint_dir)


def make_or_restore_model():
    # Either restore the latest model, or create a fresh one
    # if there is no checkpoint available.
    checkpoints = [checkpoint_dir + "/" + name for name in os.listdir(checkpoint_dir)]
    if checkpoints:
        latest_checkpoint = max(checkpoints, key=os.path.getctime)
        print("Restoring from", latest_checkpoint)
        return keras.models.load_model(latest_checkpoint)
    print("Creating a new model")
    return get_compiled_model()


model = make_or_restore_model()
callbacks = [
    # This callback saves a SavedModel every 100 batches.
    # We include the training loss in the saved model name.
    keras.callbacks.ModelCheckpoint(
        filepath=checkpoint_dir + "/ckpt-loss={loss:.2f}", save_freq=100
    )
]
model.fit(x_train, y_train, epochs=1, callbacks=callbacks)
Creating a new model
  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>

Você também pode escrever seu próprio retorno de chamada para salvar e restaurar modelos.

Para obter um guia completo sobre serialização e salvamento, consulte o guia para salvar e serializar modelos .

Usando programações de taxa de aprendizagem

Um padrão comum ao treinar modelos de aprendizado profundo é reduzir gradualmente o aprendizado à medida que o treinamento avança. Isso é geralmente conhecido como "redução da taxa de aprendizagem".

O cronograma de declínio de aprendizagem pode ser estático (fixado antecipadamente, em função da época atual ou do índice de lote atual) ou dinâmico (respondendo ao comportamento atual do modelo, em particular a perda de validação).

Passar um cronograma para um otimizador

Você pode usar facilmente uma programação de redução da taxa de aprendizagem estática passando um objeto de programação como o argumento learning_rate em seu otimizador:

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)

Vários agendamentos integrados estão disponíveis: ExponentialDecay , PiecewiseConstantDecay , PolynomialDecay e InverseTimeDecay .

Usando callbacks para implementar um cronograma de taxa de aprendizagem dinâmica

Um cronograma de taxa de aprendizado dinâmico (por exemplo, diminuir a taxa de aprendizado quando a perda de validação não está mais melhorando) não pode ser alcançado com esses objetos de cronograma, pois o otimizador não tem acesso às métricas de validação.

No entanto, os retornos de chamada têm acesso a todas as métricas, incluindo as métricas de validação! Você pode, portanto, atingir esse padrão usando um retorno de chamada que modifica a taxa de aprendizado atual no otimizador. Na verdade, isso é integrado até mesmo como o retorno de chamada ReduceLROnPlateau .

Visualizando perda e métricas durante o treinamento

A melhor maneira de ficar de olho no seu modelo durante o treinamento é usar o TensorBoard - um aplicativo baseado em navegador que você pode executar localmente e que oferece:

  • Parcelas ao vivo da perda e métricas para treinamento e avaliação
  • (opcionalmente) Visualizações dos histogramas de suas ativações de camada
  • (opcionalmente) visualizações 3D dos espaços de incorporação aprendidos por suas camadas de Embedding

Se você instalou o TensorFlow com pip, poderá iniciar o TensorBoard na linha de comando:

tensorboard --logdir=/full_path_to_your_logs

Usando o retorno de chamada do TensorBoard

A maneira mais fácil de usar o TensorBoard com um modelo Keras e o método fit() é o retorno de chamada do TensorBoard .

No caso mais simples, apenas especifique onde deseja que o retorno de chamada grave os logs e pronto:

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>

Para mais informações, consulte a documentação do retorno de chamada do TensorBoard .