Entraîner des modèles PyTorch à grande échelle avec Azure Machine Learning

S’APPLIQUE À : Kit de développement logiciel (SDK) Python azure-ai-ml v2 (actuelle)

Dans cet article, vous allez apprendre à entraîner, à optimiser les hyperparamètres et à déployer un modèle PyTorch à l’aide du Kit de développement logiciel (SDK) Python Azure Machine Learning (AzureML) v2.

Vous utiliserez les exemples de scripts dans cet article pour classifier des images de poulets et de dindes afin de créer un réseau neuronal de Deep Learning (DNN) basé sur le tutoriel sur l’apprentissage de transfert de PyTorch. L’apprentissage de transfert est une technique qui applique les connaissances acquises lors de la résolution d’un problème à un problème différent, mais connexe. L’apprentissage de transfert permet de raccourcir le processus d’entraînement en demandant moins de données, de temps et de ressources de calcul qu’un entraînement partant de zéro. Pour en savoir plus sur l’apprentissage de transfert, consultez l’article Deep Learning et Machine Learning.

Que vous soyez en train d’entraîner un modèle PyTorch de Deep Learning ou que vous déposiez un modèle existant dans le cloud, vous pouvez utiliser AzureML pour effectuer un scale-out des tâches d’entraînement open source à l’aide de ressources de calcul de cloud élastique. Vous pouvez générer, déployer, mettre à jour et surveiller des modèles de niveau production avec AzureML.

Prérequis

Pour tirer parti de cet article, vous devez :

  • Avoir accès à un abonnement Azure. Si vous n’en avez pas encore, créez un compte gratuit.
  • Exécutez le code de cet article en utilisant une instance de calcul Azure Machine Learning ou dans votre propre notebook Jupyter.
    • Instance de calcul Azure Machine Learning ; ni téléchargement ni installation nécessaires
      • Suivez le guide de démarrage rapide Prise en main d’Azure Machine Learning pour créer un serveur de notebook dédié sur lequel sont préchargés le SDK et l’exemple de dépôt.
      • Dans le dossier des exemples de Deep Learning sur le serveur de notebooks, recherchez un notebook finalisé et développé en accédant à ce répertoire : v2 > sdk > python > jobs > single-step > pytorch > train-hyperparameter-tune-deploy-with-pytorch.
    • Votre serveur de notebooks Jupyter

Vous trouverez également une version Jupyter Notebook complète de ce guide sur la page des exemples GitHub.

Avant de pouvoir exécuter le code de cet article pour créer un cluster GPU, vous devez demander une augmentation de quota pour votre espace de travail.

Configuration du travail

Cette section configure le travail pour l’entraînement en chargeant les packages Python requis, en se connectant à un espace de travail, en créant une ressource de calcul pour exécuter un travail de commande et en créant un environnement pour exécuter le travail.

Se connecter à l’espace de travail

Tout d’abord, vous devez vous connecter à votre espace de travail AzureML. L’espace de travail AzureML est la ressource de niveau supérieur du service. Il vous fournit un emplacement centralisé dans lequel utiliser tous les artefacts que vous créez quand vous utilisez Azure Machine Learning.

Nous allons utiliser DefaultAzureCredential pour accéder à l’espace de travail. Ces infos de connexion doivent être capables de gérer la plupart des scénarios d’authentification du kit SDK Azure.

Si DefaultAzureCredential ce n’est pas le cas, consultez azure-identity reference documentation ou Set up authentication pour plus d’informations d’identification disponibles.

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

# Authentication package
from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()

Si vous préférez utiliser un navigateur pour vous connecter et vous authentifier, vous devez supprimer les commentaires dans le code suivant et l’utiliser à la place.

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

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

Ensuite, obtenez un descripteur pour l’espace de travail en fournissant votre ID d’abonnement, le nom du groupe de ressources et le nom de l’espace de travail. Pour rechercher ces paramètres :

  1. Recherchez le nom de votre espace de travail dans le coin supérieur droit de la barre d’outils Azure Machine Learning studio.
  2. Sélectionnez le nom de votre espace de travail pour afficher votre groupe de ressources et votre ID d’abonnement.
  3. Copiez les valeurs du groupe de ressources et de l’ID d’abonnement dans le code.
# 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>",
)

Le résultat de l’exécution du script est un descripteur d’espace de travail que vous utiliserez pour gérer d’autres ressources et travaux.

Notes

  • La création de MLClient n’établit pas de connexion du client à l’espace de travail. L’initialisation du client est lente et elle attendra la première fois qu’il aura besoin de faire un appel. Dans cet article, cela se produit lors de la création du calcul.

Créer une ressource de calcul pour exécuter le travail

AzureML a besoin d’une ressource de calcul pour exécuter un travail. La ressource peut être constituée de machines à nœud unique ou à plusieurs nœuds avec un système d’exploitation Linux ou Windows, ou d’une structure de calcul spécifique comme Spark.

Dans l’exemple de script suivant, nous approvisionnons un compute cluster Linux. Vous pouvez voir la page Azure Machine Learning pricing pour obtenir la liste complète des tailles et des prix des machines virtuelles. Étant donné que nous avons besoin d’un cluster GPU pour cet exemple, nous allons choisir un modèle STANDARD_NC6 et créer un calcul AzureML.

from azure.ai.ml.entities import AmlCompute

gpu_compute_taget = "gpu-cluster"

try:
    # let's see if the compute target already exists
    gpu_cluster = ml_client.compute.get(gpu_compute_taget)
    print(
        f"You already have a cluster named {gpu_compute_taget}, 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_NC6",
        # 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}"
)

Créer un environnement de travail

Pour exécuter un travail AzureML, vous aurez besoin d’un environnement. Un environnement AzureML encapsule les dépendances (telles que le runtime logiciel et les bibliothèques) nécessaires pour exécuter votre script de formation Machine Learning sur votre ressource de calcul. Cet environnement est similaire à un environnement Python sur votre ordinateur local.

AzureML vous permet d’utiliser un environnement organisé (ou prêt à l’emploi) ou de créer un environnement personnalisé à l’aide d’une image Docker ou d’une configuration Conda. Dans cet article, vous allez réutiliser l’environnement AzureML AzureML-pytorch-1.9-ubuntu18.04-py37-cuda11-gpu curé. Vous utiliserez la dernière version de cet environnement à l’aide de la directive @latest.

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

Configurer et soumettre un travail de formation

Dans cette section, nous allons commencer par présenter les données pour l’entraînement. Nous allons ensuite aborder la façon d’exécuter un travail de formation à l’aide d’un script de formation que nous avons fourni. Vous apprendrez à générer le travail d’entraînement en configurant la commande pour exécuter le script d’entraînement. Ensuite, vous allez envoyer le travail d’entraînement à exécuter dans AzureML.

Obtenir les données d’entraînement

Vous utiliserez des données stockées sur un objet blob public en tant que fichier zip. Ce jeu de données se compose de 120 images d’entraînement pour chacune des deux classes (dindes et poules), avec 100 images de validation par classe. Les images sont un sous-ensemble du Jeu de données Open Images v5. Nous téléchargeons et extrayons le jeu de données dans le cadre de notre script d’entraînement pytorch_train.py.

Préparer le script d’apprentissage

Dans cet article, nous avons fourni le script d’entraînement pytorch_train.py. Dans la pratique, vous devez être capable de prendre n’importe quel script d’apprentissage personnalisé et de l’exécuter avec Azure Machine Learning sans avoir à modifier votre code.

Le script d’entraînement fourni télécharge les données, entraîne un modèle et inscrit le modèle.

Créer le travail d’entraînement

Maintenant que vous disposez de toutes les ressources nécessaires pour exécuter votre travail, il est temps de générer à l’aide du SDK Python Azure ML v2. Pour cet exemple, nous allons créer un command.

Un command AzureML est une ressource qui spécifie tous les détails nécessaires pour exécuter votre code d’entraînement dans le cloud. Ces détails incluent les entrées et sorties, le type de matériel à utiliser, le logiciel à installer et la façon d’exécuter votre code. command contient des informations pour exécuter une seule commande.

Configurer la commande

Vous utiliserez le command à usage général pour exécuter le script d’entraînement et effectuer vos tâches souhaitées. Créez un objet Command pour spécifier les détails de configuration de votre travail de formation.

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_taget,
    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",
)
  • Les entrées de cette commande incluent le nombre d’époques, le taux d’apprentissage, l’élan et le répertoire de sortie.
  • Pour les valeurs de paramètre :
    • fournissez le cluster gpu_compute_target = "gpu-cluster" de calcul que vous avez créé pour exécuter cette commande ;
    • fournissez l’environnement organisé AzureML-pytorch-1.9-ubuntu18.04-py37-cuda11-gpu que vous avez initialisé précédemment ;
    • configurez l’action de ligne de commande elle-même — dans ce cas, la commande est python pytorch_train.py. Vous pouvez accéder aux entrées et sorties dans la commande via la notation ${{ ... }} ; et
    • configurez les métadonnées telles que le nom d’affichage et le nom de l’expérience ; où une expérience est un conteneur pour toutes les itérations qu’il effectue sur un certain projet. Tous les travaux soumis sous le même nom d’expérience sont listés les uns à côtés des autres dans AzureML Studio.

Envoi du travail

Il est maintenant temps de soumettre le travail à exécuter dans Azure ML. Cette fois, vous allez utiliser create_or_update sur ml_client.jobs.

ml_client.jobs.create_or_update(job)

Une fois terminé, le travail inscrit un modèle dans votre espace de travail (suite à la formation) et génère un lien pour afficher le travail dans AzureML Studio.

Avertissement

Azure Machine Learning exécute des scripts d’apprentissage en copiant l’intégralité du répertoire source. Si vous avez des données sensibles que vous ne souhaitez pas charger, utilisez un fichier .ignore ou ne l’incluez pas dans le répertoire source.

Ce qui se passe lors de l’exécution

Quand le travail est exécuté, elle passe par les phases suivantes :

  • Préparation : une image docker est créée en fonction de l’environnement défini. L’image est chargée dans le registre de conteneurs de l’espace de travail et mise en cache pour des exécutions ultérieures. Les journaux sont également transmis en continu à l’historique des travaux et peuvent être affichés afin de surveiller la progression. Si un environnement organisé est spécifié, l’image mise en cache qui stocke cet environnement organisé est utilisée.

  • Mise à l’échelle : le cluster tente de monter en puissance si le cluster nécessite plus de nœuds pour l’exécution que la quantité disponible actuellement.

  • En cours d’exécution : tous les scripts dans le dossier de script src sont chargés dans la cible de calcul, les magasins de données sont montés ou copiés, puis le script est exécuté. Les sorties issues de stdout et du dossier ./logs sont transmises en continu à l’historique des travaux et peuvent être utilisées pour surveiller le travail.

Régler les hyperparamètres du modèle

Vous avez entraîné le modèle avec un ensemble de paramètres, voyons maintenant si vous pouvez améliorer davantage la précision de votre modèle. Vous pouvez paramétrer et optimiser les hyperparamètres de notre modèle à l’aide des fonctionnalités d’Azure sweep Machine Learning.

Pour paramétrer les hyperparamètres du modèle, définissez l’espace de paramètres dans lequel effectuer une recherche pendant la formation. Pour ce faire, remplacez certains des paramètres transmis au travail d’entraînement par des entrées spéciales du package azure.ml.sweep.

Étant donné que le script d’entraînement utilise un calendrier de taux d’apprentissage pour décomposer le taux d’apprentissage à chaque époque, vous pouvez ajuster le taux d’apprentissage initial et les paramètres de moment.

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),
)

Ensuite, vous allez configurer le balayage sur le travail de commande, en utilisant certains paramètres spécifiques au balayage, tels que la métrique principale à surveiller et l’algorithme d’échantillonnage à utiliser.

Dans le code suivant, nous utilisons l’échantillonnage aléatoire pour essayer différents jeux de configuration d’hyperparamètres dans une tentative d’optimisation de notre métrique principale, best_val_acc.

Nous définissons également une stratégie d’arrêt anticipé, BanditPolicy, pour arrêter les exécutions peu performantes. BanditPolicy terminera toute exécution qui ne correspond pas au facteur de marge de notre métrique d’évaluation principale. Vous allez appliquer cette stratégie à chaque époque (puisque nous signalons notre métrique best_val_acc à chaque époque et que evaluation_interval=1). Notez que nous allons retarder la première évaluation de la stratégie après les 10 premières époques (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
    ),
)

Maintenant, vous pouvez soumettre ce travail comme avant. Cette fois, vous exécuterez un travail de balayage qui balaye votre travail de train.

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)

Vous pouvez surveiller le travail à l’aide du lien d’interface utilisateur studio qui est présenté pendant l’exécution du travail.

Trouver le meilleur modèle

Une fois toutes les exécutions terminées, vous pouvez trouver l’exécution qui a produit le modèle avec la plus grande précision.

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
        )
    )

Déployer le modèle en tant que point de terminaison en ligne

Vous pouvez maintenant déployer votre moteur en tant que point de terminaison en ligne, c’est-à-dire en tant que service web dans le cloud Azure.

Pour déployer un service Machine Learning, vous aurez généralement besoin des éléments suivants :

  • Les ressources de modèle que vous souhaitez déployer. Ces ressources incluent le fichier et les métadonnées du modèle que vous avez déjà inscrits dans votre travail d’entraînement.
  • Du code à exécuter en tant que service. Le code exécute le modèle lors d’une requête d’entrée donnée (script d’entrée). Ce script d’entrée reçoit les données envoyées à un service web déployé, puis les passe au modèle. Une fois que le modèle a traité les données, le script retourne la réponse du modèle au client. Le script est propre à votre modèle et doit comprendre les données que le modèle attend et retourne. Lorsque vous utilisez un modèle MLFlow, AzureML crée automatiquement ce script pour vous.

Pour plus d’informations sur le déploiement, consultez Déployer et noter un modèle Machine Learning avec un point de terminaison en ligne managé à l’aide du Kit de développement logiciel (SDK) Python v2.

Créer un point de terminaison en ligne

Pour commencer à déployer votre modèle, vous devez créer votre point de terminaison en ligne. Le nom du point de terminaison doit être unique dans toute la région Azure. Pour cet article, vous allez créer un nom unique à l’aide d’un identificateur universel unique (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}")

Une fois que vous avez créé le point de terminaison, vous pouvez le récupérer comme suit :

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

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

Déployer le modèle sur le point de terminaison

Une fois que vous avez créé le point de terminaison, vous pouvez déployer le modèle avec le script d’entrée. Un point de terminaison peut avoir plusieurs déploiements. À l’aide de règles, le point de terminaison peut ensuite diriger le trafic vers ces déploiements.

Dans le code suivant, vous allez créer un déploiement unique qui gère 100 % du trafic entrant. Nous avons spécifié un nom de couleur arbitraire (aci-blue) pour le déploiement. Vous pouvez également utiliser n’importe quel autre nom tel que aci-green ou aci-red pour le déploiement. Le code permettant de déployer le modèle sur le point de terminaison effectue les opérations suivantes :

  • déploie la meilleure version du modèle que vous avez inscrit précédemment ;
  • évalue le modèle, à l’aide du fichier score.py ; et
  • utilise l’environnement organisé (que vous avez spécifié précédemment) pour effectuer une inférence.
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()

Notes

Attendez-vous à ce que ce déploiement prenne un peu de temps.

Tester le modèle déployé

Maintenant que vous avez déployé le modèle sur le point de terminaison, vous pouvez prédire la sortie du modèle déployé, à l’aide de la méthode invoke sur le point de terminaison.

Pour tester le point de terminaison, utilisons un exemple d’image pour la prédiction. Nous allons tout d’abord afficher l’image.

# 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"))

Créez une fonction pour mettre en forme et redimensionner l’image.

# 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()

Mettez en forme l’image et convertissez-la en fichier 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)

Vous pouvez ensuite appeler le point de terminaison avec ce fichier JSON et imprimer le résultat.

# 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)

Nettoyer les ressources

Si vous n’utilisez pas le point de terminaison, supprimez-le pour arrêter d’utiliser la ressource. Vérifiez qu’aucun autre déploiement n’utilise le point de terminaison avant de le supprimer.

ml_client.online_endpoints.begin_delete(name=online_endpoint_name)

Notes

Attendez-vous à ce que ce nettoyage prenne un peu de temps.

Étapes suivantes

Dans cet article, vous avez entraîné et inscrit un réseau neuronal de Deep Learning à l’aide de PyTorch sur Azure Machine Learning. Vous avez également déployé le modèle sur un point de terminaison en ligne. Consultez ces autres articles pour en savoir plus sur Azure Machine Learning.