Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/pt-br/guide/migrate/early_stopping.ipynb
25118 views
Kernel: Python 3
#@title Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.

Este notebook demonstra como configurar o treinamento de modelos com parada antecipada (early stopping), primeiro no TensorFlow 1 com tf.estimator.Estimator e um hook de parada antecipada e, em seguida, no TensorFlow 2 com APIs Keras ou um loop de treinamento personalizado. A parada antecipada é uma técnica de regularização que interrompe o treinamento se, por exemplo, a perda de validação atingir um determinado limite.

No TensorFlow 2, há três maneiras de implementar a parada antecipada:

  • Use um callback integrado do Keras — tf.keras.callbacks.EarlyStopping — e passe-o para Model.fit.

  • Defina um callback personalizado e passe-o para Keras Model.fit.

  • Escreva uma regra de parada antecipada personalizada num loop de treinamento personalizado (com tf.GradientTape).

Configuração

import time import numpy as np import tensorflow as tf import tensorflow.compat.v1 as tf1 import tensorflow_datasets as tfds

TensorFlow 1: parada antecipada com um hook de parada antecipada e tf.estimator

Comece definindo funções para carregamento e pré-processamento do dataset MNIST e definição do modelo a ser usado com tf.estimator.Estimator:

def normalize_img(image, label): return tf.cast(image, tf.float32) / 255., label def _input_fn(): ds_train = tfds.load( name='mnist', split='train', shuffle_files=True, as_supervised=True) ds_train = ds_train.map( normalize_img, num_parallel_calls=tf.data.AUTOTUNE) ds_train = ds_train.batch(128) ds_train = ds_train.repeat(100) return ds_train def _eval_input_fn(): ds_test = tfds.load( name='mnist', split='test', shuffle_files=True, as_supervised=True) ds_test = ds_test.map( normalize_img, num_parallel_calls=tf.data.AUTOTUNE) ds_test = ds_test.batch(128) return ds_test def _model_fn(features, labels, mode): flatten = tf1.layers.Flatten()(features) features = tf1.layers.Dense(128, 'relu')(flatten) logits = tf1.layers.Dense(10)(features) loss = tf1.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits) optimizer = tf1.train.AdagradOptimizer(0.005) train_op = optimizer.minimize(loss, global_step=tf1.train.get_global_step()) return tf1.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)

No TensorFlow 1, a parada antecipada funciona configurando um hook de parada antecipada com tf.estimator.experimental.make_early_stopping_hook. Você passa o hook para o método make_early_stopping_hook como um parâmetro para should_stop_fn, que pode aceitar uma função sem nenhum argumento. O treinamento para assim que should_stop_fn retorna True.

O exemplo a seguir demonstra como implementar uma técnica de parada antecipada que limita o tempo de treinamento a um máximo de 20 segundos:

estimator = tf1.estimator.Estimator(model_fn=_model_fn) start_time = time.time() max_train_seconds = 20 def should_stop_fn(): return time.time() - start_time > max_train_seconds early_stopping_hook = tf1.estimator.experimental.make_early_stopping_hook( estimator=estimator, should_stop_fn=should_stop_fn, run_every_secs=1, run_every_steps=None) train_spec = tf1.estimator.TrainSpec( input_fn=_input_fn, hooks=[early_stopping_hook]) eval_spec = tf1.estimator.EvalSpec(input_fn=_eval_input_fn) tf1.estimator.train_and_evaluate(estimator, train_spec, eval_spec)

TensorFlow 2: parada antecipada com callback integrado e Model.fit

Prepare o dataset MNIST e um modelo Keras simples:

(ds_train, ds_test), ds_info = tfds.load( 'mnist', split=['train', 'test'], shuffle_files=True, as_supervised=True, with_info=True, ) ds_train = ds_train.map( normalize_img, num_parallel_calls=tf.data.AUTOTUNE) ds_train = ds_train.batch(128) ds_test = ds_test.map( normalize_img, num_parallel_calls=tf.data.AUTOTUNE) ds_test = ds_test.batch(128) model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(input_shape=(28, 28)), tf.keras.layers.Dense(128, activation='relu'), tf.keras.layers.Dense(10) ]) model.compile( optimizer=tf.keras.optimizers.Adam(0.005), loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=[tf.keras.metrics.SparseCategoricalAccuracy()], )

No TensorFlow 2, ao usar Keras Model.fit integrado (ou Model.evaluate), você pode configurar a parada antecipada passando um callback integrado — tf.keras.callbacks.EarlyStopping — para o parâmetro callbacks de Model.fit.

O callback EarlyStopping monitora uma métrica especificada pelo usuário e encerra o treinamento quando ele para de melhorar. (Veja Treinamento e avaliação com os métodos integrados ou a Documentação da API para mais informações.)

Abaixo está um exemplo de um callback de parada antecipada que monitora a perda e interrompe o treinamento após o número de épocas que não mostram melhorias ser definido como 3 (patience):

callback = tf.keras.callbacks.EarlyStopping(monitor='loss', patience=3) # Only around 25 epochs are run during training, instead of 100. history = model.fit( ds_train, epochs=100, validation_data=ds_test, callbacks=[callback] ) len(history.history['loss'])

TensorFlow 2: parada antecipada com callback personalizado e Model.fit

Você também pode implementar um callback personalizado de parada antecipada, que também pode ser passado para o parâmetro callbacks de Model.fit (ou Model.evaluate).

Neste exemplo, o processo de treinamento é interrompido quando self.model.stop_training é definido como True:

class LimitTrainingTime(tf.keras.callbacks.Callback): def __init__(self, max_time_s): super().__init__() self.max_time_s = max_time_s self.start_time = None def on_train_begin(self, logs): self.start_time = time.time() def on_train_batch_end(self, batch, logs): now = time.time() if now - self.start_time > self.max_time_s: self.model.stop_training = True
# Limit the training time to 30 seconds. callback = LimitTrainingTime(30) history = model.fit( ds_train, epochs=100, validation_data=ds_test, callbacks=[callback] ) len(history.history['loss'])

TensorFlow 2: parada antecipada com um loop de treinamento personalizado

No TensorFlow 2, você pode implementar a parada antecipada em um loop de treinamento personalizado se não estiver treinando e avaliando com os métodos Keras integrados.

Comece usando as APIs Keras para definir outro modelo simples, um otimizador, uma função de perda e métricas:

model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(input_shape=(28, 28)), tf.keras.layers.Dense(128, activation='relu'), tf.keras.layers.Dense(10) ]) optimizer = tf.keras.optimizers.Adam(0.005) loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) train_acc_metric = tf.keras.metrics.SparseCategoricalAccuracy() train_loss_metric = tf.keras.metrics.SparseCategoricalCrossentropy() val_acc_metric = tf.keras.metrics.SparseCategoricalAccuracy() val_loss_metric = tf.keras.metrics.SparseCategoricalCrossentropy()

Defina as funções de atualização de parâmetro com tf.GradientTape e o decorador @tf.function para acelerar:

@tf.function def train_step(x, y): with tf.GradientTape() as tape: logits = model(x, training=True) loss_value = loss_fn(y, logits) grads = tape.gradient(loss_value, model.trainable_weights) optimizer.apply_gradients(zip(grads, model.trainable_weights)) train_acc_metric.update_state(y, logits) train_loss_metric.update_state(y, logits) return loss_value @tf.function def test_step(x, y): logits = model(x, training=False) val_acc_metric.update_state(y, logits) val_loss_metric.update_state(y, logits)

Em seguida, escreva um loop de treinamento personalizado, no qual você pode implementar manualmente sua regra de parada antecipada.

O exemplo abaixo mostra como interromper o treinamento quando a perda de validação não melhora depois de um determinado número de épocas:

epochs = 100 patience = 5 wait = 0 best = float('inf') for epoch in range(epochs): print("\nStart of epoch %d" % (epoch,)) start_time = time.time() for step, (x_batch_train, y_batch_train) in enumerate(ds_train): loss_value = train_step(x_batch_train, y_batch_train) if step % 200 == 0: print("Training loss at step %d: %.4f" % (step, loss_value.numpy())) print("Seen so far: %s samples" % ((step + 1) * 128)) train_acc = train_acc_metric.result() train_loss = train_loss_metric.result() train_acc_metric.reset_states() train_loss_metric.reset_states() print("Training acc over epoch: %.4f" % (train_acc.numpy())) for x_batch_val, y_batch_val in ds_test: test_step(x_batch_val, y_batch_val) val_acc = val_acc_metric.result() val_loss = val_loss_metric.result() val_acc_metric.reset_states() val_loss_metric.reset_states() print("Validation acc: %.4f" % (float(val_acc),)) print("Time taken: %.2fs" % (time.time() - start_time)) # The early stopping strategy: stop the training if `val_loss` does not # decrease over a certain number of epochs. wait += 1 if val_loss < best: best = val_loss wait = 0 if wait >= patience: break

Próximos passos