Nozioni di base su TensorFlow

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

Questa guida fornisce una rapida panoramica delle basi di TensorFlow . Ogni sezione di questo documento è una panoramica di un argomento più ampio: puoi trovare collegamenti a guide complete alla fine di ogni sezione.

TensorFlow è una piattaforma end-to-end per l'apprendimento automatico. Supporta quanto segue:

  • Calcolo numerico basato su array multidimensionali (simile a NumPy .)
  • GPU ed elaborazione distribuita
  • Differenziazione automatica
  • Costruzione, formazione ed esportazione di modelli
  • E altro ancora

Tensori

TensorFlow opera su array multidimensionali o tensori rappresentati come oggetti tf.Tensor . Ecco un tensore bidimensionale:

import tensorflow as tf

x = tf.constant([[1., 2., 3.],
                 [4., 5., 6.]])

print(x)
print(x.shape)
print(x.dtype)
tf.Tensor(
[[1. 2. 3.]
 [4. 5. 6.]], shape=(2, 3), dtype=float32)
(2, 3)
<dtype: 'float32'>

Gli attributi più importanti di un tf.Tensor sono la sua shape e dtype :

  • Tensor.shape : indica la dimensione del tensore lungo ciascuno dei suoi assi.
  • Tensor.dtype : ti dice il tipo di tutti gli elementi nel tensore.

TensorFlow implementa operazioni matematiche standard sui tensori, oltre a molte operazioni specializzate per l'apprendimento automatico.

Per esempio:

x + x
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[ 2.,  4.,  6.],
       [ 8., 10., 12.]], dtype=float32)>
5 * x
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[ 5., 10., 15.],
       [20., 25., 30.]], dtype=float32)>
x @ tf.transpose(x)
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[14., 32.],
       [32., 77.]], dtype=float32)>
tf.concat([x, x, x], axis=0)
<tf.Tensor: shape=(6, 3), dtype=float32, numpy=
array([[1., 2., 3.],
       [4., 5., 6.],
       [1., 2., 3.],
       [4., 5., 6.],
       [1., 2., 3.],
       [4., 5., 6.]], dtype=float32)>
tf.nn.softmax(x, axis=-1)
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[0.09003057, 0.24472848, 0.6652409 ],
       [0.09003057, 0.24472848, 0.6652409 ]], dtype=float32)>
tf.reduce_sum(x)
<tf.Tensor: shape=(), dtype=float32, numpy=21.0>

L'esecuzione di calcoli di grandi dimensioni sulla CPU può essere lenta. Se configurato correttamente, TensorFlow può utilizzare l'hardware dell'acceleratore come le GPU per eseguire operazioni molto rapidamente.

if tf.config.list_physical_devices('GPU'):
  print("TensorFlow **IS** using the GPU")
else:
  print("TensorFlow **IS NOT** using the GPU")
TensorFlow **IS** using the GPU

Fare riferimento alla guida Tensor per i dettagli.

Variabili

Gli oggetti normali tf.Tensor sono immutabili. Per memorizzare i pesi del modello (o altro stato mutabile) in TensorFlow, utilizzare un tf.Variable .

var = tf.Variable([0.0, 0.0, 0.0])
var.assign([1, 2, 3])
<tf.Variable 'UnreadVariable' shape=(3,) dtype=float32, numpy=array([1., 2., 3.], dtype=float32)>
var.assign_add([1, 1, 1])
<tf.Variable 'UnreadVariable' shape=(3,) dtype=float32, numpy=array([2., 3., 4.], dtype=float32)>

Fare riferimento alla guida alle variabili per i dettagli.

Differenziazione automatica

La discesa del gradiente e i relativi algoritmi sono una pietra miliare del moderno machine learning.

Per consentire ciò, TensorFlow implementa la differenziazione automatica (autodiff), che utilizza il calcolo per calcolare i gradienti. In genere lo utilizzerai per calcolare il gradiente dell'errore o della perdita di un modello rispetto ai suoi pesi.

x = tf.Variable(1.0)

def f(x):
  y = x**2 + 2*x - 5
  return y
f(x)
<tf.Tensor: shape=(), dtype=float32, numpy=-2.0>

A x = 1.0 , y = f(x) = (1**2 + 2*1 - 5) = -2 .

La derivata di y è y' = f'(x) = (2*x + 2) = 4 . TensorFlow può calcolarlo automaticamente:

with tf.GradientTape() as tape:
  y = f(x)

g_x = tape.gradient(y, x)  # g(x) = dy/dx

g_x
<tf.Tensor: shape=(), dtype=float32, numpy=4.0>

Questo esempio semplificato prende solo la derivata rispetto a un singolo scalare ( x ), ma TensorFlow può calcolare il gradiente rispetto a qualsiasi numero di tensori non scalari contemporaneamente.

Fare riferimento alla guida della differenza automatica per i dettagli.

Grafici e funzione tf

Sebbene tu possa utilizzare TensorFlow in modo interattivo come qualsiasi libreria Python, TensorFlow fornisce anche strumenti per:

  • Ottimizzazione delle prestazioni : per velocizzare l'allenamento e l'inferenza.
  • Esporta : così puoi salvare il tuo modello quando ha terminato l'allenamento.

Questi richiedono l'uso di tf.function per separare il codice TensorFlow puro da Python.

@tf.function
def my_func(x):
  print('Tracing.\n')
  return tf.reduce_sum(x)

La prima volta che esegui tf.function , sebbene venga eseguito in Python, acquisisce un grafico completo e ottimizzato che rappresenta i calcoli TensorFlow eseguiti all'interno della funzione.

x = tf.constant([1, 2, 3])
my_func(x)
Tracing.
<tf.Tensor: shape=(), dtype=int32, numpy=6>

Nelle chiamate successive TensorFlow esegue solo il grafico ottimizzato, saltando tutti i passaggi non TensorFlow. Di seguito, nota che my_func non stampa la traccia poiché print è una funzione Python, non una funzione TensorFlow.

x = tf.constant([10, 9, 8])
my_func(x)
<tf.Tensor: shape=(), dtype=int32, numpy=27>

Un grafico potrebbe non essere riutilizzabile per input con una firma diversa ( shape e dtype ), quindi viene invece generato un nuovo grafico:

x = tf.constant([10.0, 9.1, 8.2], dtype=tf.float32)
my_func(x)
Tracing.
<tf.Tensor: shape=(), dtype=float32, numpy=27.3>

Questi grafici acquisiti offrono due vantaggi:

  • In molti casi forniscono una notevole velocità di esecuzione (sebbene non questo banale esempio).
  • Puoi esportare questi grafici, utilizzando tf.saved_model , per eseguirli su altri sistemi come un server o un dispositivo mobile , senza che sia richiesta l'installazione di Python.

Fare riferimento a Introduzione ai grafici per maggiori dettagli.

Moduli, livelli e modelli

tf.Module è una classe per la gestione degli oggetti tf.Variable e degli oggetti tf.function che operano su di essi. La classe tf.Module è necessaria per supportare due caratteristiche significative:

  1. Puoi salvare e ripristinare i valori delle tue variabili usando tf.train.Checkpoint . Ciò è utile durante l'addestramento poiché consente di salvare e ripristinare rapidamente lo stato di un modello.
  2. È possibile importare ed esportare i valori tf.Variable e i grafici tf.function utilizzando tf.saved_model . Ciò ti consente di eseguire il tuo modello indipendentemente dal programma Python che lo ha creato.

Ecco un esempio completo di esportazione di un semplice oggetto tf.Module :

class MyModule(tf.Module):
  def __init__(self, value):
    self.weight = tf.Variable(value)

  @tf.function
  def multiply(self, x):
    return x * self.weight
mod = MyModule(3)
mod.multiply(tf.constant([1, 2, 3]))
<tf.Tensor: shape=(3,), dtype=int32, numpy=array([3, 6, 9], dtype=int32)>

Salva il Module :

save_path = './saved'
tf.saved_model.save(mod, save_path)
INFO:tensorflow:Assets written to: ./saved/assets
2022-01-19 02:29:48.135588: 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.

Il SavedModel risultante è indipendente dal codice che lo ha creato. Puoi caricare un SavedModel da Python, altre associazioni di lingua o TensorFlow Serving . Puoi anche convertirlo per funzionare con TensorFlow Lite o TensorFlow JS .

reloaded = tf.saved_model.load(save_path)
reloaded.multiply(tf.constant([1, 2, 3]))
<tf.Tensor: shape=(3,), dtype=int32, numpy=array([3, 6, 9], dtype=int32)>

Le classi tf.keras.layers.Layer e tf.keras.Model si basano su tf.Module fornendo funzionalità aggiuntive e metodi pratici per la creazione, l'addestramento e il salvataggio di modelli. Alcuni di questi sono illustrati nella sezione successiva.

Fare riferimento a Introduzione ai moduli per i dettagli.

Cicli di formazione

Ora metti tutto insieme per costruire un modello di base e addestrarlo da zero.

Innanzitutto, crea alcuni dati di esempio. Questo genera una nuvola di punti che segue vagamente una curva quadratica:

import matplotlib
from matplotlib import pyplot as plt

matplotlib.rcParams['figure.figsize'] = [9, 6]
x = tf.linspace(-2, 2, 201)
x = tf.cast(x, tf.float32)

def f(x):
  y = x**2 + 2*x - 5
  return y

y = f(x) + tf.random.normal(shape=[201])

plt.plot(x.numpy(), y.numpy(), '.', label='Data')
plt.plot(x, f(x),  label='Ground truth')
plt.legend();

png

Crea un modello:

class Model(tf.keras.Model):
  def __init__(self, units):
    super().__init__()
    self.dense1 = tf.keras.layers.Dense(units=units,
                                        activation=tf.nn.relu,
                                        kernel_initializer=tf.random.normal,
                                        bias_initializer=tf.random.normal)
    self.dense2 = tf.keras.layers.Dense(1)

  def call(self, x, training=True):
    # For Keras layers/models, implement `call` instead of `__call__`.
    x = x[:, tf.newaxis]
    x = self.dense1(x)
    x = self.dense2(x)
    return tf.squeeze(x, axis=1)
model = Model(64)
plt.plot(x.numpy(), y.numpy(), '.', label='data')
plt.plot(x, f(x),  label='Ground truth')
plt.plot(x, model(x), label='Untrained predictions')
plt.title('Before training')
plt.legend();

png

Scrivi un ciclo di formazione di base:

variables = model.variables

optimizer = tf.optimizers.SGD(learning_rate=0.01)

for step in range(1000):
  with tf.GradientTape() as tape:
    prediction = model(x)
    error = (y-prediction)**2
    mean_error = tf.reduce_mean(error)
  gradient = tape.gradient(mean_error, variables)
  optimizer.apply_gradients(zip(gradient, variables))

  if step % 100 == 0:
    print(f'Mean squared error: {mean_error.numpy():0.3f}')
Mean squared error: 16.123
Mean squared error: 0.997
Mean squared error: 0.964
Mean squared error: 0.946
Mean squared error: 0.932
Mean squared error: 0.921
Mean squared error: 0.913
Mean squared error: 0.907
Mean squared error: 0.901
Mean squared error: 0.897
plt.plot(x.numpy(),y.numpy(), '.', label="data")
plt.plot(x, f(x),  label='Ground truth')
plt.plot(x, model(x), label='Trained predictions')
plt.title('After training')
plt.legend();

png

Funziona, ma ricorda che le implementazioni delle utilità di formazione comuni sono disponibili nel modulo tf.keras . Quindi considera di usarli prima di scriverne uno tuo. Per cominciare, i metodi Model.compile e Model.fit implementano un ciclo di formazione per te:

new_model = Model(64)
new_model.compile(
    loss=tf.keras.losses.MSE,
    optimizer=tf.optimizers.SGD(learning_rate=0.01))

history = new_model.fit(x, y,
                        epochs=100,
                        batch_size=32,
                        verbose=0)

model.save('./my_model')
INFO:tensorflow:Assets written to: ./my_model/assets
plt.plot(history.history['loss'])
plt.xlabel('Epoch')
plt.ylim([0, max(plt.ylim())])
plt.ylabel('Loss [Mean Squared Error]')
plt.title('Keras training progress');

png

Fare riferimento a cicli di formazione di base e alla guida Keras per maggiori dettagli.