Поделиться через


Руководство по распределенному обучению с поддержкой GPU (пакет SDK версии 1)

ОБЛАСТЬ ПРИМЕНЕНИЯ: Пакет SDK для Python версии 1

Узнайте больше об использовании кода распределенного обучения с поддержкой GPU в Машинном обучении Azure (ML). Эта статья не поможет вам изучить распределенное обучение. Она поможет вам запустить существующий код распределенного обучения в Машинном обучении Azure. В ней представлены советы и примеры для каждой из платформ:

  • Интерфейс передачи сообщений (MPI)
    • Horovod
    • DeepSpeed
    • Переменные среды из Open MPI
  • PyTorch
    • инициализация группы процессов;
    • параметры запуска;
    • DistributedDataParallel (per-process-launcher);
    • использование torch.distributed.launch (per-node-launcher);
    • PyTorch Lightning;
    • библиотека Transformers в Hugging Face.
  • TensorFlow
    • переменные среды для TensorFlow (TF_CONFIG).
  • Ускорение обучения с поддержкой GPU с помощью InfiniBand.

Необходимые компоненты

Ознакомьтесь с основными принципами распределенного обучения с поддержкой GPU, например с параллельной обработкой данных, параллельной обработкой распределенных данных и параллельной обработкой моделей.

Совет

Если неизвестно, какой тип параллельной обработки нужно использовать, то более 90 % времени следует использовать параллельную обработку распределенных данных.

MPI

Машинное обучение Azure предлагает Задание MPI для запуска заданного количества процессов в каждом узле. Этот подход можно использовать для выполнения распределенного обучения в режиме per-process-launcher или per-node-launcher в зависимости от того, задано ли для параметра process_count_per_node значение 1 (по умолчанию) для per-node-launcher или для него задано число устройств и GPU для per-process-launcher. Машинное обучение Azure создает полную команду запуска MPI (mpirun) за кулисами. Вы не можете предоставить собственные полные команды head-node-launcher, такие как mpirun или DeepSpeed launcher.

Совет

В базовом образе Docker, используемом заданием MPI Машинного обучения Azure, должна быть установлена библиотека MPI. Открытие MPI включается во все базовые образы gpu Машинное обучение Azure. При использовании пользовательского образа Docker вы несете ответственность за то, чтобы он включал в себя библиотеку MPI. Рекомендуется использовать Open MPI, но вы можете также использовать другую реализацию MPI, например Intel MPI. Машинное обучение Azure также предоставляет курируемые среды для популярных платформ.

Чтобы выполнить распределенное обучение с помощью MPI, сделайте следующее.

  1. Используйте среду Машинное обучение Azure с предпочтительной платформой глубокого обучения и MPI. Машинное обучение Azure предоставляет курированную среду для популярных платформ.
  2. Определите MpiConfiguration с process_count_per_node и node_count. Значение process_count_per_node должно равняться количеству GPU на узел для режима per-process-launcher или равняться 1 (по умолчанию) для режима per-node-launcher, если пользовательский сценарий будет отвечать за запуск процессов на каждом узле.
  3. Передайте объект MpiConfiguration в параметр distributed_job_config конфигурации ScriptRunConfig.
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

Используйте конфигурацию задания MPI для распределенного обучения с помощью платформы глубокого обучения Horovod.

Убедитесь, что в вашем коде применены следующие советы.

  • Код обучения правильно инструментирован с Horovod перед добавлением Машинное обучение Azure частей
  • Среда Машинное обучение Azure содержит Horovod и MPI. Курированные среды с поддержкой GPU PyTorch и TensorFlow предварительно настроены с помощью Horovod и соответствующих зависимостей.
  • Создайте MpiConfiguration с требуемым распределением.

Пример Horovod

DeepSpeed

Не используйте пользовательский средство запуска DeepSpeed для выполнения распределенного обучения с библиотекой DeepSpeed на Машинное обучение Azure. Вместо этого настройте задание MPI для запуска задания обучения с помощью MPI.

Убедитесь, что в вашем коде применены следующие советы.

  • Среда Машинное обучение Azure содержит DeepSpeed и его зависимости, Open MPI и mpi4py.
  • Создайте MpiConfiguration с требуемым распределением.

Пример DeepSpeed

Переменные среды из Open MPI

При выполнении заданий MPI с образами Open MPI для каждого запущенного процесса используются следующие переменные среды:

  1. OMPI_COMM_WORLD_RANK — ранг процесса;
  2. OMPI_COMM_WORLD_SIZE — размер пакета;
  3. AZ_BATCH_MASTER_NODE — основной адрес с портом, MASTER_ADDR:MASTER_PORT;
  4. OMPI_COMM_WORLD_LOCAL_RANK— локальный ранг процесса на узле;
  5. OMPI_COMM_WORLD_LOCAL_SIZE — количество процессов на узле.

Совет

Несмотря на имя, переменная среды не OMPI_COMM_WORLD_NODE_RANK соответствует NODE_RANK. Чтобы использовать режим per-node-launcher, задайте process_count_per_node=1 и используйте OMPI_COMM_WORLD_RANK в качестве NODE_RANK.

PyTorch

Машинное обучение Azure поддерживает выполнение распределенных заданий с помощью собственных возможностей распределенного обучения PyTorch (torch.distributed).

Совет

Для параллельной обработки данных в официальном руководстве по PyTorch предписывается использовать DistributedDataParallel (DDP) и DataParallel для распределенного обучения как с одним узлом, так и с несколькими узлами. PyTorch также рекомендует использовать DistributedDataParallel в пакете многопроцессной обработки. Поэтому документация и примеры для Машинного обучения Azure будут сосредоточены на обучении DistributedDataParallel.

инициализация группы процессов;

Основа любого распределенного обучения — это группа процессов, которые связаны и могут взаимодействовать друг с другом, используя внутренний сервер. Для PyTorch группа процессов создается путем вызова torch.distributed.init_process_group во всех распределенных процессах для формирования группы процессов.

torch.distributed.init_process_group(backend='nccl', init_method='env://', ...)

Наиболее распространенные внутренние серверы подключений: mpi, nccl и gloo. Для обучения с поддержкой GPU рекомендуется использовать nccl, чтобы обеспечить оптимальную производительность, когда это возможно.

init_method указывает, как процессы могут обнаружить друг друга, как они инициализируются и проверяют группу процессов, используя внутренний сервер подключений. По умолчанию, если параметр init_method не указан, PyTorch будет использовать метод инициализации переменной среды (env://). init_method— рекомендуемый метод инициализации для использования в коде обучения для запуска распределенного PyTorch на Машинное обучение Azure. PyTorch будет искать следующие переменные среды для инициализации:

  • MASTER_ADDR — IP-адрес компьютера, на котором будет размещен процесс с рангом 0.
  • MASTER_PORT — свободный порт компьютера, на котором будет размещен процесс с рангом 0.
  • WORLD_SIZE — общее количество процессов. Оно должно быть равно общему количеству устройств (GPU), используемых для распределенного обучения.
  • RANK — ранг (глобальный) текущего процесса. Возможные значения: от 0 до (world_size — 1).

Дополнительные сведения об инициализации группы процессов см. в документации по PyTorch.

Помимо этого, многим приложениям также потребуются следующие переменные среды:

  • LOCAL_RANK — локальный (относительный) ранг процесса в пределах узла. Возможные значения: от 0 до (число процессов на узле — 1). Эта информация полезна, так как многие операции, такие как подготовка данных, должны выполняться один раз для каждого узла (обычно для local_rank = 0).
  • NODE_RANK — ранг узла для обучения с несколькими узлами. Возможные значения: от 0 до (общее число узлов — 1).

Параметры запуска PyTorch

Задание pyTorch Машинное обучение Azure поддерживает два типа вариантов запуска распределенного обучения:

  • Режим per-process-launcher. Система запустит все распределенные процессы со всеми соответствующими сведениями (например, переменными среды) в группе процессов.
  • Средство запуска для каждого узла: вы предоставляете Машинное обучение Azure с помощью средства запуска служебной программы, который будет выполняться на каждом узле. Эта служебная программа запуска будет обрабатывать запуск каждого процесса на заданном узле. Средство запуска локально на каждом узле настраивает RANK и LOCAL_RANK. Служебная программа torch.distributed.launch и PyTorch Lightning относятся к этой категории.

Между этими режимами запуска нет фундаментальных отличий. В основном выбор зависит от предпочтений пользователя или соглашений о платформах и библиотеках, созданных на основе обыкновенного PyTorch (такого как Lightning или Hugging Face).

В следующих разделах подробно описано, как настроить Машинное обучение Azure задания PyTorch для каждого из вариантов запуска.

DistributedDataParallel (per-process-launcher);

Не нужно использовать служебную программу запуска, например torch.distributed.launch. Чтобы отправить распределенное задание PyTorch, сделайте следующее.

  1. Укажите сценарий обучения и аргументы.
  2. Создайте PyTorchConfiguration, затем укажите process_count и node_count. process_count соответствует общему количеству процессов, которые вы хотите выполнить для задания. Обычно значение process_count равно # GPUs per node x # nodes. Если process_count не указано, Машинное обучение Azure по умолчанию запускает один процесс на узел.

Машинное обучение Azure задает MASTER_ADDRпеременные среды и MASTER_PORTNODE_RANK WORLD_SIZEпеременные среды на каждом узле и задает переменные уровня процесса RANK и LOCAL_RANK среды.

Чтобы использовать этот параметр для обучения с несколькими процессами на узел, используйте пакет SDK >= 1.22.0для Python Машинное обучение Azure. Параметр process_count был введен в версии 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)

Совет

Если ваш сценарий обучения передает такие сведения, как ранг или локальный ранг, в качестве аргументов сценария, вы можете ссылаться в аргументах на переменные среды:

arguments=['--epochs', 50, '--local_rank', $LOCAL_RANK]

Пример PyTorch для режима per-process-launcher

Использование torch.distributed.launch (per-node-launch)

PyTorch предоставляет в torch.distributed.launch служебную программу запуска, которую можно использовать для запуска нескольких процессов на каждом узле. Модуль torch.distributed.launch порождает несколько процессов обучения на каждом из узлов.

Ниже показано, как настроить задание PyTorch с помощью средства запуска для каждого узла на Машинное обучение Azure. Задание достигает эквивалента выполнения следующей команды:

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 в параметре command конструктора ScriptRunConfig. Машинное обучение Azure выполняет эту команду на каждом узле учебного кластера. Значение --nproc_per_node должно быть меньше или равно количеству GPU, доступных на каждом узле. MASTER_ADDR, MASTER_PORT и NODE_RANK задаются Машинное обучение Azure, поэтому можно просто ссылаться на переменные среды в команде. Машинное обучение Azure задает значение MASTER_PORT6105, но при желании можно передать другое значение --master_port в аргумент команды torch.distributed.launch. (Служебная программа запуска выполнит сброс переменных среды.)
  2. Создайте PyTorchConfiguration и укажите 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)

Совет

Обучение на одном узле с несколькими GPU. Если вы используете служебную программу запуска для выполнения задания обучения PyTorch на одном узле с несколькими GPU, вам не нужно указывать параметр distributed_job_config для 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-node-launcher

PyTorch Lightning;

PyTorch Lightning — это упрощенная библиотека с открытым кодом, которая предоставляет высокоуровневый интерфейс для PyTorch. Lightning абстрагируется от многих низкоуровневых конфигураций распределенного обучения, необходимых для обыкновенного PyTorch. Lightning позволяет запускать сценарии обучения на одном GPU, на одном узле с несколькими GPU и на нескольких узлах с несколькими GPU. В фоновом режиме Lightning запускает несколько процессов, как и torch.distributed.launch.

Для обучения с одним узлом (включая один узел с несколькими GPU), можно запустить код на Машинное обучение Azure без необходимости указыватьdistributed_job_config. Существует 2 варианта запуска эксперимента с использованием нескольких узлов с несколькими графическими процессорами:

  • Использование конфигурации PyTorch (рекомендуется): определите PyTorchConfiguration, укажите communication_backend="Nccl", node_count и process_count (обратите внимание, что это общее количество процессов, т. е num_nodes * process_count_per_node). В модуле Lightning Trainer укажите как num_nodes, так и gpus, чтобы они соответствовали PyTorchConfiguration. Например, num_nodes = node_count и gpus = process_count_per_node.

  • Использование конфигурации MPI:

    • Определите MpiConfiguration и укажите как node_count, так и process_count_per_node. В модуле Lightning Trainer укажите, что num_nodes и gpus должны быть соответственно такими же, как node_count и process_count_per_node из MpiConfiguration.

    • Для обучения с несколькими узлами с помощью MPI для Lightning требуется, чтобы следующие переменные среды были установлены на каждом узле кластера обучения:

      • MASTER_ADDR
      • MASTER_PORT
      • NODE_RANK
      • LOCAL_RANK

      Вручную задайте эти переменные среды, необходимые Lightning в основных сценариях обучения:

    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 обрабатывает размер пакета в соответствии с флагами инструктора --gpus и --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)
    

библиотека Transformers в Hugging Face.

Hugging Face предоставляет множество примеров использования собственной библиотеки Transformers с torch.distributed.launch для распределенного обучения. Чтобы выполнить эти примеры и собственные пользовательские сценарии обучения с помощью API Transformers Trainer, следуйте указаниям в разделе Использование torch.distributed.launch.

Пример кода конфигурации задания для точной настройки большой модели BERT в задаче классификации текста MNLI с использованием сценария run_glue.py на одном узле с 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,
)

Вы можете также использовать режим per-process-launcher, чтобы выполнить распределенное обучение без использования torch.distributed.launch. Следует помнить, что при использовании этого метода преобразователи TrainingArguments ожидают передачи локального ранга в качестве аргумента (--local_rank). torch.distributed.launchэто --use_env=Falseпроисходит, если вы используете для запуска для каждого процесса, необходимо явно передать локальный ранг в качестве аргумента в скрипт --local_rank=$LOCAL_RANK обучения, так как Машинное обучение Azure только задает LOCAL_RANK переменную среды.

TensorFlow

Если вы используете собственный распределенный TensorFlow в коде обучения, например API TensorFlow 2.xtf.distribute.Strategy, вы можете запустить распределенное задание с помощью Машинное обучение Azure.TensorflowConfiguration

Для этого укажите объект TensorflowConfiguration в параметре distributed_job_config конструктора ScriptRunConfig. Если вы используете tf.distribute.experimental.MultiWorkerMirroredStrategy, укажите worker_count в параметре TensorflowConfiguration в соответствии с количеством узлов для вашего задания обучения.

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)

Если сценарий обучения использует стратегию сервера параметров для распределенного обучения, например для устаревшего TensorFlow 1.x, вам также придется указать количество серверов параметров, которое будет использоваться в задании, например tf_config = TensorflowConfiguration(worker_count=2, parameter_server_count=1).

TF_CONFIG

В TensorFlow для обучения на нескольких компьютерах требуется переменная среды TF_CONFIG. Для заданий TensorFlow Машинное обучение Azure настраивает и задает переменную TF_CONFIG соответствующим образом для каждой рабочей роли перед выполнением скрипта обучения.

При необходимости вы можете обращаться к TF_CONFIG из сценария обучения: os.environ['TF_CONFIG'].

Пример параметра TF_CONFIG, заданного на главном рабочем узле:

TF_CONFIG='{
    "cluster": {
        "worker": ["host0:2222", "host1:2222"]
    },
    "task": {"type": "worker", "index": 0},
    "environment": "cloud"
}'

Пример TensorFlow

Ускорение распределенного обучения с поддержкой GPU с помощью InfiniBand

По мере увеличения количества виртуальных машин, обучающих модель, время, необходимое для обучения модели, должно уменьшаться. Уменьшение времени в идеальном случае должно быть пропорционально количеству обучающих виртуальных машин. Например, если обучение модели на одной виртуальной машине занимает 100 секунд, то при обучении той же модели на двух виртуальных машинах в идеале потребуется 50 секунд. Обучение модели на четырех виртуальных машинах займет 25 секунд и т. д.

InfiniBand может играть важную роль в обеспечении такого линейного масштабирования. InfiniBand обеспечивает связь на уровне GPU между узлами в кластере с низкой задержкой. Для работы с InfiniBand требуется специализированное оборудование. Некоторые серии виртуальных машин Azure, в частности серии NC, ND и H, теперь поддерживают виртуальные машины RDMA с поддержкой SR-IOV и InfiniBand. Эти виртуальные машины обмениваются данными по сети InfiniBand с низкой задержкой и высокой пропускной способностью, которая гораздо быстрее, чем сеть Ethernet. SR-IOV для InfiniBand обеспечивает производительность практически на уровне компьютера без операционной системы для любой библиотеки MPI (MPI используется многими платформами и инструментами для распределенного обучения, включая программное обеспечение NVIDIA NCCL). Эти номера SKU предназначены для удовлетворения потребностей ресурсоемких рабочих нагрузок машинного обучения с большим количеством вычислений и поддержкой GPU. Дополнительные сведения см. в разделе Accelerating Distributed Training in Azure Machine Learning with SR-IOV (Ускорение распределенного обучения в Машинном обучении Azure с помощью SR-IOV).

Как правило, номера SKU виртуальных машин, имена которых включают букву "r", имеют необходимое оборудование InfiniBand, а те номера SKU, имена которых не включают эту букву, не имеют такого оборудования. ("r" — это ссылка на сокращение "RDMA", которое означает "удаленный доступ к памяти".) Например, номер SKU виртуальной машины Standard_NC24rs_v3 поддерживает InfiniBand, а номер SKU Standard_NC24s_v3 — нет. За исключением возможностей InfiniBand характеристики этих двух номеров SKU в целом одинаковы — 24 ядра, 448 ГБ ОЗУ, 4 GPU с одним и тем же SKU и т. д. Дополнительные сведения об RDMA и о номерах SKU виртуальных машин, поддерживающих InfiniBand.

Предупреждение

Номер SKU более старого поколения виртуальных машин Standard_NC24r поддерживает RDMA, но не включает оборудование SR-IOV, необходимое для InfiniBand.

При создании кластера AmlCompute на основе одного из таких размеров с поддержкой RDMA и InfiniBand образ ОС будет содержать драйвер Mellanox OFED, необходимый для включения предварительно установленного и настроенного компонента InfiniBand.

Следующие шаги