Procesamiento de imágenes con implementaciones de modelos por lotes

SE APLICA A:Extensión ML de la CLI de Azure v2 (actual)SDK de Python azure-ai-ml v2 (actual)

Las implementaciones de modelos por lotes se pueden usar para procesar datos tabulares, pero también cualquier otro tipo de archivo como imágenes. Esas implementaciones se admiten tanto en MLflow como en modelos personalizados. En este tutorial, aprenderá a implementar un modelo que clasifica las imágenes según la taxonomía de ImageNet.

Acerca de este ejemplo

El modelo con el que vamos a trabajar se creó mediante TensorFlow junto con la arquitectura RestNet (Asignaciones de identidades en redes residuales profundas). Se puede descargar un ejemplo de este modelo desde aquí. A la hora de la implementación, es importante tener en cuenta que el modelo tiene algunas restricciones:

  • Funciona con imágenes de tamaño de 244 x 244 (tensores de (224, 224, 3)).
  • Requiere que las entradas se escalen al intervalo [0,1].

La información de este artículo se basa en ejemplos de código que se encuentran en el repositorio azureml-examples. Para ejecutar los comandos localmente sin tener que copiar y pegar YAML y otros archivos, clone el repositorio y, a continuación, cambie los directorios a cli/endpoints/batch/deploy-models/imagenet-classifier si usa la CLI de Azure o a sdk/python/endpoints/batch/deploy-models/imagenet-classifier si usa nuestro SDK para Python.

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

Siga estos pasos en Jupyter Notebooks

Puede seguir este ejemplo en un Jupyter Notebook. En el repositorio clonado, abra el cuaderno: imagenet-classifier-batch.ipynb.

Prerrequisitos

Antes de seguir los pasos de este artículo, asegúrese de que tiene los siguientes requisitos previos:

  • Suscripción a Azure. Si no tiene una suscripción de Azure, cree una cuenta gratuita antes de empezar. Pruebe la versión gratuita o de pago de Azure Machine Learning.

  • Un área de trabajo de Azure Machine Learning. Si no tiene una, siga los pasos descritos en el artículo Administración de áreas de trabajo de Azure Machine Learning para crear una.

  • Asegúrese de tener los permisos siguientes en el área de trabajo:

    • Crear o administrar implementaciones y puntos de conexión por lotes: use los roles de propietario, colaborador o un rol personalizado que permita Microsoft.MachineLearningServices/workspaces/batchEndpoints/*.

    • Crear implementaciones de ARM en el grupo de recursos del área de trabajo: use los roles de propietario, colaborador o un rol personalizado que permita Microsoft.Resources/deployments/write en el grupo de recursos donde se implemente el área de trabajo.

  • Debe instalar el siguiente software para trabajar con Azure Machine Learning:

    La CLI de Azure y la mlextensión para Azure Machine Learning.

    az extension add -n ml
    

    Nota

    Las implementaciones de componentes de canalización para puntos de conexión de Batch se introdujeron en la versión 2.7 de la extensión ml para la CLI de Azure. Use az extension update --name ml para obtener la última versión.

Conexión con su área de trabajo

El área de trabajo es el recurso de nivel superior para Azure Machine Learning, que proporciona un lugar centralizado para trabajar con todos los artefactos que crea al usar Azure Machine Learning. En esta sección, nos conectaremos al área de trabajo en la que realizará las tareas de implementación.

Pasa los valores del id. de suscripción, el área de trabajo, la ubicación y el grupo de recursos en el código siguiente:

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

Clasificación de imágenes con implementaciones por lotes

En este ejemplo, vamos a aprender a implementar un modelo de aprendizaje profundo que pueda clasificar una imagen determinada según la taxonomía de ImageNet.

Creación del punto de conexión

En primer lugar, vamos a crear el punto de conexión que hospedará el modelo:

Decida el nombre del punto de conexión:

ENDPOINT_NAME="imagenet-classifier-batch"

El siguiente archivo YAML define un punto de conexión por lotes:

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

Ejecute el código siguiente para crear el punto de conexión.

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

Registro del modelo

Las implementaciones de modelos solo pueden implementar modelos registrados, por lo que es necesario registrarlo. Puede omitir este paso si el modelo que está intentando implementar ya está registrado.

  1. Descargar una copia del modelo:

    wget https://azuremlexampledata.blob.core.windows.net/data/imagenet/model.zip
    unzip model.zip -d .
    
  2. Registrar el modelo:

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

Creación de un script de puntuación

Es necesario crear un script de puntuación que pueda leer las imágenes proporcionadas por la implementación por lotes y devolver las puntuaciones del modelo. El script siguiente:

  • Indica una función init que carga el modelo mediante el módulo keras en tensorflow.
  • Indica una función run que se ejecuta para cada miniproceso que proporciona la implementación por lotes.
  • La función run lee una imagen del archivo a la vez
  • El método run cambia el tamaño de las imágenes a los tamaños esperados del modelo.
  • El método run vuelve a escalar las imágenes al dominio de intervalo [0,1], que es lo que espera el modelo.
  • Devuelve las clases y las probabilidades asociadas a las predicciones.

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)

Sugerencia

Aunque la implementación proporciona imágenes en mini lotes, este script de puntuación procesa una imagen cada vez. Este es un patrón común, ya que intentar cargar todo el lote y enviarlo al modelo a la vez puede dar lugar a una presión de memoria alta en el ejecutor de lotes (excepciones de OOM). Sin embargo, hay ciertos casos en los que, al hacerlo, se habilita un alto rendimiento en la tarea de puntuación. Este es el caso de las implementaciones por lotes en un hardware de GPU donde queremos lograr un uso elevado de GPU. Consulte Implementaciones de alto rendimiento para obtener un ejemplo de un script de puntuación que aproveche sus ventajas.

Nota:

Si intenta implementar un modelo generativo (uno que genera archivos), lea cómo crear un script de puntuación como se explica en Implementación de modelos que generan varios archivos.

Creación de la implementación

Una vez se crea el script de puntuación, es el momento de crear una implementación por lotes para él. Siga los pasos siguientes para crearlo:

  1. Asegúrese de que tiene un clúster de proceso creado en el que podemos crear la implantación. En este ejemplo vamos a usar un clúster de proceso denominado gpu-cluster. Aunque no es necesario, usamos GPU para acelerar el procesamiento.

  2. Es necesario indicar en qué entorno vamos a ejecutar la implementación. En nuestro caso, nuestro modelo se ejecuta en TensorFlow. Azure Machine Learning ya tiene un entorno con el software necesario instalado, por lo que podemos volver a usar este entorno. Solo vamos a agregar un par de dependencias en un archivo de conda.yml.

    La definición del entorno se incluirá en el archivo de implementación.

    compute: azureml:gpu-cluster
    environment:
      name: tensorflow212-cuda11-gpu
      image: mcr.microsoft.com/azureml/curated/tensorflow-2.12-cuda11:latest
    
  3. Ahora, vamos a crear la implementación.

    Para crear una nueva implementación en el punto de conexión creado, cree una configuración de YAML como la siguiente. Puede comprobar el esquema YAML del punto de conexión por lotes completo para obtener propiedades adicionales.

    $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
    

    Después, cree la implementación con el siguiente comando:

    az ml batch-deployment create --file deployment-by-file.yml --endpoint-name $ENDPOINT_NAME --set-default
    
  4. Aunque puede invocar una implementación específica dentro de un punto de conexión, normalmente querrá invocar el propio punto de conexión y dejar que este decida qué implementación se va a usar. Esta se denomina implementación "predeterminada". Esto le ofrece la posibilidad de cambiar la implementación predeterminada y, por tanto, modificar el modelo que sirve a la implementación sin cambiar el contrato con el usuario que invoca el punto de conexión. Use la instrucción siguiente para actualizar la implementación predeterminada:

    az ml batch-endpoint update --name $ENDPOINT_NAME --set defaults.deployment_name=$DEPLOYMENT_NAME
    
  5. En este momento, nuestro punto de conexión por lotes está listo para usarse.

Prueba de la implementación

Para probar el punto de conexión, vamos a usar un ejemplo de 1 000 imágenes del conjunto de datos ImageNet original. Los puntos de conexión de lote solo pueden procesar los datos que se encuentran en la nube y que son accesibles desde el área de trabajo de Azure Machine Learning. En este ejemplo, vamos a cargarlo en un almacén de datos de Azure Machine Learning. En concreto, vamos a crear un recurso de datos que se pueda usar para invocar el punto de conexión para la puntuación. Sin embargo, tenga en cuenta que los puntos de conexión por lotes aceptan datos que se pueden colocar en varios tipos de ubicaciones.

  1. Vamos a descargar los datos de ejemplo asociados:

    wget https://azuremlexampledata.blob.core.windows.net/data/imagenet/imagenet-1000.zip
    unzip imagenet-1000.zip -d data
    
  2. Ahora, vamos a crear el recurso de datos a partir de los datos que acaba de descargar

    Cree una definición de recurso de datos en 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
    

    A continuación, cree el recurso de datos:

    az ml data create -f imagenet-sample-unlabeled.yml
    
  3. Ahora que los datos se han cargado y están listos para usarse, vamos a invocar el punto de conexión:

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

    Nota

    Es posible que la utilidad jq no esté instalada en todas las instalaciones. Puede obtener instrucciones en este vínculo.

    Sugerencia

    Observe que no se indica el nombre de implementación en la operación de invocación. Esto se debe a que el punto de conexión enruta automáticamente el trabajo a la implementación predeterminada. Dado que nuestro punto de conexión solo tiene una implementación, esa es la predeterminada. Puede tener como destino una implementación específica indicando el argumento o parámetro deployment_name.

  4. Se inicia un trabajo por lotes tan pronto como el comando vuelve. Puede supervisar el estado del trabajo hasta que finalice:

    az ml job show -n $JOB_NAME --web
    
  5. Una vez finalizada la implementación, podemos descargar las predicciones:

    Use los siguientes comandos para descargar las predicciones:

    az ml job download --name $JOB_NAME --output-name score --download-path ./
    
  6. Las predicciones del resultado tendrán un aspecto similar al siguiente. Observe que las predicciones se han combinado con las etiquetas para la comodidad del lector. Para más información sobre cómo lograr esto, consulte el cuaderno asociado.

    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
    
    archivo class probabilities etiqueta
    n02088094_Lebrel_afgano.JPEG 161 0,994745 Lebrel afgano
    n02088238_basset 162 0,999397 basset
    n02088364_beagle.JPEG 165 0,366914 bluetick
    n02088466_Perro_de_San_Huberto.JPEG 164 0,926464 Perro de San Huberto

Implementaciones de alto rendimiento

Como se mencionó anteriormente, la implementación que acabamos de crear procesa una imagen a la vez, incluso cuando la implementación por lotes proporciona un lote de imágenes. En la mayoría de los casos, este es el mejor enfoque, ya que simplifica la ejecución de los modelos y evita posibles problemas de memoria insuficiente. Sin embargo, en algunos otros es posible que queramos saturar tanto como sea posible el uso del hardware subyacente. Este es el caso de las GPU por ejemplo.

En esos casos, es posible que queramos realizar inferencias en todo el lote de datos. Esto implica cargar todo el conjunto de imágenes en memoria y enviarlos directamente al modelo. En el ejemplo siguiente se usa TensorFlow para leer el lote de imágenes y puntuarlas todas a la vez. También usa TensorFlow operaciones para realizar cualquier preprocesamiento de datos para que toda la canalización se produzca en el mismo dispositivo que se usa (CPU/GPU).

Advertencia

Algunos modelos tienen una relación no lineal con el tamaño de las entradas en términos del consumo de memoria. Cree el lote de nuevo (como se ha hecho en este ejemplo) o reduzca el tamaño de los lotes creados por la implementación por lotes para evitar excepciones de memoria insuficiente.

  1. Crear el script de puntuación:

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

    Sugerencia

    • Tenga en cuenta que este script está construyendo un conjunto de datos tensor a partir del mini lote enviado por la implementación del lote. Este conjunto de datos se preprocesa para obtener los tensores esperados para el modelo mediante la operación map con la función decode_img.
    • El conjunto de datos se vuelve a procesar por lotes (16) enviar los datos al modelo. Use este parámetro para controlar la cantidad de información que puede cargar en la memoria y enviar al modelo a la vez. Si se ejecuta en una GPU, deberá ajustar cuidadosamente este parámetro para lograr el uso máximo de la GPU justo antes de obtener una excepción de OOM.
    • Una vez calculadas las predicciones, los tensores se convierten en numpy.ndarray.
  2. Ahora, vamos a crear la implementación.

    Para crear una nueva implementación en el punto de conexión creado, cree una configuración de YAML como la siguiente. Puede comprobar el esquema YAML del punto de conexión por lotes completo para obtener propiedades adicionales.

    $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
    

    Después, cree la implementación con el siguiente comando:

    az ml batch-deployment create --file deployment-by-batch.yml --endpoint-name $ENDPOINT_NAME --set-default
    
  3. Puede usar esta nueva implementación con los datos de ejemplo mostrados anteriormente. Recuerde que para invocar esta implementación, debe indicar el nombre de la implementación en el método de invocación o establecerla como la predeterminada.

Consideraciones sobre el procesamiento de imágenes de modelos de MLflow

Los modelos de MLflow en puntos de conexión de Batch admiten la lectura de imágenes como datos de entrada. Dado que las implementaciones de MLflow no requieren un script de puntuación, tenga en cuenta las siguientes consideraciones al usarlas:

  • Los archivos de imagen admitidos incluyen: .png, .jpg, .jpeg, .tiff, .bmp y .gif.
  • Los modelos de MLflow deben esperar recibir un np.ndarray como entrada que coincida con las dimensiones de la imagen de entrada. Para admitir varios tamaños de imagen en cada lote, el ejecutor de lotes invocará el modelo de MLflow una vez por archivo de imagen.
  • Se recomienda encarecidamente que los modelos de MLflow incluyan una firma y, si lo hacen, debe ser de tipo TensorSpec. Las entradas se vuelven a configurar para que coincidan con la forma del tensor si está disponible. Si no hay ninguna firma disponible, se infieren tensores de tipo np.uint8.
  • Para los modelos que incluyen una firma y se espera que controlen el tamaño variable de las imágenes, incluya una firma que pueda garantizarlo. Por ejemplo, el siguiente ejemplo de firma permitirá lotes de 3 imágenes canalizadas.
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)

Puede encontrar un ejemplo de trabajo en el cuaderno de Jupyter imagenet-classifier-mlflow.ipynb. Para más información sobre cómo usar modelos de MLflow en implementaciones por lotes, lea Uso de modelos de MLflow en implementaciones por lotes.

Pasos siguientes