Dela via


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:

  1. 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.
  2. Definiera MpiConfiguration med process_count_per_node och node_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.
  3. Skicka - MpiConfiguration objektet till parametern distributed_job_configScriptRunConfigfö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:

  1. OMPI_COMM_WORLD_RANK - processens rangordning
  2. OMPI_COMM_WORLD_SIZE - Världens storlek
  3. AZ_BATCH_MASTER_NODE – primär adress med port, MASTER_ADDR:MASTER_PORT
  4. OMPI_COMM_WORLD_LOCAL_RANK – den lokala rangordningen för processen på noden
  5. OMPI_COMM_WORLD_LOCAL_SIZE – antal processer på noden

Tips

Trots namnet motsvarar NODE_RANKmiljö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, nccloch 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 och LOCAL_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:

  1. Ange träningsskriptet och argumenten
  2. Skapa en PyTorchConfiguration och ange process_count och node_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. Om process_count inte anges startar Azure Machine Learning som standard en process per nod.

Azure Machine Learning ställer in MASTER_ADDRmiljövariablerna , MASTER_PORT, WORLD_SIZEoch 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>
  1. torch.distributed.launch Ange kommandot till parametern command för ScriptRunConfig 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 till 6105, 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.)
  2. Skapa en PyTorchConfiguration och ange node_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 ange communication_backend="Nccl", node_countoch process_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åde num_nodes och gpus för att vara konsekvent med PyTorchConfiguration. Exempelvis num_nodes = node_count och gpus = process_count_per_node.

  • Använda MPI-konfiguration:

    • Definiera MpiConfiguration och ange både node_count och process_count_per_node. I Lightning Trainer anger du både num_nodes och gpus ska vara samma som node_count och process_count_per_node från MpiConfiguration.

    • 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.MultiWorkerMirroredStrategyanger 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.

Nästa steg