Distributed GPU training guide (SDK v1)
GÄLLER FÖR:Python SDK azureml v1
Läs mer om hur du använder distribuerad GPU-träningskod i Azure Machine Learning (ML). Den här artikeln lär dig inte om distribuerad utbildning. Det hjälper dig att köra din befintliga distribuerade träningskod på Azure Machine Learning. Den innehåller tips och exempel som du kan följa för varje ramverk:
- MPI (Message Passing Interface)
- Horovod
- Djupspeed
- Miljövariabler från Open MPI
- PyTorch
- Initiering av processgrupp
- Startalternativ
- DistributedDataParallel (per process-launch)
- Använda
torch.distributed.launch
(per nodstart) - PyTorch Lightning
- Krama ansiktstransformatorer
- TensorFlow
- Miljövariabler för TensorFlow (TF_CONFIG)
- Påskynda GPU-träning med InfiniBand
Förutsättningar
Granska dessa grundläggande begrepp för distribuerad GPU-träning , till exempel dataparallellitet, distribuerad dataparallellitet och modellparallellitet.
Tips
Om du inte vet vilken typ av parallellitet du ska använda bör du använda distribuerad dataparallellitet mer än 90 % av tiden.
MPI
Azure Machine Learning erbjuder ett MPI-jobb för att starta ett visst antal processer i varje nod. Du kan använda den här metoden för att köra distribuerad träning med antingen per process-launcher eller per nod-launcher, beroende på om process_count_per_node
är inställt på 1 (standard) för startprogrammet per nod eller lika med antalet enheter/GPU:er för startprogrammet per process. Azure Machine Learning skapar det fullständiga MPI-startkommandot (mpirun
) i bakgrunden. Du kan inte ange egna fullständiga head-node-launcher-kommandon som mpirun
eller DeepSpeed launcher
.
Tips
Den grundläggande Docker-avbildningen som används av ett Azure Machine Learning MPI-jobb måste ha ett MPI-bibliotek installerat. Open MPI ingår i alla Azure Machine Learning GPU-basavbildningar. När du använder en anpassad Docker-avbildning ansvarar du för att se till att avbildningen innehåller ett MPI-bibliotek. Öppna MPI rekommenderas, men du kan också använda en annan MPI-implementering, till exempel Intel MPI. Azure Machine Learning tillhandahåller även organiserade miljöer för populära ramverk.
Följ dessa steg om du vill köra distribuerad träning med MPI:
- Använd en Azure Machine Learning-miljö med önskat ramverk för djupinlärning och MPI. Azure Machine Learning tillhandahåller en granskad miljö för populära ramverk.
- Definiera
MpiConfiguration
medprocess_count_per_node
ochnode_count
.process_count_per_node
ska vara lika med antalet GPU:er per nod för start per process eller inställt på 1 (standard) för start per nod om användarskriptet ansvarar för att starta processerna per nod. - Skicka -
MpiConfiguration
objektet till parameterndistributed_job_config
ScriptRunConfig
för .
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
Använd MPI-jobbkonfigurationen när du använder Horovod för distribuerad träning med ramverket för djupinlärning.
Se till att koden följer dessa tips:
- Träningskoden instrumenteras korrekt med Horovod innan du lägger till Azure Machine Learning-delarna
- Din Azure Machine Learning-miljö innehåller Horovod och MPI. PyTorch- och TensorFlow-organiserade GPU-miljöer är förkonfigurerade med Horovod och dess beroenden.
- Skapa en
MpiConfiguration
med önskad distribution.
Horovod-exempel
Djupspeed
Använd inte DeepSpeeds anpassade startprogrammet för att köra distribuerad träning med DeepSpeed-biblioteket i Azure Machine Learning. Konfigurera i stället ett MPI-jobb för att starta träningsjobbet med MPI.
Se till att koden följer dessa tips:
- Din Azure Machine Learning-miljö innehåller DeepSpeed och dess beroenden, Open MPI och mpi4py.
- Skapa en
MpiConfiguration
med din distribution.
DeepSpeed-exempel
Miljövariabler från Open MPI
När du kör MPI-jobb med Öppna MPI-avbildningar startar följande miljövariabler för varje process:
OMPI_COMM_WORLD_RANK
- processens rangordningOMPI_COMM_WORLD_SIZE
- Världens storlekAZ_BATCH_MASTER_NODE
– primär adress med port,MASTER_ADDR:MASTER_PORT
OMPI_COMM_WORLD_LOCAL_RANK
– den lokala rangordningen för processen på nodenOMPI_COMM_WORLD_LOCAL_SIZE
– antal processer på noden
Tips
Trots namnet motsvarar NODE_RANK
miljövariabeln OMPI_COMM_WORLD_NODE_RANK
inte . Om du vill använda startprogrammet per nod anger process_count_per_node=1
du och använder OMPI_COMM_WORLD_RANK
som NODE_RANK
.
PyTorch
Azure Machine Learning stöder körning av distribuerade jobb med PyTorchs inbyggda distribuerade träningsfunktioner (torch.distributed
).
Tips
För dataparallellitet är den officiella PyTorch-vägledningen att använda DDP (DistributedDataParallel) över DataParallel för distribuerad träning med både en nod och flera noder. PyTorch rekommenderar också att du använder DistributedDataParallel via multiprocessningspaketet. Dokumentationen och exemplen i Azure Machine Learning fokuserar därför på DistributedDataParallel-utbildning.
Initiering av processgrupp
Ryggraden i en distribuerad träning baseras på en grupp processer som känner varandra och kan kommunicera med varandra med hjälp av en serverdel. För PyTorch skapas processgruppen genom att anropa torch.distributed.init_process_group i alla distribuerade processer för att tillsammans bilda en processgrupp.
torch.distributed.init_process_group(backend='nccl', init_method='env://', ...)
De vanligaste kommunikationsserverdelarna som används är mpi
, nccl
och gloo
. För GPU-baserad träning nccl
rekommenderas för bästa prestanda och bör användas när det är möjligt.
init_method
berättar hur varje process kan identifiera varandra, hur de initierar och verifierar processgruppen med hjälp av kommunikationsserverdelen. Om inte anges använder PyTorch som standard init_method
initieringsmetoden för miljövariabeln (env://
). init_method
är den rekommenderade initieringsmetoden som ska användas i din träningskod för att köra distribuerade PyTorch på Azure Machine Learning. PyTorch söker efter följande miljövariabler för initiering:
MASTER_ADDR
– IP-adressen för den dator som ska vara värd för processen med rangordning 0.MASTER_PORT
– En kostnadsfri port på datorn som ska vara värd för processen med rang 0.WORLD_SIZE
- Det totala antalet processer. Ska vara lika med det totala antalet enheter (GPU) som används för distribuerad träning.RANK
– Den (globala) rangordningen för den aktuella processen. Möjliga värden är 0 till (världsstorlek - 1).
Mer information om initiering av processgrupper finns i PyTorch-dokumentationen.
Utöver dessa behöver många program även följande miljövariabler:
LOCAL_RANK
– Den lokala (relativa) rangordningen för processen inom noden. Möjliga värden är 0 till (antal processer på noden – 1). Den här informationen är användbar eftersom många åtgärder, till exempel förberedelse av data, endast ska utföras en gång per nod --- vanligtvis på local_rank = 0.NODE_RANK
– Rangordningen för noden för träning med flera noder. Möjliga värden är 0 till (totalt antal noder – 1).
Startalternativ för PyTorch
Azure Machine Learning PyTorch-jobbet stöder två typer av alternativ för att starta distribuerad träning:
- Per processstartare: Systemet startar alla distribuerade processer åt dig, med all relevant information (till exempel miljövariabler) för att konfigurera processgruppen.
- Startprogrammet per nod: Du ger Azure Machine Learning det verktygsstartsprogram som ska köras på varje nod. Verktygsstartaren hanterar start av var och en av processerna på en viss nod. Lokalt inom varje nod
RANK
ochLOCAL_RANK
konfigureras av startprogrammet. Verktyget torch.distributed.launch och PyTorch Lightning hör båda till den här kategorin.
Det finns inga grundläggande skillnader mellan dessa startalternativ. Valet är till stor del upp till din preferens eller konventionerna för ramverk / bibliotek som bygger på vanilj PyTorch (till exempel Lightning eller Hugging Face).
Följande avsnitt innehåller mer information om hur du konfigurerar Azure Machine Learning PyTorch-jobb för vart och ett av startalternativen.
DistributedDataParallel (per processstart)
Du behöver inte använda ett startverktyg som torch.distributed.launch
. Så här kör du ett distribuerat PyTorch-jobb:
- Ange träningsskriptet och argumenten
- Skapa en
PyTorchConfiguration
och angeprocess_count
ochnode_count
.process_count
Motsvarar det totala antalet processer som du vill köra för jobbet.process_count
ska vanligtvis vara lika med# GPUs per node x # nodes
. Omprocess_count
inte anges startar Azure Machine Learning som standard en process per nod.
Azure Machine Learning ställer in MASTER_ADDR
miljövariablerna , MASTER_PORT
, WORLD_SIZE
och NODE_RANK
på varje nod och anger variablerna för processnivå RANK
och LOCAL_RANK
miljö.
Om du vill använda det här alternativet för träning med flera processer per nod använder du Azure Machine Learning Python SDK >= 1.22.0
. Process_count infördes i 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)
Tips
Om ditt träningsskript skickar information som lokal rangordning eller rangordning som skriptargument kan du referera till miljövariablerna i argumenten:
arguments=['--epochs', 50, '--local_rank', $LOCAL_RANK]
Pytorch per process-launch-exempel
Använda torch.distributed.launch (per nodstart)
PyTorch tillhandahåller ett startverktyg i torch.distributed.launch som du kan använda för att starta flera processer per nod. Modulen torch.distributed.launch
skapar flera träningsprocesser på var och en av noderna.
Följande steg visar hur du konfigurerar ett PyTorch-jobb med ett startsprogram per nod i Azure Machine Learning. Jobbet uppnår motsvarigheten till att köra följande kommando:
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>
torch.distributed.launch
Ange kommandot till parameterncommand
förScriptRunConfig
konstruktorn. Azure Machine Learning kör det här kommandot på varje nod i ditt träningskluster.--nproc_per_node
bör vara mindre än eller lika med antalet GPU:er som är tillgängliga på varje nod. MASTER_ADDR, MASTER_PORT och NODE_RANK anges av Azure Machine Learning, så du kan bara referera till miljövariablerna i kommandot . Azure Machine Learning anger MASTER_PORT till6105
, men du kan skicka ett annat värde till--master_port
argumentet för kommandot torch.distributed.launch om du vill. (Startverktyget återställer miljövariablerna.)- Skapa en
PyTorchConfiguration
och angenode_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)
Tips
Träning med flera GPU:n med en nod: Om du använder startverktyget för att köra pytorchträning med en nod med flera GPU:er behöver du inte ange parametern distributed_job_config
för 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,
)
PyTorch per nod-startexempel
PyTorch Lightning
PyTorch Lightning är ett enkelt bibliotek med öppen källkod som tillhandahåller ett högnivågränssnitt för PyTorch. Lightning abstraherar bort många av de distribuerade träningskonfigurationer på lägre nivå som krävs för vanilla PyTorch. Med Lightning kan du köra dina träningsskript i en enda GPU, multi-GPU med en nod och flernodsinställningar för flera GPU:er. Bakom scenen startas flera processer för dig som liknar torch.distributed.launch
.
För träning med en nod (inklusive multi-GPU med en nod) kan du köra koden i Azure Machine Learning utan att behöva ange en distributed_job_config
.
Om du vill köra ett experiment med flera noder med flera GPU:er finns det två alternativ:
Använda PyTorch-konfiguration (rekommenderas): Definiera
PyTorchConfiguration
och angecommunication_backend="Nccl"
,node_count
ochprocess_count
(observera att det här är det totala antalet processer, dvs.num_nodes * process_count_per_node
). I Lightning Trainer-modulen anger du bådenum_nodes
ochgpus
för att vara konsekvent medPyTorchConfiguration
. Exempelvisnum_nodes = node_count
ochgpus = process_count_per_node
.Använda MPI-konfiguration:
Definiera
MpiConfiguration
och ange bådenode_count
ochprocess_count_per_node
. I Lightning Trainer anger du bådenum_nodes
ochgpus
ska vara samma somnode_count
ochprocess_count_per_node
frånMpiConfiguration
.För träning med flera noder med MPI kräver Lightning att följande miljövariabler anges på varje nod i ditt träningskluster:
- MASTER_ADDR
- MASTER_PORT
- NODE_RANK
- LOCAL_RANK
Ange de här miljövariablerna manuellt som Lightning kräver i huvudträningsskripten:
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 hanterar databehandling av världsstorleken från trainerflaggor
--gpus
och--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)
Krama ansiktstransformatorer
Hugging Face innehåller många exempel på hur du använder transformeringsbiblioteket med torch.distributed.launch
för att köra distribuerad träning. Om du vill köra de här exemplen och dina egna anpassade träningsskript med hjälp av Transformers Trainer-API:et följer du avsnittet Använda torch.distributed.launch
.
Exempel på jobbkonfigurationskod för att finjustera den stora BERT-modellen för MNLI-aktiviteten för textklassificering med hjälp av skriptet run_glue.py
på en nod med 8 GPU:er:
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,
)
Du kan också använda alternativet för att starta per process för att köra distribuerad träning utan att använda torch.distributed.launch
. En sak att tänka på om du använder den här metoden är att transformatorerna TrainingArguments förväntar sig att den lokala rangordningen skickas som ett argument (--local_rank
). torch.distributed.launch
tar hand om detta när --use_env=False
, men om du använder per process-start måste du uttryckligen skicka den lokala rangordningen som ett argument till träningsskriptet --local_rank=$LOCAL_RANK
eftersom Azure Machine Learning bara anger LOCAL_RANK
miljövariabeln.
TensorFlow
Om du använder inbyggt distribuerat TensorFlow i träningskoden, till exempel TensorFlow 2.xs tf.distribute.Strategy
API, kan du starta det distribuerade jobbet via Azure Machine Learning med hjälp av TensorflowConfiguration
.
Om du vill göra det anger du ett TensorflowConfiguration
objekt till parametern distributed_job_config
för ScriptRunConfig
konstruktorn. Om du använder tf.distribute.experimental.MultiWorkerMirroredStrategy
anger worker_count
du i TensorflowConfiguration
som motsvarar antalet noder för ditt träningsjobb.
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)
Om ditt träningsskript använder parameterserverstrategin för distribuerad träning, till exempel för äldre TensorFlow 1.x, måste du också ange antalet parameterservrar som ska användas i jobbet, till exempel tf_config = TensorflowConfiguration(worker_count=2, parameter_server_count=1)
.
TF_CONFIG
I TensorFlow krävs TF_CONFIG miljövariabeln för träning på flera datorer. För TensorFlow-jobb konfigurerar och ställer Azure Machine Learning in TF_CONFIG variabeln på rätt sätt för varje arbetare innan du kör träningsskriptet.
Du kan komma åt TF_CONFIG från träningsskriptet om du behöver: os.environ['TF_CONFIG']
.
Exempel TF_CONFIG anges på en chefsarbetsnod:
TF_CONFIG='{
"cluster": {
"worker": ["host0:2222", "host1:2222"]
},
"task": {"type": "worker", "index": 0},
"environment": "cloud"
}'
TensorFlow-exempel
Påskynda distribuerad GPU-träning med InfiniBand
När antalet virtuella datorer som tränar en modell ökar bör den tid som krävs för att träna modellen minska. Den minskade tiden bör helst vara linjärt proportionell mot antalet virtuella träningsdatorer. Om det till exempel tar 100 sekunder att träna en modell på en virtuell dator bör det helst ta 50 sekunder att träna samma modell på två virtuella datorer. Det bör ta 25 sekunder att träna modellen på fyra virtuella datorer och så vidare.
InfiniBand kan vara en viktig faktor för att uppnå den här linjära skalningen. InfiniBand möjliggör GPU-till-GPU-kommunikation med låg svarstid mellan noder i ett kluster. InfiniBand kräver särskild maskinvara för att fungera. Vissa Azure VM-serier, särskilt NC-, ND- och H-serien, har nu RDMA-kompatibla virtuella datorer med stöd för SR-IOV och InfiniBand. Dessa virtuella datorer kommunicerar via infiniBand-nätverket med låg svarstid och hög bandbredd, vilket är mycket mer högpresterande än Ethernet-baserad anslutning. SR-IOV för InfiniBand möjliggör nästan bare metal-prestanda för alla MPI-bibliotek (MPI används av många distribuerade träningsramverk och verktyg, inklusive NVIDIA:s NCCL-programvara.) Dessa SKU:er är avsedda att uppfylla behoven hos beräkningsintensiva, GPU-acclererade maskininlärningsarbetsbelastningar. Mer information finns i Accelerating Distributed Training in Azure Machine Learning with SR-IOV (Accelerera distribuerad utbildning i Azure Machine Learning med SR-IOV).
Vanligtvis innehåller VM-SKU:er med ett "r" i namnet den infiniBand-maskinvara som krävs, och de som inte har ett "r" gör det vanligtvis inte. ('r' är en referens till RDMA, som står för "direktåtkomst till fjärrminne") Den virtuella datorns SKU Standard_NC24rs_v3
är till exempel InfiniBand-aktiverad, men SKU Standard_NC24s_v3
:n är inte det. Bortsett från InfiniBand-funktionerna är specifikationerna mellan dessa två SKU:er i stort sett desamma – båda har 24 kärnor, 448 GB RAM-minne, 4 GPU:er av samma SKU osv. Läs mer om RDMA- och InfiniBand-aktiverade dator-SKU:er.
Varning
Den äldre generationens SKU Standard_NC24r
är RDMA-aktiverad, men den innehåller inte SR-IOV-maskinvara som krävs för InfiniBand.
Om du skapar ett AmlCompute
kluster med någon av dessa RDMA-kompatibla, InfiniBand-aktiverade storlekar kommer OS-avbildningen med den Mellanox OFED-drivrutin som krävs för att aktivera InfiniBand förinstallerat och förkonfigurerat.