Entrenamiento de modelos de PyTorch a gran escala con Azure Machine Learning

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

En este artículo, aprenderá a entrenar, ajustar hiperparámetros e implementar un modelo de PyTorch mediante el SDK v2 de Python de Azure Machine Learning.

Usará scripts de ejemplo para clasificar imágenes de pollos y pavos para crear una red neuronal de aprendizaje profundo (DNN) basada en el tutorial de aprendizaje de transferencia de PyTorch. El aprendizaje por transferencia es una técnica que aplica los conocimientos que se adquieren al resolver un problema en un problema diferente, pero relacionado. El aprendizaje por transferencia reduce el proceso de entrenamiento, ya que requiere menos datos, tiempo y recursos de proceso que el entrenamiento que se realiza desde cero. Para más información sobre el aprendizaje por transferencia, consulte Aprendizaje profundo frente a aprendizaje automático.

Tanto si va a entrenar un modelo de PyTorch de aprendizaje profundo desde el principio como si va a incorporar un modelo existente a la nube, puede usar Azure Machine Learning para escalar horizontalmente trabajos de entrenamiento de código abierto mediante recursos de proceso en la nube elástica. Puede compilar, implementar y supervisar modelos de nivel de producción, así como crear versiones de dichos mismos, mediante Azure Machine Learning.

Requisitos previos

  • Suscripción a Azure. Si todavía no la tiene, cree una cuenta gratuita.
  • Ejecute el código de este artículo mediante una instancia de proceso de Azure Machine Learning o en su propio Jupyter Notebook.
    • Instancia de Proceso de Azure Machine Learning (no se necesitan descargas ni instalación):
      • Complete el Inicio rápido: Introducción a Azure Machine Learning para crear un servidor de cuadernos dedicado ya cargado con el SDK y el repositorio de ejemplo.
      • En la pestaña Ejemplos de la sección Cuadernos del área de trabajo, busque un cuaderno completado y expandido; para ello, vaya a este directorio: SDK v2/sdk/python/jobs/single-step/pytorch/train-hyperparameter-tune-deploy-with-pytorch
    • Su servidor de Jupyter Notebook:

También puede encontrar una versión de cuaderno de Jupyter completada de esta guía en la página de ejemplos de GitHub.

Para poder ejecutar el código de este artículo a fin de crear un clúster de GPU, deberá solicitar un aumento de cuota para el área de trabajo.

Configuración del trabajo

En esta sección se configura el trabajo para el entrenamiento mediante la carga de los paquetes de Python necesarios, la conexión a un área de trabajo, la creación de un recurso de proceso para ejecutar un trabajo de comando y la creación de un entorno para ejecutar el trabajo.

Conexión a un área de trabajo

En primer lugar, debe conectarse al área de trabajo de Azure Machine Learning. El área de trabajo es el recurso de nivel superior para el servicio. Proporciona un lugar centralizado para trabajar con todos los artefactos que cree al usar Azure Machine Learning.

Usaremos DefaultAzureCredential para obtener acceso al área de trabajo. Esta credencial es capaz de manejar la mayoría de los escenarios de autenticación del SDK de Azure.

Si DefaultAzureCredential no funciona, consulte azure.identity package o Configurar autenticación para obtener más credenciales disponibles.

# Handle to the workspace
from azure.ai.ml import MLClient

# Authentication package
from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()

Si prefiere usar un explorador para iniciar sesión y autenticarse, debe quitar la marca de comentario del código siguiente y usarlo en su lugar.

# Handle to the workspace
# from azure.ai.ml import MLClient

# Authentication package
# from azure.identity import InteractiveBrowserCredential
# credential = InteractiveBrowserCredential()

A continuación, obtenga un identificador para el área de trabajo proporcionando el identificador de suscripción, el nombre del grupo de recursos y el nombre del área de trabajo. Para buscar estos parámetros:

  1. Busque el nombre del área de trabajo en la esquina superior derecha de la barra de herramientas de Estudio de Azure Machine Learning.
  2. Seleccione el nombre del área de trabajo para mostrar el identificador de suscripción y el grupo de recursos.
  3. Copie los valores del grupo de recursos y el identificador de suscripción en el código.
# Get a handle to the workspace
ml_client = MLClient(
    credential=credential,
    subscription_id="<SUBSCRIPTION_ID>",
    resource_group_name="<RESOURCE_GROUP>",
    workspace_name="<AML_WORKSPACE_NAME>",
)

El resultado de la ejecución de este script es un manipulador del área de trabajo que puede usar para administrar otros recursos y trabajos.

Nota:

La creación de MLClient no conecta al cliente con el área de trabajo. La inicialización del cliente es lenta y espera a la primera vez que necesite hacer una llamada. En este artículo, esto sucede durante la creación del proceso.

Creación de un recurso de proceso para ejecutar el trabajo

Azure Machine Learning necesita un recurso de proceso para ejecutar un trabajo. Este recurso puede ser máquinas de un solo nodo o de varios nodos con sistema operativo Linux o Windows, o un tejido de proceso específico, como Spark.

En el siguiente script de ejemplo, aprovisionamos un clúster de proceso de Linux. Puede ver la página de precios de Azure Machine Learning para obtener la lista completa de los tamaños y precios de las máquinas virtuales. Dado que necesitamos un clúster de GPU para este ejemplo, vamos a elegir un modelo STANDARD_NC6 y crear un proceso de Azure Machine Learning.

from azure.ai.ml.entities import AmlCompute

gpu_compute_target = "gpu-cluster"

try:
    # let's see if the compute target already exists
    gpu_cluster = ml_client.compute.get(gpu_compute_target)
    print(
        f"You already have a cluster named {gpu_compute_target}, we'll reuse it as is."
    )

except Exception:
    print("Creating a new gpu compute target...")

    # Let's create the Azure ML compute object with the intended parameters
    gpu_cluster = AmlCompute(
        # Name assigned to the compute cluster
        name="gpu-cluster",
        # Azure ML Compute is the on-demand VM service
        type="amlcompute",
        # VM Family
        size="STANDARD_NC6s_v3",
        # Minimum running nodes when there is no job running
        min_instances=0,
        # Nodes in cluster
        max_instances=4,
        # How many seconds will the node running after the job termination
        idle_time_before_scale_down=180,
        # Dedicated or LowPriority. The latter is cheaper but there is a chance of job termination
        tier="Dedicated",
    )

    # Now, we pass the object to MLClient's create_or_update method
    gpu_cluster = ml_client.begin_create_or_update(gpu_cluster).result()

print(
    f"AMLCompute with name {gpu_cluster.name} is created, the compute size is {gpu_cluster.size}"
)

Creación de un entorno de trabajo

Para ejecutar un trabajo de Azure Machine Learning, necesita un entorno. Un entorno de Azure Machine Learning encapsula las dependencias (como el tiempo de ejecución de software y las bibliotecas) necesarias para ejecutar el script de entrenamiento de aprendizaje automático en el recurso de proceso. Este entorno es similar a un entorno de Python en la máquina local.

Azure Machine Learning le permite usar un entorno mantenido (o listo) o crear un entorno personalizado mediante una imagen de Docker o una configuración de Conda. En este artículo, reutilizará el entorno de Azure Machine Learning mantenido AzureML-pytorch-1.9-ubuntu18.04-py37-cuda11-gpu. Use la versión más reciente de este entorno mediante la directiva @latest.

curated_env_name = "AzureML-pytorch-1.9-ubuntu18.04-py37-cuda11-gpu@latest"

Configuración y envío del trabajo de entrenamiento

En esta sección, comenzaremos introduciendo los datos para el entrenamiento. A continuación, explicaremos cómo ejecutar un trabajo de entrenamiento mediante un script de entrenamiento que hemos proporcionado. Aprenderá a compilar el trabajo de entrenamiento mediante la configuración del comando para ejecutar el script de entrenamiento. A continuación, enviará el trabajo de entrenamiento para que se ejecute en Azure Machine Learning.

Obtención de los datos de entrenamiento

Puede usar el conjunto de datos en este archivo comprimido. El conjunto de datos consta de aproximadamente 120 imágenes de entrenamiento para dos clases (pavos y pollos), con 100 imágenes de validación para cada clase. Las imágenes son un subconjunto del conjunto de datos Open Images v5. El script de entrenamiento pytorch_train.py descarga y extrae el conjunto de datos.

Preparar el script de entrenamiento

En la sección de requisitos previos, proporcionamos el script de entrenamiento pytorch_train.py. En la práctica, debería poder usar cualquier script de entrenamiento personalizado tal cual y ejecutarlo con Azure Machine Learning sin tener que modificar el código.

El script de entrenamiento proporcionado descarga los datos, entrena un modelo y registra el modelo.

Compilación del trabajo de entrenamiento

Ahora que tiene todos los recursos necesarios para ejecutar el trabajo, es el momento de compilar mediante el SDK de Python v2 de Azure Machine Learning. En este ejemplo, se crea un command.

Un command de Azure Machine Learning es un recurso que especifica todos los detalles necesarios para ejecutar el código de entrenamiento en la nube. Estos detalles incluyen las entradas y salidas, el tipo de hardware que se va a usar, el software que se va a instalar y cómo ejecutar el código. command contiene información para ejecutar un único comando.

Configuración del comando

Usará el propósito general command para ejecutar el script de entrenamiento y realizar las tareas deseadas. Cree un objeto command para especificar los detalles de configuración del trabajo de entrenamiento.

from azure.ai.ml import command
from azure.ai.ml import Input

job = command(
    inputs=dict(
        num_epochs=30, learning_rate=0.001, momentum=0.9, output_dir="./outputs"
    ),
    compute=gpu_compute_target,
    environment=curated_env_name,
    code="./src/",  # location of source code
    command="python pytorch_train.py --num_epochs ${{inputs.num_epochs}} --output_dir ${{inputs.output_dir}}",
    experiment_name="pytorch-birds",
    display_name="pytorch-birds-image",
)
  • Las entradas de este comando incluyen el número de épocas, velocidad de aprendizaje, impulso y directorio de salida.
  • Para los valores de parámetro:
    1. Proporcione el clúster de proceso gpu_compute_target = "gpu-cluster" que creó para ejecutar este comando.
    2. Proporcione el entorno mantenido AzureML-pytorch-1.9-ubuntu18.04-py37-cuda11-gpu que ha inicializado anteriormente.
    3. Si no usa el cuaderno completado en la carpeta Ejemplos, especifique la ubicación del archivo pytorch_train.py.
    4. Configure la propia acción de la línea de comandos; en este caso, el comando es python pytorch_train.py. Puede acceder a las entradas y salidas en el comando a través de la notación ${{ ... }}.
    5. Configure algunos metadatos, como el nombre para mostrar y el nombre del experimento, donde un experimento es un contenedor para todas las iteraciones que se realizan en un proyecto determinado. Todos los trabajos enviados en el mismo nombre de experimento se enumerarán de manera correlativa en Estudio de Azure Machine Learning.

Enviar el archivo

Ahora es el momento de enviar el trabajo para que se ejecute en Azure Machine Learning. Esta vez se usa create_or_update en ml_client.jobs.

ml_client.jobs.create_or_update(job)

Una vez completado, el trabajo registra un modelo en el área de trabajo (como resultado del entrenamiento) y genera un vínculo para ver el trabajo en Estudio de Azure Machine Learning.

Advertencia

Azure Machine Learning ejecuta scripts de entrenamiento mediante la copia de todo el directorio de origen. Si tiene información confidencial que no quiere cargar, use un archivo .ignore o no la incluya en el directorio de origen.

¿Qué ocurre durante la ejecución del trabajo?

Durante la ejecución del trabajo, este pasa por las fases siguientes:

  • Preparando: se crea una imagen de Docker según el entorno definido. La imagen se carga en el registro de contenedor del área de trabajo y se almacena en memoria caché para ejecuciones posteriores. Los registros también se transmiten al historial de trabajos y se pueden consultar para supervisar el progreso. Si se especifica un entorno mantenido, se usa la imagen almacenada en caché que respalda el entorno mantenido.

  • Escalado: el clúster intenta escalar verticalmente si requiere más nodos para ejecutar la ejecución de los que están disponibles actualmente.

  • En ejecución: todos los scripts de la carpeta de scripts src se cargan en el destino de proceso, se montan o copian los almacenes de datos y se ejecuta el script. Las salidas de stdout y la carpeta ./logs se transmiten al historial de trabajos y se pueden usar para supervisar el trabajo.

Ajuste de hiperparámetros del modelo

Ha entrenado el modelo con un conjunto de parámetros. Veamos ahora si puede mejorar aún más la precisión del modelo. Puede ajustar y optimizar los hiperparámetros del modelo mediante las funcionalidades de sweep de Azure Machine Learning.

Para ajustar los hiperparámetros del modelo, defina el espacio de parámetros en el que se va a buscar durante el entrenamiento. Para ello, reemplace algunos de los parámetros pasados al trabajo de entrenamiento con entradas especiales del paquete azure.ml.sweep.

Puesto que el script de entrenamiento usa una programación de velocidad de aprendizaje para degradar la velocidad de aprendizaje cada varias épocas, puede ajustar la velocidad de aprendizaje inicial y los parámetros de impulso.

from azure.ai.ml.sweep import Uniform

# we will reuse the command_job created before. we call it as a function so that we can apply inputs
job_for_sweep = job(
    learning_rate=Uniform(min_value=0.0005, max_value=0.005),
    momentum=Uniform(min_value=0.9, max_value=0.99),
)

A continuación, puede configurar el barrido en el trabajo de comando, con algunos parámetros específicos del barrido, como la métrica principal para inspeccionar y el algoritmo de muestreo que se va a usar.

En el código siguiente se usa el muestreo aleatorio para probar diferentes conjuntos de configuración de hiperparámetros en un intento de maximizar la métrica principal, best_val_acc.

También definimos una directiva de terminación anticipada, BanditPolicy, para finalizar las ejecuciones con un rendimiento deficiente. BanditPolicy finaliza cualquier ejecución que no se encuentre dentro del factor de demora de la métrica de evaluación principal. Aplique esta directiva cada época (ya que notificamos nuestra métrica best_val_acc cada época y evaluation_interval=1). Observe que retrasamos la primera evaluación de directivas hasta después de las primeras 10 épocas (delay_evaluation=10).

from azure.ai.ml.sweep import BanditPolicy

sweep_job = job_for_sweep.sweep(
    compute="gpu-cluster",
    sampling_algorithm="random",
    primary_metric="best_val_acc",
    goal="Maximize",
    max_total_trials=8,
    max_concurrent_trials=4,
    early_termination_policy=BanditPolicy(
        slack_factor=0.15, evaluation_interval=1, delay_evaluation=10
    ),
)

Ahora, puede enviar este trabajo como antes. Esta vez, va a ejecutar un trabajo de barrido que barrerá el trabajo de entrenamiento.

returned_sweep_job = ml_client.create_or_update(sweep_job)

# stream the output and wait until the job is finished
ml_client.jobs.stream(returned_sweep_job.name)

# refresh the latest status of the job after streaming
returned_sweep_job = ml_client.jobs.get(name=returned_sweep_job.name)

Puede supervisar el trabajo mediante el vínculo de la interfaz de usuario de Studio que se presenta durante la ejecución del trabajo.

Identificación del mejor modelo

Una vez completadas todas las ejecuciones, puede encontrar la ejecución que generó el modelo con la mayor precisión.

from azure.ai.ml.entities import Model

if returned_sweep_job.status == "Completed":

    # First let us get the run which gave us the best result
    best_run = returned_sweep_job.properties["best_child_run_id"]

    # lets get the model from this run
    model = Model(
        # the script stores the model as "outputs"
        path="azureml://jobs/{}/outputs/artifacts/paths/outputs/".format(best_run),
        name="run-model-example",
        description="Model created from run.",
        type="custom_model",
    )

else:
    print(
        "Sweep job status: {}. Please wait until it completes".format(
            returned_sweep_job.status
        )
    )

Implementación del modelo como un punto de conexión en línea

Ahora puede implementar el modelo como punto de conexión en línea, es decir, como un servicio web en la nube de Azure.

Para implementar un Machine Learning Service, normalmente necesita lo siguiente:

  • Los recursos del modelo que desea implementar. Estos recursos incluyen el archivo y los metadatos del modelo que ya registró en el trabajo de entrenamiento.
  • Algún código que se ejecutará como servicio. El código ejecuta el modelo en una solicitud de entrada determinada (un script de entrada). El script de entrada recibe los datos enviados a un servicio web implementado y los pasa al modelo. Una vez que el modelo procesa los datos, el script devuelve la respuesta del modelo al cliente. El script es específico para el modelo, y debe entender los datos que el modelo espera y devuelve. Cuando se usa un modelo de MLFlow, Azure Machine Learning crea automáticamente este script.

Para más información sobre la implementación, consulte Implementación y puntuación de un modelo de Machine Learning con un punto de conexión en línea administrado mediante el SDK de Python v2.

Creación de un punto de conexión en línea

Como primer paso para implementar el modelo, debe crear el punto de conexión en línea. El nombre del punto de conexión debe ser único en toda la región de Azure. En este artículo, creará un nombre único mediante un identificador único universal (UUID).

import uuid

# Creating a unique name for the endpoint
online_endpoint_name = "aci-birds-endpoint-" + str(uuid.uuid4())[:8]
from azure.ai.ml.entities import ManagedOnlineEndpoint

# create an online endpoint
endpoint = ManagedOnlineEndpoint(
    name=online_endpoint_name,
    description="Classify turkey/chickens using transfer learning with PyTorch",
    auth_mode="key",
    tags={"data": "birds", "method": "transfer learning", "framework": "pytorch"},
)

endpoint = ml_client.begin_create_or_update(endpoint).result()

print(f"Endpoint {endpoint.name} provisioning state: {endpoint.provisioning_state}")

Después de crear el punto de conexión, puede recuperarlo de la siguiente manera:

endpoint = ml_client.online_endpoints.get(name=online_endpoint_name)

print(
    f'Endpint "{endpoint.name}" with provisioning state "{endpoint.provisioning_state}" is retrieved'
)

Implementación del modelo en el punto de conexión

Ahora puede implementar el modelo con el script de entrada. Un punto de conexión puede tener varias implementaciones. Mediante reglas, el punto de conexión puede dirigir el tráfico a estas implementaciones.

En el siguiente código, creará una única implementación que controla el 100 % del tráfico entrante. Se especificó un nombre de color arbitrario aci-blue para la implementación. También puede usar cualquier otro nombre, como aci-green o aci-red para la implementación.

Código para implementar el modelo en el punto de conexión:

  • Implementa la mejor versión del modelo que registró anteriormente.
  • Puntúa el modelo mediante el archivo score.py.
  • Usa el entorno mantenido (que ha especificado anteriormente) para realizar la inferencia.
from azure.ai.ml.entities import (
    ManagedOnlineDeployment,
    Model,
    Environment,
    CodeConfiguration,
)

online_deployment_name = "aci-blue"

# create an online deployment.
blue_deployment = ManagedOnlineDeployment(
    name=online_deployment_name,
    endpoint_name=online_endpoint_name,
    model=model,
    environment=curated_env_name,
    code_configuration=CodeConfiguration(code="./score/", scoring_script="score.py"),
    instance_type="Standard_NC6s_v3",
    instance_count=1,
)

blue_deployment = ml_client.begin_create_or_update(blue_deployment).result()

Nota

Esta implementación tardará un poco en finalizar.

Prueba del modelo implementado

Ahora que implementó el modelo en el punto de conexión, puede predecir la salida del modelo implementado mediante el método invoke en el punto de conexión.

Para probar el punto de conexión, vamos a usar una imagen de ejemplo para la predicción. En primer lugar, vamos a mostrar la imagen.

# install pillow if PIL cannot imported
%pip install pillow
import json
from PIL import Image
import matplotlib.pyplot as plt

%matplotlib inline
plt.imshow(Image.open("test_img.jpg"))

Cree una función para dar formato y cambiar el tamaño de la imagen.

# install torch and torchvision if needed
%pip install torch
%pip install torchvision

import torch
from torchvision import transforms


def preprocess(image_file):
    """Preprocess the input image."""
    data_transforms = transforms.Compose(
        [
            transforms.Resize(256),
            transforms.CenterCrop(224),
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
        ]
    )

    image = Image.open(image_file)
    image = data_transforms(image).float()
    image = torch.tensor(image)
    image = image.unsqueeze(0)
    return image.numpy()

Dé formato a la imagen y conviértela en un archivo JSON.

image_data = preprocess("test_img.jpg")
input_data = json.dumps({"data": image_data.tolist()})
with open("request.json", "w") as outfile:
    outfile.write(input_data)

Después, puede invocar el punto de conexión con este JSON e imprimir el resultado.

# test the blue deployment
result = ml_client.online_endpoints.invoke(
    endpoint_name=online_endpoint_name,
    request_file="request.json",
    deployment_name=online_deployment_name,
)

print(result)

Limpieza de recursos

Si ya no necesita el punto de conexión, elimínelo para dejar de usar el recurso. Asegúrese de que ninguna otra implementación use el punto de conexión antes de eliminarlo.

ml_client.online_endpoints.begin_delete(name=online_endpoint_name)

Nota

Esta limpieza tardará un poco en finalizar.

Pasos siguientes

En este artículo ha entrenado y registrado un aprendizaje profundo y una red neuronal mediante PyTorch en Azure Machine Learning. También ha implementado el modelo en un punto de conexión en línea. Consulte estos otros artículos para más información sobre Azure Machine Learning.