RSVP para seu evento TensorFlow Everywhere hoje mesmo!
Esta página foi traduzida pela API Cloud Translation.
Switch to English

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() , model.predict() ).

Se você estiver interessado em aproveitar fit() enquanto especifica 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. Para treinamento distribuído, consulte 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 modelo a seguir (aqui, criamos 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]

Especificamos a configuração de 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 dividindo os dados em "lotes" do tamanho "batch_size" e repetidamente iterando em todo o conjunto de dados por um determinado número de "épocas".

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.5821 - sparse_categorical_accuracy: 0.8361 - val_loss: 0.1893 - val_sparse_categorical_accuracy: 0.9483
Epoch 2/2
782/782 [==============================] - 2s 3ms/step - loss: 0.1676 - sparse_categorical_accuracy: 0.9500 - val_loss: 0.1631 - val_sparse_categorical_accuracy: 0.9488

O objeto "histórico" retornado mantém um registro dos valores de perda e valores métricos durante o treinamento:

history.history
{'loss': [0.344687819480896, 0.15941613912582397],
 'sparse_categorical_accuracy': [0.9019200205802917, 0.9523000121116638],
 'val_loss': [0.1892719268798828, 0.1630939543247223],
 'val_sparse_categorical_accuracy': [0.9483000040054321, 0.9488000273704529]}

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.1750 - sparse_categorical_accuracy: 0.9460
test loss, test acc: [0.17500483989715576, 0.9459999799728394]
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 tiver 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 do zero suas próprias perdas, métricas ou otimizadores, 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

Existem duas maneiras de fornecer perdas personalizadas com Keras. O primeiro exemplo cria uma função que aceita 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 [==============================] - 2s 2ms/step - loss: 0.0265

<tensorflow.python.keras.callbacks.History at 0x7fb27c7a6cf8>

Se você precisar de uma função de perda que y_true parâmetros além 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 previsã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 o modelo não ficar 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.0485

<tensorflow.python.keras.callbacks.History at 0x7fb27c64d438>

Métricas personalizadas

Se precisar de uma métrica que não faz parte da API, você 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 [==============================] - 3s 2ms/step - loss: 0.5801 - categorical_true_positives: 22009.8493
Epoch 2/3
782/782 [==============================] - 2s 2ms/step - loss: 0.1717 - categorical_true_positives: 23861.7190
Epoch 3/3
782/782 [==============================] - 2s 2ms/step - loss: 0.1200 - categorical_true_positives: 24233.9246

<tensorflow.python.keras.callbacks.History at 0x7fb27c56f2e8>

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 de y_true e y_pred , em que y_pred é uma saída de seu modelo. Mas nem 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.2794

<tensorflow.python.keras.callbacks.History at 0x7fb27c4ea3c8>

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.5627 - std_of_activation: 0.9609

<tensorflow.python.keras.callbacks.History at 0x7fb27c39e320>

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.6785 - std_of_activation: 0.0020

<tensorflow.python.keras.callbacks.History at 0x7fb27c2b4860>

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 entropia cruzada por meio de add_loss() . Ele também rastreia a precisão da classificação através 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 destinos), 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 260ms/step - loss: 1.0546 - binary_accuracy: 0.0000e+00

<tensorflow.python.keras.callbacks.History at 0x7fb27c09cc88>

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 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 de ajuste, 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 3ms/step - loss: 0.6332 - sparse_categorical_accuracy: 0.8232 - val_loss: 0.2352 - val_sparse_categorical_accuracy: 0.9284

<tensorflow.python.keras.callbacks.History at 0x7fb27014f0f0>

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 ajuste, 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 uma 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 3ms/step - loss: 0.5405 - sparse_categorical_accuracy: 0.8524
Epoch 2/3
782/782 [==============================] - 2s 3ms/step - loss: 0.1624 - sparse_categorical_accuracy: 0.9517
Epoch 3/3
782/782 [==============================] - 2s 3ms/step - loss: 0.1150 - sparse_categorical_accuracy: 0.9660
Evaluate
157/157 [==============================] - 0s 2ms/step - loss: 0.1337 - sparse_categorical_accuracy: 0.9583

{'loss': 0.13374954462051392, 'sparse_categorical_accuracy': 0.958299994468689}

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 3ms/step - loss: 1.2317 - sparse_categorical_accuracy: 0.6776
Epoch 2/3
100/100 [==============================] - 0s 2ms/step - loss: 0.3834 - sparse_categorical_accuracy: 0.8949
Epoch 3/3
100/100 [==============================] - 0s 3ms/step - loss: 0.3568 - sparse_categorical_accuracy: 0.8912

<tensorflow.python.keras.callbacks.History at 0x7fb21c3b7320>

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 [==============================] - 3s 3ms/step - loss: 0.5587 - sparse_categorical_accuracy: 0.8436 - val_loss: 0.1735 - val_sparse_categorical_accuracy: 0.9517

<tensorflow.python.keras.callbacks.History at 0x7fb21c19c7b8>

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 desse 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 [==============================] - 3s 3ms/step - loss: 0.5708 - sparse_categorical_accuracy: 0.8453 - val_loss: 0.2911 - val_sparse_categorical_accuracy: 0.9312

<tensorflow.python.keras.callbacks.History at 0x7fb21c31ff98>

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

O argumento validation_split (gerando um conjunto de validação a partir 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 muitos processamentos personalizados do lado do Python que não podem ser feitos 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 como subclasse 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 essa 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.6531 - sparse_categorical_accuracy: 0.8268

<tensorflow.python.keras.callbacks.History at 0x7fb27c4e6da0>

Pesos de amostra

Para um controle refinado, ou se 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.6471 - sparse_categorical_accuracy: 0.8342

<tensorflow.python.keras.callbacks.History at 0x7fb21c1257f0>

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 3ms/step - loss: 0.6161 - sparse_categorical_accuracy: 0.8486

<tensorflow.python.keras.callbacks.History at 0x7fb27c7a46a0>

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 os modelos que possuem 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()],
    ],
)

Uma vez que 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 dar 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 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 certas saídas, se essas saídas forem destinadas à previsão, mas não ao 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 ajuste 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 [==============================] - 2s 12ms/step - loss: 19.3697 - score_output_loss: 1.3639 - class_output_loss: 18.0058
4/4 [==============================] - 0s 6ms/step - loss: 17.6548 - score_output_loss: 0.7146 - class_output_loss: 16.9402

<tensorflow.python.keras.callbacks.History at 0x7fb27c5d51d0>

Este é o caso de uso do Dataset : de maneira 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 29ms/step - loss: 17.3215 - score_output_loss: 0.5076 - class_output_loss: 16.8139

<tensorflow.python.keras.callbacks.History at 0x7fb27c46b438>

Usando callbacks

Callbacks em 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.) e que podem ser usados ​​para implementar 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 aprendizagem 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.6313 - sparse_categorical_accuracy: 0.8207 - val_loss: 0.2313 - val_sparse_categorical_accuracy: 0.9307
Epoch 2/20
625/625 [==============================] - 2s 3ms/step - loss: 0.1827 - sparse_categorical_accuracy: 0.9459 - val_loss: 0.1989 - val_sparse_categorical_accuracy: 0.9410
Epoch 3/20
625/625 [==============================] - 2s 3ms/step - loss: 0.1298 - sparse_categorical_accuracy: 0.9619 - val_loss: 0.1561 - val_sparse_categorical_accuracy: 0.9529
Epoch 4/20
625/625 [==============================] - 2s 2ms/step - loss: 0.0977 - sparse_categorical_accuracy: 0.9713 - val_loss: 0.1434 - val_sparse_categorical_accuracy: 0.9576
Epoch 5/20
625/625 [==============================] - 2s 3ms/step - loss: 0.0799 - sparse_categorical_accuracy: 0.9755 - val_loss: 0.1364 - val_sparse_categorical_accuracy: 0.9614
Epoch 6/20
625/625 [==============================] - 2s 3ms/step - loss: 0.0648 - sparse_categorical_accuracy: 0.9806 - val_loss: 0.1351 - val_sparse_categorical_accuracy: 0.9617
Epoch 00006: early stopping

<tensorflow.python.keras.callbacks.History at 0x7fb29ca68940>

Muitos retornos de chamada integrados estão disponíveis

  • 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 callback

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 conseguir 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 3ms/step - loss: 0.6208 - sparse_categorical_accuracy: 0.8258 - val_loss: 0.2241 - val_sparse_categorical_accuracy: 0.9326

Epoch 00001: val_loss improved from inf to 0.22410, saving model to mymodel_1
INFO:tensorflow:Assets written to: mymodel_1/assets
Epoch 2/2
625/625 [==============================] - 2s 3ms/step - loss: 0.1820 - sparse_categorical_accuracy: 0.9470 - val_loss: 0.1621 - val_sparse_categorical_accuracy: 0.9497

Epoch 00002: val_loss improved from 0.22410 to 0.16212, saving model to mymodel_2
INFO:tensorflow:Assets written to: mymodel_2/assets

<tensorflow.python.keras.callbacks.History at 0x7fb21c3e8a20>

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
  94/1563 [>.............................] - ETA: 3s - loss: 1.4324 - sparse_categorical_accuracy: 0.5773INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.96/assets
 193/1563 [==>...........................] - ETA: 5s - loss: 1.1162 - sparse_categorical_accuracy: 0.6814INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.69/assets
 290/1563 [====>.........................] - ETA: 6s - loss: 0.9546 - sparse_categorical_accuracy: 0.7298INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.57/assets
 395/1563 [======>.......................] - ETA: 6s - loss: 0.8447 - sparse_categorical_accuracy: 0.7617INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.51/assets
 493/1563 [========>.....................] - ETA: 6s - loss: 0.7744 - sparse_categorical_accuracy: 0.7817INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.47/assets
 598/1563 [==========>...................] - ETA: 5s - loss: 0.7186 - sparse_categorical_accuracy: 0.7973INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.44/assets
 696/1563 [============>.................] - ETA: 5s - loss: 0.6778 - sparse_categorical_accuracy: 0.8086INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.42/assets
 794/1563 [==============>...............] - ETA: 4s - loss: 0.6445 - sparse_categorical_accuracy: 0.8178INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.40/assets
 898/1563 [================>.............] - ETA: 4s - loss: 0.6146 - sparse_categorical_accuracy: 0.8260INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.38/assets
 995/1563 [==================>...........] - ETA: 3s - loss: 0.5907 - sparse_categorical_accuracy: 0.8326INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.36/assets
1095/1563 [====================>.........] - ETA: 2s - loss: 0.5693 - sparse_categorical_accuracy: 0.8385INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.35/assets
1196/1563 [=====================>........] - ETA: 2s - loss: 0.5503 - sparse_categorical_accuracy: 0.8437INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.34/assets
1297/1563 [=======================>......] - ETA: 1s - loss: 0.5334 - sparse_categorical_accuracy: 0.8484INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.33/assets
1391/1563 [=========================>....] - ETA: 1s - loss: 0.5193 - sparse_categorical_accuracy: 0.8523INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.32/assets
1497/1563 [===========================>..] - ETA: 0s - loss: 0.5050 - sparse_categorical_accuracy: 0.8563INFO:tensorflow:Assets written to: ./ckpt/ckpt-loss=0.31/assets
1563/1563 [==============================] - 11s 6ms/step - loss: 0.4966 - sparse_categorical_accuracy: 0.8586

<tensorflow.python.keras.callbacks.History at 0x7fb2700955c0>

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 conforme o treinamento avança. Isso geralmente é conhecido como "redução da taxa de aprendizagem".

O cronograma de declínio do aprendizado 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 uma programação 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 cronogramas integrados estão disponíveis: ExponentialDecay , PiecewiseConstantDecay , PolynomialDecay e InverseTimeDecay .

Usando callbacks para implementar uma programação dinâmica de taxa de aprendizagem

Um cronograma de taxa de aprendizado dinâmico (por exemplo, diminuindo 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 fornece:

  • 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 TensorBoard

A maneira mais fácil de usar o TensorBoard com um modelo Keras e o método de ajuste é 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 0x7fb21c22deb8>

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