Partage via


Créer des scripts de scoring pour les déploiements par lots

S’APPLIQUE À :Extension Azure ML CLI v2 (actuelle)Kit de développement logiciel (SDK) Python azure-ai-ml v2 (préversion)

Les points de terminaison par lots vous permettent de déployer des modèles qui effectuent une inférence de longue durée à grande échelle. Pendant le déploiement de modèles, vous devez créer et spécifier un script de scoring (également appelé script de pilote par lot) afin d’indiquer comment l’utiliser sur les données d’entrée pour la création de prédictions. Dans cet article, vous allez apprendre à utiliser des scripts de scoring dans des modèles de déploiement pour les différents scénarios. Vous allez également découvrir les meilleures pratiques pour les points de terminaison par lots.

Conseil

Les modèles MLflow ne nécessitent pas de script de scoring. Il est généré automatiquement pour vous. Pour plus d’informations sur le fonctionnement des points de terminaison par lots avec les modèles MLflow, consultez le tutoriel dédié Utilisation de modèles MLflow dans les déploiements par lots.

Avertissement

Pour déployer un modèle ML automatisé sous un point de terminaison par lots, notez que le ML automatisé fournit un script de scoring qui fonctionne uniquement pour les points de terminaison en ligne. Ce script de scoring n’est pas conçu pour l’exécution par lots. Suivez ces instructions afin d’obtenir plus d’informations sur la création d’un script de scoring, personnalisé pour l’utilisation de votre modèle.

Présentation le script de scoring

Le script de scoring est un fichier Python (.py) qui spécifie comment exécuter le modèle et lire les données d’entrée envoyées par l’exécuteur de déploiement par lots. Chaque modèle de déploiement fournit le script de scoring (ainsi que toutes autres dépendances nécessaires) au moment de la création. Le script de scoring ressemble généralement à ceci :

deployment.yml

code_configuration:
  code: code
  scoring_script: batch_driver.py

Le script de scoring doit contenir deux méthodes :

Méthode init

Utilisez la méthode init() pour toute préparation coûteuse ou courante. Par exemple, utilisez-la pour charger le modèle en mémoire. Le début de l’ensemble du programme de traitement par lots appelle cette fonction une fois. Les fichiers de votre modèle sont disponibles dans un chemin d’accès déterminé par la variable d’environnement AZUREML_MODEL_DIR. Selon la façon dont votre modèle a été inscrit, ses fichiers peuvent être contenus dans un dossier. Dans l’exemple suivant, le modèle comporte plusieurs fichiers dans un dossier nommé model. Pour plus d’informations, consultez Déterminer le dossier utilisé par votre modèle.

def init():
    global model

    # AZUREML_MODEL_DIR is an environment variable created during deployment
    # The path "model" is the name of the registered model's folder
    model_path = os.path.join(os.environ["AZUREML_MODEL_DIR"], "model")

    # load the model
    model = load_model(model_path)

Dans cet exemple, le modèle est placé dans la variable globale model. Pour rendre disponible les ressources nécessaires à l’inférence sur votre fonction de scoring, utilisez ds variables globales.

Méthode run

Utilisez la méthode run(mini_batch: List[str]) -> Union[List[Any], pandas.DataFrame] pour gérer le scoring de chaque mini-lot généré par le déploiement par lots. Cette méthode est appelée une fois pour chaque mini_batch généré pour vos données d’entrée. Les déploiements par lots lisent les données par lots en fonction de la configuration du déploiement.

import pandas as pd
from typing import List, Any, Union

def run(mini_batch: List[str]) -> Union[List[Any], pd.DataFrame]:
    results = []

    for file in mini_batch:
        (...)

    return pd.DataFrame(results)

La méthode reçoit une liste de chemins de fichiers comme paramètre (mini_batch). Vous pouvez utiliser cette liste pour itérer et traiter individuellement chaque fichier, ou pour lire l’intégralité du lot et le traiter d’un seul coup. La meilleure option dépend de votre mémoire de calcul et du débit que vous devez obtenir. Pour obtenir un exemple de lecture de lots de données entiers en même temps, consultez Déploiements à haut débit.

Remarque

Comment le travail est-il distribué ?

Les déploiements par lots distribuent le travail au niveau des fichiers, ce qui signifie qu’un dossier contenant 100 fichiers, avec des mini-lots de 10 fichiers, génère 10 lots de 10 fichiers chacun. Notez que la taille des fichiers concernés n’a aucune importance. Pour les fichiers trop volumineux à traiter dans de grands mini-lots, nous vous suggérons de les fractionner en fichiers plus petits pour atteindre un niveau de parallélisme plus élevé, ou de réduire le nombre de fichiers par mini-lot. À ce stade, le déploiement par lots ne peut pas tenir compte des asymétries dans la distribution de la taille du fichier.

La méthode run() doit retourner un Pandas DataFrame ou un tableau/une liste. Chaque élément de sortie retourné indique une exécution réussie d’un élément d’entrée dans le mini_batch. Pour des ressources de données de fichier ou de dossier, chaque ligne/élément retourné représente un seul fichier traité. Pour une ressource de données tabulaires, chaque ligne/élément retourné représente une ligne dans un fichier traité.

Important

Comment écrire des prédictions ?

Tout ce que la fonction run() retourne sera ajoutée dans le fichier de prédictions de sortie généré par le programme de traitement par lots. Il est important de retourner le bon type de données à partir de cette fonction. Retournez des tableaux quand vous avez besoin de générer une seule prédiction. Retournez des DataFrames Pandas quand vous avez besoin de retourner divers éléments d’information. Par exemple, pour les données tabulaires, vous pouvez ajouter vos prédictions à l’enregistrement d’origine. Utilisez un DataFrame pandas pour effectuer cette opération. Même si un DataFrame pandas peut contenir des noms de colonnes, le fichier de sortie n’inclut pas ces noms.

Pour écrire les prédictions d’une façon différente, vous pouvez personnaliser les sorties dans les déploiements par lots.

Avertissement

Dans la fonction run, ne générez pas de types de données complexes (ni de listes de types de données complexes) au lieu de pandas.DataFrame. Ces sorties sont transformées en chaîne et deviennent difficiles à lire.

Le DataFrame ou le tableau résultant est ajouté au fichier de sortie indiqué. Il n’y a aucune exigence sur la cardinalité des résultats. Un fichier peut générer 1 ou plusieurs lignes/éléments dans la sortie. Tous les éléments du dataframe ou du tableau de résultats sont écrits dans le fichier de sortie en l’état (en considérant que output_action n’est pas summary_only).

Packages Python pour le scoring

Vous devez indiquer toute bibliothèque dont votre script de scoring a besoin pour s’exécuter dans l’environnement dans lequel votre déploiement par lots s’exécute. Pour les scripts de scoring, les environnements sont indiqués par déploiement. En règle générale, vous indiquez vos exigences en utilisant un fichier de dépendances conda.yml qui peut se présenter comme ceci :

mnist/environment/conda.yaml

name: mnist-env
channels:
  - conda-forge
dependencies:
  - python=3.8.5
  - pip<22.0
  - pip:
    - torch==1.13.0
    - torchvision==0.14.0
    - pytorch-lightning
    - pandas
    - azureml-core
    - azureml-dataset-runtime[fuse]

Pour plus d’informations sur la façon d’indiquer l’environnement de votre modèle, consultez Créer un déploiement par lots.

Écriture de prédictions d’une autre manière

Par défaut, le déploiement par lots écrit les prédictions du modèle dans un seul fichier, comme indiqué dans le déploiement. Toutefois, dans certains cas, vous devez écrire les prédictions dans plusieurs fichiers. Par exemple, pour les données d’entrée partitionnée, vous souhaiterez probablement générer également une sortie partitionnée. Dans ces cas, vous pouvez personnaliser les sorties dans les déploiements par lots pour indiquer :

  • Le format de fichier (CSV, parquet, json, etc.) utilisé pour écrire des prédictions
  • Le mode de partitionnement des données dans la sortie

Consultez Personnaliser les sorties dans les déploiements par lots pour obtenir plus d’informations sur la façon d’y parvenir.

Contrôle de code source des scripts de scoring

Il est vivement recommandé de placer les scripts de scoring sous contrôle de code source.

Meilleures pratiques pour l’écriture de scripts de scoring

Lorsque vous écrivez des scripts de scoring qui gèrent des grandes quantités de données, vous devez prendre en compte plusieurs facteurs, notamment

  • La taille de chaque fichier
  • La quantité de données dans chaque fichier
  • La quantité de mémoire nécessaire pour lire chaque fichier
  • La quantité de mémoire nécessaire pour lire un lot entier de fichiers
  • L’empreinte mémoire du modèle
  • L’empreinte mémoire du modèle lors de l’exécution sur les données d’entrée
  • La mémoire disponible dans votre calcul

Les déploiements par lots distribuent le travail au niveau des fichiers. Cela signifie qu’un dossier contenant 100 fichiers, dans des mini-lots de 10 fichiers, génère 10 lots de 10 fichiers chacun (quelle que soit la taille des fichiers impliqués). Pour les fichiers trop volumineux à traiter dans de grands mini-lots, nous vous suggérons de les fractionner en fichiers plus petits pour atteindre un niveau de parallélisme plus élevé, ou de réduire le nombre de fichiers par mini-lot. À ce stade, le déploiement par lots ne peut pas tenir compte des asymétries dans la distribution de la taille du fichier.

Relation entre le degré de parallélisme et le script de scoring

Votre configuration de déploiement contrôle à la fois la taille de chaque mini-lot et le nombre de rôles de travail sur chaque nœud. Cela devient important lorsque vous décidez si vous souhaitez ou non lire l’intégralité du mini-lot pour effectuer l’inférence, pour exécuter le fichier d’inférence par fichier ou pour exécuter l’inférence ligne par ligne (tabulaire). Pour plus d’informations, consultez Exécution de l’inférence au niveau du mini-lot, du fichier ou de la ligne.

Lors de l’exécution de plusieurs rôles de travail sur la même instance, tenez compte du fait que la mémoire est partagée entre tous ces rôles. Une augmentation du nombre de rôles de travail par nœud doit généralement s’accompagner d’une diminution de la taille du mini-lot ou d’une modification de la stratégie de scoring si la taille des données et la référence SKU de calcul restent les mêmes.

L’exécution de l’inférence au niveau du mini-lot, du fichier ou de la ligne

Les points de terminaison par lots appellent la fonction run() dans un script de scoring une fois par mini-lot. Cependant, vous pouvez décider si vous souhaitez exécuter l’inférence sur l’ensemble du lot, sur un fichier à la fois ou sur une ligne à la fois pour les données tabulaires.

Niveau du mini-lot

Vous souhaiterez généralement exécuter l’inférence sur le lot d’un seul coup, afin d’obtenir un débit élevé dans votre processus de scoring par lots. C’est le cas si vous exécutez l’inférence sur un GPU où vous souhaitez obtenir la saturation de l’appareil d’inférence. Vous pouvez également utiliser un chargeur de données capable de gérer le traitement par lot lui-même si les données ne tiennent pas dans la mémoire, comme les chargeurs de données TensorFlow ou PyTorch. Dans ces situations, vous pouvez exécuter l’inférence sur l’ensemble du lot.

Avertissement

L’exécution de l’inférence au niveau du lot peut nécessiter un contrôle étroit sur la taille des données d’entrée afin de prendre correctement en compte les exigences en matière de mémoire et éviter les exceptions de mémoire insuffisante. La possibilité ou non de charger l’intégralité du mini-lot en mémoire dépend de la taille du mini-lot, de la taille des instances dans le cluster et du nombre de rôles de travail sur chaque nœud.

Consultez Déploiements à débit élevé pour savoir comment y parvenir. Cet exemple traite un lot entier de fichiers à la fois.

Niveau du fichier

L’une des façons les plus simples d’effectuer une inférence consiste à effectuer une itération sur tous les fichiers du mini-lot, puis d’exécuter le modèle sur celui-ci. Dans certains cas, par exemple pour le traitement d’images, cette approche est efficace. Pour les données tabulaires, il est conseillé de faire une bonne estimation du nombre de lignes dans chaque fichier. Cette estimation peut indiquer si votre modèle peut gérer les exigences en matière de mémoire afin de charger l’intégralité des données en mémoire et d’effectuer une inférence sur celle-ci. Certains modèles (en particulier ceux basés sur des réseaux neuronaux récurrents) déplient et présentent une empreinte mémoire avec un nombre de lignes potentiellement non linéaire. Pour un modèle avec une consommation de mémoire haute, envisagez d’exécuter l’inférence au niveau de la ligne.

Conseil

Nous vous conseillons de décomposer les fichiers trop volumineux pour lire simultanément dans plusieurs fichiers plus petits, afin de tenir compte d’une meilleure parallélisation.

Pour plus d’informations sur cette procédure, consultez Traitement d’images avec des déploiements par lots. Cet exemple traite un fichier à la fois.

Niveau de la ligne (tabulaire)

Pour les modèles qui présentent des défis dus à leurs tailles d’entrée, vous pouvez exécuter l’inférence au niveau de la ligne. Votre déploiement par lots fournit toujours votre script de scoring avec un mini-lot de fichiers. Toutefois, vous allez lire un fichier, une ligne à la fois. Cela peut sembler inefficace, mais pour certains modèles de Deep Learning, il peut s’agir de la seule façon d’effectuer une inférence sans augmenter vos ressources matérielles.

Pour plus d’informations sur cette procédure, consultez Traitement de texte avec des déploiements par lots. Cet exemple traite une ligne à la fois.

Utilisation de modèles qui sont des dossiers

La variable d’environnement AZUREML_MODEL_DIR contient le chemin d’accès vers l’emplacement du modèle sélectionné et la fonction init() l’utilise généralement pour charger le modèle dans la mémoire. Toutefois, certains modèles peuvent contenir leurs fichiers à l’intérieur d’un dossier et il est possible que vous deviez en tenir compte lors de leur chargement. Vous pouvez identifier la structure du dossier de votre modèle comme indiqué ci-dessous :

  1. Accédez au portail Azure Machine Learning.

  2. Accédez à la section Modèles.

  3. Sélectionnez le modèle à déployer et sélectionnez l’onglet Artefacts.

  4. Notez le dossier affiché. Ce dossier a été indiqué lors de l’inscription du modèle.

    Capture d’écran montrant le dossier dans lequel les artefacts de modèle sont placés.

Utilisez ce chemin d’accès pour charger le modèle :

def init():
    global model

    # AZUREML_MODEL_DIR is an environment variable created during deployment
    # The path "model" is the name of the registered model's folder
    model_path = os.path.join(os.environ["AZUREML_MODEL_DIR"], "model")

    model = load_model(model_path)

Étapes suivantes