Precisione mista

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

Panoramica

La precisione mista è l'uso di tipi a virgola mobile sia a 16 bit che a 32 bit in un modello durante l'addestramento per renderlo più veloce e utilizzare meno memoria. Mantenendo alcune parti del modello nei tipi a 32 bit per la stabilità numerica, il modello avrà un tempo di passaggio inferiore e si allenerà allo stesso modo in termini di metriche di valutazione come l'accuratezza. Questa guida descrive come utilizzare l'API di precisione mista Keras per velocizzare i tuoi modelli. L'utilizzo di questa API può migliorare le prestazioni di oltre 3 volte sulle GPU moderne e del 60% sulle TPU.

Oggi, la maggior parte dei modelli utilizza float32 dtype, che occupa 32 bit di memoria. Tuttavia, ci sono due dtype di precisione inferiore, float16 e bfloat16, ognuno dei quali occupa invece 16 bit di memoria. I moderni acceleratori possono eseguire operazioni più velocemente nei dtype a 16 bit, poiché dispongono di hardware specializzato per eseguire calcoli a 16 bit e i dtype a 16 bit possono essere letti dalla memoria più velocemente.

Le GPU NVIDIA possono eseguire operazioni in float16 più velocemente che in float32 e le TPU possono eseguire operazioni in bfloat16 più velocemente di float32. Pertanto, questi tipi d di precisione inferiore dovrebbero essere utilizzati quando possibile su tali dispositivi. Tuttavia, le variabili e alcuni calcoli dovrebbero essere ancora in float32 per ragioni numeriche in modo che il modello si alleni con la stessa qualità. L'API di precisione mista Keras consente di utilizzare un mix di float16 o bfloat16 con float32, per ottenere i vantaggi in termini di prestazioni da float16/bfloat16 e la stabilità numerica di float32.

Impostare

import tensorflow as tf

from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras import mixed_precision

Hardware supportato

Sebbene la precisione mista funzionerà sulla maggior parte dell'hardware, accelererà solo i modelli sulle recenti GPU NVIDIA e Cloud TPU. Le GPU NVIDIA supportano l'utilizzo di un mix di float16 e float32, mentre le TPU supportano un mix di bfloat16 e float32.

Tra le GPU NVIDIA, quelle con capacità di calcolo 7.0 o successive vedranno il massimo vantaggio in termini di prestazioni dalla precisione mista perché dispongono di unità hardware speciali, chiamate Tensor Core, per accelerare le moltiplicazioni e le convoluzioni di matrici float16. Le GPU precedenti non offrono alcun vantaggio in termini di prestazioni matematiche per l'utilizzo di precisione mista, tuttavia il risparmio di memoria e larghezza di banda può consentire alcuni aumenti di velocità. Puoi cercare la capacità di calcolo per la tua GPU nella pagina Web della GPU CUDA di NVIDIA . Esempi di GPU che beneficeranno maggiormente della precisione mista includono GPU RTX, V100 e A100.

Puoi controllare il tuo tipo di GPU con quanto segue. Il comando esiste solo se i driver NVIDIA sono installati, quindi quanto segue genererà un errore in caso contrario.

nvidia-smi -L
GPU 0: Tesla V100-SXM2-16GB (UUID: GPU-99e10c4d-de77-42ee-4524-6c41c4e5e47d)

Tutti i Cloud TPU supportano bfloat16.

Anche su CPU e GPU meno recenti, dove non è previsto alcun aumento di velocità, le API di precisione mista possono comunque essere utilizzate per unit test, debug o semplicemente per provare l'API. Sulle CPU, tuttavia, la precisione mista sarà notevolmente più lenta.

Impostazione della politica dtype

Per utilizzare la precisione mista in Keras, è necessario creare un tf.keras.mixed_precision.Policy , generalmente indicato come dtype policy . Le politiche Dtype specificano i livelli dtypes in cui verranno eseguiti. In questa guida, costruirai una politica dalla stringa 'mixed_float16' e la imposterai come politica globale. Ciò farà sì che i livelli creati successivamente utilizzino la precisione mista con un mix di float16 e float32.

policy = mixed_precision.Policy('mixed_float16')
mixed_precision.set_global_policy(policy)
INFO:tensorflow:Mixed precision compatibility check (mixed_float16): OK
Your GPU will likely run quickly with dtype policy mixed_float16 as it has compute capability of at least 7.0. Your GPU: Tesla V100-SXM2-16GB, compute capability 7.0

In breve, puoi passare direttamente una stringa a set_global_policy , cosa che in genere viene eseguita in pratica.

# Equivalent to the two lines above
mixed_precision.set_global_policy('mixed_float16')

La politica specifica due aspetti importanti di un livello: il dtype in cui vengono eseguiti i calcoli del livello e il dtype delle variabili di un livello. Sopra, hai creato una policy mixed_float16 (ovvero, una mixed_precision.Policy creata passando la stringa 'mixed_float16' al suo costruttore). Con questa politica, i livelli utilizzano i calcoli float16 e le variabili float32. I calcoli vengono eseguiti in float16 per le prestazioni, ma le variabili devono essere mantenute in float32 per la stabilità numerica. È possibile interrogare direttamente queste proprietà della politica.

print('Compute dtype: %s' % policy.compute_dtype)
print('Variable dtype: %s' % policy.variable_dtype)
Compute dtype: float16
Variable dtype: float32

Come accennato in precedenza, la policy mixed_float16 migliorerà in modo più significativo le prestazioni sulle GPU NVIDIA con capacità di calcolo di almeno 7,0. Il criterio verrà eseguito su altre GPU e CPU ma potrebbe non migliorare le prestazioni. Per le TPU, dovrebbe essere utilizzata invece la policy mixed_bfloat16 .

Costruire il modello

Quindi, iniziamo a costruire un modello semplice. I modelli di giocattoli molto piccoli in genere non traggono vantaggio dalla precisione mista, perché il sovraccarico del runtime TensorFlow in genere domina il tempo di esecuzione, rendendo trascurabile qualsiasi miglioramento delle prestazioni della GPU. Pertanto, se viene utilizzata una GPU, costruiamo due livelli Dense di grandi dimensioni con 4096 unità ciascuno.

inputs = keras.Input(shape=(784,), name='digits')
if tf.config.list_physical_devices('GPU'):
  print('The model will run with 4096 units on a GPU')
  num_units = 4096
else:
  # Use fewer units on CPUs so the model finishes in a reasonable amount of time
  print('The model will run with 64 units on a CPU')
  num_units = 64
dense1 = layers.Dense(num_units, activation='relu', name='dense_1')
x = dense1(inputs)
dense2 = layers.Dense(num_units, activation='relu', name='dense_2')
x = dense2(x)
The model will run with 4096 units on a GPU

Ogni livello ha una politica e utilizza la politica globale per impostazione predefinita. Ciascuno dei livelli Dense ha quindi la politica mixed_float16 perché in precedenza hai impostato la politica globale su mixed_float16 . Ciò farà sì che i livelli densi eseguano calcoli float16 e abbiano variabili float32. Trasmettono i loro input a float16 per eseguire calcoli float16, il che fa sì che i loro output siano float16 di conseguenza. Le loro variabili sono float32 e verranno convertite in float16 quando i livelli vengono chiamati per evitare errori da disadattamenti di dtype.

print(dense1.dtype_policy)
print('x.dtype: %s' % x.dtype.name)
# 'kernel' is dense1's variable
print('dense1.kernel.dtype: %s' % dense1.kernel.dtype.name)
<Policy "mixed_float16">
x.dtype: float16
dense1.kernel.dtype: float32

Quindi, crea le previsioni di output. Normalmente, puoi creare le previsioni di output come segue, ma questo non è sempre numericamente stabile con float16.

# INCORRECT: softmax and model output will be float16, when it should be float32
outputs = layers.Dense(10, activation='softmax', name='predictions')(x)
print('Outputs dtype: %s' % outputs.dtype.name)
Outputs dtype: float16

Un'attivazione softmax alla fine del modello dovrebbe essere float32. Poiché la politica dtype è mixed_float16 , l'attivazione softmax normalmente avrebbe un float16 calcola dtype e genera tensori float16.

Questo può essere risolto separando i livelli Dense e softmax e passando dtype='float32' al livello softmax:

# CORRECT: softmax and model output are float32
x = layers.Dense(10, name='dense_logits')(x)
outputs = layers.Activation('softmax', dtype='float32', name='predictions')(x)
print('Outputs dtype: %s' % outputs.dtype.name)
Outputs dtype: float32

Il passaggio dtype='float32' al costruttore del livello softmax sovrascrive la politica dtype del livello in modo che sia la politica float32 , che esegue i calcoli e mantiene le variabili in float32. In modo equivalente, avresti invece potuto passare dtype=mixed_precision.Policy('float32') ; i layer convertono sempre l'argomento dtype in una policy. Poiché il livello di Activation non ha variabili, la variabile dtype della politica viene ignorata, ma il calcolo dtype della politica di float32 fa sì che softmax e l'output del modello siano float32.

L'aggiunta di un float16 softmax nel mezzo di un modello va bene, ma un softmax alla fine del modello dovrebbe essere in float32. Il motivo è che se il tensore intermedio che scorre dal softmax alla perdita è float16 o bfloat16, possono verificarsi problemi numerici.

Puoi sovrascrivere dtype di qualsiasi livello in modo che sia float32 passando dtype='float32' se pensi che non sarà numericamente stabile con i calcoli float16. Ma in genere, questo è necessario solo sull'ultimo livello del modello, poiché la maggior parte dei livelli ha una precisione sufficiente con mixed_float16 e mixed_bfloat16 .

Anche se il modello non termina con un softmax, le uscite dovrebbero comunque essere float32. Sebbene non necessari per questo modello specifico, è possibile eseguire il cast degli output del modello su float32 con quanto segue:

# The linear activation is an identity function. So this simply casts 'outputs'
# to float32. In this particular case, 'outputs' is already float32 so this is a
# no-op.
outputs = layers.Activation('linear', dtype='float32')(outputs)

Quindi, completa e compila il modello e genera i dati di input:

model = keras.Model(inputs=inputs, outputs=outputs)
model.compile(loss='sparse_categorical_crossentropy',
              optimizer=keras.optimizers.RMSprop(),
              metrics=['accuracy'])

(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train.reshape(60000, 784).astype('float32') / 255
x_test = x_test.reshape(10000, 784).astype('float32') / 255

Questo esempio esegue il cast dei dati di input da int8 a float32. Non esegui il cast su float16 poiché la divisione per 255 è sulla CPU, che esegue operazioni float16 più lentamente delle operazioni float32. In questo caso, la differenza di prestazioni è trascurabile, ma in generale dovresti eseguire l'elaborazione dell'input matematica in float32 se funziona sulla CPU. Il primo livello del modello eseguirà il cast degli input su float16, poiché ogni livello trasmette gli input in virgola mobile al proprio compute dtype.

Vengono recuperati i pesi iniziali del modello. Ciò consentirà di allenarsi nuovamente da zero caricando i pesi.

initial_weights = model.get_weights()

Allenare il modello con Model.fit

Quindi, addestra il modello:

history = model.fit(x_train, y_train,
                    batch_size=8192,
                    epochs=5,
                    validation_split=0.2)
test_scores = model.evaluate(x_test, y_test, verbose=2)
print('Test loss:', test_scores[0])
print('Test accuracy:', test_scores[1])
Epoch 1/5
6/6 [==============================] - 2s 78ms/step - loss: 4.9609 - accuracy: 0.4132 - val_loss: 0.6643 - val_accuracy: 0.8437
Epoch 2/5
6/6 [==============================] - 0s 34ms/step - loss: 0.7752 - accuracy: 0.7789 - val_loss: 0.3098 - val_accuracy: 0.9175
Epoch 3/5
6/6 [==============================] - 0s 34ms/step - loss: 0.3620 - accuracy: 0.8848 - val_loss: 0.3149 - val_accuracy: 0.8969
Epoch 4/5
6/6 [==============================] - 0s 34ms/step - loss: 0.2998 - accuracy: 0.9066 - val_loss: 0.2988 - val_accuracy: 0.9068
Epoch 5/5
6/6 [==============================] - 0s 33ms/step - loss: 0.2298 - accuracy: 0.9285 - val_loss: 0.5062 - val_accuracy: 0.8414
313/313 - 0s - loss: 0.5163 - accuracy: 0.8392
Test loss: 0.5163048505783081
Test accuracy: 0.8392000198364258

Notare che il modello stampa il tempo per passo nei log: ad esempio, "25ms/passo". La prima epoca potrebbe essere più lenta poiché TensorFlow impiega un po' di tempo per ottimizzare il modello, ma in seguito il tempo per passaggio dovrebbe stabilizzarsi.

Se stai eseguendo questa guida in Colab, puoi confrontare le prestazioni della precisione mista con float32. Per fare ciò, cambia il criterio da mixed_float16 a float32 nella sezione "Impostazione del criterio dtype", quindi esegui nuovamente tutte le celle fino a questo punto. Sulle GPU con capacità di calcolo 7.X, dovresti vedere un aumento significativo del tempo per passaggio, indicando che una precisione mista ha accelerato il modello. Assicurati di riportare la politica su mixed_float16 ed esegui nuovamente le celle prima di continuare con la guida.

Su GPU con capacità di calcolo di almeno 8,0 (GPU Ampere e superiori), è probabile che non si noterà alcun miglioramento delle prestazioni nel modello giocattolo in questa guida quando si utilizza la precisione mista rispetto a float32. Ciò è dovuto all'uso di TensorFloat-32 , che utilizza automaticamente la matematica di precisione inferiore in alcune operazioni float32 come tf.linalg.matmul . TensorFloat-32 offre alcuni dei vantaggi in termini di prestazioni della precisione mista quando si utilizza float32. Tuttavia, nei modelli del mondo reale, in genere vedrai ancora miglioramenti significativi delle prestazioni rispetto alla precisione mista a causa del risparmio di larghezza di banda della memoria e delle operazioni che TensorFloat-32 non supporta.

Se si esegue una precisione mista su una TPU, non si vedrà un aumento delle prestazioni rispetto all'esecuzione di precisione mista su GPU, in particolare GPU pre-Ampere. Questo perché le TPU eseguono determinate operazioni in bfloat16 sotto il cofano anche con la politica predefinita dtype di float32. Questo è simile al modo in cui le GPU Ampere utilizzano TensorFloat-32 per impostazione predefinita. Rispetto alle GPU Ampere, le TPU in genere vedono meno guadagni in termini di prestazioni con una precisione mista sui modelli del mondo reale.

Per molti modelli del mondo reale, la precisione mista consente anche di raddoppiare la dimensione del batch senza esaurire la memoria, poiché i tensori float16 occupano metà della memoria. Ciò non si applica tuttavia a questo modello giocattolo, poiché è probabile che tu possa eseguire il modello in qualsiasi dtype in cui ogni batch è costituito dall'intero set di dati MNIST di 60.000 immagini.

Ridimensionamento delle perdite

Il ridimensionamento della perdita è una tecnica che tf.keras.Model.fit esegue automaticamente con la policy mixed_float16 per evitare un underflow numerico. Questa sezione descrive cos'è il ridimensionamento delle perdite e la sezione successiva descrive come utilizzarlo con un ciclo di formazione personalizzato.

Underflow e Overflow

Il tipo di dati float16 ha un intervallo dinamico ristretto rispetto a float32. Ciò significa che i valori al di sopra \(65504\) andranno in overflow all'infinito e i valori al di sotto \(6.0 \times 10^{-8}\) saranno inferiori a zero. float32 e bfloat16 hanno una gamma dinamica molto più alta in modo che overflow e underflow non siano un problema.

Per esempio:

x = tf.constant(256, dtype='float16')
(x ** 2).numpy()  # Overflow
inf
x = tf.constant(1e-5, dtype='float16')
(x ** 2).numpy()  # Underflow
0.0

In pratica, si verifica raramente l'overflow con float16. Inoltre, l'underflow si verifica raramente anche durante il passaggio in avanti. Tuttavia, durante il passaggio all'indietro, le pendenze possono arrivare a zero. Il ridimensionamento della perdita è una tecnica per prevenire questo underflow.

Panoramica del ridimensionamento delle perdite

Il concetto di base del ridimensionamento delle perdite è semplice: moltiplica semplicemente la perdita per un numero elevato, ad esempio \(1024\), e ottieni il valore della scala delle perdite . Ciò farà sì che i gradienti vengano ridimensionati anche di \(1024\) , riducendo notevolmente la possibilità di underflow. Una volta calcolati i gradienti finali, dividerli per \(1024\) per riportarli ai valori corretti.

Lo pseudocodice per questo processo è:

loss_scale = 1024
loss = model(inputs)
loss *= loss_scale
# Assume `grads` are float32. You do not want to divide float16 gradients.
grads = compute_gradient(loss, model.trainable_variables)
grads /= loss_scale

La scelta di una scala di perdita può essere difficile. Se la scala delle perdite è troppo bassa, i gradienti possono ancora arrivare a zero. Se troppo alto, si verifica il problema opposto: i gradienti possono traboccare all'infinito.

Per risolvere questo problema, TensorFlow determina dinamicamente la scala delle perdite, quindi non è necessario sceglierne una manualmente. Se usi tf.keras.Model.fit , il ridimensionamento delle perdite viene eseguito per te, quindi non devi fare alcun lavoro extra. Se utilizzi un ciclo di addestramento personalizzato, devi usare in modo esplicito lo speciale wrapper tf.keras.mixed_precision.LossScaleOptimizer per utilizzare il ridimensionamento delle perdite. Questo è descritto nella prossima sezione.

Addestrare il modello con un ciclo di allenamento personalizzato

Finora, hai addestrato un modello Keras con precisione mista usando tf.keras.Model.fit . Successivamente, utilizzerai la precisione mista con un ciclo di allenamento personalizzato. Se non sai già cos'è un ciclo di formazione personalizzato, leggi prima la guida alla formazione personalizzata .

L'esecuzione di un ciclo di addestramento personalizzato con precisione mista richiede due modifiche rispetto all'esecuzione in float32:

  1. Costruisci il modello con precisione mista (l'hai già fatto)
  2. Usa esplicitamente il ridimensionamento della perdita se viene utilizzato mixed_float16 .

Per il passaggio (2), utilizzerai la classe tf.keras.mixed_precision.LossScaleOptimizer , che esegue il wrapping di un ottimizzatore e applica il ridimensionamento delle perdite. Per impostazione predefinita, determina dinamicamente la scala delle perdite, quindi non devi sceglierne una. Costruisci un LossScaleOptimizer come segue.

optimizer = keras.optimizers.RMSprop()
optimizer = mixed_precision.LossScaleOptimizer(optimizer)

Se lo si desidera, è possibile scegliere una scala di perdita esplicita o personalizzare in altro modo il comportamento di ridimensionamento delle perdite, ma si consiglia vivamente di mantenere il comportamento di ridimensionamento delle perdite predefinito, poiché è stato riscontrato che funziona bene su tutti i modelli noti. Consulta la documentazione tf.keras.mixed_precision.LossScaleOptimizer se desideri personalizzare il comportamento di ridimensionamento delle perdite.

Quindi, definisci l'oggetto della perdita e il tf.data.Dataset s:

loss_object = tf.keras.losses.SparseCategoricalCrossentropy()
train_dataset = (tf.data.Dataset.from_tensor_slices((x_train, y_train))
                 .shuffle(10000).batch(8192))
test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(8192)

Quindi, definire la funzione della fase di allenamento. Utilizzerai due nuovi metodi dall'ottimizzatore di scala delle perdite per ridimensionare la perdita e annullare la scala dei gradienti:

  • get_scaled_loss(loss) : Moltiplica la perdita per la scala di perdita
  • get_unscaled_gradients(gradients) : accetta un elenco di gradienti scalati come input e li divide per la scala di perdita per annullarne la scala

Queste funzioni devono essere utilizzate per evitare un underflow nelle pendenze. LossScaleOptimizer.apply_gradients applicherà quindi i gradienti se nessuno di essi ha Inf s o NaN s. Aggiornerà anche la scala di perdita, dimezzandola se i gradienti avevano Inf s o NaN s e potenzialmente aumentandola in caso contrario.

@tf.function
def train_step(x, y):
  with tf.GradientTape() as tape:
    predictions = model(x)
    loss = loss_object(y, predictions)
    scaled_loss = optimizer.get_scaled_loss(loss)
  scaled_gradients = tape.gradient(scaled_loss, model.trainable_variables)
  gradients = optimizer.get_unscaled_gradients(scaled_gradients)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))
  return loss

Il LossScaleOptimizer probabilmente salterà i primi passaggi all'inizio dell'allenamento. La scala delle perdite inizia in alto in modo da poter determinare rapidamente la scala delle perdite ottimale. Dopo alcuni passaggi, la scala delle perdite si stabilizzerà e verranno saltati pochissimi passaggi. Questo processo avviene automaticamente e non influisce sulla qualità dell'allenamento.

Ora definiamo la fase del test:

@tf.function
def test_step(x):
  return model(x, training=False)

Carica i pesi iniziali del modello, in modo da poterlo riqualificare da zero:

model.set_weights(initial_weights)

Infine, esegui il ciclo di formazione personalizzato:

for epoch in range(5):
  epoch_loss_avg = tf.keras.metrics.Mean()
  test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(
      name='test_accuracy')
  for x, y in train_dataset:
    loss = train_step(x, y)
    epoch_loss_avg(loss)
  for x, y in test_dataset:
    predictions = test_step(x)
    test_accuracy.update_state(y, predictions)
  print('Epoch {}: loss={}, test accuracy={}'.format(epoch, epoch_loss_avg.result(), test_accuracy.result()))
Epoch 0: loss=4.869325160980225, test accuracy=0.7221999764442444
Epoch 1: loss=0.4893573224544525, test accuracy=0.878000020980835
Epoch 2: loss=0.36011582612991333, test accuracy=0.9440000057220459
Epoch 3: loss=0.27391332387924194, test accuracy=0.9318000078201294
Epoch 4: loss=0.247697651386261, test accuracy=0.933899998664856

Suggerimenti per le prestazioni della GPU

Ecco alcuni suggerimenti sulle prestazioni quando si utilizza la precisione mista su GPU.

Aumentare la dimensione del lotto

Se non influisce sulla qualità del modello, provare a eseguire con il doppio della dimensione batch quando si utilizza la precisione mista. Poiché i tensori float16 utilizzano metà della memoria, questo spesso consente di raddoppiare la dimensione del batch senza esaurire la memoria. L'aumento delle dimensioni del batch in genere aumenta la velocità effettiva di addestramento, ovvero gli elementi di addestramento al secondo su cui può essere eseguito il modello.

Garantire l'utilizzo dei Tensor Core della GPU

Come accennato in precedenza, le moderne GPU NVIDIA utilizzano un'unità hardware speciale chiamata Tensor Cores che può moltiplicare le matrici float16 molto rapidamente. Tuttavia, Tensor Cores richiede che alcune dimensioni dei tensori siano un multiplo di 8. Negli esempi seguenti, un argomento è in grassetto se e solo se deve essere un multiplo di 8 per poter utilizzare Tensor Core.

  • tf.keras.layers.Dense( unità=64 )
  • tf.keras.layers.Conv2d( filtri=48 , kernel_size=7, stride=3)
    • E allo stesso modo per altri livelli convoluzionali, come tf.keras.layers.Conv3d
  • tf.keras.layers.LSTM( unità=64 )
    • E simili per altri RNN, come tf.keras.layers.GRU
  • tf.keras.Model.fit(epochs=2, batch_size=128 )

Dovresti provare a usare i Tensor Core quando possibile. Se vuoi saperne di più, la guida alle prestazioni del deep learning NVIDIA descrive i requisiti esatti per l'utilizzo di Tensor Core e altre informazioni sulle prestazioni relative a Tensor Core.

XLA

XLA è un compilatore che può aumentare ulteriormente le prestazioni di precisione mista, nonché le prestazioni float32 in misura minore. Fare riferimento alla guida XLA per i dettagli.

Suggerimenti per le prestazioni di Cloud TPU

Come con le GPU, dovresti provare a raddoppiare la dimensione del batch quando usi Cloud TPU perché i tensori bfloat16 utilizzano metà della memoria. Il raddoppio della dimensione del batch può aumentare la produttività dell'addestramento.

I TPU non richiedono nessun'altra messa a punto specifica per la precisione mista per ottenere prestazioni ottimali. Richiedono già l'uso di XLA. I TPU traggono vantaggio dall'avere determinate dimensioni multiple di \(128\), ma questo vale sia per il tipo float32 che per la precisione mista. Consulta la guida alle prestazioni di Cloud TPU per suggerimenti generali sulle prestazioni di TPU, che si applicano alla precisione mista e ai tensori float32.

Riepilogo

  • Dovresti usare una precisione mista se utilizzi TPU o GPU NVIDIA con capacità di calcolo almeno 7.0, poiché migliorerà le prestazioni fino a 3 volte.
  • È possibile utilizzare la precisione mista con le seguenti righe:

    # On TPUs, use 'mixed_bfloat16' instead
    mixed_precision.set_global_policy('mixed_float16')
    
  • Se il tuo modello termina con softmax, assicurati che sia float32. E indipendentemente da cosa finisce il tuo modello, assicurati che l'output sia float32.

  • Se usi un ciclo di addestramento personalizzato con mixed_float16 , oltre alle righe precedenti, devi eseguire il wrapping dell'ottimizzatore con un tf.keras.mixed_precision.LossScaleOptimizer . Quindi chiama optimizer.get_scaled_loss per ridimensionare la perdita e optimizer.get_unscaled_gradients per annullare la scala dei gradienti.

  • Raddoppia la dimensione del batch di addestramento se non riduce l'accuratezza della valutazione

  • Sulle GPU, assicurati che la maggior parte delle dimensioni del tensore siano un multiplo di \(8\) per massimizzare le prestazioni

Per ulteriori esempi di precisione mista utilizzando l'API tf.keras.mixed_precision , controlla il repository ufficiale dei modelli . La maggior parte dei modelli ufficiali, come ResNet e Transformer , verrà eseguita utilizzando una precisione mista passando --dtype=fp16 .