Creación de scripts de puntuación para implementaciones por lotes

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

Los puntos de conexión por lotes permiten implementar modelos que realizan inferencias de larga duración a gran escala. Cuando implemente modelos, debe crear y especificar un script de puntuación (también conocido como script de controlador por lotes), que indique cómo usarlo con los datos de entrada para crear predicciones. En este artículo, aprenderá a usar los scripts de puntuación en la implementación de modelos para diferentes escenarios. También obtendrá información sobre los procedimientos recomendados para los puntos de conexión por lotes.

Sugerencia

Los modelos de MLflow no requieren un script de puntuación. Se genera automáticamente para usted. Para más información sobre cómo funcionan los puntos de conexión por lotes con modelos de MLflow, consulte el tutorial dedicado Uso de modelos de MLflow en implementaciones por lotes.

Advertencia

Para implementar un modelo de ML automatizado en un punto de conexión por lotes, tenga en cuenta que el Ml automatizado proporciona un script de puntuación que solo funciona para los puntos de conexión en línea. Ese script de puntuación no está diseñado para la ejecución por lotes. Siga estas instrucciones para obtener más información sobre cómo crear un script de puntuación, personalizado para lo que hace el modelo.

Descripción del script de puntuación

El script de puntuación es un archivo de Python (.py) que especifica cómo ejecutar el modelo y leer los datos de entrada que envía el ejecutor de implementación por lotes. Cada implementación de modelo proporciona el script de puntuación (junto con todas las demás dependencias necesarias) en el momento de la creación. Normalmente, el script de puntuación tiene el siguiente aspecto:

deployment.yml

code_configuration:
  code: code
  scoring_script: batch_driver.py

El script de puntuación debe contener dos métodos:

El método init

Use el método init() en el caso de cualquier preparación costosa o común. Por ejemplo, úselo para cargar el modelo en memoria. El inicio de todo el trabajo por lotes llama a esta función una vez. Los archivos del modelo están disponibles en una ruta de acceso determinada por la variable de entorno AZUREML_MODEL_DIR. Dependiendo de cómo se registró el modelo, es posible que sus archivos se contengan en una carpeta. En el ejemplo siguiente, el modelo tiene varios archivos en una carpeta denominada model. Para obtener más información, visite cómo puede determinar la carpeta que usa el modelo.

def init():
    global model

    # AZUREML_MODEL_DIR is an environment variable created during deployment
    # The path "model" is the name of the registered model's folder
    model_path = os.path.join(os.environ["AZUREML_MODEL_DIR"], "model")

    # load the model
    model = load_model(model_path)

En este ejemplo, colocamos el modelo en la variable global model. Para disponer de los recursos necesarios para realizar inferencias sobre su función de puntuación, use variables globales.

El método run

Use el método run(mini_batch: List[str]) -> Union[List[Any], pandas.DataFrame] para controlar la puntuación de cada minilote que genera la implementación por lotes. Se llama a este método una vez para cada mini_batch generado para los datos de entrada. Las implementaciones por lotes leen datos en lotes según la configuración de la implementación.

import pandas as pd
from typing import List, Any, Union

def run(mini_batch: List[str]) -> Union[List[Any], pd.DataFrame]:
    results = []

    for file in mini_batch:
        (...)

    return pd.DataFrame(results)

El método recibe una lista de rutas de acceso de archivo como parámetro (mini_batch). Puede usar esta lista para iterar y procesar individualmente cada archivo, o para leer todo el lote y procesarlo todo a la vez. La mejor opción depende de la memoria de proceso y del rendimiento que necesite lograr. Para obtener un ejemplo que describe cómo leer lotes completos de datos a la vez, visite Implementaciones de alto rendimiento.

Nota:

¿Cómo se distribuye el trabajo?

Las implementaciones por lotes distribuyen el trabajo en el nivel de archivo, lo que significa que una carpeta contiene 100 archivos, con minilotes de 10 archivos, genera 10 lotes de 10 archivos cada uno. Tenga en cuenta que los tamaños de los archivos pertinentes no tienen relevancia. Para que los archivos sean demasiado grandes para procesar en minilotes grandes, se recomienda dividir los archivos en archivos más pequeños para lograr un mayor nivel de paralelismo o reducir el número de archivos por minilote. En este momento, la implementación por lotes no puede tener en cuenta las distorsiones en la distribución de tamaños del archivo.

El método run() debe devolver un DataFrame de Pandas o una matriz/lista. Cada elemento de salida devuelto indica una ejecución correcta del elemento de entrada en el mini_batch de entrada. Para los recursos de datos de archivos o carpetas, cada fila o elemento devuelto representa un único archivo procesado. Para un recurso de datos tabulares, cada fila o elemento devuelto representará una fila en un archivo procesado.

Importante

¿Cómo se escriben las predicciones?

Todo lo que devuelve la función run() se anexará en el archivo de predicciones de salida que genera el trabajo por lotes. Es importante devolver el tipo de datos correcto desde esta función. Devuelve matrices cuando necesites generar una sola predicción. Devuelve DataFrames de Pandas cuando necesites devolver varios fragmentos de información. Por ejemplo, para los datos tabulares, es posible que desee anexar las predicciones al registro original. Use un DataFrame de Pandas para hacerlo. Aunque un DataFrame de Pandas puede contener nombres de columna, el archivo de salida no incluye esos nombres.

para escribir predicciones de otra manera, puedes personalizar las salidas en implementaciones por lotes.

Advertencia

En la función run, no genere tipos de datos complejos (ni listas de tipos de datos complejos) en lugar de pandas.DataFrame. Esas salidas se transformarán en cadenas y serán difíciles de leer.

El DataFrame o la matriz resultantes se anexan al archivo de salida indicado. No hay ningún requisito sobre la cardinalidad de los resultados. Un archivo puede generar 1 o varios elementos o filas en la salida. Todos los elementos del DataFrame o la matriz de resultados se escriben en el archivo de salida tal cual (siempre que output_action no sea summary_only).

Paquetes de Python para puntuar

Debe indicar cualquier biblioteca que requiera ejecutar el script de puntuación en el entorno donde se ejecuta la implementación por lotes. Para los scripts de puntuación, los entornos se indican por implementación. Normalmente, indica los requisitos mediante un archivo de dependencias conda.yml que podría tener este aspecto:

mnist/environment/conda.yaml

name: mnist-env
channels:
  - conda-forge
dependencies:
  - python=3.8.5
  - pip<22.0
  - pip:
    - torch==1.13.0
    - torchvision==0.14.0
    - pytorch-lightning
    - pandas
    - azureml-core
    - azureml-dataset-runtime[fuse]

Visite Creación de una implementación por lotes para obtener más información sobre cómo indicar el entorno del modelo.

Escritura de predicciones de una forma distinta

De manera predeterminada, la implementación por lotes escribe las predicciones del modelo en un único archivo, como se indica en la implementación. Sin embargo, en algunos casos, debe escribir las predicciones en varios archivos. Por ejemplo, en el caso de los datos de entrada con particiones, es probable que también desee generar la salida con particiones. En esos casos, puede personalizar salidas en implementaciones por lotes para indicar lo siguiente:

  • Formato de archivo (CSV, parquet, json, etc.) usado para escribir predicciones
  • La forma en que los datos se dividen en particiones en la salida

Visite Personalización de salidas en implementaciones por lotes para obtener más información sobre cómo lograrlo.

Control de código fuente de scripts de puntuación

Es muy recomendable colocar scripts de puntuación en el control de código fuente.

Procedimientos recomendados para escribir scripts de puntuación

Al escribir scripts de puntuación que controlen grandes cantidades de datos, debe tener en cuenta varios factores, entre ellos

  • Tamaño de los archivos
  • Cantidad de datos que contiene cada archivo
  • Cantidad de memoria necesaria para leer cada archivo
  • Cantidad de memoria necesaria para leer un lote completo de archivos
  • Superficie de memoria del modelo
  • Superficie de memoria del modelo, cuando se ejecuta sobre los datos de entrada
  • Memoria disponible en el proceso

Las implementaciones por lotes distribuyen el trabajo en el nivel de archivo. Esto significa que una carpeta que contiene 100 archivos, en minilotes de 10 archivos, genera 10 lotes de 10 archivos cada uno (independientemente del tamaño de los archivos implicados). Para que los archivos sean demasiado grandes para procesar en minilotes grandes, se recomienda dividir los archivos en archivos más pequeños para lograr un mayor nivel de paralelismo o reducir el número de archivos por minilote. En este momento, la implementación por lotes no puede tener en cuenta las distorsiones en la distribución de tamaños del archivo.

Relación entre el grado de paralelismo y el script de puntuación

La configuración de implementación controla tanto el tamaño de cada minilote como el número de trabajos de cada nodo. Esto es importante cuando se decide si se debe leer o no todo el minilote para realizar la inferencia, ejecutar el archivo de inferencia por archivo o ejecutar la fila de inferencia por fila (para tabular). Visite Ejecución de la inferencia en el minilote, el archivo o el nivel de fila para obtener más información.

Al ejecutar varios trabajos en la misma instancia, debe tener en cuenta el hecho de que la memoria se comparte en todos los trabajos. Por lo general, un aumento del número de trabajadores por nodo debe ir acompañado de una disminución del tamaño del minilote o de un cambio en la estrategia de puntuación si el tamaño de los datos y el SKU de cálculo siguen siendo los mismos.

Ejecución de la inferencia en el minilote, el archivo o el nivel de fila.

Los puntos de conexión por lotes llaman a la función run() en un script de puntuación una vez por minilote. Sin embargo, puede decidir si desea ejecutar la inferencia en todo el lote, en un archivo a la vez, o en una fila a la vez para los datos tabulares.

Nivel de minilote

Normalmente, querrá ejecutar la inferencia en todo el lote de una vez para lograr un alto rendimiento en el proceso de puntuación por lotes. Esto sucede si ejecuta la inferencia en una GPU, donde quiere lograr la saturación del dispositivo de inferencia. También puede confiar en un cargador de datos que pueda controlar el procesamiento por lotes si los datos no caben en la memoria, como los cargadores de datos TensorFlow o PyTorch. En estos casos, es posible que quiera ejecutar la inferencia en todo el lote.

Advertencia

La ejecución de la inferencia en el nivel de lote puede requerir un control cercano sobre el tamaño de los datos de entrada, tener en cuenta correctamente los requisitos de la memoria y evitar excepciones de memoria insuficiente. Si puede cargar o no todo el minilote en la memoria depende del tamaño de este, del tamaño de las instancias del clúster y del número de trabajos en cada nodo.

Visite Implementaciones de alto rendimiento para obtener información sobre cómo lograrlo. En este ejemplo se procesa un lote completo de archivos a la vez.

Nivel de archivo

Una de las formas más fáciles de realizar la inferencia es iterar en todos los archivos del minilote y, a continuación, ejecutar el modelo sobre él. En algunos casos, como el procesamiento de imágenes, esto puede ser una buena idea. En el caso de los datos tabulares, es posible que tenga que realizar una buena estimación sobre el número de filas de cada archivo. Esta estimación puede mostrar si el modelo puede controlar los requisitos de memoria tanto para cargar todos los datos en la memoria como para realizar la inferencia sobre él. Algunos modelos (especialmente los modelos basados en redes neuronales recurrentes) se despliegan y presentan una superficie de memoria con un número de filas potencialmente no lineal. Para un modelo con un alto gasto de memoria, considere la posibilidad de ejecutar la inferencia en el nivel de fila.

Sugerencia

Considere la posibilidad de dividir los archivos demasiado grandes para leerlos de una sola vez en varios archivos más pequeños, para tener en cuenta una mejor paralelización.

Visite Procesamiento de imágenes con implementaciones por lotes para obtener información sobre cómo hacerlo. En ese ejemplo se procesa un archivo a la vez.

Nivel de fila (tabular)

En el caso de los modelos que presentan desafíos con sus tamaños de entrada, es posible que desee ejecutar la inferencia en el nivel de fila. La implementación por lotes sigue proporcionando el script de puntuación con un minilote de archivos. Sin embargo, leerá un archivo, una fila a la vez. Esto podría parecer ineficaz, pero para algunos modelos de aprendizaje profundo podría ser la única manera de realizar la inferencia sin escalar verticalmente los requisitos de hardware.

Visite Procesamiento de texto con implementaciones por lotes para obtener información sobre cómo hacerlo. En ese ejemplo se procesa una fila a la vez.

Uso de modelos que son carpetas

La variable de entorno AZUREML_MODEL_DIR contiene la ruta de acceso a la ubicación del modelo seleccionada y la función init() normalmente la usa para cargar el modelo en la memoria. Sin embargo, algunos modelos pueden contener sus archivos en una carpeta y es posible que deba tener eso en consideración al cargarlos. Puede identificar la estructura de carpeta del modelo como se muestra aquí:

  1. Vaya al portal de Azure Machine Learning.

  2. Vaya a la sección Modelos.

  3. Seleccione el modelo que desea implementar y seleccione la pestaña Artefactos.

  4. Anote la carpeta mostrada. Esta carpeta se indicó cuando se registró el modelo.

    Captura de pantalla en la que se muestra la carpeta donde se colocan los artefactos del modelo.

Use esta ruta de acceso para cargar el modelo:

def init():
    global model

    # AZUREML_MODEL_DIR is an environment variable created during deployment
    # The path "model" is the name of the registered model's folder
    model_path = os.path.join(os.environ["AZUREML_MODEL_DIR"], "model")

    model = load_model(model_path)

Pasos siguientes