Ver en TensorFlow.org | Ejecutar en Google Colab | Ver fuente en GitHub | Descargar libreta |
En las guías anteriores, aprendió sobre tensores , variables , cinta de degradado y módulos . En esta guía, los combinará para entrenar modelos.
TensorFlow también incluye la API tf.Keras , una API de red neuronal de alto nivel que proporciona abstracciones útiles para reducir la repetición. Sin embargo, en esta guía, utilizará clases básicas.
Configuración
import tensorflow as tf
import matplotlib.pyplot as plt
colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
Resolución de problemas de aprendizaje automático
Resolver un problema de aprendizaje automático generalmente consta de los siguientes pasos:
- Obtener datos de entrenamiento.
- Defina el modelo.
- Defina una función de pérdida.
- Ejecute los datos de entrenamiento, calculando la pérdida a partir del valor ideal
- Calcule gradientes para esa pérdida y use un optimizador para ajustar las variables para que se ajusten a los datos.
- Evalúa tus resultados.
Con fines ilustrativos, en esta guía desarrollará un modelo lineal simple, \(f(x) = x * W + b\), que tiene dos variables: \(W\) (pesos) y \(b\) (sesgo).
Este es el más básico de los problemas de aprendizaje automático: dados \(x\) y \(y\), intente encontrar la pendiente y el desplazamiento de una línea a través de una regresión lineal simple .
Datos
El aprendizaje supervisado utiliza entradas (generalmente indicadas como x ) y salidas (indicadas como y , a menudo llamadas etiquetas ). El objetivo es aprender de las entradas y salidas emparejadas para poder predecir el valor de una salida a partir de una entrada.
Cada entrada de sus datos, en TensorFlow, casi siempre está representada por un tensor y, a menudo, es un vector. En el entrenamiento supervisado, la salida (o el valor que le gustaría predecir) también es un tensor.
Aquí hay algunos datos sintetizados agregando ruido gaussiano (normal) a puntos a lo largo de una línea.
# 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()
Los tensores generalmente se reúnen en lotes , o grupos de entradas y salidas apiladas juntas. El procesamiento por lotes puede conferir algunos beneficios de capacitación y funciona bien con aceleradores y computación vectorizada. Dado lo pequeño que es este conjunto de datos, puede tratar todo el conjunto de datos como un solo lote.
Definir el modelo
Use tf.Variable
para representar todos los pesos en un modelo. Una tf.Variable
almacena un valor y lo proporciona en forma de tensor según sea necesario. Consulte la guía de variables para obtener más detalles.
Utilice tf.Module
para encapsular las variables y el cálculo. Podría usar cualquier objeto de Python, pero de esta manera se puede guardar fácilmente.
Aquí, define w y b como variables.
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.
Las variables iniciales se configuran aquí de forma fija, pero Keras viene con cualquiera de una serie de inicializadores que puede usar, con o sin el resto de Keras.
Definir una función de pérdida
Una función de pérdida mide qué tan bien la salida de un modelo para una entrada determinada coincide con la salida objetivo. El objetivo es minimizar esta diferencia durante el entrenamiento. Defina la pérdida L2 estándar, también conocida como error de "cuadrado medio":
# 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 entrenar el modelo, puede visualizar el valor de pérdida trazando las predicciones del modelo en rojo y los datos de entrenamiento en 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())
Current loss: 10.301712
Definir un ciclo de entrenamiento
El ciclo de entrenamiento consiste en realizar repetidamente tres tareas en orden:
- Envío de un lote de entradas a través del modelo para generar salidas
- Cálculo de la pérdida comparando las salidas con la salida (o etiqueta)
- Usar cinta de degradado para encontrar los degradados
- Optimizando las variables con esos gradientes
Para este ejemplo, puede entrenar el modelo mediante el descenso de gradiente .
Hay muchas variantes del esquema de descenso de gradiente que se capturan en tf.keras.optimizers
. Pero con el espíritu de construir a partir de los primeros principios, aquí implementará las matemáticas básicas usted mismo con la ayuda de tf.GradientTape
para la diferenciación automática y tf.assign_sub
para disminuir un valor (que combina tf.assign
y 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 ver el entrenamiento, puede enviar el mismo lote de x e y a través del ciclo de entrenamiento y ver cómo evolucionan W
y 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))
hacer el entrenamiento
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
Graficar la evolución de los pesos en el tiempo:
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()
Visualice cómo se desempeña el modelo entrenado
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
La misma solución, pero con Keras
Es útil contrastar el código anterior con el equivalente en Keras.
La definición del modelo se ve exactamente igual si subclasifica tf.keras.Model
. Recuerde que los modelos de Keras heredan en última instancia del 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.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
En lugar de escribir nuevos bucles de entrenamiento cada vez que crea un modelo, puede utilizar las funciones integradas de Keras como acceso directo. Esto puede ser útil cuando no desea escribir o depurar bucles de entrenamiento de Python.
Si lo hace, deberá usar model.compile()
para establecer los parámetros y model.fit()
para entrenar. Puede ser menos código usar las implementaciones de Keras de pérdida de L2 y descenso de gradiente, nuevamente como un atajo. Las pérdidas y los optimizadores de Keras también se pueden usar fuera de estas funciones de conveniencia, y el ejemplo anterior podría haberlas 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 datos por lotes o un conjunto de datos completo como una matriz NumPy. Las matrices NumPy se dividen en lotes y por defecto tienen un tamaño de lote de 32.
En este caso, para que coincida con el comportamiento del bucle escrito a mano, debe pasar x
como un solo lote de tamaño 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>
Tenga en cuenta que Keras imprime la pérdida después del entrenamiento, no antes, por lo que la primera pérdida aparece más baja, pero por lo demás muestra esencialmente el mismo rendimiento de entrenamiento.
Próximos pasos
En esta guía, ha visto cómo usar las clases principales de tensores, variables, módulos y cinta de degradado para construir y entrenar un modelo, y cómo esas ideas se asignan a Keras.
Este es, sin embargo, un problema extremadamente simple. Para obtener una introducción más práctica, consulte Tutorial de capacitación personalizada .
Para obtener más información sobre el uso de bucles de entrenamiento de Keras integrados, consulte esta guía . Para obtener más información sobre bucles de entrenamiento y Keras, consulte esta guía . Para escribir bucles de entrenamiento distribuidos personalizados, consulte esta guía .