Guía de entrenamiento distribuido de GPU (SDK v2)

SE APLICA A: SDK de Python azure-ai-ml v2 (actual)

Obtenga más información sobre el uso de código de entrenamiento distribuido de GPU en Azure Machine Learning. Este artículo le ayuda a ejecutar el código de entrenamiento distribuido existente, y ofrece sugerencias y ejemplos que puede seguir para cada marco:

  • Interfaz de paso de mensajes (MPI)
    • Horovod
    • Variables de entorno de Open MPI
  • PyTorch
  • TensorFlow
  • Aceleración de entrenamiento de GPU con InfiniBand

Requisitos previos

Revise los conceptos básicos de entrenamiento distribuido de GPU, como el paralelismo de datos, el paralelismo de datos distribuido y el paralelismo de modelos.

Sugerencia

Si no sabe qué tipo de paralelismo usar, más del 90 % de las veces debe tratarse del paralelismo de datos distribuido.

MPI

Azure Machine Learning ofrece un trabajo de MPI para iniciar un determinado número de procesos en cada nodo. Azure Machine Learning crea el comando de inicio de MPI completo (mpirun) en segundo plano. No puede proporcionar sus propios comandos completos de iniciador de nodo principal, como mpirun o DeepSpeed launcher.

Sugerencia

La imagen base de Docker que usa un trabajo de MPI de Azure Machine Learning debe tener instalada una biblioteca de MPI. Open MPI está incluido en todas las imágenes base de GPU de Azure Machine Learning. Si usa una imagen de Docker personalizada, es responsable de asegurarse de que esta incluya una biblioteca de MPI. Se recomienda Open MPI, pero también puede usar otra implementación de MPI, como Intel MPI. Azure Machine Learning también proporciona entornos mantenidos de marcos populares.

Para ejecutar el entrenamiento distribuido mediante MPI, siga estos pasos:

  1. Use un entorno de Azure Machine Learning con el marco de aprendizaje profundo y MPI preferidos. Azure Machine Learning proporciona un entornos mantenidos para marcos populares. O bien, cree un entorno personalizado con el marco de aprendizaje profundo preferido y MPI.
  2. Defina command con instance_count. instance_count debe ser igual al número de GPU por nodo en el inicio por proceso, o establecerse en 1 (valor predeterminado) en el inicio por nodo si el script de usuario es responsable de iniciar los procesos por nodo.
  3. Use el parámetro distribution de command para especificar la configuración de MpiDistribution.
from azure.ai.ml import command, MpiDistribution

job = command(
    code="./src",  # local path where the code is stored
    command="python train.py --epochs ${{inputs.epochs}}",
    inputs={"epochs": 1},
    environment="AzureML-tensorflow-2.7-ubuntu20.04-py38-cuda11-gpu@latest",
    compute="gpu-cluster",
    instance_count=2,
    distribution=MpiDistribution(process_count_per_instance=2),
    display_name="tensorflow-mnist-distributed-horovod-example"
    # experiment_name: tensorflow-mnist-distributed-horovod-example
    # description: Train a basic neural network with TensorFlow on the MNIST dataset, distributed via Horovod.
)

Horovod

Use la configuración del trabajo de MPI si usa Horovod para el entrenamiento distribuido con el marco de aprendizaje profundo.

Asegúrese de que el código siga estas sugerencias:

  • El código de entrenamiento se instrumenta correctamente con Horovod antes de agregar los elementos de Azure Machine Learning.
  • El entorno de Azure Machine Learning contiene Horovod y MPI. Los entornos de GPU mantenidos de PyTorch y TensorFlow vienen preconfigurados con Horovod y sus dependencias.
  • Cree command con la distribución deseada.

Ejemplo de Horovod

Variables de entorno de Open MPI

Al ejecutar trabajos de MPI con imágenes de Open MPI, puede usar las siguientes variables de entorno de cada proceso:

  1. OMPI_COMM_WORLD_RANK: el rango del proceso
  2. OMPI_COMM_WORLD_SIZE: el tamaño del mundo
  3. AZ_BATCH_MASTER_NODE: la dirección principal con puerto, MASTER_ADDR:MASTER_PORT
  4. OMPI_COMM_WORLD_LOCAL_RANK: la clasificación local del proceso en el nodo
  5. OMPI_COMM_WORLD_LOCAL_SIZE: el número de procesos en el nodo

Sugerencia

A pesar del nombre, la variable de entorno OMPI_COMM_WORLD_NODE_RANK no se corresponde con el NODE_RANK. Para usar el iniciador por nodo, establezca process_count_per_node=1 y use OMPI_COMM_WORLD_RANK como NODE_RANK.

PyTorch

Azure Machine Learning permite ejecutar trabajos distribuidos mediante las funciones de entrenamiento distribuido nativas de PyTorch (torch.distributed).

Sugerencia

En el caso del paralelismo de datos, las instrucciones oficiales de PyTorch son usar DistributedDataParallel (DDP) en lugar de DataParallel para el entrenamiento distribuido de un solo nodo y de varios nodos. PyTorch además recomienda usar DistributedDataParallel en lugar del paquete de multiprocesamiento. Por tanto, la documentación y los ejemplos de Azure Machine Learning se centran en el entrenamiento DistributedDataParallel.

Inicialización de grupo de control de proceso

La columna vertebral de cualquier entrenamiento distribuido se basa en un grupo de procesos que se conocen entre sí y que pueden comunicarse entre ellos mediante un back-end. En PyTorch, el grupo de control de proceso se crea al llamar a torch.distributed.init_process_group en todos los procesos distribuidos para formar colectivamente un grupo de control de proceso.

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

Los back-end de comunicación más comunes que se usan son mpi, nccl y gloo. En el caso del entrenamiento basado en GPU, se recomienda nccl para lograr el mejor rendimiento, y se debe usar siempre que sea posible.

init_method indica cómo pueden detectarse los procesos entre sí, cómo se inicializan, y comprueba el grupo de control de proceso mediante el back-end de comunicación. De forma predeterminada, si no se especifica init_method, PyTorch usa el método de inicialización de la variable de entorno (env://). init_method es el método de inicialización recomendado que se usa en el código de entrenamiento para ejecutar PyTorch distribuido en Azure Machine Learning. PyTorch busca las siguientes variables de entorno para la inicialización:

  • MASTER_ADDR: dirección IP de la máquina que hospeda el proceso con la clasificación 0
  • MASTER_PORT: puerto libre de la máquina que hospeda el proceso con la clasificación 0
  • WORLD_SIZE: número total de procesos. Debe ser igual al número total de dispositivos (GPU) usados para el entrenamiento distribuido
  • RANK: clasificación (global) del proceso actual. Los valores posibles son de 0 a (tamaño mundial - 1)

Para obtener más información sobre la inicialización de grupos de control de procesos, vea la documentación de PyTorch.

Muchas aplicaciones también necesitan las siguientes variables de entorno:

  • LOCAL_RANK: clasificación local (relativa) del proceso dentro del nodo. Los valores posibles son de 0 a (n.º de procesos en el nodo - 1). Esta información es útil porque muchas operaciones, como la preparación de datos, solo se deben realizar una vez por nodo, normalmente en local_rank = 0.
  • NODE_RANK: clasificación del nodo para el entrenamiento de varios nodos. Los valores posibles son de 0 a (número total de nodos - 1).

No es necesario usar una utilidad de iniciador como torch.distributed.launch. Para ejecutar un trabajo distribuido de PyTorch:

  1. Especifique el script de entrenamiento y los argumentos.
  2. Cree command y especifique el tipo como PyTorch y process_count_per_instance en el parámetro distribution. process_count_per_instance corresponde al número total de procesos que desea ejecutar para su trabajo. process_count_per_instance normalmente debe ser igual a # of GPUs per node. Si no se especifica process_count_per_instance, Azure Machine Learning iniciará de manera predeterminada un proceso por nodo.

Azure Machine Learning establece las variables de entorno MASTER_ADDR, MASTER_PORT, WORLD_SIZE y NODE_RANK en cada nodo, además de las variables de entorno RANK y LOCAL_RANK de nivel de proceso.

from azure.ai.ml import command
from azure.ai.ml.entities import Data
from azure.ai.ml import Input
from azure.ai.ml import Output
from azure.ai.ml.constants import AssetTypes

# === Note on path ===
# can be can be a local path or a cloud path. AzureML supports https://`, `abfss://`, `wasbs://` and `azureml://` URIs.
# Local paths are automatically uploaded to the default datastore in the cloud.
# More details on supported paths: https://docs.microsoft.com/azure/machine-learning/how-to-read-write-data-v2#supported-paths

inputs = {
    "cifar": Input(
        type=AssetTypes.URI_FOLDER, path=returned_job.outputs.cifar.path
    ),  # path="azureml:azureml_stoic_cartoon_wgb3lgvgky_output_data_cifar:1"), #path="azureml://datastores/workspaceblobstore/paths/azureml/stoic_cartoon_wgb3lgvgky/cifar/"),
    "epoch": 10,
    "batchsize": 64,
    "workers": 2,
    "lr": 0.01,
    "momen": 0.9,
    "prtfreq": 200,
    "output": "./outputs",
}

from azure.ai.ml.entities import ResourceConfiguration

job = command(
    code="./src",  # local path where the code is stored
    command="python train.py --data-dir ${{inputs.cifar}} --epochs ${{inputs.epoch}} --batch-size ${{inputs.batchsize}} --workers ${{inputs.workers}} --learning-rate ${{inputs.lr}} --momentum ${{inputs.momen}} --print-freq ${{inputs.prtfreq}} --model-dir ${{inputs.output}}",
    inputs=inputs,
    environment="azureml-acpt-pytorch-2.0-cuda11.7:26",
    instance_count=2,  # In this, only 2 node cluster was created.
    distribution={
        "type": "PyTorch",
        # set process count to the number of gpus per node
        # NC6s_v3 has only 1 GPU
        "process_count_per_instance": 1,
    },
)
job.resources = ResourceConfiguration(
    instance_type="Standard_NC6s_v3", instance_count=2
)  # Serverless compute resources

Ejemplo de Pytorch

DeepSpeed

Azure Machine Learning admite DeepSpeed como ciudadano de primera clase para ejecutar trabajos distribuidos con escalabilidad casi lineal en términos de:

  • Aumento del tamaño del modelo
  • Aumento del número de GPU

DeepSpeed se puede habilitar mediante la distribución de Pytorch o MPI para ejecutar el entrenamiento distribuido. Azure Machine Learning admite el iniciador DeepSpeed para iniciar el entrenamiento distribuido, así como el ajuste automático para obtener una configuración óptima ds.

Puede usar un entorno mantenido para un entorno listo para usar con las últimas tecnologías de última generación, como DeepSpeed, ORT, MSSCCL y Pytorch para los trabajos de entrenamiento de DeepSpeed.

Ejemplo de DeepSpeed

  • Para obtener ejemplos de entrenamiento y ajuste automático de DeepSpeed, consulte estas carpetas.

TensorFlow

Si usa TensorFlow distribuido nativo en el código de entrenamiento, como la API tf.distribute.Strategy de TensorFlow 2.x, puede iniciar el trabajo distribuido mediante Azure Machine Learning con parámetros distribution o el objeto TensorFlowDistribution.

# create the command
job = command(
    code="./src",  # local path where the code is stored
    command="python main.py --epochs ${{inputs.epochs}} --model-dir ${{inputs.model_dir}}",
    inputs={"epochs": 1, "model_dir": "outputs/keras-model"},
    environment="AzureML-tensorflow-2.4-ubuntu18.04-py37-cuda11-gpu@latest",
    compute="cpu-cluster",
    instance_count=2,
    # distribution = {"type": "mpi", "process_count_per_instance": 1},
    # distribution={
    #     "type": "tensorflow",
    #     "parameter_server_count": 1,  # for legacy TensorFlow 1.x
    #     "worker_count": 2,
    #     "added_property": 7,
    # },
    # distribution = {
    #        "type": "pytorch",
    #        "process_count_per_instance": 4,
    #        "additional_prop": {"nested_prop": 3},
    #    },
    display_name="tensorflow-mnist-distributed-example"
    # experiment_name: tensorflow-mnist-distributed-example
    # description: Train a basic neural network with TensorFlow on the MNIST dataset, distributed via TensorFlow.
)

# can also set the distribution in a separate step and using the typed objects instead of a dict
job.distribution = TensorFlowDistribution(worker_count=2)

Si el script de entrenamiento usa la estrategia de servidor de parámetros para el entrenamiento distribuido, como en TensorFlow 1.x heredado, también debe especificar el número de servidores de parámetros que se van a usar en el trabajo, dentro del parámetro distribution de command. En lo anterior, por ejemplo, "parameter_server_count" : 1 y "worker_count": 2.

TF_CONFIG

En TensorFlow, la variable de entorno TF_CONFIG es necesaria para el entrenamiento en varios equipos. En los trabajos de TensorFlow, Azure Machine Learning configura y establece la variable TF_CONFIG correctamente en cada trabajo antes de ejecutar el script de entrenamiento.

Puede acceder a TF_CONFIG desde el script de entrenamiento si necesita: os.environ['TF_CONFIG'].

Ejemplo de TF_CONFIG establecido en un nodo de trabajo principal:

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

Ejemplo de TensorFlow

Aceleración de entrenamiento de GPU distribuida con InfiniBand

A medida que aumenta el número de máquinas virtuales que entrenan un modelo, el tiempo necesario para entrenar el modelo debe disminuir. Lo ideal es que la disminución del tiempo sea linealmente proporcional al número de máquinas virtuales de entrenamiento. Por ejemplo, si entrenar un modelo en una máquina virtual tarda 100 segundos, el entrenamiento del mismo modelo en dos máquinas virtuales debería tardar 50 segundos. El entrenamiento del modelo en cuatro máquinas virtuales debe tardar 25 segundos, y así sucesivamente.

InfiniBand puede ser un factor importante para lograr este escalado lineal. InfiniBand permite la comunicación de GPU a GPU de baja latencia entre los nodos de un clúster. InfiniBand requiere hardware especializado para funcionar. Algunas series de máquinas virtuales de Azure, en concreto NC, ND y H, ahora tienen máquinas virtuales compatibles con RDMA que admiten SR-IOV e InfiniBand. Estas máquinas virtuales se comunican a través de la red InfiniBand de baja latencia y alto ancho de banda, que es mucho más eficaz que la conectividad basada en Ethernet. SR-IOV para InfiniBand permite un rendimiento casi sin sistema operativo para cualquier biblioteca MPI (MPI se usa en muchos marcos de entrenamiento distribuidos y herramientas, incluido el software NCCL de NVIDIA). Estas SKU están diseñadas para satisfacer las necesidades de cargas de trabajo de aprendizaje automático aceleradas por GPU con uso intensivo de cálculo. Para obtener más información, vea Aceleración del entrenamiento distribuido en Azure Machine Learning con SR-IOV.

Normalmente, las SKU de máquina virtual con una "r" en su nombre contienen el hardware InfiniBand necesario, mientras que las que no tienen una "r", normalmente no. ("r" es una referencia a RDMA, que significa acceso directo a memoria remoto). Por ejemplo, la SKU de máquina virtual Standard_NC24rs_v3 está habilitada para InfiniBand, pero la SKU Standard_NC24s_v3. Además de las funcionalidades de InfiniBand, las especificaciones entre estas dos SKU son en gran medida las mismas. Ambas tienen 24 núcleos, 448 GB de RAM, 4 GPU de la misma SKU, etc. Obtenga más información sobre las SKU de máquina habilitadas para RDMA e InfiniBand.

Advertencia

La SKU de máquina de generación anterior Standard_NC24r está habilitada para RDMA, pero no contiene el hardware de SR-IOV necesario para InfiniBand.

Si crea un clúster AmlCompute de uno de estos tamaños compatibles con RDMA habilitados para InfiniBand, la imagen del sistema operativo viene con el controlador Mellanox OFED necesario para habilitar InfiniBand preinstalado y preconfigurado.

Pasos siguientes