Loops de treinamento básico

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

Nos guias anteriores, você aprendeu sobre tensores , variáveis , fita de gradiente e módulos . Neste guia, você irá encaixá-los todos juntos para treinar modelos.

O TensorFlow também inclui a API tf.Keras , uma API de rede neural de alto nível que fornece abstrações úteis para reduzir o clichê. No entanto, neste guia, você usará classes básicas.

Configurar

import tensorflow as tf

import matplotlib.pyplot as plt

colors = plt.rcParams['axes.prop_cycle'].by_key()['color']

Resolvendo problemas de aprendizado de máquina

A resolução de um problema de aprendizado de máquina geralmente consiste nas seguintes etapas:

  • Obter dados de treinamento.
  • Defina o modelo.
  • Defina uma função de perda.
  • Percorra os dados de treinamento, calculando a perda a partir do valor ideal
  • Calcule gradientes para essa perda e use um otimizador para ajustar as variáveis ​​aos dados.
  • Avalie seus resultados.

Para fins de ilustração, neste guia você desenvolverá um modelo linear simples, \(f(x) = x * W + b\), que possui duas variáveis: \(W\) (pesos) e \(b\) (bias).

Este é o mais básico dos problemas de aprendizado de máquina: Dado \(x\) e \(y\), tente encontrar a inclinação e o deslocamento de uma linha por meio de regressão linear simples .

Dados

O aprendizado supervisionado usa entradas (geralmente indicadas como x ) e saídas (indicadas por y , geralmente chamadas de rótulos ). O objetivo é aprender com entradas e saídas pareadas para que você possa prever o valor de uma saída a partir de uma entrada.

Cada entrada de seus dados, no TensorFlow, quase sempre é representada por um tensor e geralmente é um vetor. No treinamento supervisionado, a saída (ou valor que você gostaria de prever) também é um tensor.

Aqui estão alguns dados sintetizados pela adição de ruído Gaussiano (Normal) a pontos ao longo de uma linha.

# The actual line
TRUE_W = 3.0
TRUE_B = 2.0

NUM_EXAMPLES = 201

# A vector of random x values
x = tf.linspace(-2,2, NUM_EXAMPLES)
x = tf.cast(x, tf.float32)

def f(x):
  return x * TRUE_W + TRUE_B

# Generate some noise
noise = tf.random.normal(shape=[NUM_EXAMPLES])

# Calculate y
y = f(x) + noise
# Plot all the data
plt.plot(x, y, '.')
plt.show()

png

Tensores são geralmente reunidos em lotes , ou grupos de entradas e saídas empilhadas. Batching pode conferir alguns benefícios de treinamento e funciona bem com aceleradores e computação vetorizada. Dado o tamanho desse conjunto de dados, você pode tratar todo o conjunto de dados como um único lote.

Defina o modelo

Use tf.Variable para representar todos os pesos em um modelo. Um tf.Variable armazena um valor e o fornece na forma de tensor conforme necessário. Consulte o guia de variáveis para obter mais detalhes.

Use tf.Module para encapsular as variáveis ​​e a computação. Você pode usar qualquer objeto Python, mas dessa forma ele pode ser salvo facilmente.

Aqui, você define w e b como variáveis.

class MyModel(tf.Module):
  def __init__(self, **kwargs):
    super().__init__(**kwargs)
    # Initialize the weights to `5.0` and the bias to `0.0`
    # In practice, these should be randomly initialized
    self.w = tf.Variable(5.0)
    self.b = tf.Variable(0.0)

  def __call__(self, x):
    return self.w * x + self.b

model = MyModel()

# List the variables tf.modules's built-in variable aggregation.
print("Variables:", model.variables)

# Verify the model works
assert model(3.0).numpy() == 15.0
Variables: (<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0>, <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=5.0>)
2021-12-08 17:11:44.542944: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.

As variáveis ​​iniciais são definidas aqui de forma fixa, mas o Keras vem com vários inicializadores que você pode usar, com ou sem o resto do Keras.

Defina uma função de perda

Uma função de perda mede quão bem a saída de um modelo para uma determinada entrada corresponde à saída alvo. O objetivo é minimizar essa diferença durante o treinamento. Defina a perda L2 padrão, também conhecida como erro "mean squared":

# This computes a single loss value for an entire batch
def loss(target_y, predicted_y):
  return tf.reduce_mean(tf.square(target_y - predicted_y))

Antes de treinar o modelo, você pode visualizar o valor da perda plotando as previsões do modelo em vermelho e os dados de treinamento em azul:

plt.plot(x, y, '.', label="Data")
plt.plot(x, f(x), label="Ground truth")
plt.plot(x, model(x), label="Predictions")
plt.legend()
plt.show()

print("Current loss: %1.6f" % loss(y, model(x)).numpy())

png

Current loss: 10.301712

Definir um loop de treinamento

O loop de treinamento consiste em executar repetidamente três tarefas em ordem:

  • Enviando um lote de entradas por meio do modelo para gerar saídas
  • Calculando a perda comparando as saídas com a saída (ou rótulo)
  • Usando fita gradiente para encontrar os gradientes
  • Otimizando as variáveis ​​com esses gradientes

Para este exemplo, você pode treinar o modelo usando gradiente descendente .

Existem muitas variantes do esquema de descida de gradiente que são capturadas em tf.keras.optimizers . Mas no espírito de construir a partir dos primeiros princípios, aqui você implementará a matemática básica com a ajuda de tf.GradientTape para diferenciação automática e tf.assign_sub para decrementar um valor (que combina tf.assign e tf.sub ):

# Given a callable model, inputs, outputs, and a learning rate...
def train(model, x, y, learning_rate):

  with tf.GradientTape() as t:
    # Trainable variables are automatically tracked by GradientTape
    current_loss = loss(y, model(x))

  # Use GradientTape to calculate the gradients with respect to W and b
  dw, db = t.gradient(current_loss, [model.w, model.b])

  # Subtract the gradient scaled by the learning rate
  model.w.assign_sub(learning_rate * dw)
  model.b.assign_sub(learning_rate * db)

Para dar uma olhada no treinamento, você pode enviar o mesmo lote de x e y pelo loop de treinamento e ver como W e b evoluem.

model = MyModel()

# Collect the history of W-values and b-values to plot later
weights = []
biases = []
epochs = range(10)

# Define a training loop
def report(model, loss):
  return f"W = {model.w.numpy():1.2f}, b = {model.b.numpy():1.2f}, loss={current_loss:2.5f}"


def training_loop(model, x, y):

  for epoch in epochs:
    # Update the model with the single giant batch
    train(model, x, y, learning_rate=0.1)

    # Track this before I update
    weights.append(model.w.numpy())
    biases.append(model.b.numpy())
    current_loss = loss(y, model(x))

    print(f"Epoch {epoch:2d}:")
    print("    ", report(model, current_loss))

Faça o treinamento

current_loss = loss(y, model(x))

print(f"Starting:")
print("    ", report(model, current_loss))

training_loop(model, x, y)
Starting:
     W = 5.00, b = 0.00, loss=10.30171
Epoch  0:
     W = 4.46, b = 0.40, loss=10.30171
Epoch  1:
     W = 4.06, b = 0.72, loss=10.30171
Epoch  2:
     W = 3.77, b = 0.97, loss=10.30171
Epoch  3:
     W = 3.56, b = 1.18, loss=10.30171
Epoch  4:
     W = 3.40, b = 1.34, loss=10.30171
Epoch  5:
     W = 3.29, b = 1.47, loss=10.30171
Epoch  6:
     W = 3.21, b = 1.58, loss=10.30171
Epoch  7:
     W = 3.15, b = 1.66, loss=10.30171
Epoch  8:
     W = 3.10, b = 1.73, loss=10.30171
Epoch  9:
     W = 3.07, b = 1.78, loss=10.30171

Plote a evolução dos pesos ao longo do tempo:

plt.plot(epochs, weights, label='Weights', color=colors[0])
plt.plot(epochs, [TRUE_W] * len(epochs), '--',
         label = "True weight", color=colors[0])

plt.plot(epochs, biases, label='bias', color=colors[1])
plt.plot(epochs, [TRUE_B] * len(epochs), "--",
         label="True bias", color=colors[1])

plt.legend()
plt.show()

png

Visualize o desempenho do modelo treinado

plt.plot(x, y, '.', label="Data")
plt.plot(x, f(x), label="Ground truth")
plt.plot(x, model(x), label="Predictions")
plt.legend()
plt.show()

print("Current loss: %1.6f" % loss(model(x), y).numpy())

png

Current loss: 0.897898

A mesma solução, mas com Keras

É útil comparar o código acima com o equivalente em Keras.

Definir o modelo parece exatamente o mesmo se você subclassificar tf.keras.Model . Lembre-se de que os modelos Keras herdam, em última análise, de module.

class MyModelKeras(tf.keras.Model):
  def __init__(self, **kwargs):
    super().__init__(**kwargs)
    # Initialize the weights to `5.0` and the bias to `0.0`
    # In practice, these should be randomly initialized
    self.w = tf.Variable(5.0)
    self.b = tf.Variable(0.0)

  def call(self, x):
    return self.w * x + self.b

keras_model = MyModelKeras()

# Reuse the training loop with a Keras model
training_loop(keras_model, x, y)

# You can also save a checkpoint using Keras's built-in support
keras_model.save_weights("my_checkpoint")
Epoch  0:
     W = 4.46, b = 0.40, loss=10.30171
Epoch  1:
     W = 4.06, b = 0.72, loss=10.30171
Epoch  2:
     W = 3.77, b = 0.97, loss=10.30171
Epoch  3:
     W = 3.56, b = 1.18, loss=10.30171
Epoch  4:
     W = 3.40, b = 1.34, loss=10.30171
Epoch  5:
     W = 3.29, b = 1.47, loss=10.30171
Epoch  6:
     W = 3.21, b = 1.58, loss=10.30171
Epoch  7:
     W = 3.15, b = 1.66, loss=10.30171
Epoch  8:
     W = 3.10, b = 1.73, loss=10.30171
Epoch  9:
     W = 3.07, b = 1.78, loss=10.30171

Em vez de escrever novos loops de treinamento cada vez que você cria um modelo, você pode usar os recursos internos do Keras como um atalho. Isso pode ser útil quando você não deseja escrever ou depurar loops de treinamento do Python.

Se fizer isso, você precisará usar model.compile() para definir os parâmetros e model.fit() para treinar. Pode ser menos código usar implementações Keras de perda L2 e descida de gradiente, novamente como um atalho. As perdas e otimizadores Keras também podem ser usados ​​fora dessas funções de conveniência, e o exemplo anterior poderia tê-los usado.

keras_model = MyModelKeras()

# compile sets the training parameters
keras_model.compile(
    # By default, fit() uses tf.function().  You can
    # turn that off for debugging, but it is on now.
    run_eagerly=False,

    # Using a built-in optimizer, configuring as an object
    optimizer=tf.keras.optimizers.SGD(learning_rate=0.1),

    # Keras comes with built-in MSE error
    # However, you could use the loss function
    # defined above
    loss=tf.keras.losses.mean_squared_error,
)

Keras fit espera dados em lote ou um conjunto de dados completo como um array NumPy. As matrizes NumPy são divididas em lotes e padronizadas para um tamanho de lote de 32.

Nesse caso, para corresponder ao comportamento do loop escrito à mão, você deve passar x como um único lote de tamanho 1000.

print(x.shape[0])
keras_model.fit(x, y, epochs=10, batch_size=1000)
201
Epoch 1/10
1/1 [==============================] - 0s 242ms/step - loss: 10.3017
Epoch 2/10
1/1 [==============================] - 0s 3ms/step - loss: 6.3148
Epoch 3/10
1/1 [==============================] - 0s 3ms/step - loss: 4.0341
Epoch 4/10
1/1 [==============================] - 0s 3ms/step - loss: 2.7191
Epoch 5/10
1/1 [==============================] - 0s 3ms/step - loss: 1.9548
Epoch 6/10
1/1 [==============================] - 0s 2ms/step - loss: 1.5068
Epoch 7/10
1/1 [==============================] - 0s 3ms/step - loss: 1.2422
Epoch 8/10
1/1 [==============================] - 0s 2ms/step - loss: 1.0845
Epoch 9/10
1/1 [==============================] - 0s 2ms/step - loss: 0.9899
Epoch 10/10
1/1 [==============================] - 0s 3ms/step - loss: 0.9327
<keras.callbacks.History at 0x7f02ad940050>

Observe que o Keras imprime a perda após o treinamento, não antes, portanto, a primeira perda parece menor, mas, caso contrário, isso mostra essencialmente o mesmo desempenho de treinamento.

Próximos passos

Neste guia, você viu como usar as classes principais de tensores, variáveis, módulos e fita de gradiente para construir e treinar um modelo e ainda como essas ideias são mapeadas para Keras.

Este é, no entanto, um problema extremamente simples. Para obter uma introdução mais prática, consulte Passo a passo de treinamento personalizado .

Para saber mais sobre como usar loops de treinamento Keras integrados, consulte este guia . Para obter mais informações sobre loops de treinamento e Keras, consulte este guia . Para escrever loops de treinamento distribuídos personalizados, consulte este guia .