Traitement d’images avec des modèles de déploiement par lots

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

Vous pouvez utiliser des déploiements de modèles par lots pour traiter des données tabulaires et aussi tous les autres types de fichiers, comme des images. Ces déploiements sont pris en charge dans les modèles MLflow et personnalisés. Dans cet article, vous découvrez comment déployer un modèle qui classifie des images en fonction de la taxonomie ImageNet.

Prérequis

  • Un abonnement Azure. Si vous n’avez pas d’abonnement Azure, créez un compte gratuit avant de commencer. Essayez la version gratuite ou payante d’Azure Machine Learning.

  • Un espace de travail Azure Machine Learning. Pour créer un espace de travail, consultez Gérer les espaces de travail Azure Machine Learning.

  • Vérifiez que vous disposez des autorisations suivantes dans l’espace de travail Machine Learning :

    • Créez ou gérez des points de terminaison et des déploiements par lots : utilisez un rôle propriétaire, contributeur ou personnalisé autorisant Microsoft.MachineLearningServices/workspaces/batchEndpoints/*.
    • Créer des déploiements Azure Resource Manager dans le groupe de ressources de l’espace de travail : utilisez un rôle Propriétaire, Contributeur ou un rôle personnalisé autorisant Microsoft.Resources/deployments/write dans le groupe de ressources où l’espace de travail est déployé.
  • Installez le logiciel suivant pour utiliser Machine Learning :

    Exécutez la commande suivante pour installer l’interface de ligne de commande Azure et l’extension pour Azure Machine Learning ml :

    az extension add -n ml
    

    Les déploiements de composants de pipeline pour des points de terminaison Batch sont introduits dans la version 2.7 de l’extension ml pour l’interface de ligne de commande Azure. Utilisez la commande az extension update --name ml pour obtenir la dernière version.


Se connecter à un espace de travail

L’espace de travail est la ressource de niveau supérieur pour le Machine Learning. Il fournit un emplacement centralisé pour travailler avec tous les artefacts que vous créez lorsque vous utilisez Machine Learning. Dans cette section, vous vous connectez à l’espace de travail dans lequel vous effectuez vos tâches de déploiement.

Dans la commande suivante, entrez les valeurs de votre ID d’abonnement, de votre espace de travail, de votre emplacement et de votre groupe de ressources :

az account set --subscription <subscription>
az configure --defaults workspace=<workspace> group=<resource-group> location=<location>

À propos de cet exemple

Cet article utilise un modèle créé en utilisant TensorFlow avec l’architecture RestNet. Pour plus d’informations, consultez Mappages d’identités dans les réseaux résiduels profonds. Vous pouvez télécharger un exemple de ce modèle. Le modèle a les contraintes suivantes :

  • Il fonctionne avec des images de taille 244x244 (tenseurs de (224, 224, 3)).
  • Il nécessite que les entrées soient mises à l’échelle à la plage [0,1].

Les informations de cet article sont basées sur des exemples de code contenus dans le référentiel azureml-examples. Pour exécuter les commandes localement sans devoir copier/coller du code YAML et d’autres fichiers, clonez le référentiel. Changez les répertoires en cli/endpoints/batch/deploy-models/imagenet-classifier si vous utilisez Azure CLI ou en sdk/python/endpoints/batch/deploy-models/imagenet-classifier si vous utilisez le Kit de développement logiciel (SDK) pour Python.

git clone https://github.com/Azure/azureml-examples --depth 1
cd azureml-examples/cli/endpoints/batch/deploy-models/imagenet-classifier

Suivre dans les notebooks Jupyter

Vous pouvez suivre cet exemple dans un notebook Jupyter. Dans le dépôt cloné, ouvrez le notebook : imagenet-classifier-batch.ipynb.

Classification d’images avec déploiements par lots

Dans cet exemple, vous découvrez comment déployer un modèle Deep Learning qui peut classifier une image donnée en fonction de la taxonomie d’ImageNet.

Créer le point de terminaison

Créez le point de terminaison qui héberge le modèle :

  1. Spécifiez le nom du point de terminaison.

    ENDPOINT_NAME="imagenet-classifier-batch"
    
  2. Créez le fichier YAML suivant pour définir le point de terminaison de lot, nommé endpoint.yml :

    $schema: https://azuremlschemas.azureedge.net/latest/batchEndpoint.schema.json
    name: imagenet-classifier-batch
    description: A batch endpoint for performing image classification using a TFHub model ImageNet model.
    auth_mode: aad_token
    

    Pour créer le point de terminaison, exécutez le code suivant :

    az ml batch-endpoint create --file endpoint.yml  --name $ENDPOINT_NAME
    

Inscrire le modèle

Les déploiements de modèles peuvent déployer seulement des modèles inscrits. Vous devez inscrire le modèle. Vous pouvez ignorer cette étape si le modèle que vous essayez de déployer est déjà inscrit.

  1. Téléchargez une copie du modèle.

    wget https://azuremlexampledata.blob.core.windows.net/data/imagenet/model.zip
    unzip model.zip -d .
    
  2. Inscrire le modèle.

    MODEL_NAME='imagenet-classifier'
    az ml model create --name $MODEL_NAME --path "model"
    

Créer un script de scoring

Créez un script de scoring qui peut lire les images fournies par le déploiement par lots et retourner les scores du modèle.

  • La méthode init charge le modèle en utilisant le module keras dans tensorflow.
  • La méthode run s’exécute pour chaque mini-lot fourni par le déploiement par lots.
  • La méthode run lit une image du fichier à la fois.
  • La méthode run redimensionne les images aux tailles attendues du modèle.
  • La méthode run redimensionne les images vers le domaine de plage [0,1], ce qui est ce que le modèle attend.
  • Le script retourne les classes et les probabilités associées aux prédictions.

Ce code correspond au fichier code/score-by-file/batch_driver.py :

import os
import numpy as np
import pandas as pd
import tensorflow as tf
from os.path import basename
from PIL import Image
from tensorflow.keras.models import load_model


def init():
    global model
    global input_width
    global input_height

    # AZUREML_MODEL_DIR is an environment variable created during deployment
    model_path = os.path.join(os.environ["AZUREML_MODEL_DIR"], "model")

    # load the model
    model = load_model(model_path)
    input_width = 244
    input_height = 244


def run(mini_batch):
    results = []

    for image in mini_batch:
        data = Image.open(image).resize(
            (input_width, input_height)
        )  # Read and resize the image
        data = np.array(data) / 255.0  # Normalize
        data_batch = tf.expand_dims(
            data, axis=0
        )  # create a batch of size (1, 244, 244, 3)

        # perform inference
        pred = model.predict(data_batch)

        # Compute probabilities, classes and labels
        pred_prob = tf.math.reduce_max(tf.math.softmax(pred, axis=-1)).numpy()
        pred_class = tf.math.argmax(pred, axis=-1).numpy()

        results.append([basename(image), pred_class[0], pred_prob])

    return pd.DataFrame(results)

Conseil

Bien que les images soient fournies dans des mini-lots par le déploiement, ce script de scoring traite une image à la fois. C’est un modèle courant, car une tentative pour charger l’intégralité du lot et l’envoyer au modèle en une seule fois peut entraîner une forte sollicitation de la mémoire sur l’exécuteur de lot (exceptions de mémoire insuffisante).

Dans certains cas, ceci permet d’obtenir un débit élevé dans la tâche de scoring. C’est le cas pour les déploiements par lots sur du matériel GPU quand vous voulez atteindre une utilisation élevée du GPU. Pour obtenir un script de scoring qui tire parti de cette approche, consultez Déploiements à haut débit.

Remarque

Si vous voulez déployer un modèle génératif qui génère des fichiers, découvrez comment créer un script de scoring : Personnaliser les sorties dans les déploiements par lots.

Créer le déploiement

Après avoir créé le script de scoring, créez un déploiement par lots pour celui-ci. Suivez la procédure suivante :

  1. Vérifiez que vous disposez d’un cluster de calcul créé là où vous pouvez créer le déploiement. Dans cet exemple, utilisez un cluster de calcul nommé gpu-cluster. Bien que ce ne soit pas obligatoire, l’utilisation de GPU accélère le traitement.

  2. Indiquez sur quel environnement exécuter le déploiement. Dans cet exemple, le modèle s’exécute sur TensorFlow. Azure Machine Learning a déjà d’un environnement où les logiciels requis sont installés : vous pouvez donc réutiliser cet environnement. Vous devez ajouter quelques dépendances dans un fichier conda.yml.

    La définition d’environnement est incluse dans le fichier de déploiement.

    compute: azureml:gpu-cluster
    environment:
      name: tensorflow212-cuda11-gpu
      image: mcr.microsoft.com/azureml/curated/tensorflow-2.12-cuda11:latest
    
  3. Créez le déploiement.

    Pour créer un déploiement sous le point de terminaison créé, créez une configuration YAML comme l’exemple suivant. Pour d’autres propriétés, consultez le schéma YAML de point de terminaison de lot complet.

    $schema: https://azuremlschemas.azureedge.net/latest/modelBatchDeployment.schema.json
    endpoint_name: imagenet-classifier-batch
    name: imagenet-classifier-resnetv2
    description: A ResNetV2 model architecture for performing ImageNet classification in batch
    type: model
    model: azureml:imagenet-classifier@latest
    compute: azureml:gpu-cluster
    environment:
      name: tensorflow212-cuda11-gpu
      image: mcr.microsoft.com/azureml/curated/tensorflow-2.12-cuda11:latest
      conda_file: environment/conda.yaml
    code_configuration:
      code: code/score-by-file
      scoring_script: batch_driver.py
    resources:
      instance_count: 2
    settings:
      max_concurrency_per_instance: 1
      mini_batch_size: 5
      output_action: append_row
      output_file_name: predictions.csv
      retry_settings:
        max_retries: 3
        timeout: 300
      error_threshold: -1
      logging_level: info
    

    Créez le déploiement avec la commande suivante :

    az ml batch-deployment create --file deployment-by-file.yml --endpoint-name $ENDPOINT_NAME --set-default
    
  4. Si vous pouvez appeler un déploiement spécifique à l’intérieur d’un point de terminaison, en général, vous allez appeler le point de terminaison lui-même et le laisser décider du déploiement à utiliser. Un tel déploiement est appelé déploiement par défaut.

    Cette approche vous permet de changer le déploiement par défaut et de changer le modèle qui sert le déploiement sans changer le contrat avec l’utilisateur appelant le point de terminaison. Utilisez le code suivant pour mettre à jour le déploiement par défaut :

    az ml batch-endpoint update --name $ENDPOINT_NAME --set defaults.deployment_name=$DEPLOYMENT_NAME
    

Votre point de terminaison de lot est prêt à être utilisé.

test du déploiement

Pour tester le point de terminaison, utilisez un échantillon de 1 000 images provenant du jeu de données ImageNet d’origine. Les points de terminaison de lot peuvent uniquement traiter les données situées dans le cloud et accessibles à partir de l’espace de travail Azure Machine Learning. Chargez-le dans un magasin de données Azure Machine Learning. Créez une ressource de données qui peut être utilisé pour appeler le point de terminaison pour le scoring.

Remarque

Les points de terminaison de lot acceptent des données qui peuvent être placées dans plusieurs types d’emplacements.

  1. Téléchargez les exemples de données associés.

    wget https://azuremlexampledata.blob.core.windows.net/data/imagenet/imagenet-1000.zip
    unzip imagenet-1000.zip -d data
    

    Remarque

    Si wget n’est pas installé localement, installez-le ou utilisez un navigateur pour obtenir le fichier .zip.

  2. Créez la ressource de données à partir des données téléchargées.

    1. Créez une définition de ressource de données dans un fichier YAML appelé imagenet-sample-unlabeled.yml :

      $schema: https://azuremlschemas.azureedge.net/latest/data.schema.json
      name: imagenet-sample-unlabeled
      description: A sample of 1000 images from the original ImageNet dataset. Download content from https://azuremlexampledata.blob.core.windows.net/data/imagenet-1000.zip.
      type: uri_folder
      path: data
      
    2. Créez la ressource de données.

      az ml data create -f imagenet-sample-unlabeled.yml
      
  3. Quand les données sont chargées et prêtes à être utilisées, appelez le point de terminaison.

    JOB_NAME=$(az ml batch-endpoint invoke --name $ENDPOINT_NAME --input azureml:imagenet-sample-unlabeled@latest --query name -o tsv)
    

    Remarque

    Si l’utilitaire jq n’est pas installé, consultez Télécharger jq.


Conseil

Vous n’indiquez pas le nom du déploiement dans l’opération d’appel. Cela est dû au fait que le point de terminaison achemine automatiquement le travail vers le déploiement par défaut. Comme le point de terminaison n’a qu’un seul déploiement, celui-là est le déploiement par défaut. Vous pouvez cibler un déploiement spécifique en indiquant l’argument/le paramètre deployment_name.

  1. Un programme de traitement par lots démarre dès que la commande retourne. Vous pouvez surveiller l’état du travail jusqu’à ce qu’il se termine.

    az ml job show -n $JOB_NAME --web
    
  2. Une fois le déploiement terminé, téléchargez les prédictions.

    Utilisez les commandes suivantes pour télécharger les prédictions :

    az ml job download --name $JOB_NAME --output-name score --download-path ./
    
  3. Les prédictions se présentent comme la sortie suivante. Pour la commodité du lecteur, les prédictions sont combinées avec les étiquettes. Pour découvrir comment obtenir cet effet, consultez le notebook associé.

    import pandas as pd
    score = pd.read_csv("named-outputs/score/predictions.csv", header=None,  names=['file', 'class', 'probabilities'], sep=' ')
    score['label'] = score['class'].apply(lambda pred: imagenet_labels[pred])
    score
    
    file class probabilities label
    n02088094_Afghan_hound.JPEG 161 0.994745 Afghan hound
    n02088238_basset 162 0.999397 basset
    n02088364_beagle.JPEG 165 0.366914 bluetick
    n02088466_bloodhound.JPEG 164 0.926464 bloodhound
    ... ... ... ...

Déploiements à haut débit

Comme mentionné précédemment, le déploiement traite une image à la fois, même quand le déploiement par lots en fournit un lot. Dans la plupart des cas, cette approche est la meilleure. Elle simplifie la façon dont les modèles s’exécutent et évite les éventuels problèmes de mémoire insuffisante. Cependant, dans certains autres cas, vous souhaitez saturer autant que possible le matériel sous-jacent. C’est par exemple le cas des GPU.

Dans ces situations, vous pouvez exécuter l’inférence sur l’ensemble du lot de données. Cette approche implique de charger le jeu complet des images en mémoire et de les envoyer directement au modèle. L’exemple suivant utilise TensorFlow pour lire le lot d’images et les noter en même temps. Elle utilise également des opérations TensorFlow pour prétraiter les données. Tout le pipeline s’exécute sur le même appareil utilisé (PROCESSEUR/GPU).

Avertissement

Certains modèles ont une relation non linéaire avec la taille des entrées en termes de consommation de mémoire. Pour éviter des exceptions de mémoire insuffisante, recréez les lots (comme dans cet exemple) ou réduisez la taille des lots créés par le déploiement par lots.

  1. Créez le script de scoring code/score-by-batch/batch_driver.py :

    import os
    import numpy as np
    import pandas as pd
    import tensorflow as tf
    from tensorflow.keras.models import load_model
    
    
    def init():
        global model
        global input_width
        global input_height
    
        # AZUREML_MODEL_DIR is an environment variable created during deployment
        model_path = os.path.join(os.environ["AZUREML_MODEL_DIR"], "model")
    
        # load the model
        model = load_model(model_path)
        input_width = 244
        input_height = 244
    
    
    def decode_img(file_path):
        file = tf.io.read_file(file_path)
        img = tf.io.decode_jpeg(file, channels=3)
        img = tf.image.resize(img, [input_width, input_height])
        return img / 255.0
    
    
    def run(mini_batch):
        images_ds = tf.data.Dataset.from_tensor_slices(mini_batch)
        images_ds = images_ds.map(decode_img).batch(64)
    
        # perform inference
        pred = model.predict(images_ds)
    
        # Compute probabilities, classes and labels
        pred_prob = tf.math.reduce_max(tf.math.softmax(pred, axis=-1)).numpy()
        pred_class = tf.math.argmax(pred, axis=-1).numpy()
    
        return pd.DataFrame(
            [mini_batch, pred_prob, pred_class], columns=["file", "probability", "class"]
        )
    
    • Ce script construit un jeu de données de tenseur à partir du mini-lot envoyé par le déploiement par lots. Ce jeu de données est prétraité pour obtenir les tenseurs attendus pour le modèle à l’aide de l’opération map avec la fonction decode_img.
    • Le jeu de données est remis en lot (16) pour envoyer les données au modèle. Utilisez ce paramètre pour contrôler la quantité d’informations que vous pouvez charger en mémoire et envoyer au modèle à la fois. Si vous travaillez sur un GPU, vous devez ajuster soigneusement ce paramètre pour obtenir l’utilisation maximale du GPU juste avant d’obtenir une exception de mémoire insuffisante.
    • Une fois les prédictions calculées, les tenseurs sont convertis en numpy.ndarray.
  2. Créez le déploiement.

    1. Pour créer un déploiement sous le point de terminaison créé, créez une configuration YAML comme l’exemple suivant. Pour d’autres propriétés, consultez le schéma YAML de point de terminaison de lot complet.
    $schema: https://azuremlschemas.azureedge.net/latest/modelBatchDeployment.schema.json
    endpoint_name: imagenet-classifier-batch
    name: imagenet-classifier-resnetv2
    description: A ResNetV2 model architecture for performing ImageNet classification in batch
    type: model
    model: azureml:imagenet-classifier@latest
    compute: azureml:gpu-cluster
    environment:
      name: tensorflow212-cuda11-gpu
      image: mcr.microsoft.com/azureml/curated/tensorflow-2.12-cuda11:latest
      conda_file: environment/conda.yaml
    code_configuration:
      code: code/score-by-batch
      scoring_script: batch_driver.py
    resources:
      instance_count: 2
    tags:
      device_acceleration: CUDA
      device_batching: 16
    settings:
      max_concurrency_per_instance: 1
      mini_batch_size: 5
      output_action: append_row
      output_file_name: predictions.csv
      retry_settings:
        max_retries: 3
        timeout: 300
      error_threshold: -1
      logging_level: info
    
    1. Créez le déploiement avec la commande suivante :
    az ml batch-deployment create --file deployment-by-batch.yml --endpoint-name $ENDPOINT_NAME --set-default
    
  3. Vous pouvez utiliser ce nouveau déploiement avec les exemples de données présentés précédemment. Rappelez-vous que pour appeler ce déploiement, vous devez indiquer le nom du déploiement dans la méthode d’appel ou le définir comme déploiement par défaut.

Considérations relatives au traitement des images de modèles MLflow

Les modèles MLflow dans les points de terminaison de lot prennent en charge la lecture d’images en tant que données d’entrée. Étant donné que les déploiements MLflow ne nécessitent pas de script de scoring, tenez compte des considérations suivantes au moment de les utiliser :

  • Les fichiers image pris en charge sont les suivants : .png, .jpg, .jpeg, .tiff, .bmp et .gif.
  • Les modèles MLflow doivent être prêts à recevoir un np.ndarray en entrée, correspondant aux dimensions de l’image d’entrée. Pour prendre en charge plusieurs tailles d’image sur chaque lot, l’exécuteur de lot appelle le modèle MLflow une fois par fichier image.
  • Il est fortement recommandé que les modèles MLflow incluent une signature. Le cas échéant, elle doit être du type TensorSpec. Les entrées sont remodelées pour correspondre à la forme du tenseur si disponible. Si aucune signature n’est disponible, les tenseurs de type np.uint8 sont déduits.
  • Pour les modèles qui incluent une signature et doivent gérer des tailles d’images variables, incluez une signature qui peut garantir cela. Ainsi, l’exemple de signature suivant autorise les lots de 3 images chaînées.
import numpy as np
import mlflow
from mlflow.models.signature import ModelSignature
from mlflow.types.schema import Schema, TensorSpec

input_schema = Schema([
  TensorSpec(np.dtype(np.uint8), (-1, -1, -1, 3)),
])
signature = ModelSignature(inputs=input_schema)

(...)

mlflow.<flavor>.log_model(..., signature=signature)

Vous pouvez trouver un exemple fonctionnel dans le notebook Jupyter imagenet-classifier-mlflow.ipynb. Pour plus d’informations sur l’utilisation de modèles MLflow dans les déploiements par lots, consultez Utilisation de modèles MLflow dans les déploiements par lots.

Étapes suivantes