Guida al training della GPU distribuita (SDK v1)
Si applica a: Python SDK azureml v1
Altre informazioni su come usare il codice di training GPU distribuito in Azure Machine Learning (ML). Questo articolo non illustra il training distribuito. Consente di eseguire il codice di training distribuito esistente in Azure Machine Learning. Offre suggerimenti ed esempi da seguire per ogni framework:
- Message Passing Interface (MPI)
- Horovod
- DeepSpeed
- Variabili di ambiente da Open MPI
- PyTorch
- Inizializzazione del gruppo di processi
- Opzioni di avvio
- DistributedDataParallel (avvio per processo)
- Uso di
torch.distributed.launch
(avvio a nodo) - PyTorch Lightning
- Hugging Face Transformers
- TensorFlow
- Variabili di ambiente per TensorFlow (TF_CONFIG)
- Accelerare il training GPU con InfiniBand
Prerequisiti
Esaminare questi concetti di base del training GPU distribuito, ad esempio parallelismo dei dati, parallelismo dei dati distribuitie parallelismo del modello.
Suggerimento
Se non si conosce il tipo di parallelismo da usare, più del 90% del tempo è consigliabile usare Parallelismo dei dati distribuiti.
MPI
Azure Machine Learning offre un processo MPI per avviare un determinato numero di processi in ogni nodo. È possibile adottare questo approccio per eseguire il training distribuito usando per ogni utilità di avvio per processo o per ogni avvio per nodo, a seconda che process_count_per_node
sia impostato su 1 (impostazione predefinita) per ogni utilità di avvio dei nodi o sia uguale al numero di dispositivi/GPU per ogni utilità di avvio per processo. Azure Machine Learning costruisce il comando di avvio MPI completo (mpirun
) dietro le quinte. Non è possibile fornire comandi head-node-launcher completi, ad esempio mpirun
o DeepSpeed launcher
.
Suggerimento
L'immagine Docker di base usata da un processo MPI di Azure Machine Learning deve avere una libreria MPI installata. Open MPI è incluso in tutte le immagini di base GPU di Azure Machine Learning. Quando si usa un'immagine Docker personalizzata, è necessario assicurarsi che l'immagine includa una libreria MPI. È consigliabile usare Open MPI, ma è anche possibile usare un'implementazione MPI diversa, ad esempio Intel MPI. Azure Machine Learning offre anche ambienti curati per i framework più diffusi.
Per eseguire il training distribuito tramite MPI, seguire questa procedura:
- Usare un ambiente di Azure Machine Learning con il framework di Deep Learning preferito e MPI. Azure Machine Learning offre ambienti curati per i framework più diffusi.
- Definire
MpiConfiguration
conprocess_count_per_node
enode_count
.process_count_per_node
deve essere uguale al numero di GPU per nodo per avvio per processo o impostato su 1 (impostazione predefinita) per ogni avvio per nodo se lo script utente sarà responsabile dell'avvio dei processi per nodo. - Passare l'oggetto
MpiConfiguration
al parametrodistributed_job_config
diScriptRunConfig
.
from azureml.core import Workspace, ScriptRunConfig, Environment, Experiment
from azureml.core.runconfig import MpiConfiguration
curated_env_name = 'AzureML-PyTorch-1.6-GPU'
pytorch_env = Environment.get(workspace=ws, name=curated_env_name)
distr_config = MpiConfiguration(process_count_per_node=4, node_count=2)
run_config = ScriptRunConfig(
source_directory= './src',
script='train.py',
compute_target=compute_target,
environment=pytorch_env,
distributed_job_config=distr_config,
)
# submit the run configuration to start the job
run = Experiment(ws, "experiment_name").submit(run_config)
Horovod
Usare la configurazione del processo MPI quando si usa Horovod per il training distribuito con il framework di Deep Learning.
Assicurarsi che il codice segua questi suggerimenti:
- Il codice di training viene instrumentato correttamente con Horovod prima di aggiungere le parti di Azure Machine Learning
- L'ambiente di Azure Machine Learning contiene Horovod e MPI. Gli ambienti GPU curati da PyTorch e TensorFlow sono preconfigurati con Horovod e le relative dipendenze.
- Creare un
MpiConfiguration
con la distribuzione desiderata.
Esempio Horovod
DeepSpeed
Non usare l'utilità di avvio personalizzata di DeepSpeed per eseguire il training distribuito con la libreria di DeepSpeed in Azure Machine Learning. Configurare invece un processo MPI per avviare il processo di training con MPI.
Assicurarsi che il codice segua questi suggerimenti:
- L'ambiente di Azure Machine Learning contiene DeepSpeed e le relative dipendenze, Open MPI e mpi4py.
- Creare un
MpiConfiguration
con la distribuzione.
Esempio di DeepSpeed
Variabili di ambiente da Open MPI
Quando si eseguono processi MPI con immagini Open MPI, le variabili di ambiente seguenti per ogni processo avviato sono:
OMPI_COMM_WORLD_RANK
: classificazione del processoOMPI_COMM_WORLD_SIZE
: dimensione globaleAZ_BATCH_MASTER_NODE
: indirizzo primario con porta,MASTER_ADDR:MASTER_PORT
OMPI_COMM_WORLD_LOCAL_RANK
: classificazione locale del processo nel nodoOMPI_COMM_WORLD_LOCAL_SIZE
: numero di processi nel nodo
Suggerimento
Nonostante il nome, la variabile di ambiente OMPI_COMM_WORLD_NODE_RANK
non corrisponde al NODE_RANK
. Per usare l'utilità di avvio per nodo, impostare process_count_per_node=1
e usare OMPI_COMM_WORLD_RANK
come NODE_RANK
.
PyTorch
Azure Machine Learning supporta l'esecuzione di processi distribuiti usando le funzionalità di training distribuite native di PyTorch (torch.distributed
).
Suggerimento
Per il parallelismo dei dati, il materiale sussidiario ufficiale di PyTorch prevede l’uso di DistributedDataParallel (DDP) su DataParallel per il training distribuito a nodo singolo e multinodo. PyTorch consiglia anche di usare DistributedDataParallel sul pacchetto multielaborazione. La documentazione e gli esempi di Azure Machine Learning saranno quindi incentrati sul training DistributedDataParallel.
Inizializzazione del gruppo di processi
La parte principale di qualsiasi training distribuito si basa su un gruppo di processi che si conoscono tra loro e possono comunicare tra loro usando un back-end. Per PyTorch, il gruppo di processi viene creato chiamando torch.distributed.init_process_group in tutti i processi distribuiti per formare collettivamente un gruppo di processi.
torch.distributed.init_process_group(backend='nccl', init_method='env://', ...)
I back-end di comunicazione più comuni usati sono mpi
, nccl
e gloo
. Per il training basato su GPU, è consigliato nccl
per ottenere prestazioni ottimali e deve essere usato quando possibile.
init_method
indica in che modo i processi possono individuarsi tra loro, come si inizializzano e verificano il gruppo di processi usando il back-end di comunicazione. Per impostazione predefinita, se init_method
non è specificato PyTorch userà il metodo di inizializzazione della variabile di ambiente (env://
). init_method
è il metodo di inizializzazione consigliato da usare nel codice di training per eseguire PyTorch distribuito in Azure Machine Learning. PyTorch cercherà le variabili di ambiente seguenti per l'inizializzazione:
MASTER_ADDR
: indirizzo IP del computer che ospiterà il processo con classificazione 0.MASTER_PORT
: una porta libera sul computer che ospiterà il processo con classificazione 0.WORLD_SIZE
: il numero totale di processi. Deve essere uguale al numero totale di dispositivi (GPU) usati per il training distribuito.RANK
: classificazione (globale) del processo corrente. I valori possibili sono da 0 a (dimensione globale -1).
Per altre informazioni sull'inizializzazione del gruppo di processi, vedere la documentazione di PyTorch.
Oltre a queste, molte applicazioni necessitano anche delle variabili di ambiente seguenti:
LOCAL_RANK
: classificazione locale (relativa) del processo all'interno del nodo. I valori possibili sono da 0 a (numero di processi nel nodo - 1). Queste informazioni sono utili perché molte operazioni, ad esempio la preparazione dei dati, devono essere eseguite una sola volta per ogni nodo --- in genere in local_rank = 0.NODE_RANK
: classificazione del nodo per il training multinodo. I valori possibili sono da 0 a (numero totale di nodi -1).
Opzioni di avvio PyTorch
Il processo PyTorch di Azure Machine Learning supporta due tipi di opzioni per l'avvio del training distribuito:
- Utilità di avvio per processo: il sistema avvierà automaticamente tutti i processi distribuiti, con tutte le informazioni rilevanti (ad esempio le variabili di ambiente) per configurare il gruppo di processi.
- Avvio per nodo: si fornisce ad Azure Machine Learning l'utilità di avvio che verrà eseguita in ogni nodo. L'utilità di avvio gestirà l'avvio di ognuno dei processi in un determinato nodo. In locale all'interno di ogni nodo,
RANK
eLOCAL_RANK
vengono configurati dall'utilità di avvio. L'utilità torch.distributed.launch e PyTorch Lightning appartengono entrambi a questa categoria.
Non esistono differenze fondamentali tra queste opzioni di avvio. La scelta dipende in gran parte dalle preferenze o dalle convenzioni dei framework/librerie basate su vanilla PyTorch (ad esempio Lightning o Hugging Face).
Le sezioni seguenti illustrano in dettaglio come configurare i processi PyTorch di Azure Machine Learning per ognuna delle opzioni di avvio.
DistributedDataParallel (avvio per processo)
Non è necessario usare un'utilità di avvio come torch.distributed.launch
. Per eseguire un processo PyTorch distribuito:
- Specificare lo script di training e gli argomenti
- Creare un
PyTorchConfiguration
e specificare ilprocess_count
enode_count
. Ilprocess_count
corrisponde al numero totale di processi da eseguire per il processo stesso.process_count
in genere deve essere uguale a# GPUs per node x # nodes
. Seprocess_count
non è specificato, Azure Machine Learning avvierà per impostazione predefinita un processo per nodo.
Azure Machine Learning imposta le variabili di ambiente MASTER_ADDR
, MASTER_PORT
, WORLD_SIZE
e NODE_RANK
in ogni nodo e imposta le variabili di ambiente RANK
e LOCAL_RANK
a livello di processo.
Per usare questa opzione per il training su più processi per nodo, usare Azure Machine Learning Python SDK >= 1.22.0
. Process_count è stato introdotto nella versione 1.22.0.
from azureml.core import ScriptRunConfig, Environment, Experiment
from azureml.core.runconfig import PyTorchConfiguration
curated_env_name = 'AzureML-PyTorch-1.6-GPU'
pytorch_env = Environment.get(workspace=ws, name=curated_env_name)
distr_config = PyTorchConfiguration(process_count=8, node_count=2)
run_config = ScriptRunConfig(
source_directory='./src',
script='train.py',
arguments=['--epochs', 50],
compute_target=compute_target,
environment=pytorch_env,
distributed_job_config=distr_config,
)
run = Experiment(ws, 'experiment_name').submit(run_config)
Suggerimento
Se lo script di training passa informazioni come classificazione locale o classificazione come argomenti script, è possibile fare riferimento alle variabili di ambiente negli argomenti:
arguments=['--epochs', 50, '--local_rank', $LOCAL_RANK]
Esempio di Pytorch di avvio per processo
Uso di torch.distributed.launch (avvio per nodo)
PyTorch offre un'utilità di avvio in torch.distributed.launch che è possibile usare per avviare più processi per nodo. Il modulo torch.distributed.launch
genera più processi di training in ognuno dei nodi.
La procedura seguente illustra come configurare un processo PyTorch con un'utilità di avvio per nodo in Azure Machine Learning. Il processo ottiene l'equivalente dell'esecuzione del comando seguente:
python -m torch.distributed.launch --nproc_per_node <num processes per node> \
--nnodes <num nodes> --node_rank $NODE_RANK --master_addr $MASTER_ADDR \
--master_port $MASTER_PORT --use_env \
<your training script> <your script arguments>
- Specificare il comando
torch.distributed.launch
al parametrocommand
del costruttoreScriptRunConfig
. Azure Machine Learning esegue questo comando in ogni nodo del cluster di training.--nproc_per_node
deve essere minore o uguale al numero di GPU disponibili in ogni nodo. MASTER_ADDR, MASTER_PORT e NODE_RANK sono tutti impostati da Azure Machine Learning, quindi è sufficiente fare riferimento alle variabili di ambiente nel comando. Azure Machine Learning imposta MASTER_PORT su6105
, ma è possibile passare un valore diverso all'argomento--master_port
del comando torch.distributed.launch, se lo si desidera. (L'utilità di avvio reimposta le variabili di ambiente.) - Creare un
PyTorchConfiguration
e specificare ilnode_count
.
from azureml.core import ScriptRunConfig, Environment, Experiment
from azureml.core.runconfig import PyTorchConfiguration
curated_env_name = 'AzureML-PyTorch-1.6-GPU'
pytorch_env = Environment.get(workspace=ws, name=curated_env_name)
distr_config = PyTorchConfiguration(node_count=2)
launch_cmd = "python -m torch.distributed.launch --nproc_per_node 4 --nnodes 2 --node_rank $NODE_RANK --master_addr $MASTER_ADDR --master_port $MASTER_PORT --use_env train.py --epochs 50".split()
run_config = ScriptRunConfig(
source_directory='./src',
command=launch_cmd,
compute_target=compute_target,
environment=pytorch_env,
distributed_job_config=distr_config,
)
run = Experiment(ws, 'experiment_name').submit(run_config)
Suggerimento
Training su più GPU a nodo singolo: se si usa l'utilità di avvio per eseguire il training PyTorch multi GPU a nodo singolo, non è necessario specificare il parametro distributed_job_config
di ScriptRunConfig.
launch_cmd = "python -m torch.distributed.launch --nproc_per_node 4 --use_env train.py --epochs 50".split()
run_config = ScriptRunConfig(
source_directory='./src',
command=launch_cmd,
compute_target=compute_target,
environment=pytorch_env,
)
Esempio di PyTorch per processo-avvio
PyTorch Lightning
PyTorch Lightning è una libreria open source leggera che fornisce un'interfaccia di alto livello per PyTorch. Lightning astrae molte delle configurazioni di training distribuite di livello inferiore necessarie per vanilla PyTorch. Lightning consente di eseguire gli script di training con impostazioni a GPU singola, multi GPU a nodo singolo e multinodo multi GPU. Di nascosto, avvia più processi simili a torch.distributed.launch
per l'utente.
Per il training a nodo singolo (incluso multi GPU a nodo singolo), è possibile eseguire il codice in Azure Machine Learning senza dover specificare un distributed_job_config
.
Per eseguire un esperimento usando più nodi con più GPU, sono disponibili 2 opzioni:
Uso della configurazione di PyTorch (scelta consigliata): definire
PyTorchConfiguration
e specificarecommunication_backend="Nccl"
,node_count
eprocess_count
(si noti che si tratta del numero totale di processi, ad esempionum_nodes * process_count_per_node
). Nel modulo Lightning Trainer specificare sianum_nodes
chegpus
per essere coerenti conPyTorchConfiguration
. Ad esempio,num_nodes = node_count
egpus = process_count_per_node
.Uso della configurazione MPI:
Definire
MpiConfiguration
e specificare sianode_count
cheprocess_count_per_node
. In Lightning Trainer specificare sianum_nodes
chegpus
rispettivamente comenode_count
eprocess_count_per_node
daMpiConfiguration
.Per il training multinodo con MPI, Lightning richiede l'impostazione delle variabili di ambiente seguenti in ogni nodo del cluster di training:
- MASTER_ADDR
- MASTER_PORT
- NODE_RANK
- LOCAL_RANK
Impostare manualmente queste variabili di ambiente richieste da Lightning negli script di training principali:
import os from argparse import ArgumentParser def set_environment_variables_for_mpi(num_nodes, gpus_per_node, master_port=54965): if num_nodes > 1: os.environ["MASTER_ADDR"], os.environ["MASTER_PORT"] = os.environ["AZ_BATCH_MASTER_NODE"].split(":") else: os.environ["MASTER_ADDR"] = os.environ["AZ_BATCHAI_MPI_MASTER_NODE"] os.environ["MASTER_PORT"] = str(master_port) try: os.environ["NODE_RANK"] = str(int(os.environ.get("OMPI_COMM_WORLD_RANK")) // gpus_per_node) # additional variables os.environ["MASTER_ADDRESS"] = os.environ["MASTER_ADDR"] os.environ["LOCAL_RANK"] = os.environ["OMPI_COMM_WORLD_LOCAL_RANK"] os.environ["WORLD_SIZE"] = os.environ["OMPI_COMM_WORLD_SIZE"] except: # fails when used with pytorch configuration instead of mpi pass if __name__ == "__main__": parser = ArgumentParser() parser.add_argument("--num_nodes", type=int, required=True) parser.add_argument("--gpus_per_node", type=int, required=True) args = parser.parse_args() set_environment_variables_for_mpi(args.num_nodes, args.gpus_per_node) trainer = Trainer( num_nodes=args.num_nodes, gpus=args.gpus_per_node )
Lightning gestisce il calcolo delle dimensioni globali dai flag Trainer
--gpus
e--num_nodes
.from azureml.core import ScriptRunConfig, Experiment from azureml.core.runconfig import MpiConfiguration nnodes = 2 gpus_per_node = 4 args = ['--max_epochs', 50, '--gpus_per_node', gpus_per_node, '--accelerator', 'ddp', '--num_nodes', nnodes] distr_config = MpiConfiguration(node_count=nnodes, process_count_per_node=gpus_per_node) run_config = ScriptRunConfig( source_directory='./src', script='train.py', arguments=args, compute_target=compute_target, environment=pytorch_env, distributed_job_config=distr_config, ) run = Experiment(ws, 'experiment_name').submit(run_config)
Hugging Face Transformers
Hugging Face offre molti esempi per l'uso della libreria Transformers con torch.distributed.launch
per eseguire il training distribuito. Per eseguire questi esempi e gli script di training personalizzati usando l'API Transformers Trainer, seguire la sezione Utilizzo ditorch.distributed.launch
.
Codice di configurazione del processo di esempio per ottimizzare il modello BERT di grandi dimensioni nell'attività MNLI di classificazione del testo usando lo script run_glue.py
in un nodo con 8 GPU:
from azureml.core import ScriptRunConfig
from azureml.core.runconfig import PyTorchConfiguration
distr_config = PyTorchConfiguration() # node_count defaults to 1
launch_cmd = "python -m torch.distributed.launch --nproc_per_node 8 text-classification/run_glue.py --model_name_or_path bert-large-uncased-whole-word-masking --task_name mnli --do_train --do_eval --max_seq_length 128 --per_device_train_batch_size 8 --learning_rate 2e-5 --num_train_epochs 3.0 --output_dir /tmp/mnli_output".split()
run_config = ScriptRunConfig(
source_directory='./src',
command=launch_cmd,
compute_target=compute_target,
environment=pytorch_env,
distributed_job_config=distr_config,
)
È anche possibile usare l'opzione avvio per processo per eseguire il training distribuito senza usare torch.distributed.launch
. Un aspetto da tenere presente se si usa questo metodo è che i trasformatori TrainingArguments si aspettano che la classificazione locale venga passata come argomento (--local_rank
). torch.distributed.launch
si occupa di questa situazione quando --use_env=False
, ma se si usa l'avvio per processo, è necessario passare in modo esplicito la classificazione locale come argomento allo script di training --local_rank=$LOCAL_RANK
perché Azure Machine Learning imposta solo la variabile di ambiente LOCAL_RANK
.
TensorFlow
Se si usa TensorFlow distribuito nativo nel codice di training, ad esempio l'API tf.distribute.Strategy
di TensorFlow 2.x, è possibile avviare il processo distribuito tramite Azure Machine Learning usando il TensorflowConfiguration
.
A tale scopo, specificare un oggetto TensorflowConfiguration
per il parametro distributed_job_config
del costruttore ScriptRunConfig
. Se si usa tf.distribute.experimental.MultiWorkerMirroredStrategy
, specificare il worker_count
nella TensorflowConfiguration
corrispondente al numero di nodi per il processo di training.
from azureml.core import ScriptRunConfig, Environment, Experiment
from azureml.core.runconfig import TensorflowConfiguration
curated_env_name = 'AzureML-TensorFlow-2.3-GPU'
tf_env = Environment.get(workspace=ws, name=curated_env_name)
distr_config = TensorflowConfiguration(worker_count=2, parameter_server_count=0)
run_config = ScriptRunConfig(
source_directory='./src',
script='train.py',
compute_target=compute_target,
environment=tf_env,
distributed_job_config=distr_config,
)
# submit the run configuration to start the job
run = Experiment(ws, "experiment_name").submit(run_config)
Se lo script di training usa la strategia del server dei parametri per il training distribuito, ad esempio per TensorFlow 1.x legacy, sarà necessario specificare anche il numero di server di parametri da usare nel processo, ad esempio tf_config = TensorflowConfiguration(worker_count=2, parameter_server_count=1)
.
TF_CONFIG
In TensorFlow la variabile di ambiente TF_CONFIG è necessaria per il training su più computer. Per i processi TensorFlow, Azure Machine Learning configurerà e imposterà la variabile TF_CONFIG in modo appropriato per ogni ruolo di lavoro prima di eseguire lo script di training.
È possibile accedere TF_CONFIG dallo script di training se è necessario: os.environ['TF_CONFIG']
.
Esempio TF_CONFIG impostato in un nodo di lavoro principale:
TF_CONFIG='{
"cluster": {
"worker": ["host0:2222", "host1:2222"]
},
"task": {"type": "worker", "index": 0},
"environment": "cloud"
}'
Esempio di TensorFlow
Accelerazione del training della GPU distribuita con InfiniBand
Man mano che aumenta il numero di macchine virtuali che eseguono il training di un modello, il tempo necessario per eseguire il training del modello stesso deve diminuire. La diminuzione del tempo, idealmente, deve essere proporzionale in modo lineare al numero di macchine virtuali di training. Ad esempio, se il training di un modello in una macchina virtuale richiede 100 secondi, il training dello stesso modello in due macchine virtuali dovrebbe richiedere idealmente 50 secondi. Il training del modello su quattro macchine virtuali richiederà 25 secondi e così via.
InfiniBand può essere un fattore importante per ottenere questo ridimensionamento lineare. InfiniBand consente la comunicazione da GPU a GPU a bassa latenza tra nodi in un cluster. Il funzionamento di InfiniBand richiede hardware specializzato. Alcune serie di macchine virtuali di Azure, in particolare NC, ND e serie H, dispongono ora di macchine virtuali con capacità RDMA e con il supporto SR-IOV e InfiniBand. Queste macchine virtuali comunicano tramite la bassa latenza e la rete InfiniBand a larghezza di banda elevata, che è molto più efficiente rispetto alla connettività basata su Ethernet. SR-IOV per InfiniBand consente prestazioni quasi bare metal per qualsiasi libreria MPI (MPI viene usato da molti framework di training distribuiti e strumenti, incluso il software NCCL di NVIDIA). Questi SKU sono progettati per soddisfare le esigenze di carichi di lavoro di Machine Learning a elevato utilizzo di calcolo e di apprendimento automatico con GPU. Per altre informazioni, vedere Accelerare il Training distribuito in Azure Machine Learning con SR-IOV.
In genere, gli SKU delle macchine virtuali con un nome "r" contengono l'hardware InfiniBand richiesto, differentemente da quelli senza "r" in genere. ("r" è un riferimento a RDMA, che è l'acronimo di "remote direct memory access.") Ad esempio, lo SKU della macchina virtuale Standard_NC24rs_v3
è abilitato per InfiniBand, ma lo SKU Standard_NC24s_v3
non lo è. A parte le funzionalità InfiniBand, le specifiche tra questi due SKU sono in gran parte le stesse: hanno 24 core, 448 GB di RAM, 4 GPU dello stesso SKU e così via. Altre informazioni sugli SKU dei computer abilitati per RDMA e InfiniBand.
Avviso
Lo SKU del computer di generazione precedente Standard_NC24r
è abilitato per RDMA, ma non contiene un hardware SR-IOV necessario per InfiniBand.
Se si crea un cluster AmlCompute
di una di queste dimensioni abilitate per RDMA, le dimensioni abilitate per InfiniBand, l'immagine del sistema operativo verrà fornita con il driver Mellanox OFED necessario per abilitare InfiniBand preinstallato e preconfigurato.