Cicli di allenamento di base

Visualizza su TensorFlow.org Esegui in Google Colab Visualizza l'origine su GitHub Scarica quaderno

Nelle guide precedenti, hai imparato a conoscere tensori , variabili , nastro gradiente e moduli . In questa guida, li adatterai tutti insieme per addestrare i modelli.

TensorFlow include anche l' API tf.Keras , un'API di rete neurale di alto livello che fornisce utili astrazioni per ridurre il boilerplate. Tuttavia, in questa guida utilizzerai le classi di base.

Impostare

import tensorflow as tf

import matplotlib.pyplot as plt

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

Risolvere problemi di apprendimento automatico

La risoluzione di un problema di machine learning di solito consiste nei seguenti passaggi:

  • Ottieni dati di allenamento.
  • Definisci il modello.
  • Definire una funzione di perdita.
  • Esegui i dati di allenamento, calcolando la perdita dal valore ideale
  • Calcola i gradienti per quella perdita e usa un ottimizzatore per regolare le variabili per adattarle ai dati.
  • Valuta i tuoi risultati.

A scopo illustrativo, in questa guida svilupperai un semplice modello lineare, \(f(x) = x * W + b\), che ha due variabili: \(W\) (pesi) e \(b\) (bias).

Questo è il più elementare dei problemi di apprendimento automatico: dati \(x\) e \(y\), prova a trovare la pendenza e l'offset di una linea tramite una semplice regressione lineare .

Dati

L'apprendimento supervisionato utilizza input (di solito indicati come x ) e output (indicati con y , spesso chiamati etichette ). L'obiettivo è imparare da input e output accoppiati in modo da poter prevedere il valore di un output da un input.

Ogni input dei tuoi dati, in TensorFlow, è quasi sempre rappresentato da un tensore e spesso è un vettore. Nell'allenamento supervisionato, anche l'output (o il valore che si desidera prevedere) è un tensore.

Ecco alcuni dati sintetizzati aggiungendo il rumore gaussiano (normale) ai punti lungo una linea.

# 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

I tensori sono generalmente raccolti in batch o gruppi di input e output impilati insieme. Il batch può conferire alcuni vantaggi di formazione e funziona bene con acceleratori e calcolo vettorizzato. Data la dimensione di questo set di dati, puoi trattare l'intero set di dati come un unico batch.

Definisci il modello

Utilizzare tf.Variable per rappresentare tutti i pesi in un modello. Una tf.Variable memorizza un valore e lo fornisce sotto forma di tensore secondo necessità. Vedere la guida alle variabili per maggiori dettagli.

Usa tf.Module per incapsulare le variabili e il calcolo. Puoi usare qualsiasi oggetto Python, ma in questo modo può essere facilmente salvato.

Qui definisci sia w che b come variabili.

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.

Le variabili iniziali sono impostate qui in modo fisso, ma Keras viene fornito con uno qualsiasi dei numerosi inizializzatori che potresti usare, con o senza il resto di Keras.

Definire una funzione di perdita

Una funzione di perdita misura quanto bene l'output di un modello per un dato input corrisponde all'output di destinazione. L'obiettivo è ridurre al minimo questa differenza durante l'allenamento. Definire la perdita L2 standard, nota anche come errore "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))

Prima di eseguire il training del modello, è possibile visualizzare il valore della perdita tracciando le previsioni del modello in rosso e i dati di training in blu:

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

Definisci un ciclo di allenamento

Il ciclo di formazione consiste nell'eseguire ripetutamente tre attività in ordine:

  • Invio di un batch di input attraverso il modello per generare output
  • Calcolo della perdita confrontando gli output con l'output (o etichetta)
  • Usando il nastro sfumato per trovare i gradienti
  • Ottimizzazione delle variabili con quei gradienti

Per questo esempio, puoi addestrare il modello usando la discesa del gradiente .

Esistono molte varianti dello schema di discesa del gradiente che vengono acquisite in tf.keras.optimizers . Ma nello spirito della costruzione dai primi principi, qui implementerai tu stesso la matematica di base con l'aiuto di tf.GradientTape per la differenziazione automatica e tf.assign_sub per decrementare un valore (che 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)

Per dare un'occhiata all'allenamento, puoi inviare lo stesso batch di xey attraverso il ciclo di addestramento e vedere come si evolvono W e 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))

Fai l'allenamento

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

Traccia l'evoluzione dei pesi nel 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

Visualizza come si comporta il modello addestrato

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

Stessa soluzione, ma con Keras

È utile confrontare il codice sopra con l'equivalente in Keras.

La definizione del modello sembra esattamente la stessa se si esegue la sottoclasse tf.keras.Model . Ricorda che i modelli Keras ereditano in definitiva dal modulo.

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

Anziché scrivere nuovi cicli di addestramento ogni volta che crei un modello, puoi utilizzare le funzionalità integrate di Keras come scorciatoia. Questo può essere utile quando non si desidera scrivere o eseguire il debug dei cicli di addestramento di Python.

Se lo fai, dovrai usare model.compile() per impostare i parametri e model.fit() per addestrare. Può essere meno codice utilizzare le implementazioni Keras della perdita di L2 e della discesa del gradiente, sempre come scorciatoia. Le perdite e gli ottimizzatori Keras possono essere utilizzati anche al di fuori di queste funzioni utili e l'esempio precedente potrebbe averle utilizzate.

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 prevede dati in batch o un set di dati completo come array NumPy. Gli array NumPy sono suddivisi in batch e per impostazione predefinita hanno una dimensione batch di 32.

In questo caso, per abbinare il comportamento del ciclo scritto a mano, dovresti passare x come un singolo batch di dimensione 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>

Nota che Keras stampa la perdita dopo l'allenamento, non prima, quindi la prima perdita appare più bassa, ma per il resto mostra essenzialmente la stessa prestazione di allenamento.

Prossimi passi

In questa guida, hai visto come utilizzare le classi principali di tensori, variabili, moduli e nastro gradiente per costruire e addestrare un modello e ulteriormente come queste idee si associano a Keras.

Questo è, tuttavia, un problema estremamente semplice. Per un'introduzione più pratica, vedere Procedura dettagliata per la formazione personalizzata .

Per ulteriori informazioni sull'utilizzo dei cicli di formazione Keras integrati, consulta questa guida . Per ulteriori informazioni sui cicli di allenamento e su Keras, consulta questa guida . Per la scrittura di cicli di formazione distribuiti personalizzati, vedere questa guida .