Elaborazione di immagini con distribuzioni di modelli batch

SI APPLICA A:Estensione ML dell'interfaccia della riga di comando di Azure v2 (corrente)Python SDK azure-ai-ml v2 (corrente)

Le distribuzioni di modelli batch possono essere usate per l'elaborazione di dati tabulari, ma anche qualsiasi altro tipo di file, ad esempio immagini. Queste distribuzioni sono supportate sia in MLflow sia in modelli personalizzati. In questa esercitazione si apprenderà come distribuire un modello che classifica le immagini in base alla tassonomia imageNet.

Informazioni sull'esempio

Il modello con cui verrà usato è stato creato usando TensorFlow insieme all'architettura RestNet (mapping di identità in reti residui profonde). Un esempio di questo modello può essere scaricato da qui. Il modello presenta i vincoli seguenti che è importante tenere presente per la distribuzione:

  • Funziona con immagini di dimensioni 244x244 (tensori di (224, 224, 3)).
  • Richiede che gli input vengano ridimensionati nell'intervallo [0,1].

Le informazioni contenute in questo articolo si basano sugli esempi di codice contenuti nel repository azureml-examples. Per eseguire i comandi in locale senza dover copiare/incollare il file YAML e altri file, clonare il repository e quindi passare alla directory cli/endpoints/batch/deploy-models/imagenet-classifier se si usa l'interfaccia della riga di comando di Azure o sdk/python/endpoints/batch/deploy-models/imagenet-classifier se si usa l'SDK per Python.

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

Seguire la procedura in Jupyter Notebooks

È possibile seguire questo esempio in un notebook Jupyter. Nel repository clonato aprire il notebook: imagenet-classifier-batch.ipynb.

Prerequisiti

Prima di seguire la procedura descritta in questo articolo, assicurarsi di disporre dei prerequisiti seguenti:

  • Una sottoscrizione di Azure. Se non si ha una sottoscrizione di Azure, creare un account gratuito prima di iniziare. Provare la versione gratuita o a pagamento di Azure Machine Learning.

  • Un'area di lavoro di Azure Machine Learning. Se non è disponibile, usare la procedura descritta nell'articolo Gestire le aree di lavoro di Azure Machine Learning per crearne una.

  • Assicurarsi di disporre delle autorizzazioni seguenti nell'area di lavoro:

    • Creare o gestire endpoint e distribuzioni batch: usare un ruolo Proprietario, Collaboratore o Personalizzato che consenta Microsoft.MachineLearningServices/workspaces/batchEndpoints/*.

    • Creare distribuzioni arm nel gruppo di risorse dell'area di lavoro: usare un ruolo Proprietario, Collaboratore o Personalizzato che consenta Microsoft.Resources/deployments/write nel gruppo di risorse in cui viene distribuita l'area di lavoro.

  • Per usare Azure Machine Learning, è necessario installare il software seguente:

    L'Interfaccia della riga di comando di Azure e l'mlestensione per Azure Machine Learning.

    az extension add -n ml
    

    Nota

    Le distribuzioni dei componenti della pipeline per gli endpoint batch sono state introdotte nella versione 2.7 dell'estensione ml per l'interfaccia della riga di comando di Azure. Usare az extension update --name ml per ottenere l'ultima versione.

Connettersi all'area di lavoro

L'area di lavoro è la risorsa di primo livello per Azure Machine Learning, che fornisce una posizione centralizzata da cui gestire tutti gli artefatti creati quando si usa Azure Machine Learning. In questa sezione ci si connetterà all'area di lavoro in cui verranno eseguite le attività di distribuzione.

Passare i valori per l'ID sottoscrizione, l'area di lavoro, la posizione e il gruppo di risorse nel codice seguente:

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

Classificazione delle immagini con distribuzioni batch

In questo esempio si apprenderà come distribuire un modello di Deep Learning in grado di classificare una determinata immagine in base alla tassonomia di ImageNet.

Creare l'endpoint

Creare prima di tutto l'endpoint che ospiterà il modello:

Decidere il nome dell'endpoint:

ENDPOINT_NAME="imagenet-classifier-batch"

Il file YAML seguente definisce un endpoint batch:

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

Eseguire il codice seguente per creare l'endpoint.

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

Registrazione del modello

Le distribuzioni di modelli possono distribuire solo i modelli registrati, quindi è necessario registrarla. È possibile ignorare questo passaggio se il modello che si sta tentando di distribuire è già registrato.

  1. Download di una copia del modello:

    wget https://azuremlexampledata.blob.core.windows.net/data/imagenet/model.zip
    unzip model.zip -d .
    
  2. Registrare il modello:

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

Creazione di uno script di assegnazione dei punteggi

È necessario creare uno script di assegnazione dei punteggi in grado di leggere le immagini fornite dalla distribuzione batch e restituire i punteggi del modello. Lo script seguente:

  • Indica una funzione init che carica il modello usando il modulokeras in tensorflow.
  • Indica una funzione run eseguita per ogni mini batch fornito dalla distribuzione batch.
  • La funzione run legge un'immagine del file alla volta
  • Il metodo run ridimensiona le immagini alle dimensioni previste per il modello.
  • Il metodo run ridimensiona le immagini nell'intervallo di dominio [0,1], ovvero quello previsto dal modello.
  • Restituisce le classi e le probabilità associate alle stime.

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)

Suggerimento

Anche se le immagini vengono fornite in mini batch dalla distribuzione, questo script di assegnazione dei punteggi elabora un'immagine alla volta. Si tratta di un modello comune come il tentativo di caricare l'intero batch e inviarlo al modello contemporaneamente può comportare un utilizzo elevato della memoria sull'executor batch (exeptions OOM). Tuttavia, esistono alcuni casi in cui questa operazione abilita una velocità effettiva elevata nell'attività di assegnazione dei punteggi. Questo è il caso per le distribuzioni batch su un hardware GPU in cui si vuole ottenere un utilizzo elevato della GPU. Vedere Distribuzioni a velocità effettiva elevata per un esempio di script di assegnazione dei punteggi che ne sfrutta i vantaggi.

Nota

Se si sta provando a distribuire un modello generativo (uno che genera file), leggere come creare uno script di assegnazione dei punteggi come illustrato in Distribuzione di modelli che produce più file.

Creazione della distribuzione

Uno script di assegnazione dei punteggi viene creato, è il momento di creare una distribuzione batch per essa. Per crearlo, seguire questa procedura:

  1. Assicurarsi di avere creato un cluster di calcolo in cui è possibile creare la distribuzione. In questo esempio si userà un cluster di calcolo denominato gpu-cluster. Anche se non è necessario, si usano GPU per velocizzare l'elaborazione.

  2. È necessario indicare l'ambiente in cui verrà eseguita la distribuzione. In questo caso, il modello viene eseguito in TensorFlow. Azure Machine Learning ha già un ambiente con il software necessario installato, quindi è possibile riutilizzare questo ambiente. Si aggiungeranno solo un paio di dipendenze in un file di conda.yml.

    La definizione dell'ambiente verrà inclusa nel file di distribuzione.

    compute: azureml:gpu-cluster
    environment:
      name: tensorflow212-cuda11-gpu
      image: mcr.microsoft.com/azureml/curated/tensorflow-2.12-cuda11:latest
    
  3. A questo punto, è possibile creare la distribuzione.

    Per creare una nuova distribuzione nell'endpoint creato, creare una YAML configurazione simile alla seguente. È possibile controllare lo schema YAML dell'endpoint batch completo per ottenere proprietà aggiuntive.

    $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
    

    Creare quindi la distribuzione con il comando seguente:

    az ml batch-deployment create --file deployment-by-file.yml --endpoint-name $ENDPOINT_NAME --set-default
    
  4. Anche se è possibile richiamare una distribuzione specifica all'interno di un endpoint, in genere si vuole richiamare l'endpoint stesso e consentire all'endpoint di decidere quale distribuzione usare. Tale distribuzione è denominata distribuzione "predefinita". In questo modo è possibile modificare la distribuzione predefinita e quindi modificare il modello che gestisce la distribuzione senza modificare il contratto con l'utente che richiama l'endpoint. Usare l'istruzione seguente per aggiornare la distribuzione predefinita:

    az ml batch-endpoint update --name $ENDPOINT_NAME --set defaults.deployment_name=$DEPLOYMENT_NAME
    
  5. A questo punto, l'endpoint batch è pronto per essere usato.

Test della distribuzione

Per testare l'endpoint, si userà un esempio di 1000 immagini del set di dati ImageNet originale. Gli endpoint batch possono elaborare solo i dati che si trovano nel cloud e sono accessibili dall'area di lavoro di Azure Machine Learning. In questo esempio verranno caricati in un archivio dati di Azure Machine Learning. In particolare, verrà creato un asset di dati che può essere usato per richiamare l'endpoint per l'assegnazione dei punteggi. Si noti tuttavia che gli endpoint batch accettano dati che possono essere inseriti in più tipi di posizioni.

  1. Scaricare i dati di esempio associati:

    wget https://azuremlexampledata.blob.core.windows.net/data/imagenet/imagenet-1000.zip
    unzip imagenet-1000.zip -d data
    
  2. A questo punto, creare l'asset di dati dai dati appena scaricati

    Creare una definizione di asset di dati in 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
    

    Creare quindi l'asset di dati:

    az ml data create -f imagenet-sample-unlabeled.yml
    
  3. Ora che i dati sono stati caricati e pronti per l'uso, richiamare l'endpoint:

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

    Nota

    L'utilità jq potrebbe non essere installata in ogni installazione. È possibile ottenere istruzioni in questo collegamento.

    Suggerimento

    Si noti che non si indica il nome della distribuzione nell'operazione invoke. Questo perché l'endpoint instrada automaticamente il processo alla distribuzione predefinita. Poiché l'endpoint ha una sola distribuzione, quella predefinita è quella. È possibile specificare come destinazione una distribuzione specifica indicando l'argomento/parametro deployment_name.

  4. Un processo batch viene avviato non appena viene restituito il comando. È possibile monitorare lo stato del processo fino al termine dell'operazione:

    az ml job show -n $JOB_NAME --web
    
  5. Al termine della distribuzione, è possibile scaricare le stime:

    Per scaricare le previsioni, usare il comando seguente:

    az ml job download --name $JOB_NAME --output-name score --download-path ./
    
  6. Le stime di output saranno simili alle seguenti. Si noti che le stime sono state combinate con le etichette per praticità del lettore. Per altre informazioni su come ottenere questo risultato, vedere il notebook associato.

    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 probabilità label
    n02088094_Afghan_hound.JPEG 161 0.994745 Levriero afghano
    n02088238_basset 162 0.999397 bassotto
    n02088364_beagle.JPEG 165 0.366914 bracco
    n02088466_bloodhound.JPEG 164 0.926464 segugio
    ... ... ... ...

Distribuzioni a velocità effettiva elevata

Come accennato in precedenza, la distribuzione appena creata elabora un'immagine alla volta, anche quando la distribuzione batch fornisce un batch di essi. Nella maggior parte dei casi questo è l'approccio migliore perché semplifica l'esecuzione dei modelli ed evita eventuali problemi di memoria insufficiente. Tuttavia, in alcuni altri potrebbe essere necessario saturare il più possibile l'utilizzo dell'hardware sottostante. Questo è il caso di GPU, ad esempio.

In questi casi, è possibile eseguire l'inferenza sull'intero batch di dati. Ciò implica il caricamento dell'intero set di immagini in memoria e l'invio diretto al modello. L'esempio seguente usa TensorFlow per leggere batch di immagini e assegnare punteggi contemporaneamente. Usa anche operazioni TensorFlow per eseguire la pre-elaborazione dei dati in modo che l'intera pipeline venga eseguita sullo stesso dispositivo usato (CPU/GPU).

Avviso

Alcuni modelli hanno una relazione non lineare con le dimensioni degli input in termini di consumo di memoria. Eseguire di nuovo batch (come fatto in questo esempio) o ridurre le dimensioni dei batch creati dalla distribuzione batch per evitare eccezioni di memoria insufficiente.

  1. Creazione dello script di assegnazione dei punteggi:

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

    Suggerimento

    • Si noti che questo script sta creando un set di dati tensor dal mini batch inviato dalla distribuzione batch. Questo set di dati viene pre-elaborato per ottenere i tensori previsti per il modello usando l'operazione map con la funzione decode_img.
    • Il set di dati viene nuovamente inviato in batch (16) per inviare i dati al modello. Usare questo parametro per controllare la quantità di informazioni che è possibile caricare in memoria e inviare al modello contemporaneamente. Se è in esecuzione in una GPU, è necessario ottimizzare attentamente questo parametro per ottenere l'utilizzo massimo della GPU subito prima di ottenere un'eccezione OOM.
    • Una volta calcolate le stime, i tensori vengono convertiti in numpy.ndarray.
  2. A questo punto, è possibile creare la distribuzione.

    Per creare una nuova distribuzione nell'endpoint creato, creare una YAML configurazione simile alla seguente. È possibile controllare lo schema YAML dell'endpoint batch completo per ottenere proprietà aggiuntive.

    $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
    

    Creare quindi la distribuzione con il comando seguente:

    az ml batch-deployment create --file deployment-by-batch.yml --endpoint-name $ENDPOINT_NAME --set-default
    
  3. È possibile usare questa nuova distribuzione con i dati di esempio mostrati in precedenza. Tenere presente che per richiamare questa distribuzione è necessario indicare il nome della distribuzione nel metodo di chiamata o impostarlo come predefinito.

Considerazioni per i modelli MLflow che elaborano immagini

I modelli MLflow negli endpoint batch supportano la lettura delle immagini come dati di input. Poiché le distribuzioni di MLflow non richiedono uno script di assegnazione dei punteggi, quando vengono usati, tenere presenti le considerazioni seguenti:

  • I file di immagine supportati includono: .png, .jpg, .jpeg, .tiff, .bmp e .gif.
  • I modelli MLflow dovrebbero ricevere un np.ndarray come input che corrisponderà alle dimensioni dell'immagine di input. Per supportare più dimensioni di immagine in ogni batch, l'executor batch richiamerà il modello MLflow una volta per ogni file di immagine.
  • I modelli MLflow sono altamente invitati a includere una firma e, se lo fanno, devono essere di tipo TensorSpec. Gli input vengono rimodellati in modo che corrispondano alla forma del tensore, se disponibile. Se non è disponibile alcuna firma, vengono dedotti tensori di tipo np.uint8.
  • Per i modelli che includono una firma e devono gestire le dimensioni variabili delle immagini, quindi includere una firma che possa garantirla. Ad esempio, l'esempio di firma seguente consentirà batch di 3 immagini con canali.
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)

È possibile trovare un esempio funzionante nel notebook jupyter imagenet-classifier-mlflow.ipynb. Per altre informazioni su come usare i modelli MLflow nelle distribuzioni batch, leggere Uso di modelli MLflow nelle distribuzioni batch.

Passaggi successivi