Zobacz na TensorFlow.org | Uruchom w Google Colab | Wyświetl źródło na GitHub | Pobierz notatnik |
W poprzednich przewodnikach poznałeś tensory , zmienne , taśmę gradientową i moduły . W tym przewodniku dopasujesz je wszystkie, aby trenować modele.
TensorFlow zawiera również tf.Keras API , wysokopoziomowy interfejs API sieci neuronowej, który zapewnia przydatne abstrakcje w celu ograniczenia schematu. Jednak w tym poradniku użyjesz podstawowych klas.
Ustawiać
import tensorflow as tf
import matplotlib.pyplot as plt
colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
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 dla tej straty i użyj optymalizatora , aby dopasować zmienne do 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\) (bias).
Jest to najbardziej podstawowy problem z uczeniem maszynowym: Biorąc pod uwagę \(x\) i \(y\), spróbuj znaleźć nachylenie i przesunięcie linii za pomocą prostej regresji liniowej .
Dane
Uczenie nadzorowane wykorzystuje dane wejściowe (zwykle oznaczane jako x ) i wyniki (oznaczane jako y , często nazywane etykietami ). 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 = 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()
Tensory są zwykle gromadzone w partiach lub grupach wejść i wyjść ułożonych razem. Grupowanie może przynieść pewne korzyści szkoleniowe i dobrze współpracuje 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 w razie potrzeby udostępnia ją w postaci tensorowej. Więcej informacji znajdziesz w przewodniku po zmiennych .
Użyj tf.Module
do hermetyzacji zmiennych i obliczeń. Możesz użyć dowolnego obiektu Pythona, ale w ten sposób można go łatwo zapisać.
Tutaj definiujesz zarówno w , jak i b jako zmienne.
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.
Początkowe zmienne są tutaj ustawione w ustalony sposób, ale Keras jest dostarczany z dowolnym z wielu inicjatorów , których można użyć, z resztą Keras lub bez.
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żesz zwizualizować wartość straty, wykreślając prognozy modelu na czerwono, a dane szkoleniowe na niebiesko:
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())
Current loss: 10.301712
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 model można trenować za pomocą funkcji gradientu .
W tf.keras.optimizers
znajduje się wiele wariantów schematu zejścia gradientowego. Ale w duchu budowania od pierwszych zasad, tutaj samodzielnie zaimplementujesz podstawową matematykę za pomocą tf.GradientTape
do automatycznego różnicowania i tf.assign_sub
do dekrementacji 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 przyjrzeć się treningowi, możesz wysłać tę samą partię x i y przez pętlę treningową i zobaczyć, jak ewoluują W
i b
.
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))
Zrób szkolenie
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
Wykreśl ewolucję wag w czasie:
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()
Wizualizuj, jak działa wytrenowany model
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())
Current loss: 0.897898
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.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
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 to zrobisz, będziesz musiał użyć model.compile()
do ustawienia parametrów i model.fit()
do trenowania. 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 danych wsadowych lub pełnego zestawu danych jako tablicy NumPy. Tablice NumPy są dzielone na partie i domyślnie mają rozmiar 32.
W takim przypadku, aby dopasować zachowanie pętli odręcznej, należy przekazać x
jako pojedynczą partię o rozmiarze 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>
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. Aby uzyskać bardziej praktyczne wprowadzenie, zobacz Przewodnik dotyczący szkolenia niestandardowego .
Więcej informacji na temat korzystania z wbudowanych pętli treningowych Keras można znaleźć w tym przewodniku . Więcej informacji o pętlach treningowych i Keras znajdziesz w tym przewodniku . Aby napisać niestandardowe rozproszone pętle szkoleniowe, zapoznaj się z tym przewodnikiem .