Podstawowe pętle treningowe

Zobacz na TensorFlow.org Uruchom w Google Colab Wyświetl źródło na GitHub Pobierz notatnik

W poprzednich przewodników, nauczyłeś się o tensorów , zmiennych , taśmy gradientu i modułów . W tym przewodniku dopasujesz je wszystkie, aby trenować modele.

TensorFlow obejmuje również API tf.Keras , wysokiego poziomu sieci neuronowych API zawierającego użyteczne abstrakcje zmniejszenie schematycznych. Jednak w tym poradniku użyjesz podstawowych klas.

Ustawiać

import tensorflow as tf

Rozwiązywanie problemów z uczeniem maszynowym

Rozwiązanie problemu z uczeniem maszynowym zwykle składa się z następujących kroków:

  • Uzyskaj dane treningowe.
  • Zdefiniuj model.
  • Zdefiniuj funkcję straty.
  • Przejrzyj dane treningowe, obliczając stratę z idealnej wartości
  • Oblicz gradienty tej straty i stosowanie do regulacji optimizer zmienne dla dostosowania danych.
  • Oceń swoje wyniki.

W celach ilustracyjnych w tym przewodniku opracujesz prosty model liniowy, $f(x) = x * W + b$, który ma dwie zmienne: $W$ (wagi) i $b$ (obciążenie).

Jest to najbardziej podstawowe problemy Machine Learning: Biorąc $ x $ i $ y $, spróbuj znaleźć nachylenie i przesunięcie linii poprzez prostą regresji liniowej .

Dane

Nadzorowane użyje uczenia wejścia (zwykle oznaczane jako x) i wyjścia (oznaczona T, często zwane etykiety). Celem jest uczenie się na podstawie sparowanych danych wejściowych i wyjściowych, aby można było przewidzieć wartość danych wyjściowych z danych wejściowych.

Każde wejście danych w TensorFlow jest prawie zawsze reprezentowane przez tensor i często jest wektorem. W nadzorowanym treningu wyjście (lub wartość, którą chcesz przewidzieć) jest również tensorem.

Oto niektóre dane zsyntetyzowane przez dodanie szumu gaussowskiego (normalnego) do punktów wzdłuż linii.

# 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

Tensory zwykle są zebrane razem w partiach lub grupy wejść i wyjść one razem. Grupowanie może przynieść pewne korzyści szkoleniowe i działa dobrze z akceleratorami i obliczeniami wektorowymi. Biorąc pod uwagę, jak mały jest ten zestaw danych, możesz traktować cały zestaw danych jako pojedynczą partię.

Zdefiniuj model

Użyj tf.Variable do reprezentowania wszystkich wag w modelu. tf.Variable przechowuje wartość i zapewnia w ten tensor postaci, ile potrzeba. Zobacz zmienną przewodnik po więcej szczegółów.

Użyj tf.Module do hermetyzacji zmienne i obliczeń. Możesz użyć dowolnego obiektu Pythona, ale w ten sposób można go łatwo zapisać.

Tutaj można zdefiniować zarówno w B, jak i zmiennych.

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-09-22 20:35:50.826720: 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.

Zmienne początkowe są tutaj w ustalony sposób, ale Keras pochodzi z dowolną liczbą initalizers można wykorzystać, z lub bez reszty Keras.

Zdefiniuj funkcję straty

Funkcja straty mierzy, jak dobrze dane wyjściowe modelu dla danego wejścia odpowiadają docelowym wynikom. Celem jest zminimalizowanie tej różnicy podczas treningu. Zdefiniuj standardową stratę L2, znaną również jako błąd „średniokwadratowy”:

# 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))

Przed trenowaniem modelu można zwizualizować wartość straty, wykreślając prognozy modelu na czerwono, a dane szkoleniowe na niebiesko:

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: 8.964072

Zdefiniuj pętlę treningową

Pętla treningowa polega na wielokrotnym wykonywaniu trzech zadań w kolejności:

  • Wysyłanie partii danych wejściowych przez model w celu wygenerowania danych wyjściowych
  • Obliczanie straty poprzez porównanie wyjść z wyjściem (lub etykietą)
  • Używanie taśmy gradientowej do znajdowania gradientów
  • Optymalizacja zmiennych za pomocą tych gradientów

W tym przykładzie, można trenować model używając metoda gradientu prostego .

Istnieje wiele wariantów tego programu metoda gradientu prostego, które są ujęte w tf.keras.optimizers . Ale w duchu budowania z pierwszych zasad, tutaj można wdrożyć podstaw matematyki siebie z pomocą tf.GradientTape automatycznego różnicowania i tf.assign_sub na zmniejszanie wartości (która łączy tf.assign i 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)

Aby spojrzeć na szkolenia, można wysłać tę samą partię z X i Y przez pętlę szkoleniowej, i zobaczyć, jak W i b ewoluować.

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=8.96407
Epoch  0: W=4.62 b=0.40, loss=6.17553
Epoch  1: W=4.31 b=0.73, loss=4.36827
Epoch  2: W=4.06 b=0.99, loss=3.19682
Epoch  3: W=3.85 b=1.19, loss=2.43738
Epoch  4: W=3.69 b=1.36, loss=1.94497
Epoch  5: W=3.56 b=1.49, loss=1.62565
Epoch  6: W=3.45 b=1.60, loss=1.41855
Epoch  7: W=3.36 b=1.68, loss=1.28421
Epoch  8: W=3.29 b=1.75, loss=1.19705
Epoch  9: W=3.23 b=1.80, loss=1.14050

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.140498

To samo rozwiązanie, ale z Keras

Warto skontrastować powyższy kod z jego odpowiednikiem w Keras.

Definiowanie modelu wygląda dokładnie tak samo jeśli podklasa tf.keras.Model . Pamiętaj, że modele Keras dziedziczą ostatecznie z modułu.

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.62 b=0.40, loss=6.17553
Epoch  1: W=4.31 b=0.73, loss=4.36827
Epoch  2: W=4.06 b=0.99, loss=3.19682
Epoch  3: W=3.85 b=1.19, loss=2.43738
Epoch  4: W=3.69 b=1.36, loss=1.94497
Epoch  5: W=3.56 b=1.49, loss=1.62565
Epoch  6: W=3.45 b=1.60, loss=1.41855
Epoch  7: W=3.36 b=1.68, loss=1.28421
Epoch  8: W=3.29 b=1.75, loss=1.19705
Epoch  9: W=3.23 b=1.80, loss=1.14050

Zamiast pisać nowe pętle szkoleniowe za każdym razem, gdy tworzysz model, możesz użyć wbudowanych funkcji Keras jako skrótu. Może to być przydatne, gdy nie chcesz pisać ani debugować pętli szkoleniowych Pythona.

Jeśli nie, trzeba będzie użyć model.compile() , aby ustawić parametry i model.fit() do pociągu. Użycie implementacji Keras utraty L2 i spadku gradientu może być mniej kodu, ponownie jako skrótu. Straty Keras i optymalizatory mogą być również używane poza tymi funkcjami wygody, a poprzedni przykład mógł ich użyć.

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 oczekuje batched danych lub kompletny zestaw danych w postaci tablicy numpy. Tablice NumPy są dzielone na partie i domyślnie mają rozmiar 32.

W tym przypadku, aby dopasować zachowanie pętli odręcznego, należy przekazać x w postaci pojedynczej partii wielkości 1000.

print(x.shape[0])
keras_model.fit(x, y, epochs=10, batch_size=1000)
1000
Epoch 1/10
1/1 [==============================] - 0s 227ms/step - loss: 8.9641
Epoch 2/10
1/1 [==============================] - 0s 2ms/step - loss: 6.1755
Epoch 3/10
1/1 [==============================] - 0s 3ms/step - loss: 4.3683
Epoch 4/10
1/1 [==============================] - 0s 2ms/step - loss: 3.1968
Epoch 5/10
1/1 [==============================] - 0s 2ms/step - loss: 2.4374
Epoch 6/10
1/1 [==============================] - 0s 3ms/step - loss: 1.9450
Epoch 7/10
1/1 [==============================] - 0s 2ms/step - loss: 1.6257
Epoch 8/10
1/1 [==============================] - 0s 2ms/step - loss: 1.4185
Epoch 9/10
1/1 [==============================] - 0s 2ms/step - loss: 1.2842
Epoch 10/10
1/1 [==============================] - 0s 2ms/step - loss: 1.1971
<keras.callbacks.History at 0x7fe0e83b5a90>

Zauważ, że Keras wypisuje stratę po treningu, a nie przed, więc pierwsza strata wydaje się mniejsza, ale poza tym pokazuje to zasadniczo tę samą wydajność treningową.

Następne kroki

W tym przewodniku zobaczyłeś, jak używać podstawowych klas tensorów, zmiennych, modułów i taśmy gradientowej do budowania i trenowania modelu, a także jak te pomysły mapują się na Keras.

Jest to jednak niezwykle prosty problem. Dla bardziej praktycznym wprowadzeniem patrz niestandardowy szkoleniowy instruktażu .

Więcej informacji na temat korzystania wbudowanych Keras pętle treningowe, zobacz ten poradnik . Więcej informacji na temat szkoleń i Keras pętli, zobacz ten poradnik . Do pisania zwyczaj rozproszonych pętle treningowe, zobacz ten poradnik .