Руководство по распределенному обучению с поддержкой GPU (пакет SDK версии 1)
ОБЛАСТЬ ПРИМЕНЕНИЯ:Пакет SDK для Python azureml версии 1
Узнайте больше об использовании кода распределенного обучения с поддержкой GPU в Машинном обучении Azure (ML). Эта статья не поможет вам изучить распределенное обучение. Она поможет вам запустить существующий код распределенного обучения в Машинном обучении Azure. В ней представлены советы и примеры для каждой из платформ:
- Message Passing Interface (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, сделайте следующее.
- Используйте среду машинного обучения Azure с предпочтительной платформой глубокого обучения и MPI. Машинное обучение Azure предоставляет курируемую среду для популярных платформ.
- Определите
MpiConfiguration
сprocess_count_per_node
иnode_count
. Значениеprocess_count_per_node
должно равняться количеству GPU на узел для режима per-process-launcher или равняться 1 (по умолчанию) для режима per-node-launcher, если пользовательский сценарий будет отвечать за запуск процессов на каждом узле. - Передайте объект
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 для каждого запущенного процесса используются следующие переменные среды:
OMPI_COMM_WORLD_RANK
— ранг процесса;OMPI_COMM_WORLD_SIZE
— размер пакета;AZ_BATCH_MASTER_NODE
— основной адрес с портом,MASTER_ADDR:MASTER_PORT
;OMPI_COMM_WORLD_LOCAL_RANK
— локальный ранг процесса на узле;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).
В следующих разделах подробно описывается настройка заданий PyTorch Машинного обучения Azure для каждого из вариантов запуска.
DistributedDataParallel (per-process-launcher);
Не нужно использовать служебную программу запуска, например torch.distributed.launch
. Чтобы отправить распределенное задание PyTorch, сделайте следующее.
- Укажите сценарий обучения и аргументы.
- Создайте
PyTorchConfiguration
, затем укажитеprocess_count
иnode_count
.process_count
соответствует общему количеству процессов, которые вы хотите выполнить для задания. Обычно значениеprocess_count
равно# GPUs per node x # nodes
. Еслиprocess_count
параметр не указан, Машинное обучение Azure по умолчанию запустит по одному процессу на каждом узле.
Машинное обучение Azure задаст MASTER_ADDR
переменные среды , MASTER_PORT
, WORLD_SIZE
и NODE_RANK
на каждом узле, а также задаст переменные уровня 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>
- Укажите команду
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. (Служебная программа запуска выполнит сброс переменных среды.) - Создайте
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.x tf.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.