Loops de treinamento básico

Ver 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ê encaixará todos esses itens para treinar modelos.

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

Configurar

import tensorflow as tf

Resolvendo problemas de aprendizado de máquina

Resolver um problema de aprendizado de máquina geralmente consiste nas seguintes etapas:

  • Obtenha 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
  • Calcular gradientes para que a perda de e utilizar um optimizador de ajustar as variáveis para ajustar os dados.
  • Avalie seus resultados.

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

Este é o mais básico dos problemas de aprendizado de máquina: Dada $ x $ e $ y $, tentar encontrar a inclinação e deslocamento de uma linha através de regressão linear simples .

Dados

Entradas supervisionadas usos de aprendizagem (normalmente designadas por x) e saídas (y denotado, muitas vezes chamado de etiquetas). O objetivo é aprender com entradas e saídas emparelhadas 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 adicionando ruído gaussiano (normal) a pontos ao longo de uma linha.

# The actual line
TRUE_W = 3.0
TRUE_B = 2.0

NUM_EXAMPLES = 1000

# A vector of random x values
x = tf.random.normal(shape=[NUM_EXAMPLES])

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

# Calculate y
y = x * TRUE_W + TRUE_B + noise
# Plot all the data
import matplotlib.pyplot as plt

plt.scatter(x, y, c="b")
plt.show()

png

Tensores são geralmente reunidos em lotes, ou grupos de entradas e saídas empilhadas em conjunto. O batching pode conferir alguns benefícios de treinamento e funciona bem com aceleradores e computação vetorial. Dado o quão pequeno este 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. A tf.Variable armazena um valor e proporciona isso em tensor formulário conforme necessário. Consulte o guia variável para mais detalhes.

Use tf.Module para encapsular as variáveis e o cálculo. Você pode usar qualquer objeto Python, mas dessa forma ele pode ser facilmente salvo.

Aqui, você definir tanto 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-08-28 01:32:13.430236: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.

As variáveis iniciais são definidos aqui de forma fixa, mas Keras vem com qualquer um de uma série de initalizers você poderia usar, com ou sem o resto do Keras.

Defina uma função de perda

Uma função de perda mede o 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 o erro "quadrático médio":

# 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.scatter(x, y, c="b")
plt.scatter(x, model(x), c="r")
plt.show()

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

png

Current loss: 9.245524

Defina um ciclo de treinamento

O ciclo de treinamento consiste em fazer repetidamente três tarefas em ordem:

  • Envio de 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 .

Há muitas variantes do esquema de descida gradiente que são capturados tf.keras.optimizers . Mas no espírito de construir a partir de primeiros princípios, aqui você vai implementar a matemática básica mesmo com a ajuda de tf.GradientTape para a 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 um olhar para treinamento, você pode enviar o mesmo lote de x e y através do laço de treinamento, e ver como W e b evoluir.

model = MyModel()

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

# Define a training loop
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
    Ws.append(model.w.numpy())
    bs.append(model.b.numpy())
    current_loss = loss(y, model(x))

    print("Epoch %2d: W=%1.2f b=%1.2f, loss=%2.5f" %
          (epoch, Ws[-1], bs[-1], current_loss))
print("Starting: W=%1.2f b=%1.2f, loss=%2.5f" %
      (model.w, model.b, loss(y, model(x))))

# Do the training
training_loop(model, x, y)

# Plot it
plt.plot(epochs, Ws, "r",
         epochs, bs, "b")

plt.plot([TRUE_W] * len(epochs), "r--",
         [TRUE_B] * len(epochs), "b--")

plt.legend(["W", "b", "True W", "True b"])
plt.show()
Starting: W=5.00 b=0.00, loss=9.24552
Epoch  0: W=4.58 b=0.42, loss=6.15542
Epoch  1: W=4.26 b=0.74, loss=4.22496
Epoch  2: W=4.00 b=1.01, loss=3.01894
Epoch  3: W=3.79 b=1.21, loss=2.26549
Epoch  4: W=3.63 b=1.37, loss=1.79478
Epoch  5: W=3.51 b=1.50, loss=1.50070
Epoch  6: W=3.41 b=1.61, loss=1.31697
Epoch  7: W=3.33 b=1.69, loss=1.20218
Epoch  8: W=3.26 b=1.75, loss=1.13046
Epoch  9: W=3.22 b=1.80, loss=1.08565

png

# Visualize how the trained model performs
plt.scatter(x, y, c="b")
plt.scatter(x, model(x), c="r")
plt.show()

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

png

Current loss: 1.085646

A mesma solução, mas com Keras

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

Definindo os olhares modelo exatamente o mesmo se você subclasse tf.keras.Model . Lembre-se de que os modelos Keras herdam basicamente do módulo.

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.58 b=0.42, loss=6.15542
Epoch  1: W=4.26 b=0.74, loss=4.22496
Epoch  2: W=4.00 b=1.01, loss=3.01894
Epoch  3: W=3.79 b=1.21, loss=2.26549
Epoch  4: W=3.63 b=1.37, loss=1.79478
Epoch  5: W=3.51 b=1.50, loss=1.50070
Epoch  6: W=3.41 b=1.61, loss=1.31697
Epoch  7: W=3.33 b=1.69, loss=1.20218
Epoch  8: W=3.26 b=1.75, loss=1.13046
Epoch  9: W=3.22 b=1.80, loss=1.08565

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

Se você fizer isso, você vai precisar usar model.compile() para definir os parâmetros e model.fit() para treinar. Pode ser menos código usar as implementações Keras de perda de 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 batched dados ou um conjunto de dados completo como uma matriz NumPy. As matrizes NumPy são divididas em lotes e o tamanho de lote padrão é 32.

Neste caso, para coincidir com o comportamento do circuito de escrita à mão, você deve passar x como um único lote de tamanho de 1000.

print(x.shape[0])
keras_model.fit(x, y, epochs=10, batch_size=1000)
1000
Epoch 1/10
1/1 [==============================] - 0s 189ms/step - loss: 9.2455
Epoch 2/10
1/1 [==============================] - 0s 2ms/step - loss: 6.1554
Epoch 3/10
1/1 [==============================] - 0s 2ms/step - loss: 4.2250
Epoch 4/10
1/1 [==============================] - 0s 2ms/step - loss: 3.0189
Epoch 5/10
1/1 [==============================] - 0s 2ms/step - loss: 2.2655
Epoch 6/10
1/1 [==============================] - 0s 2ms/step - loss: 1.7948
Epoch 7/10
1/1 [==============================] - 0s 2ms/step - loss: 1.5007
Epoch 8/10
1/1 [==============================] - 0s 2ms/step - loss: 1.3170
Epoch 9/10
1/1 [==============================] - 0s 2ms/step - loss: 1.2022
Epoch 10/10
1/1 [==============================] - 0s 2ms/step - loss: 1.1305
<keras.callbacks.History at 0x7fbe7ceb57d0>

Observe que Keras imprime a perda após o treinamento, não antes, então a primeira perda parece menor, mas por outro lado, 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 uma introdução mais prático, ver passo a passo de treinamento personalizado .

Para saber mais sobre o uso de loops de treinamento embutidos Keras, consulte este guia . Para saber mais sobre ciclos de formação e Keras, consulte este guia . Para escrever loops de treinamento distribuídos personalizado, consulte este guia .