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)
Les modèles de déploiement par lots peuvent être utilisés pour traiter des données tabulaires, mais aussi tout autre type de fichier, comme des images. Ces déploiements sont pris en charge dans les modèles MLflow et personnalisés. Dans ce tutoriel, nous allons apprendre à déployer un modèle qui classifie les images en fonction de la taxonomie ImageNet.
À propos de cet exemple
Le modèle avec lequel nous allons travailler a été créé à l’aide de TensorFlow avec l’architecture RestNet (Mappages d’identités dans les réseaux résiduels profonds). Vous pouvez télécharger un exemple de ce modèle ici. Le modèle présente les contraintes suivantes qu’il est important de garder à l’esprit pour le déploiement :
- 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 avoir à copier/coller le fichier YAML et d’autres fichiers, clonez le dépôt, puis définissez les répertoires sur cli/endpoints/batch/deploy-models/imagenet-classifier
si vous utilisez l’interface Azure CLI ou sur sdk/python/endpoints/batch/deploy-models/imagenet-classifier
si vous utilisez notre 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.
Prérequis
Avant de suivre les étapes décrites dans cet article, vérifiez que vous disposez des composants requis suivants :
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. Si vous n’en avez pas, suivez les étapes décrites dans l’article Gérer des espaces de travail Azure Machine Learning pour en créer un.
Vérifiez que vous disposez des autorisations suivantes dans l’espace de travail :
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éez des déploiements ARM dans le groupe de ressources de l’espace de travail : utilisez un rôle propriétaire, contributeur ou personnalisé autorisant
Microsoft.Resources/deployments/write
dans le groupe de ressources où l’espace de travail est déployé.
Vous devez installer le logiciel suivant pour utiliser Azure Machine Learning :
L’interface Azure CLI et l’
ml
extension pour Azure Machine Learning.az extension add -n ml
Notes
Les déploiements de composants de pipeline pour des points de terminaison Batch ont été introduits dans la version 2.7 de l’extension
ml
pour Azure CLI. Utilisezaz extension update --name ml
pour en obtenir la dernière version.
Se connecter à un espace de travail
L’espace de travail est la ressource de niveau supérieur pour Azure Machine Learning. Il fournit un emplacement centralisé dans lequel exploiter tous les artefacts que vous créez lorsque vous utilisez Azure Machine Learning. Dans cette section, nous allons nous connecter à l’espace de travail dans lequel vous allez effectuer des tâches de déploiement.
Transmettez les valeurs de votre ID d’abonnement, de votre espace de travail, de votre emplacement et de votre groupe de ressources dans le code suivant :
az account set --subscription <subscription>
az configure --defaults workspace=<workspace> group=<resource-group> location=<location>
Classification d’images avec déploiements par lots
Dans cet exemple, nous allons apprendre à déployer un modèle d’apprentissage automatique qui peut classifier une image donnée en fonction de la taxonomie d’ImageNet.
Créer le point de terminaison
Commençons par créer le point de terminaison qui hébergera le modèle :
Choisissez le nom du point de terminaison :
ENDPOINT_NAME="imagenet-classifier-batch"
Le fichier YAML suivant définit un point de terminaison de lot :
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
Exécutez le code suivant pour créer le point de terminaison.
az ml batch-endpoint create --file endpoint.yml --name $ENDPOINT_NAME
Inscription du modèle
Un modèle de déploiement ne peut déployer que des modèles inscrits, nous devons donc l’inscrire. Vous pouvez ignorer cette étape si le modèle que vous essayez de déployer est déjà inscrit.
Téléchargement d’une copie du modèle :
Inscrivez le modèle :
Création d’un script de scoring
Nous devons créer un script de scoring qui peut lire les images fournies par le déploiement par lot et retourner les scores du modèle. Le script suivant :
- Indique une fonction
init
qui charge le modèle à l’aide du modulekeras
danstensorflow
. - Indique une fonction
run
exécutée pour chaque mini-lot fourni par le déploiement par lot. - La fonction
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. - Elle retourne les classes et les probabilités associées aux prédictions.
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. Il s’agit d’un modèle courant, car une tentative de charger l’intégralité du lot et de l’envoyer au modèle en une fois peut entraîner une pression de mémoire élevée sur l’exécuteur de lot (exceptions de mémoire insuffisante). Toutefois, il existe certains cas où cela permet un débit élevé dans les tâches de scoring. Il s’agit de l’exemple de déploiements par lots sur un matériel GPU où nous voulons obtenir une utilisation élevée du GPU. Consultez Déploiements à haut débit pour obtenir un exemple de script de scoring qui en tire parti.
Notes
Si vous essayez de déployer un modèle génératif (qui génère des fichiers), découvrez comment créer un script de scoring dans Déploiement de modèles qui produisent plusieurs fichiers.
Création du déploiement
Un script de scoring est créé ; il est temps de créer un déploiement par lots pour celui-ci. Suivez les étapes suivantes pour le créer :
Vérifiez que vous avez créé un cluster de calcul dans lequel nous pouvons créer le déploiement. Dans cet exemple, nous allons utiliser un cluster de calcul nommé
gpu-cluster
. Bien que ce ne soit pas obligatoire, nous utilisons des GPU pour accélérer le traitement.Nous devons indiquer sur quel environnement nous allons exécuter le déploiement. Dans notre cas, notre modèle s’exécute sur
TensorFlow
. Azure Machine Learning dispose déjà d’un environnement avec les logiciels requiss installés. Nous pouvons donc réutiliser cet environnement. Nous allons simplement ajouter quelques dépendances dans un fichierconda.yml
.Maintenant, attendez la création du déploiement.
Pour créer un nouveau déploiement sous le point de terminaison créé, créez une configuration
YAML
comme suit. Vous pouvez vérifier le schéma YAML du point de terminaison de lot complet pour obtenir des propriétés supplémentaires.$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
Ensuite, 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
Bien que vous puissiez appeler un déploiement spécifique à l’intérieur d’un point de terminaison, vous souhaiterez généralement appeler le point de terminaison lui-même et laisser le point de terminaison décider du déploiement à utiliser. Ce déploiement s’appelle le déploiement « par défaut ». Cela vous donne la possibilité de modifier le déploiement par défaut et donc de modifier le modèle qui sert le déploiement sans modifier le contrat avec l’utilisateur appelant le point de terminaison. Utilisez l’instruction suivante pour mettre à jour le déploiement par défaut :
az ml batch-endpoint update --name $ENDPOINT_NAME --set defaults.deployment_name=$DEPLOYMENT_NAME
À ce stade, notre point de terminaison batch est prêt à être utilisé.
Test du déploiement
Pour tester notre point de terminaison, nous allons utiliser un échantillon de 1 000 images à partir 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. Dans cet exemple, nous allons les charger dans un magasin de données Azure Machine Learning. En particulier, nous allons créer une ressource de données qui peut être utilisée pour appeler le point de terminaison pour le scoring. Toutefois, notez que les points de terminaison de lot acceptent les données pouvant être placées dans plusieurs types d’emplacements.
Nous allons télécharger les exemples de données associés :
Maintenant, nous allons créer la ressource de données à partir des données que nous venons de télécharger
Créez une définition de ressource de données dans
YAML
: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
Ensuite, créez la ressource de données :
az ml data create -f imagenet-sample-unlabeled.yml
Maintenant que les données sont chargées et prêtes à être utilisées, appelons le point de terminaison :
JOB_NAME=$(az ml batch-endpoint invoke --name $ENDPOINT_NAME --input azureml:imagenet-sample-unlabeled@latest --query name -o tsv)
Notes
L’utilitaire
jq
peut ne pas être installé sur chaque installation. Vous pouvez obtenir plus d’instructions sur ce lien.Conseil
Notez comment nous n’indiquons pas le nom de 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. Étant donné que notre point de terminaison n’a qu’un seul déploiement, il s’agit de celui par défaut. Vous pouvez cibler un déploiement spécifique en indiquant l’argument/le paramètre
deployment_name
.Une tâche de lot est démarrée dès que la commande retourne son résultat. Vous pouvez surveiller l’état du travail jusqu’à ce qu’il se termine :
Une fois le déploiement terminé, nous pouvons télécharger les prédictions :
Les prédictions de sortie se présentent comme suit : Notez que les prédictions ont été combinées avec les étiquettes pour la commodité du lecteur. Pour en savoir plus sur l’obtention de ce résultat, consultez ce bloc-notes 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
fichier 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 que nous venons de créer traite une image par heure, même lorsque le déploiement par lots en fournit un lot. Dans la plupart des cas, il s’agit de la meilleure approche, car elle simplifie l’exécution des modèles et évite les problèmes éventuels de manque de mémoire. Toutefois, dans certains autres cas, nous pouvons vouloir saturer autant que possible l’utilisation du matériel sous-jacent. C’est le cas des GPU par exemple.
Dans ces cas, nous pouvons souhaiter effectuer une inférence sur l’ensemble du lot de données. Cela implique de charger le jeu d’images entier 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. Il utilise également des opérations TensorFlow
pour effectuer un prétraitement des données afin que l’ensemble du pipeline se produise sur le même appareil utilisé (UC/GPU).
Avertissement
Certains modèles ont une relation non linéaire avec la taille des entrées en termes de consommation de mémoire. Recréez les lots (comme dans cet exemple) ou réduisez la taille des lots créés par le déploiement de lots pour éviter les exceptions de manque de mémoire.
Création du 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"] )
Conseil
- Notez que 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 fonctiondecode_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
.
- Notez que 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
Maintenant, attendez la création du déploiement.
Pour créer un nouveau déploiement sous le point de terminaison créé, créez une configuration
YAML
comme suit. Vous pouvez vérifier le schéma YAML du point de terminaison de lot complet pour obtenir des propriétés supplémentaires.$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
Ensuite, 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
Vous pouvez utiliser ce nouveau déploiement avec les exemples de données présentés précédemment. N’oubliez pas 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 méthode 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 comprennent :
.png
,.jpg
,.jpeg
,.tiff
,.bmp
et.gif
. - Les modèles MLflow doivent s’attendre à recevoir une entrée
np.ndarray
qui correspondra 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, et s’ils le font, qu’elle soit de 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 typenp.uint8
sont déduits. - Pour les modèles qui incluent une signature et sont supposés gérer une taille variable d’images, incluez une signature qui peut le garantir. Par exemple, l’exemple de signature suivant autorise les lots de 3 images canalisé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, lisez Utilisation de modèles MLflow dans les déploiements par lots.