Addestramento distribuito

In questa pagina viene descritto come eseguire job di addestramento distribuito su Vertex AI.

Requisiti di codice

Utilizzare un framework ML che supporta l'addestramento distribuito. Nel codice di addestramento, puoi utilizzare le variabili di ambiente CLUSTER_SPEC o TF_CONFIG per fare riferimento a parti specifiche del cluster di addestramento.

Struttura del cluster di addestramento

Se esegui un job di addestramento distribuito con Vertex AI, devi specificare più macchine (nodi) in un cluster di addestramento. Il servizio di addestramento alloca le risorse per i tipi di macchine specificati. Il job in esecuzione su un determinato nodo è chiamato replica. Un gruppo di repliche con la stessa configurazione è chiamato pool di worker.

A ogni replica nel cluster di addestramento viene assegnato un singolo ruolo o una singola attività nell'addestramento distribuito. Ad esempio:

  • Replica principale: viene indicata esattamente una replica come replica principale. Questa attività gestisce gli altri e riporta lo stato del lavoro nel suo complesso.

  • Lavoratori: una o più repliche possono essere definite come lavoratori. Queste repliche eseguono la parte del lavoro che designi nella configurazione del job.

  • Server dei parametri: se supportato dal framework ML, una o più repliche possono essere designate come server dei parametri. Queste repliche memorizzano i parametri del modello e coordinano lo stato del modello condiviso tra i worker.

  • Valutatori: se supportati dal tuo framework ML, una o più repliche possono essere definite come valutatori. Queste repliche possono essere utilizzate per valutare il tuo modello. Se utilizzi TensorFlow, tieni presente che in genere TensorFlow si aspetta che tu non utilizzi più di un valutatore.

Configurare un job di addestramento distribuito

Puoi configurare qualsiasi job di addestramento personalizzato come job di addestramento distribuito definendo più pool di worker. Puoi anche eseguire un addestramento distribuito all'interno di una pipeline di addestramento o di un job di ottimizzazione degli iperparametri.

Per configurare un job di addestramento distribuito, definisci il tuo elenco di pool di worker (workerPoolSpecs[]), contrassegnando un WorkerPoolSpec per ogni tipo di attività:

Posizione in workerPoolSpecs[] Attività eseguita nel cluster
Prima (workerPoolSpecs[0]) Principale, principale, scheduler o "master".
Secondo (workerPoolSpecs[1]) Secondarie, repliche, worker
Terzo (workerPoolSpecs[2]) Server dei parametri, server di riduzione
Quarto (workerPoolSpecs[3]) Valutatori

Devi specificare una replica principale, che coordina il lavoro svolto da tutte le altre repliche. Utilizza la prima specifica del pool di worker solo per la replica principale e imposta replicaCount su 1:

{
  "workerPoolSpecs": [
     // `WorkerPoolSpec` for worker pool 0, primary replica, required
     {
       "machineSpec": {...},
       "replicaCount": 1,
       "diskSpec": {...},
       ...
     },
     // `WorkerPoolSpec` for worker pool 1, optional
     {},
     // `WorkerPoolSpec` for worker pool 2, optional
     {},
     // `WorkerPoolSpec` for worker pool 3, optional
     {}
   ]
   ...
}

Specifica pool di worker aggiuntivi

A seconda del framework ML, puoi specificare pool di worker aggiuntivi per altri scopi. Ad esempio, se utilizzi TensorFlow, puoi specificare i pool di worker per configurare le repliche dei worker, le repliche del server dei parametri e le repliche del valutatore.

L'ordine dei pool di worker specificati nell'elenco workerPoolSpecs[] determina il tipo di pool di worker. Imposta valori vuoti per i pool di worker che non vuoi utilizzare, in modo da poterli ignorare nell'elenco workerPoolSpecs[] per specificare i pool worker che vuoi utilizzare. Ad esempio:

Se vuoi specificare un job con una replica principale e un pool di worker server dei parametri, devi impostare un valore vuoto per il pool di worker 1:

{
  "workerPoolSpecs": [
     // `WorkerPoolSpec` for worker pool 0, required
     {
       "machineSpec": {...},
       "replicaCount": 1,
       "diskSpec": {...},
       ...
     },
     // `WorkerPoolSpec` for worker pool 1, optional
     {},
     // `WorkerPoolSpec` for worker pool 2, optional
     {
       "machineSpec": {...},
       "replicaCount": 1,
       "diskSpec": {...},
       ...
     },
     // `WorkerPoolSpec` for worker pool 3, optional
     {}
   ]
   ...
}

Riduci il tempo di addestramento con il server di riduzione

Quando addestri un modello di ML di grandi dimensioni utilizzando più nodi, comunicare i gradienti tra i nodi può contribuire a una latenza significativa. Redution Server è un algoritmo per la riduzione completa della velocità effettiva in grado di aumentare la velocità effettiva e ridurre la latenza per l'addestramento distribuito. Vertex AI rende disponibile il server di riduzione in un'immagine container Docker che puoi utilizzare per uno dei tuoi pool di worker durante l'addestramento distribuito.

Per informazioni sul funzionamento di Reduction Server, consulta Formazione su GPU più rapida distribuita con Reduction Server su Vertex AI.

Prerequisiti

Puoi utilizzare il server di riduzione se soddisfi i seguenti requisiti:

  • Stai eseguendo un addestramento distribuito con i worker GPU.

  • Il codice di addestramento utilizza TensorFlow o PyTorch ed è configurato per l'addestramento parallelo ai dati multi-host con GPU che utilizzano NCCL in modalità completa. Potresti anche essere in grado di utilizzare altri framework di ML che utilizzano il NCCL.

  • I container in esecuzione sul tuo nodo primario (workerPoolSpecs[0]) e sui worker (workerPoolSpecs[1]) supportano il server di riduzione. In particolare, ogni container è uno dei seguenti:

    • Un container di addestramento predefinito di TensorFlow, versione 2.3 o successiva.

    • Un contenitore di addestramento Pytorch predefinito, versione 1.4 o successiva.

    • Un contenitore personalizzato con NCCL 2.7 o versione successiva e il pacchetto google-reduction-server installato. Puoi installare questo pacchetto su un'immagine container personalizzata aggiungendo la seguente riga al Dockerfile:

      RUN echo "deb https://packages.cloud.google.com/apt google-fast-socket main" | tee /etc/apt/sources.list.d/google-fast-socket.list && \
          curl -s -L https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
          apt update && apt install -y google-reduction-server
      

Addestra utilizzando il server di riduzione

Per utilizzare il server di riduzione, procedi nel seguente modo quando crei una risorsa di addestramento personalizzato:

  1. Specifica uno dei seguenti URI nel campo containerSpec.imageUri del terzo pool di worker (workerPoolSpecs[2]):

    • us-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest
    • europe-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest
    • asia-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest

    La scelta di più aree geografiche più vicine a dove esegui l'addestramento personalizzato potrebbe ridurre la latenza.

  2. Quando selezioni il tipo di macchina e il numero di nodi per il terzo pool di worker, assicurati che la larghezza di banda totale della rete del terzo pool di worker corrisponda o superi la larghezza di banda totale della rete del primo e del secondo pool di worker.

    Per informazioni sulla larghezza di banda massima disponibile per ogni nodo nel secondo pool di worker, consulta la sezione Larghezza di banda di rete e GPU.

    Non utilizzi GPU per i nodi Server di riduzione. Per informazioni sulla larghezza di banda massima disponibile per ogni nodo nel terzo pool di worker, consulta le colonne "Larghezza di banda massima in uscita (Gbps)" nella Famiglia di macchine per uso generico.

    Ad esempio, se configuri il primo e il secondo pool di worker per utilizzare 5 nodi n1-highmem-96, ognuno con 8 GPU NVIDIA_TESLA_V100, ogni nodo avrà una larghezza di banda massima disponibile di 100 Gbps, per una larghezza di banda totale di 500 Gbps. Per creare una corrispondenza con questa larghezza di banda nel terzo pool di worker, potresti utilizzare 16 nodi n1-highcpu-16, ognuno con una larghezza di banda massima di 32 Gbps, per una larghezza di banda totale di 512 Gbps.

    Ti consigliamo di utilizzare il tipo di macchina n1-highcpu-16 per i nodi Server di riduzione, poiché questo tipo di macchina offre una larghezza di banda relativamente elevata per le sue risorse.

Il seguente comando fornisce un esempio di come creare una risorsa CustomJob che utilizza il server di riduzione:

gcloud ai custom-jobs create \
  --region=LOCATION \
  --display-name=JOB_NAME \
  --worker-pool-spec=machine-type=n1-highmem-96,replica-count=1,accelerator-type=NVIDIA_TESLA_V100,accelerator-count=8,container-image-uri=CUSTOM_CONTAINER_IMAGE_URI \
  --worker-pool-spec=machine-type=n1-highmem-96,replica-count=4,accelerator-type=NVIDIA_TESLA_V100,accelerator-count=8,container-image-uri=CUSTOM_CONTAINER_IMAGE_URI \
  --worker-pool-spec=machine-type=n1-highcpu-16,replica-count=16,container-image-uri=us-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest

Per maggiore contesto, consulta la sezione

Guida alla creazione di una CustomJob.

Best practice per l'addestramento utilizzando il server di riduzione

Tipo di macchina e conteggio

Nell'addestramento del server di riduzione, ogni worker deve connettersi a tutti gli host riduttori. Per ridurre al minimo il numero di connessioni sull'host worker, utilizza un tipo di macchina con la larghezza di banda di rete più elevata per l'host del programma di riduzione.

Un'ottima scelta per i riduttori host è una VM N1/N2 per uso generico con almeno 16 vCPU che forniscono larghezza di banda in uscita da 32 Gbps, come n1-highcpu-16 e n2-highcpu-16. La larghezza di banda della VM di livello 1 per le VM N1/N2 aumenta la larghezza di banda massima in uscita da 50 Gbps e 100 Gbps, rendendo queste un'ottima scelta per i nodi VM inferiori.

La larghezza di banda totale in uscita di worker e riduzioni deve essere la stessa. Ad esempio, se utilizzi 8 VM a2-megagpu-8g come worker, devi utilizzare almeno 25 VM n1-highcpu-16 come riduttori.

`(8 worker VMs * 100 Gbps) / 32 Gbps egress = 25 reducer VMs`.

Raggruppare i messaggi di piccole dimensioni

Il server di riduzione funziona meglio se i messaggi da raggruppare sono sufficientemente grandi. La maggior parte dei framework ML fornisce già tecniche con terminologia diversa per il batch di piccoli tensori di sfumatura prima di eseguire la riduzione completa.

Horovod

Horovod supporta Tensor Fusion per raggruppare i tensori di piccole dimensioni per la riduzione completa. I Tensor vengono riempiti in un buffer di fusione fino a quando il buffer non viene completamente riempito e viene eseguita l'operazione di riduzione del buffer. Puoi regolare le dimensioni del buffer di fusione impostando la variabile di ambiente HOROVOD_FUSION_THRESHOLD.

Il valore consigliato per la variabile di ambiente HOROVOD_FUSION_THRESHOLD è almeno 128 MB. In questo caso, imposta la variabile di ambiente HOROVOD_FUSION_THRESHOLD su 134217728 (128 * 1024 * 1024).

PyTorch

PyTorch DistributedDataParallel supporta i messaggi batch come "bucket di sfumatura". Imposta il parametro bucket_cap_mb nel costruttore DistributedDataParallel per controllare le dimensioni dei bucket del batch. La dimensione predefinita è 25 MB.

BEST PRACTICE: il valore consigliato di bucket_cap_mb è 64 (64 MB).

Variabili di ambiente per il cluster

Vertex AI completa una variabile di ambiente, CLUSTER_SPEC, in ogni replica per descrivere come è configurato il cluster complessivo. Come TensorFlow's TF_CONFIG, CLUSTER_SPEC descrive ogni replica nel cluster, incluso il suo indice e ruolo (principale, worker, server dei parametri o valutatore).

Quando esegui addestramento distribuito con TensorFlow, TF_CONFIG viene analizzato per creare tf.train.ClusterSpec. Allo stesso modo, quando esegui l'addestramento distribuito con altri framework ML, devi analizzare CLUSTER_SPEC per completare le variabili di ambiente o le impostazioni richieste dal framework.

Il formato di CLUSTER_SPEC

La variabile di ambiente CLUSTER_SPEC è una stringa JSON con il seguente formato:

Chiave Descrizione
"cluster"

La descrizione del cluster per il container personalizzato. Come con TF_CONFIG, questo oggetto è formattato come specifica del cluster TensorFlow e può essere passato al costruttore di tf.train.ClusterSpec.

La descrizione del cluster contiene un elenco di nomi di repliche per ogni pool di worker specificato.

"workerpool0" Tutti i job di addestramento distribuito hanno una replica primaria nel primo pool di worker.
"workerpool1" Questo pool di worker contiene le repliche dei worker, se le hai specificate durante la creazione del job.
"workerpool2" Questo pool di worker contiene i server dei parametri, se li hai specificati durante la creazione del job.
"workerpool3" Questo pool di worker contiene valutatori, se li hai specificati durante la creazione del job.
"environment" La stringa cloud.
"task" Descrive l'attività del nodo specifico su cui è in esecuzione il codice. Puoi utilizzare queste informazioni per scrivere codice per worker specifici in un job distribuito. Questa voce è un dizionario con le seguenti chiavi:
"type" Il tipo di pool di worker in cui è in esecuzione questa attività. Ad esempio, "workerpool0" si riferisce alla replica principale.
"index"

L'indice in base zero dell'attività. Ad esempio, se il job di addestramento include due worker, questo valore è impostato su 0 su uno dei job e su 1 sull'altro.

"trial" L'identificatore della prova di ottimizzazione degli iperparametri attualmente in esecuzione. Quando configuri l'ottimizzazione degli iperparametri per il job, imposti una serie di prove per l'addestramento. Questo valore ti consente di distinguere nel codice le prove in esecuzione. L'identificatore è una stringa contenente il numero della prova, che inizia da 1.
job

Il CustomJobSpec che hai fornito per creare il job di addestramento corrente, rappresentato come dizionario.

Esempio di CLUSTER_SPEC

Ecco un valore di esempio:


{
   "cluster":{
      "workerpool0":[
         "cmle-training-workerpool0-ab-0:2222"
      ],
      "workerpool1":[
         "cmle-training-workerpool1-ab-0:2222",
         "cmle-training-workerpool1-ab-1:2222"
      ],
      "workerpool2":[
         "cmle-training-workerpool2-ab-0:2222",
         "cmle-training-workerpool2-ab-1:2222"
      ],
      "workerpool3":[
         "cmle-training-workerpool3-ab-0:2222",
         "cmle-training-workerpool3-ab-1:2222",
         "cmle-training-workerpool3-ab-2:2222"
      ]
   },
   "environment":"cloud",
   "task":{
      "type":"workerpool0",
      "index":0,
      "trial":"TRIAL_ID"
   },
   "job": {
      ...
   }
}

Il formato di TF_CONFIG

Oltre a CLUSTER_SPEC, Vertex AI imposta la variabile di ambiente TF_CONFIG su ogni replica di tutti i job di addestramento distribuiti. Vertex AI non imposta TF_CONFIG per job di addestramento con replica singola.

CLUSTER_SPEC e TF_CONFIG condividono alcuni valori, ma hanno formati diversi. Entrambe le variabili di ambiente includono campi aggiuntivi oltre a quelli richiesti da TensorFlow.

L'addestramento distribuito con TensorFlow funziona allo stesso modo quando utilizzi container personalizzati e quando usi un container predefinito.

La variabile di ambiente TF_CONFIG è una stringa JSON con il seguente formato:

Campi TF_CONFIG
cluster

La descrizione del cluster TensorFlow. Un dizionario che mappa uno o più nomi delle attività (chief, worker, ps o master) agli elenchi di indirizzi di rete in cui vengono eseguite queste attività. Per un determinato job di addestramento, questo dizionario è lo stesso su ogni VM.

Questo è un primo argomento valido per il costruttore tf.train.ClusterSpec. Tieni presente che questo dizionario non contiene mai evaluator come chiave, dato che i valutatori non vengono considerati parte del cluster di addestramento anche se li utilizzi per il tuo lavoro.

task

La descrizione dell'attività della VM in cui è impostata questa variabile di ambiente. Per un determinato job di addestramento, questo dizionario è diverso per ogni VM. Puoi utilizzare queste informazioni per personalizzare il codice che viene eseguito su ogni VM in un job di addestramento distribuito. Puoi anche utilizzarlo per modificare il comportamento del codice di addestramento per diverse prove di un job di ottimizzazione degli iperparametri.

Questo dizionario include le seguenti coppie chiave-valore:

Campi task
type

Il tipo di attività eseguita da questa VM. Questo valore è impostato su worker sui worker, ps sui server dei parametri e evaluator sui valutatori. Nel file del master del job, il valore è impostato su chief o master. Scopri di più sulla differenza tra i due nella sezione chief rispetto a master di questo documento.

index

L'indice in base zero dell'attività. Ad esempio, se il job di addestramento include due worker, questo valore è impostato su 0 su uno dei job e su 1 sull'altro.

trial

L'ID della prova di ottimizzazione degli iperparametri in esecuzione su questa VM. Questo campo viene impostato solo se il job di addestramento corrente è un job di ottimizzazione degli iperparametri.

Per i job di ottimizzazione degli iperparametri, Vertex AI esegue ripetutamente il codice di addestramento in molte prove con diversi iperparametri ogni volta. Questo campo contiene il numero di prova corrente, a partire dalla data 1 per la prima prova.

cloud

Un ID utilizzato internamente da Vertex AI. Puoi ignorare questo campo.

job

Il CustomJobSpec che hai fornito per creare il job di addestramento corrente, rappresentato come dizionario.

environment

La stringa cloud.

Esempio di TF_CONFIG

Il seguente codice di esempio stampa la variabile di ambiente TF_CONFIG nei tuoi log di addestramento:

import json
import os

tf_config_str = os.environ.get('TF_CONFIG')
tf_config_dict  = json.loads(tf_config_str)

# Convert back to string just for pretty printing
print(json.dumps(tf_config_dict, indent=2))

In un job di ottimizzazione degli iperparametri eseguito in versione di runtime 2.1 o successiva e che utilizza un worker master, due worker e un server parametri, questo codice produce il log seguente per uno dei worker durante la prima prova di ottimizzazione degli iperparametri. L'output di esempio nasconde il campo job per la concisione e sostituisce alcuni ID con valori generici.

{
  "cluster": {
    "chief": [
      "training-workerpool0-[ID_STRING_1]-0:2222"
    ],
    "ps": [
      "training-workerpool2-[ID_STRING_1]-0:2222"
    ],
    "worker": [
      "training-workerpool1-[ID_STRING_1]-0:2222",
      "training-workerpool1-[ID_STRING_1]-1:2222"
    ]
  },
  "environment": "cloud",
  "job": {
    ...
  },
  "task": {
    "cloud": "[ID_STRING_2]",
    "index": 0,
    "trial": "1",
    "type": "worker"
  }
}

Quando utilizzare TF_CONFIG

TF_CONFIG è impostato solo per i job di addestramento distribuito.

Probabilmente non dovrai interagire con la variabile di ambiente TF_CONFIG direttamente nel codice di addestramento. Accedi alla variabile di ambiente TF_CONFIG solo se le strategie di distribuzione di TensorFlow e le flussi di lavoro di ottimizzazione degli iperparametri di Vertex AI standard, entrambe descritte nelle sezioni successive, non funzionano per il tuo job.

Addestramento distribuito

Vertex AI imposta la variabile di ambiente TF_CONFIG per estendere le specifiche richieste da TensorFlow per l'addestramento distribuito.

Per eseguire l'addestramento distribuito con TensorFlow, utilizza l'API tf.distribute.Strategy. In particolare, vi consigliamo di utilizzare l'API Keras insieme a MultiWorkerMirroredStrategy o, se specificate i server dei parametri per il vostro job, ParameterServerStrategy. Tuttavia, attualmente TensorFlow fornisce solo supporto sperimentale per queste strategie.

Queste strategie di distribuzione utilizzano la variabile di ambiente TF_CONFIG per assegnare ruoli a ogni VM nel job di addestramento e per facilitare la comunicazione tra le VM. Non è necessario accedere alla variabile di ambiente TF_CONFIG direttamente nel codice di addestramento, perché TensorFlow lo gestisce per te.

Analizza direttamente la variabile di ambiente TF_CONFIG solo se vuoi personalizzare il comportamento delle diverse VM in esecuzione del job di addestramento.

Ottimizzazione degli iperparametri

Quando esegui un job di ottimizzazione iperparametri, Vertex AI fornisce argomenti diversi al tuo codice di addestramento per ogni prova. Il tuo codice di addestramento non deve necessariamente essere a conoscenza di quale prova è attualmente in esecuzione. Inoltre, puoi monitorare l'avanzamento dei job di ottimizzazione degli iperparametri in Cloud Console.

Se necessario, il codice può leggere il numero di prova corrente nel campo trial del campo task della variabile di ambiente TF_CONFIG.

Passaggi successivi