Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Formazione distribuita con TensorFlow

Visualizza su TensorFlow.org Esegui in Google Colab Visualizza sorgente su GitHub Scarica notebook

Panoramica

tf.distribute.Strategy è un'API TensorFlow per distribuire la formazione su più GPU, più macchine o TPU. Utilizzando questa API, puoi distribuire i tuoi modelli esistenti e il codice di addestramento con modifiche minime al codice.

tf.distribute.Strategy è stato progettato con questi obiettivi chiave in mente:

  • Facile da usare e supportare più segmenti di utenti, inclusi ricercatori, ingegneri ML, ecc.
  • Fornire buone prestazioni fuori dagli schemi.
  • Facile passaggio da una strategia all'altra.

tf.distribute.Strategy può essere utilizzato con un'API di alto livello come Keras e può anche essere utilizzato per distribuire cicli di addestramento personalizzati (e, in generale, qualsiasi calcolo utilizzando TensorFlow).

In TensorFlow 2.x, puoi eseguire i tuoi programmi con entusiasmo o in un grafico usando tf.function . tf.distribute.Strategy intende supportare entrambe queste modalità di esecuzione, ma funziona meglio con tf.function . La modalità Eager è consigliata solo a scopo di debug e non è supportata per TPUStrategy . Sebbene la formazione sia il fulcro di questa guida, questa API può essere utilizzata anche per distribuire valutazioni e previsioni su diverse piattaforme.

Puoi utilizzare tf.distribute.Strategy con pochissime modifiche al tuo codice, perché abbiamo modificato i componenti sottostanti di TensorFlow per diventare consapevoli della strategia. Ciò include variabili, livelli, modelli, ottimizzatori, metriche, riepiloghi e punti di controllo.

In questa guida spieghiamo vari tipi di strategie e come utilizzarle in diverse situazioni. Per informazioni su come eseguire il debug dei problemi di prestazioni, consulta la guida Ottimizzazione delle prestazioni della GPU TensorFlow .

# Import TensorFlow
import tensorflow as tf

Tipi di strategie

tf.distribute.Strategy intende coprire una serie di casi d'uso lungo diversi assi. Alcune di queste combinazioni sono attualmente supportate e altre verranno aggiunte in futuro. Alcuni di questi assi sono:

  • Formazione sincrona e asincrona: questi sono due modi comuni per distribuire l'addestramento con il parallelismo dei dati. Nella formazione sulla sincronizzazione, tutti i lavoratori si allenano su diverse sezioni di dati di input sincronizzati e aggregano i gradienti ad ogni passaggio. Nell'addestramento asincrono, tutti i lavoratori eseguono l'addestramento indipendente sui dati di input e aggiornano le variabili in modo asincrono. In genere la formazione sulla sincronizzazione è supportata tramite all-reduce e async tramite l'architettura del server dei parametri.
  • Piattaforma hardware: potresti voler scalare la tua formazione su più GPU su una macchina o su più macchine in una rete (con 0 o più GPU ciascuna) o su Cloud TPU.

Per supportare questi casi d'uso, sono disponibili sei strategie. La sezione successiva spiega quali di questi sono supportati in quali scenari in TF. Ecco una rapida panoramica:

API di formazione MirroredStrategy TPUStrategy MultiWorkerMirroredStrategy CentralStorageStrategy ParameterServerStrategy
API Keras Supportato Supportato Supporto sperimentale Supporto sperimentale Post programmato sostenuto 2.3
Ciclo di allenamento personalizzato Supportato Supportato Supporto sperimentale Supporto sperimentale Post programmato sostenuto 2.3
API dello stimatore Supporto limitato Non supportato Supporto limitato Supporto limitato Supporto limitato

MirroredStrategy

tf.distribute.MirroredStrategy supporta l'addestramento distribuito sincrono su più GPU su una macchina. Crea una replica per dispositivo GPU. Ogni variabile nel modello viene specchiata su tutte le repliche. Insieme, queste variabili formano una singola variabile concettuale chiamata MirroredVariable . Queste variabili vengono mantenute sincronizzate tra loro applicando aggiornamenti identici.

Algoritmi di riduzione totale vengono utilizzati per comunicare gli aggiornamenti delle variabili tra i dispositivi. All-reduce aggrega i tensori su tutti i dispositivi sommandoli e rendendoli disponibili su ogni dispositivo. È un algoritmo fuso che è molto efficiente e può ridurre in modo significativo il sovraccarico della sincronizzazione. Sono disponibili molti algoritmi e implementazioni all-reduce, a seconda del tipo di comunicazione disponibile tra i dispositivi. Per impostazione predefinita, utilizza NVIDIA NCCL come implementazione di riduzione totale. Puoi scegliere tra alcune altre opzioni o scrivere la tua.

Ecco il modo più semplice per creare MirroredStrategy :

mirrored_strategy = tf.distribute.MirroredStrategy()
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0',)

Questo creerà un'istanza MirroredStrategy che utilizzerà tutte le GPU visibili a TensorFlow e utilizzerà NCCL come comunicazione cross-device.

Se desideri utilizzare solo alcune delle GPU sulla tua macchina, puoi farlo in questo modo:

mirrored_strategy = tf.distribute.MirroredStrategy(devices=["/gpu:0", "/gpu:1"])
WARNING:tensorflow:Some requested devices in `tf.distribute.Strategy` are not visible to TensorFlow: /job:localhost/replica:0/task:0/device:GPU:0,/job:localhost/replica:0/task:0/device:GPU:1
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1')

Se si desidera sovrascrivere la comunicazione cross-device, è possibile farlo utilizzando l'argomento cross_device_ops fornendo un'istanza di tf.distribute.CrossDeviceOps . Attualmente, tf.distribute.HierarchicalCopyAllReduce e tf.distribute.ReductionToOneDevice sono due opzioni diverse da tf.distribute.NcclAllReduce che è l'impostazione predefinita.

mirrored_strategy = tf.distribute.MirroredStrategy(
    cross_device_ops=tf.distribute.HierarchicalCopyAllReduce())
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0',)

TPUStrategy

tf.distribute.TPUStrategy ti consente di eseguire la formazione TensorFlow su unità di elaborazione tensoriale (TPU). Le TPU sono gli ASIC specializzati di Google progettati per accelerare notevolmente i carichi di lavoro di machine learning. Sono disponibili su Google Colab, TensorFlow Research Cloud e Cloud TPU .

In termini di architettura di formazione distribuita, TPUStrategy è la stessa MirroredStrategy : implementa la formazione distribuita sincrona. Le TPU forniscono la propria implementazione di operazioni collettive efficienti di riduzione totale e di altro tipo su più core TPU, che vengono utilizzati in TPUStrategy .

Ecco come istanziare TPUStrategy :

cluster_resolver = tf.distribute.cluster_resolver.TPUClusterResolver(
    tpu=tpu_address)
tf.config.experimental_connect_to_cluster(cluster_resolver)
tf.tpu.experimental.initialize_tpu_system(cluster_resolver)
tpu_strategy = tf.distribute.TPUStrategy(cluster_resolver)

L'istanza TPUClusterResolver aiuta a individuare le TPU. In Colab, non è necessario specificare alcun argomento.

Se vuoi usarlo per Cloud TPU:

  • È necessario specificare il nome della risorsa TPU nell'argomento tpu .
  • È necessario inizializzare esplicitamente il sistema tpu all'inizio del programma. Ciò è necessario prima che le TPU possano essere utilizzate per il calcolo. L'inizializzazione del sistema tpu cancella anche la memoria TPU, quindi è importante completare prima questo passaggio per evitare di perdere lo stato.

MultiWorkerMirroredStrategy

tf.distribute.experimental.MultiWorkerMirroredStrategy è molto simile a MirroredStrategy . Implementa una formazione distribuita sincrona tra più lavoratori, ciascuno con potenzialmente più GPU. Simile a MirroredStrategy , crea copie di tutte le variabili nel modello su ogni dispositivo su tutti i worker.

Utilizza CollectiveOps come metodo di comunicazione multi-worker per ridurre tutto utilizzato per mantenere le variabili sincronizzate. Un'operazione collettiva è una singola operazione nel grafico TensorFlow che può scegliere automaticamente un algoritmo di riduzione totale nel runtime di TensorFlow in base all'hardware, alla topologia di rete e alle dimensioni del tensore.

Implementa inoltre ulteriori ottimizzazioni delle prestazioni. Ad esempio, include un'ottimizzazione statica che converte più riduzioni totali su tensori piccoli in meno riduzioni totali su tensori più grandi. Inoltre, è progettato per avere un'architettura plug-in, in modo che in futuro sarai in grado di collegare algoritmi che sono meglio sintonizzati per il tuo hardware. Nota che le operazioni collettive implementano anche altre operazioni collettive come broadcast e all-gather.

Ecco il modo più semplice per creare MultiWorkerMirroredStrategy :

multiworker_strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy()
WARNING:tensorflow:Collective ops is not configured at program startup. Some performance features may not be enabled.
INFO:tensorflow:Using MirroredStrategy with devices ('/device:GPU:0',)
INFO:tensorflow:Single-worker MultiWorkerMirroredStrategy with local_devices = ('/device:GPU:0',), communication = CollectiveCommunication.AUTO

MultiWorkerMirroredStrategy attualmente consente di scegliere tra due diverse implementazioni di operazioni collettive. CollectiveCommunication.RING implementa collettivi basati su anello utilizzando gRPC come livello di comunicazione. CollectiveCommunication.NCCL utilizza NCCL di Nvidia per implementare i collettivi. CollectiveCommunication.AUTO rimanda la scelta al runtime. La scelta migliore per l'implementazione collettiva dipende dal numero e dal tipo di GPU e dall'interconnessione di rete nel cluster. Puoi specificarli nel modo seguente:

multiworker_strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy(
    tf.distribute.experimental.CollectiveCommunication.NCCL)
WARNING:tensorflow:Collective ops is not configured at program startup. Some performance features may not be enabled.
INFO:tensorflow:Using MirroredStrategy with devices ('/device:GPU:0',)
INFO:tensorflow:Single-worker MultiWorkerMirroredStrategy with local_devices = ('/device:GPU:0',), communication = CollectiveCommunication.NCCL

Una delle principali differenze per ottenere la formazione multi-lavoratore, rispetto alla formazione multi-GPU, è la configurazione multi-lavoratore. La variabile di ambiente TF_CONFIG è il modo standard in TensorFlow per specificare la configurazione del cluster a ogni worker che fa parte del cluster. Ulteriori informazioni sulla configurazione di TF_CONFIG .

ParameterServerStrategy

L'addestramento del server dei parametri è un metodo comune in parallelo ai dati per aumentare l'addestramento del modello su più macchine. Un cluster di formazione del server dei parametri è costituito da worker e server dei parametri. Le variabili vengono create sui server dei parametri e vengono lette e aggiornate dai lavoratori in ogni fase. Per i dettagli, vedere il tutorial sulla formazione del server dei parametri .

La formazione del server dei parametri TensorFlow 2 utilizza un'architettura basata sul coordinatore centrale tramite la classe tf.distribute.experimental.coordinator.ClusterCoordinator .

In questa implementazione, le attività del parameter server worker e del parameter server eseguono tf.distribute.Server che ascoltano le attività dal coordinatore. Il coordinatore crea risorse, invia attività di formazione, scrive checkpoint e gestisce gli errori delle attività.

Nella programmazione in esecuzione sul coordinatore, utilizzerai un oggetto ParameterServerStrategy per definire una fase di addestramento e utilizzerai un ClusterCoordinator per inviare le fasi di formazione ai lavoratori remoti. Ecco il modo più semplice per crearli:

strategy = tf.distribute.experimental.ParameterServerStrategy(
    tf.distribute.cluster_resolver.TFConfigClusterResolver(),
    variable_partitioner=variable_partitioner)
coordinator = tf.distribute.experimental.coordinator.ClusterCoordinator(
    strategy)

Nota che dovrai configurare la variabile d'ambiente TF_CONFIG se usi TFConfigClusterResolver . E 'simile a TF_CONFIG in MultiWorkerMirroredStrategy ma ha altri caveat.

In TF 1, ParameterServerStrategy è disponibile solo con estimator tramite il simbolo tf.compat.v1.distribute.experimental.ParameterServerStrategy .

CentralStorageStrategy

tf.distribute.experimental.CentralStorageStrategy esegue anche l'addestramento sincrono. Le variabili non vengono specchiate, ma vengono posizionate sulla CPU e le operazioni vengono replicate su tutte le GPU locali. Se è presente una sola GPU, tutte le variabili e le operazioni verranno posizionate su quella GPU.

Crea un'istanza di CentralStorageStrategy tramite:

central_storage_strategy = tf.distribute.experimental.CentralStorageStrategy()
INFO:tensorflow:ParameterServerStrategy (CentralStorageStrategy if you are using a single machine) with compute_devices = ['/job:localhost/replica:0/task:0/device:GPU:0'], variable_device = '/job:localhost/replica:0/task:0/device:GPU:0'

Questo creerà un'istanza CentralStorageStrategy che utilizzerà tutte le GPU e CPU visibili. L'aggiornamento alle variabili sulle repliche verrà aggregato prima di essere applicato alle variabili.

Altre strategie

Oltre alle strategie di cui sopra, ci sono altre due strategie che potrebbero essere utili per la prototipazione e il debug quando si utilizzano tf.distribute API tf.distribute .

Strategia predefinita

La strategia predefinita è una strategia di distribuzione che è presente quando nessuna strategia di distribuzione esplicita è nell'ambito. Implementa l'interfaccia tf.distribute.Strategy ma è un pass-through e non fornisce alcuna distribuzione effettiva. Ad esempio, strategy.run(fn) chiamerà semplicemente fn . Il codice scritto utilizzando questa strategia dovrebbe comportarsi esattamente come il codice scritto senza alcuna strategia. Puoi pensarla come una strategia "no-op".

La strategia predefinita è un singleton e non è possibile crearne più istanze. Può essere ottenuto utilizzando tf.distribute.get_strategy() al di fuori dell'ambito di una strategia esplicita (la stessa API che può essere utilizzata per ottenere la strategia corrente all'interno dell'ambito di una strategia esplicita).

default_strategy = tf.distribute.get_strategy()

Questa strategia ha due scopi principali:

  • Permette di scrivere incondizionatamente il codice della libreria che riconosce la distribuzione. Ad esempio, in tf.optimizer s possiamo usare tf.distribute.get_strategy() e usare quella strategia per ridurre i gradienti: restituirà sempre un oggetto strategia su cui possiamo chiamare l'API reduce.
# In optimizer or other library code
# Get currently active strategy
strategy = tf.distribute.get_strategy()
strategy.reduce("SUM", 1., axis=None)  # reduce some values
1.0
  • Simile al codice della libreria, può essere utilizzato per scrivere programmi degli utenti finali per lavorare con e senza strategia di distribuzione, senza richiedere logica condizionale. Uno snippet di codice di esempio che illustra questo:
if tf.config.list_physical_devices('gpu'):
  strategy = tf.distribute.MirroredStrategy()
else:  # use default strategy
  strategy = tf.distribute.get_strategy() 

with strategy.scope():
  # do something interesting
  print(tf.Variable(1.))
<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=1.0>

OneDeviceStrategy

tf.distribute.OneDeviceStrategy è una strategia per posizionare tutte le variabili e il calcolo su un singolo dispositivo specificato.

strategy = tf.distribute.OneDeviceStrategy(device="/gpu:0")

Questa strategia è diversa dalla strategia predefinita in molti modi. Nella strategia predefinita, la logica di posizionamento delle variabili rimane invariata rispetto all'esecuzione di TensorFlow senza alcuna strategia di distribuzione. Tuttavia, quando si utilizza OneDeviceStrategy , tutte le variabili create nel suo ambito vengono posizionate esplicitamente sul dispositivo specificato. Inoltre, tutte le funzioni chiamate tramite OneDeviceStrategy.run verranno posizionate anche sul dispositivo specificato.

L'input distribuito tramite questa strategia verrà precaricato al dispositivo specificato. Nella strategia predefinita, non c'è distribuzione dell'input.

Simile alla strategia predefinita, questa strategia potrebbe essere utilizzata anche per testare il codice prima di passare ad altre strategie che vengono effettivamente distribuite a più dispositivi / macchine. Questo eserciterà il meccanismo della strategia di distribuzione un po 'più della strategia predefinita, ma non nella misura massima come quando si utilizza MirroredStrategy o TPUStrategy ecc. Se si desidera che il codice si comporti come se non fosse una strategia, utilizzare la strategia predefinita.

Finora hai visto le diverse strategie disponibili e come puoi istanziarle. Le prossime sezioni mostrano i diversi modi in cui puoi usarli per distribuire la tua formazione.

Utilizzo di tf.distribute.Strategy con tf.keras.Model.fit

tf.distribute.Strategy è integrato in tf.keras che è l'implementazione di TensorFlow della specifica API di Keras . tf.keras è tf.keras alto livello per creare e addestrare modelli. Grazie all'integrazione nel backend tf.keras , abbiamo tf.keras distribuzione della formazione scritta nel framework di formazione Keras utilizzando model.fit .

Ecco cosa devi cambiare nel tuo codice:

  1. Crea un'istanza del file tf.distribute.Strategy appropriato.
  2. Sposta la creazione del modello, dell'ottimizzatore e delle metriche di Keras all'interno di strategy.scope .

Supportiamo tutti i tipi di modelli Keras: sequenziali, funzionali e sottoclasse.

Ecco uno snippet di codice per eseguire questa operazione per un modello Keras molto semplice con uno strato denso:

mirrored_strategy = tf.distribute.MirroredStrategy()

with mirrored_strategy.scope():
  model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))])

model.compile(loss='mse', optimizer='sgd')
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0',)

Questo esempio utilizza MirroredStrategy modo da poterlo eseguire su una macchina con più GPU. strategy.scope() indica a Keras quale strategia utilizzare per distribuire la formazione. La creazione di modelli / ottimizzatori / metriche all'interno di questo ambito ci consente di creare variabili distribuite invece di variabili regolari. Una volta impostato, puoi adattare il tuo modello come faresti normalmente. MirroredStrategy si occupa di replicare l'addestramento del modello sulle GPU disponibili, aggregando i gradienti e altro ancora.

dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100).batch(10)
model.fit(dataset, epochs=2)
model.evaluate(dataset)
Epoch 1/2
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/data/ops/multi_device_iterator_ops.py:601: get_next_as_optional (from tensorflow.python.data.ops.iterator_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.data.Iterator.get_next_as_optional()` instead.
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
10/10 [==============================] - 0s 2ms/step - loss: 0.2137
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
Epoch 2/2
10/10 [==============================] - 0s 2ms/step - loss: 0.0945
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
10/10 [==============================] - 0s 1ms/step - loss: 0.0587

0.0586698018014431

Qui untf.data.Dataset fornisce l'addestramento e l'input ditf.data.Dataset . Puoi anche usare array numpy:

import numpy as np
inputs, targets = np.ones((100, 1)), np.ones((100, 1))
model.fit(inputs, targets, epochs=2, batch_size=10)
Epoch 1/2
10/10 [==============================] - 0s 2ms/step - loss: 0.0418
Epoch 2/2
10/10 [==============================] - 0s 2ms/step - loss: 0.0185

<tensorflow.python.keras.callbacks.History at 0x7f4dc01c5b70>

In entrambi i casi (dataset o numpy), ogni batch dell'input fornito viene diviso equamente tra le repliche multiple. Ad esempio, se si utilizza MirroredStrategy con 2 GPU, ogni lotto di dimensione 10 verrà diviso tra le 2 GPU, con ciascuna che riceverà 5 esempi di input in ogni passaggio. Ogni epoca verrà quindi addestrata più velocemente man mano che si aggiungono più GPU. In genere, si desidera aumentare la dimensione del batch aggiungendo più acceleratori in modo da utilizzare in modo efficace la potenza di calcolo extra. Dovrai anche risintonizzare il tuo tasso di apprendimento, a seconda del modello. Puoi utilizzare strategy.num_replicas_in_sync per ottenere il numero di repliche.

# Compute global batch size using number of replicas.
BATCH_SIZE_PER_REPLICA = 5
global_batch_size = (BATCH_SIZE_PER_REPLICA *
                     mirrored_strategy.num_replicas_in_sync)
dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100)
dataset = dataset.batch(global_batch_size)

LEARNING_RATES_BY_BATCH_SIZE = {5: 0.1, 10: 0.15}
learning_rate = LEARNING_RATES_BY_BATCH_SIZE[global_batch_size]

Cosa è supportato ora?

API di formazione MirroredStrategy TPUStrategy MultiWorkerMirroredStrategy ParameterServerStrategy CentralStorageStrategy
API Keras Supportato Supportato Supporto sperimentale Supporto sperimentale Supporto sperimentale

Esempi e tutorial

Ecco un elenco di tutorial ed esempi che illustrano l'integrazione di cui sopra end to end con Keras:

  1. Tutorial per addestrare MNIST con MirroredStrategy .
  2. Tutorial per addestrare MNIST utilizzando MultiWorkerMirroredStrategy .
  3. Guida alla formazione di MNIST utilizzando TPUStrategy .
  4. Tutorial per l'addestramento del server dei parametri in TensorFlow 2 con ParameterServerStrategy .
  5. Repository TensorFlow Model Garden contenente raccolte di modelli all'avanguardia implementati utilizzando varie strategie.

Utilizzo di tf.distribute.Strategy con cicli di addestramento personalizzati

Come hai visto, l'utilizzo di tf.distribute.Strategy con Keras model.fit richiede la modifica solo di un paio di righe del codice. Con un piccolo sforzo in più, puoi anche utilizzare tf.distribute.Strategy con cicli di addestramento personalizzati.

Se hai bisogno di maggiore flessibilità e controllo sui tuoi cicli di allenamento rispetto a quanto è possibile con Estimator o Keras, puoi scrivere cicli di allenamento personalizzati. Ad esempio, quando si utilizza un GAN, è possibile eseguire un numero diverso di passaggi del generatore o del discriminatore ogni round. Allo stesso modo, i quadri di alto livello non sono molto adatti per la formazione sull'apprendimento per rinforzo.

Le classi tf.distribute.Strategy forniscono una serie di metodi fondamentali per supportare i cicli di addestramento personalizzati. L'utilizzo di questi potrebbe richiedere inizialmente una piccola ristrutturazione del codice, ma una volta fatto, dovresti essere in grado di passare da GPU, TPU e più macchine semplicemente cambiando l'istanza della strategia.

Qui mostreremo un breve snippet che illustra questo caso d'uso per un semplice esempio di addestramento usando lo stesso modello Keras di prima.

Innanzitutto, crea il modello e l'ottimizzatore all'interno dell'ambito della strategia. Ciò garantisce che tutte le variabili create con il modello e l'ottimizzatore siano variabili speculari.

with mirrored_strategy.scope():
  model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))])
  optimizer = tf.keras.optimizers.SGD()

Quindi, creare il set di dati di input e chiamare tf.distribute.Strategy.experimental_distribute_dataset per distribuire il set di dati in base alla strategia.

dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100).batch(
    global_batch_size)
dist_dataset = mirrored_strategy.experimental_distribute_dataset(dataset)

Quindi, definire una fase della formazione. Usatf.GradientTape per calcolare i gradienti e l'ottimizzatore per applicare quei gradienti per aggiornare le variabili del nostro modello. Per distribuire questo passaggio di formazione, inseriscilo in una funzione train_step e tf.distrbute.Strategy.run a tf.distrbute.Strategy.run insieme agli input del set di dati ottenuto dal dist_dataset creato in precedenza:

loss_object = tf.keras.losses.BinaryCrossentropy(
  from_logits=True,
  reduction=tf.keras.losses.Reduction.NONE)

def compute_loss(labels, predictions):
  per_example_loss = loss_object(labels, predictions)
  return tf.nn.compute_average_loss(per_example_loss, global_batch_size=global_batch_size)

def train_step(inputs):
  features, labels = inputs

  with tf.GradientTape() as tape:
    predictions = model(features, training=True)
    loss = compute_loss(labels, predictions)

  gradients = tape.gradient(loss, model.trainable_variables)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))
  return loss

@tf.function
def distributed_train_step(dist_inputs):
  per_replica_losses = mirrored_strategy.run(train_step, args=(dist_inputs,))
  return mirrored_strategy.reduce(tf.distribute.ReduceOp.SUM, per_replica_losses,
                         axis=None)

Alcune altre cose da notare nel codice sopra:

  1. Ha utilizzato tf.nn.compute_average_loss per calcolare la perdita. tf.nn.compute_average_loss somma la perdita per esempio e divide la somma per global_batch_size. Questo è importante perché in seguito, dopo che i gradienti sono stati calcolati su ciascuna replica, vengono aggregati tra le repliche sommandoli .
  2. Ha utilizzato l'API tf.distribute.Strategy.reduce per aggregare i risultati restituiti da tf.distribute.Strategy.run . tf.distribute.Strategy.run restituisce i risultati di ciascuna replica locale nella strategia e sono disponibili diversi modi per utilizzare questo risultato. Puoi reduce per ottenere un valore aggregato. Puoi anche eseguire tf.distribute.Strategy.experimental_local_results per ottenere l'elenco dei valori contenuti nel risultato, uno per replica locale.
  3. Quando apply_gradients viene chiamato nell'ambito di una strategia di distribuzione, il suo comportamento viene modificato. In particolare, prima di applicare i gradienti su ogni istanza parallela durante l'addestramento sincrono, esegue una somma su tutte le repliche dei gradienti.

Infine, una volta definita la fase di addestramento, possiamo iterare su dist_dataset ed eseguire la formazione in un ciclo:

for dist_inputs in dist_dataset:
  print(distributed_train_step(dist_inputs))
tf.Tensor(0.18279998, shape=(), dtype=float32)
tf.Tensor(0.18224256, shape=(), dtype=float32)
tf.Tensor(0.18168819, shape=(), dtype=float32)
tf.Tensor(0.1811369, shape=(), dtype=float32)
tf.Tensor(0.18058868, shape=(), dtype=float32)
tf.Tensor(0.18004347, shape=(), dtype=float32)
tf.Tensor(0.17950125, shape=(), dtype=float32)
tf.Tensor(0.178962, shape=(), dtype=float32)
tf.Tensor(0.17842571, shape=(), dtype=float32)
tf.Tensor(0.17789237, shape=(), dtype=float32)
tf.Tensor(0.17736195, shape=(), dtype=float32)
tf.Tensor(0.17683437, shape=(), dtype=float32)
tf.Tensor(0.17630969, shape=(), dtype=float32)
tf.Tensor(0.17578785, shape=(), dtype=float32)
tf.Tensor(0.17526883, shape=(), dtype=float32)
tf.Tensor(0.17475258, shape=(), dtype=float32)
tf.Tensor(0.17423911, shape=(), dtype=float32)
tf.Tensor(0.17372845, shape=(), dtype=float32)
tf.Tensor(0.17322046, shape=(), dtype=float32)
tf.Tensor(0.1727152, shape=(), dtype=float32)

Nell'esempio sopra, hai ripetuto il dist_dataset per fornire input alla tua formazione. Forniamo anche il tf.distribute.Strategy.make_experimental_numpy_dataset per supportare gli input numpy. È possibile utilizzare questa API per creare un set di dati prima di chiamare tf.distribute.Strategy.experimental_distribute_dataset .

Un altro modo per eseguire l'iterazione sui dati è utilizzare esplicitamente gli iteratori. È possibile eseguire questa operazione quando si desidera eseguire un determinato numero di passaggi anziché eseguire l'iterazione sull'intero set di dati. Quanto sopra iterazione sarebbe ora essere modificato per creare un iteratore prima e poi esplicitamente chiamare next su di esso per ottenere i dati di input.

iterator = iter(dist_dataset)
for _ in range(10):
  print(distributed_train_step(next(iterator)))
tf.Tensor(0.17221266, shape=(), dtype=float32)
tf.Tensor(0.17171277, shape=(), dtype=float32)
tf.Tensor(0.17121558, shape=(), dtype=float32)
tf.Tensor(0.17072096, shape=(), dtype=float32)
tf.Tensor(0.17022902, shape=(), dtype=float32)
tf.Tensor(0.16973962, shape=(), dtype=float32)
tf.Tensor(0.16925281, shape=(), dtype=float32)
tf.Tensor(0.1687686, shape=(), dtype=float32)
tf.Tensor(0.1682869, shape=(), dtype=float32)
tf.Tensor(0.16780771, shape=(), dtype=float32)

Questo copre il caso più semplice di utilizzo dell'API tf.distribute.Strategy per distribuire cicli di addestramento personalizzati.

Cosa è supportato ora?

API di formazione MirroredStrategy TPUStrategy MultiWorkerMirroredStrategy ParameterServerStrategy CentralStorageStrategy
Ciclo di allenamento personalizzato Supportato Supportato Supporto sperimentale Supporto sperimentale Supporto sperimentale

Esempi e tutorial

Di seguito sono riportati alcuni esempi per l'utilizzo della strategia di distribuzione con cicli di addestramento personalizzati:

  1. Tutorial per addestrare MNIST utilizzando MirroredStrategy .
  2. Guida alla formazione di MNIST utilizzando TPUStrategy .
  3. Repository TensorFlow Model Garden contenente raccolte di modelli all'avanguardia implementati utilizzando varie strategie.

Altri argomenti

Questa sezione copre alcuni argomenti rilevanti per più casi d'uso.

Configurazione della variabile d'ambiente TF_CONFIG

Per la formazione multi-worker, come accennato in precedenza, è necessario impostare la variabile d'ambiente TF_CONFIG per ogni binario in esecuzione nel cluster. La variabile d'ambiente TF_CONFIG è una stringa JSON che specifica quali attività costituiscono un cluster, i loro indirizzi e il ruolo di ciascuna attività nel cluster. Il repository tensorflow / ecosistema fornisce un modello Kubernetes in cui imposta TF_CONFIG per le tue attività di formazione.

Ci sono due componenti di TF_CONFIG: cluster e task. cluster fornisce informazioni sul cluster di formazione, che è un dict costituito da diversi tipi di lavori come il lavoratore. Nella formazione multi-lavoratore, di solito c'è un lavoratore che si assume un po 'più di responsabilità, come salvare il checkpoint e scrivere un file di riepilogo per TensorBoard, oltre a ciò che fa un lavoratore normale. Tale lavoratore è indicato come il lavoratore "capo" ed è consuetudine che il lavoratore con indice 0 sia nominato capo lavoratore (in effetti è così che viene implementato tf.distribute.Strategy). task d'altra parte fornisce informazioni sull'attività corrente. Il primo cluster di componenti è lo stesso per tutti i lavoratori e la seconda attività del componente è diversa su ogni lavoratore e specifica il tipo e l'indice di quel lavoratore.

Un esempio di TF_CONFIG è:

os.environ["TF_CONFIG"] = json.dumps({
    "cluster": {
        "worker": ["host1:port", "host2:port", "host3:port"],
        "ps": ["host4:port", "host5:port"]
    },
   "task": {"type": "worker", "index": 1}
})

Questo TF_CONFIG specifica che ci sono tre worker e due task ps nel cluster insieme ai loro host e porte. La parte "attività" specifica che il ruolo dell'attività corrente nel cluster, lavoratore 1 (il secondo lavoratore). I ruoli validi in un cluster sono "capo", "lavoratore", "ps" e "valutatore". Non dovrebbe esserci alcun lavoro "ps" tranne quando si utilizza tf.distribute.experimental.ParameterServerStrategy .

Qual è il prossimo?

tf.distribute.Strategy è attivamente in fase di sviluppo. Provalo e fornisci il tuo feedback utilizzando i problemi di GitHub .