Apache MXNet - Formazione distribuita

Questo capitolo riguarda la formazione distribuita in Apache MXNet. Cominciamo col capire quali sono le modalità di calcolo in MXNet.

Modalità di calcolo

MXNet, una libreria ML multilingue, offre ai suoi utenti le seguenti due modalità di calcolo:

Modalità imperativa

Questa modalità di calcolo espone un'interfaccia come NumPy API. Ad esempio, in MXNet, utilizza il seguente codice imperativo per costruire un tensore di zeri sia sulla CPU che sulla GPU -

import mxnet as mx
tensor_cpu = mx.nd.zeros((100,), ctx=mx.cpu())
tensor_gpu= mx.nd.zeros((100,), ctx=mx.gpu(0))

Come vediamo nel codice sopra, MXNets specifica la posizione in cui tenere il tensore, nella CPU o nel dispositivo GPU. Nell'esempio sopra, è nella posizione 0. MXNet raggiunge un utilizzo incredibile del dispositivo, perché tutti i calcoli avvengono in modo pigramente anziché istantaneo.

Modalità simbolica

Sebbene la modalità imperativa sia abbastanza utile, ma uno degli svantaggi di questa modalità è la sua rigidità, cioè tutti i calcoli devono essere conosciuti in anticipo insieme a strutture dati predefinite.

D'altra parte, la modalità simbolica espone un grafico di calcolo come TensorFlow. Rimuove lo svantaggio dell'API imperativa consentendo a MXNet di lavorare con simboli o variabili invece di strutture di dati fisse / predefinite. Successivamente, i simboli possono essere interpretati come un insieme di operazioni come segue:

import mxnet as mx
x = mx.sym.Variable(“X”)
y = mx.sym.Variable(“Y”)
z = (x+y)
m = z/100

Tipi di parallelismo

Apache MXNet supporta la formazione distribuita. Ci consente di sfruttare più macchine per una formazione più rapida ed efficace.

Di seguito sono riportati i due modi in cui possiamo distribuire il carico di lavoro dell'addestramento di un NN su più dispositivi, CPU o dispositivo GPU:

Parallelismo dei dati

In questo tipo di parallelismo, ogni dispositivo memorizza una copia completa del modello e funziona con una parte diversa del set di dati. I dispositivi aggiornano anche un modello condiviso collettivamente. Possiamo individuare tutti i dispositivi su una singola macchina o su più macchine.

Parallelismo del modello

È un altro tipo di parallelismo, utile quando i modelli sono così grandi da non entrare nella memoria del dispositivo. Nel parallelismo del modello, a diversi dispositivi viene assegnato il compito di apprendere diverse parti del modello. Il punto importante da notare qui è che attualmente Apache MXNet supporta il parallelismo dei modelli solo in una singola macchina.

Lavoro di formazione distribuita

I concetti forniti di seguito sono la chiave per comprendere il funzionamento della formazione distribuita in Apache MXNet -

Tipi di processi

I processi comunicano tra loro per realizzare la formazione di un modello. Apache MXNet ha i seguenti tre processi:

Lavoratore

Il compito del nodo di lavoro è eseguire l'addestramento su un batch di campioni di addestramento. I nodi di lavoro estrarranno i pesi dal server prima di elaborare ogni batch. I nodi di lavoro invieranno gradienti al server, una volta elaborato il batch.

server

MXNet può avere più server per memorizzare i parametri del modello e per comunicare con i nodi di lavoro.

Scheduler

Il ruolo dello scheduler è impostare il cluster, che include l'attesa dei messaggi che ogni nodo ha generato e la porta su cui il nodo è in ascolto. Dopo aver impostato il cluster, lo scheduler comunica a tutti i processi di conoscere ogni altro nodo del cluster. È perché i processi possono comunicare tra loro. C'è solo uno scheduler.

Negozio KV

Negozi KV sta per Key-Valuenegozio. È un componente critico utilizzato per l'addestramento multi-dispositivo. È importante perché la comunicazione dei parametri tra i dispositivi su una singola così come su più macchine viene trasmessa attraverso uno o più server con un KVStore per i parametri. Comprendiamo il funzionamento di KVStore con l'aiuto dei seguenti punti:

  • Ogni valore in KVStore è rappresentato da un file key e a value.

  • A ogni array di parametri nella rete viene assegnato un file key e il peso di tale matrice di parametri è riferito da value.

  • Dopodiché, il nodo di lavoro pushgradienti dopo l'elaborazione di un batch. Essi anchepull pesi aggiornati prima di elaborare un nuovo batch.

La nozione di server KVStore esiste solo durante l'addestramento distribuito e la sua modalità distribuita viene abilitata chiamando mxnet.kvstore.create funzione con un argomento stringa contenente la parola dist -

kv = mxnet.kvstore.create(‘dist_sync’)

Distribuzione delle chiavi

Non è necessario che tutti i server memorizzino tutti i parametri dell'array o delle chiavi, ma sono distribuiti su diversi server. Tale distribuzione di chiavi su diversi server è gestita in modo trasparente da KVStore e la decisione su quale server memorizza una chiave specifica viene presa a caso.

KVStore, come discusso sopra, assicura che ogni volta che la chiave viene estratta, la sua richiesta viene inviata a quel server, che ha il valore corrispondente. E se il valore di una chiave è grande? In tal caso, potrebbe essere condiviso tra diversi server.

Dati di allenamento divisi

Essendo gli utenti, desideriamo che ogni macchina lavori su parti diverse del set di dati, in particolare quando si esegue l'addestramento distribuito in modalità parallela dei dati. Sappiamo che, per dividere un batch di campioni forniti dall'iteratore di dati per l'addestramento parallelo dei dati su un singolo lavoratore, possiamo utilizzaremxnet.gluon.utils.split_and_load quindi, carica ogni parte del batch sul dispositivo che lo elaborerà ulteriormente.

D'altra parte, in caso di formazione distribuita, all'inizio dobbiamo dividere il set di dati in nparti diverse in modo che ogni lavoratore riceva una parte diversa. Una volta ottenuto, ogni lavoratore può quindi utilizzaresplit_and_loadper dividere nuovamente quella parte del set di dati su diversi dispositivi su una singola macchina. Tutto questo avviene tramite l'iteratore di dati.mxnet.io.MNISTIterator e mxnet.io.ImageRecordIter sono due di questi iteratori in MXNet che supportano questa funzione.

Aggiornamento pesi

Per aggiornare i pesi, KVStore supporta le seguenti due modalità:

  • Il primo metodo aggrega i gradienti e aggiorna i pesi utilizzando quei gradienti.

  • Nel secondo metodo il server aggrega solo i gradienti.

Se stai usando Gluon, c'è un'opzione per scegliere tra i metodi sopra indicati passando update_on_kvstorevariabile. Comprendiamolo creando il filetrainer oggetto come segue -

trainer = gluon.Trainer(net.collect_params(), optimizer='sgd',
   optimizer_params={'learning_rate': opt.lr,
      'wd': opt.wd,
      'momentum': opt.momentum,
      'multi_precision': True},
      kvstore=kv,
   update_on_kvstore=True)

Modalità di formazione distribuita

Se la stringa di creazione di KVStore contiene la parola dist, significa che l'addestramento distribuito è abilitato. Di seguito sono riportate diverse modalità di formazione distribuita che possono essere abilitate utilizzando diversi tipi di KVStore:

dist_sync

Come suggerisce il nome, denota addestramento distribuito sincrono. In questo, tutti i lavoratori utilizzano lo stesso set sincronizzato di parametri del modello all'inizio di ogni batch.

Lo svantaggio di questa modalità è che, dopo ogni batch, il server dovrebbe attendere di ricevere i gradienti da ogni worker prima di aggiornare i parametri del modello. Ciò significa che se un lavoratore si blocca, si fermerebbe il progresso di tutti i lavoratori.

dist_async

Come suggerisce il nome, denota addestramento distribuito sincrono. In questo, il server riceve gradienti da un lavoratore e aggiorna immediatamente il suo archivio. Il server utilizza l'archivio aggiornato per rispondere a qualsiasi ulteriore pull.

Il vantaggio, rispetto a dist_sync mode, è che un lavoratore che termina l'elaborazione di un batch può estrarre i parametri correnti dal server e avviare il batch successivo. Il lavoratore può farlo, anche se l'altro lavoratore non ha ancora terminato l'elaborazione del batch precedente. È anche più veloce della modalità dist_sync perché possono essere necessarie più epoche per convergere senza alcun costo di sincronizzazione.

dist_sync_device

Questa modalità è la stessa di dist_syncmodalità. L'unica differenza è che, quando ci sono più GPU utilizzate su ogni nododist_sync_device aggrega gradienti e aggiorna i pesi sulla GPU mentre, dist_sync aggrega gradienti e aggiorna i pesi sulla memoria della CPU.

Riduce le costose comunicazioni tra GPU e CPU. Ecco perché è più veloce didist_sync. Lo svantaggio è che aumenta l'utilizzo della memoria sulla GPU.

dist_async_device

Questa modalità funziona come dist_sync_device modalità, ma in modalità asincrona.