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)

È possibile usare le distribuzioni di modelli batch 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 questo articolo si apprenderà come distribuire un modello che classifica le immagini in base alla tassonomia ImageNet.

Prerequisiti

  • 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. Per creare un'area di lavoro, vedere Gestire le aree di lavoro di Azure Machine Learning.

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

    • Creare o gestire endpoint e distribuzioni batch: usare un ruolo di proprietario, collaboratore o personalizzato che consenta Microsoft.MachineLearningServices/workspaces/batchEndpoints/*.
    • Creare distribuzioni di Azure Resource Manager nel gruppo di risorse dell'area di lavoro: usare un ruolo di Proprietario, Contributore o Personalizzato che consenta Microsoft.Resources/deployments/write nel gruppo di risorse in cui viene distribuita l'area di lavoro.
  • Installare il software seguente per usare Azure Machine Learning:

    Eseguire il comando seguente per installare l'interfaccia della riga di comando di Azure e l'mlestensione per Azure Machine Learning:

    az extension add -n ml
    

    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 il comando az extension update --name ml per ottenere la versione più recente.


Connettersi all'area di lavoro

L'area di lavoro è la risorsa di primo livello per Machine Learning. Fornisce una posizione centralizzata per lavorare con tutti gli artefatti creati durante l'uso di Machine Learning. In questa sezione ci si connette all'area di lavoro in cui verranno eseguite le attività di distribuzione.

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

Informazioni sull'esempio

Questo articolo usa un modello compilato usando TensorFlow insieme all'architettura RestNet. Per altre informazioni, vedere Mapping di identità nelle reti residue profonde. È possibile scaricare un esempio di questo modello. Il modello presenta i vincoli seguenti:

  • 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 YAML e altri file, clonare il repository. Modificare le directory in 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 Notebook

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

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 l'endpoint che ospita il modello:

  1. Specificare il nome dell'endpoint.

    ENDPOINT_NAME="imagenet-classifier-batch"
    
  2. Creare il file YAML seguente per definire l'endpoint batch denominato 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
    

Registrare il modello

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

  1. Scaricare 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"
    

Creare uno script di punteggio

Creare uno script di assegnazione dei punteggi in grado di leggere le immagini fornite dalla distribuzione batch e restituire i punteggi del modello.

  • Il metodo init carica il modello usando il modulo keras in tensorflow.
  • Il metodo run viene eseguito per ogni mini batch fornito dalla distribuzione batch.
  • Il metodo 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.
  • Lo script restituisce le classi e le probabilità associate alle stime.

Questo codice è il file 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 criterio comune come il tentativo di caricare l'intero batch e inviarlo al modello contemporaneamente potrebbe comportare un utilizzo elevato della memoria sull'executor batch (eccezioni OOM).

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 desidera ottenere un utilizzo elevato della GPU. Per uno script di assegnazione dei punteggi che sfrutta questo approccio, vedere Distribuzioni a velocità effettiva elevata.

Nota

Se si desidera distribuire un modello generativo, che genera file, apprendere come creare uno script di assegnazione dei punteggi: Personalizzare gli output nelle distribuzioni batch.

Creare la distribuzione

Dopo aver creato lo script di assegnazione dei punteggi, creare una distribuzione batch. A tale scopo, seguire questa procedura:

  1. Assicurarsi di avere creato un cluster di elaborazione in cui è possibile creare la distribuzione. In questo esempio usare un cluster di elaborazione denominato gpu-cluster. Sebbene non sia necessario, l'uso di GPU velocizza l'elaborazione.

  2. Indicare l'ambiente in cui eseguire la distribuzione. In questo esempio il modello viene eseguito su TensorFlow. Azure Machine Learning ha già un ambiente con il software necessario installato, quindi è possibile riutilizzare questo ambiente. È necessario aggiungere un paio di dipendenze in un file conda.yml.

    La definizione dell'ambiente è 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. Creare la distribuzione.

    Per creare una nuova distribuzione nell'endpoint creato, creare una YAMLconfigurazione simile all'esempio seguente. Per altre proprietà, vedere lo schema YAML dell'endpoint batch completo.

    $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 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 desidera richiamare l'endpoint stesso e consentire all'endpoint di decidere quale distribuzione usare. Tale distribuzione è denominata distribuzione predefinita.

    Questo approccio consente di modificare la distribuzione predefinita, oltre che modificare il modello che gestisce la distribuzione, senza modificare il contratto con l'utente che richiama l'endpoint. Usare il codice seguente per aggiornare la distribuzione predefinita:

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

L'endpoint batch è pronto per l'uso.

Testare la distribuzione

Per testare l'endpoint, usare un esempio di 1.000 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. Caricarlo in un archivio dati di Azure Machine Learning. Creare un asset di dati che può essere usato per richiamare l'endpoint per l'assegnazione dei punteggi.

Nota

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
    

    Nota

    Se non wget è installato in locale, installarlo o usare un browser per ottenere il file .zip.

  2. Creare l'asset di dati dai dati scaricati.

    1. Creare una definizione di asset di dati in un file YAML denominato 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. Creare l'asset di dati.

      az ml data create -f imagenet-sample-unlabeled.yml
      
  3. Una volta che i dati sono stati caricati e sono 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

    Se l'utilità jq non è installata, vedere Scaricare jq.


Suggerimento

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 è l'impostazione predefinita. È possibile specificare come destinazione una distribuzione specifica indicando l'argomento/parametro deployment_name.

  1. 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
    
  2. Al termine della distribuzione, scaricare le stime.

    Per scaricare le previsioni, usare il comando seguente:

    az ml job download --name $JOB_NAME --output-name score --download-path ./
    
  3. Le previsioni hanno un aspetto simile all'output seguente. Le stime vengono combinate con le etichette per praticità del lettore. Per altre informazioni su come ottenere questo effetto, 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 elabora un'immagine alla volta, anche quando la distribuzione batch fornisce un batch di essi. Nella maggior parte dei casi, questo approccio è ottimale. Semplifica l'esecuzione dei modelli ed evita eventuali problemi di memoria insufficiente. Tuttavia, in alcuni altri casi, potrebbe essere necessario saturare il più possibile l'hardware sottostante. Questa situazione è il caso di GPU, ad esempio.

In questi casi, è possibile eseguire l'inferenza sull'intero batch di dati. Questo approccio 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. L'intera pipeline si verifica 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. Creare lo 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"]
        )
    
    • Questo script costruisce 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. Creare la distribuzione.

    1. Per creare una nuova distribuzione nell'endpoint creato, creare una YAMLconfigurazione simile all'esempio seguente. Per altre proprietà, vedere lo schema YAML dell'endpoint batch completo.
    $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. Creare 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 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 le si utilizza tenere presenti le seguenti considerazioni:

  • I file di immagine supportati includono: .png, .jpg, .jpeg, .tiff, .bmp e .gif.
  • I modelli MLflow dovrebbero ricevere un np.ndarray come input che corrisponde alle dimensioni dell'immagine di input. Per supportare più dimensioni di immagine in ogni batch, l'executor batch richiama il modello MLflow una volta per ogni file di immagine.
  • I modelli MLflow sono altamente incoraggiati a includere una firma. In caso affermativo, deve 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, includere una firma che possa garantirla. Ad esempio, la firma seguente consente 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 Jupyter Notebook imagenet-classifier-mlflow.ipynb. Per altre informazioni su come usare i modelli MLflow nelle distribuzioni batch, vedere Uso di modelli MLflow nelle distribuzioni batch.

Passaggi successivi