Implementar modelos de lenguaje en puntos de conexión 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 de Batch se pueden usar para implementar modelos costosos, como modelos de lenguaje, sobre datos de texto. En este tutorial, aprenderá a implementar un modelo que puede realizar un resumen de secuencias largas de texto mediante un modelo de HuggingFace. También se muestra cómo realizar la optimización de inferencia mediante las bibliotecas de HuggingFace optimum
y accelerate
.
Acerca de este ejemplo
El modelo con el que vamos a trabajar se creó usando los conocidos transformadores de biblioteca de HuggingFace junto con un modelo previamente entrenado de Facebook con la arquitectura BART. Se introdujo en el documento BART: Entrenamiento previo de eliminación de ruido de secuencia a secuencia para la generación de lenguaje natural. Este modelo tiene las siguientes limitaciones que es importante tener en cuenta para su implementación:
- Puede trabajar con secuencias de hasta 1024 tokens.
- Está entrenado para resumir el texto en inglés.
- Utilizaremos Torch como backend.
El ejemplo de este artículo se basa en ejemplos de código incluidos en el repositorio azureml-examples. Para ejecutar los comandos localmente sin tener que copiar o pegar YAML y otros archivos, use los siguientes comandos para clonar el repositorio e ir a la carpeta del lenguaje de codificación:
git clone https://github.com/Azure/azureml-examples --depth 1
cd azureml-examples/cli
Los archivos de este ejemplo están en:
cd endpoints/batch/deploy-models/huggingface-text-summarization
Siga estos pasos en Jupyter Notebooks
Puede seguir este ejemplo en un Jupyter Notebook. En el repositorio clonado, abra el cuaderno: text-summarization-batch.ipynb.
Requisitos previos
Suscripción a Azure. Si no tiene una suscripción a Azure, cree una cuenta gratuita antes de empezar.
Un área de trabajo de Azure Machine Learning. Para crear un área de trabajo, vea Administración de áreas de trabajo de Azure Machine Learning.
Los siguientes permisos en el área de trabajo de Azure Machine Learning:
- Para crear o administrar puntos de conexión e implementaciones: Use un rol de Propietario, Colaborador o personalizado al que se le hayan asignado los permisos
Microsoft.MachineLearningServices/workspaces/batchEndpoints/*
. - Para crear implementaciones de Azure Resource Manager en el grupo de recursos del área de trabajo: Use un rol de Propietario, Colaborador o personalizado que tenga asignado el permiso
Microsoft.Resources/deployments/write
en el grupo de recursos donde se implementa el área de trabajo.
- Para crear o administrar puntos de conexión e implementaciones: Use un rol de Propietario, Colaborador o personalizado al que se le hayan asignado los permisos
La CLI de Azure Machine Learning o el SDK de Azure Machine Learning para Python:
Ejecute el siguiente comando para instalar la CLI de Azure y la extensión
ml
para Azure Machine Learning:az extension add -n ml
Las implementaciones de componentes de canalización para puntos de conexión por lotes se introdujeron en la versión 2.7 de la extensión
ml
para la CLI de Azure. Use el comandoaz extension update --name ml
para obtener la versión más reciente.
Conexión con su área de trabajo
El área de trabajo es el recurso de nivel superior de Azure Machine Learning. Proporciona un lugar centralizado para trabajar con todos los artefactos que cree al usar Azure Machine Learning. En esta sección, se conectará al área de trabajo donde realizará las tareas de implementación.
En el siguiente comando, escriba el id. de suscripción, el nombre del área de trabajo, el nombre de grupo de recursos y la ubicación:
az account set --subscription <subscription>
az configure --defaults workspace=<workspace> group=<resource-group> location=<location>
Registro del modelo
Debido al tamaño del modelo, no se ha incluido en este repositorio. En su lugar, puede descargar una copia desde el centro del modelo HuggingFace. Necesita los paquetes transformers
e torch
instalados en el entorno que está usando.
%pip install transformers torch
Utilice el siguiente código para descargar el modelo en una carpeta model
:
from transformers import pipeline
model = pipeline("summarization", model="facebook/bart-large-cnn")
model_local_path = 'model'
summarizer.save_pretrained(model_local_path)
Ahora podemos registrar este modelo en el registro de Azure Machine Learning:
MODEL_NAME='bart-text-summarization'
az ml model create --name $MODEL_NAME --path "model"
Creación del punto de conexión
Vamos a crear un punto de conexión por lotes denominado text-summarization-batch
donde implementar el modelo HuggingFace para ejecutar el resumen de texto en archivos de texto en inglés.
Decida el nombre del punto de conexión. El nombre del punto de conexión termina en el URI asociado al punto de conexión. Por este motivo, los nombres de punto de conexión por lotes deben ser únicos dentro de una región de Azure. Por ejemplo, solo puede haber un punto de conexión por lotes con el nombre
mybatchendpoint
enwestus2
.En este caso, vamos a colocar el nombre del punto de conexión en una variable para que podamos hacer referencia a él más adelante.
ENDPOINT_NAME="text-summarization-batch"
Configuración del punto de conexión por lotes
El siguiente archivo YAML define un punto de conexión por lotes:
endpoint.yml
$schema: https://azuremlschemas.azureedge.net/latest/batchEndpoint.schema.json name: text-summarization-batch description: A batch endpoint for summarizing text using a HuggingFace transformer model. auth_mode: aad_token
Creación del punto de conexión:
az ml batch-endpoint create --file endpoint.yml --name $ENDPOINT_NAME
Creación de la implementación
Vamos a crear la implementación que hospeda el modelo:
Es necesario crear un script de puntuación que pueda leer los archivos .csv proporcionados por la implementación por lotes y devolver las puntuaciones del modelo junto con el resumen. El siguiente script realiza las siguientes acciones:
- Indica una función
init
que detecta la configuración de hardware (CPU vs GPU) y carga el modelo en consecuencia. Tanto el modelo como el tokenizador se cargan en variables globales. No estamos utilizando un objetopipeline
de HuggingFace para tener en cuenta la limitación en la secuencia lenghs del modelo que estamos utilizando actualmente. - Tenga en cuenta que estamos realizando optimizaciones del modelo para mejorar el rendimiento mediante
optimum
yaccelerate
las bibliotecas. Si el modelo o hardware no lo admite, ejecutaremos la implementación sin estas optimizaciones. - Indica una función
run
que se ejecuta para cada miniproceso que proporciona la implementación por lotes. - La función
run
lee todo el lote mediante la bibliotecadatasets
. El texto que necesitamos resumir está en la columnatext
. - El método
run
itera en cada una de las filas del texto y ejecuta la predicción. Dado que se trata de un modelo con un costo elevado, la ejecución de la predicción en archivos enteros dará lugar a una excepción de memoria insuficiente. Observe que el modelo no se ejecuta con el objetopipeline
detransformers
. Esto se hace para tener en cuenta secuencias largas de texto y la limitación de 1024 tokens en el modelo subyacente que usamos. - Devuelve el resumen del texto proporcionado.
code/batch_driver.py
import os import time import torch import subprocess import mlflow from pprint import pprint from transformers import AutoTokenizer, BartForConditionalGeneration from optimum.bettertransformer import BetterTransformer from datasets import load_dataset def init(): global model global tokenizer global device cuda_available = torch.cuda.is_available() device = "cuda" if cuda_available else "cpu" if cuda_available: print(f"[INFO] CUDA version: {torch.version.cuda}") print(f"[INFO] ID of current CUDA device: {torch.cuda.current_device()}") print("[INFO] nvidia-smi output:") pprint( subprocess.run(["nvidia-smi"], stdout=subprocess.PIPE).stdout.decode( "utf-8" ) ) else: print( "[WARN] CUDA acceleration is not available. This model takes hours to run on medium size data." ) # AZUREML_MODEL_DIR is an environment variable created during deployment model_path = os.path.join(os.environ["AZUREML_MODEL_DIR"], "model") # load the tokenizer tokenizer = AutoTokenizer.from_pretrained( model_path, truncation=True, max_length=1024 ) # Load the model try: model = BartForConditionalGeneration.from_pretrained( model_path, device_map="auto" ) except Exception as e: print( f"[ERROR] Error happened when loading the model on GPU or the default device. Error: {e}" ) print("[INFO] Trying on CPU.") model = BartForConditionalGeneration.from_pretrained(model_path) device = "cpu" # Optimize the model if device != "cpu": try: model = BetterTransformer.transform(model, keep_original_model=False) print("[INFO] BetterTransformer loaded.") except Exception as e: print( f"[ERROR] Error when converting to BetterTransformer. An unoptimized version of the model will be used.\n\t> {e}" ) mlflow.log_param("device", device) mlflow.log_param("model", type(model).__name__) def run(mini_batch): resultList = [] print(f"[INFO] Reading new mini-batch of {len(mini_batch)} file(s).") ds = load_dataset("csv", data_files={"score": mini_batch}) start_time = time.perf_counter() for idx, text in enumerate(ds["score"]["text"]): # perform inference inputs = tokenizer.batch_encode_plus( [text], truncation=True, padding=True, max_length=1024, return_tensors="pt" ) input_ids = inputs["input_ids"].to(device) summary_ids = model.generate( input_ids, max_length=130, min_length=30, do_sample=False ) summaries = tokenizer.batch_decode( summary_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False ) # Get results: resultList.append(summaries[0]) rps = idx / (time.perf_counter() - start_time + 00000.1) print("Rows per second:", rps) mlflow.log_metric("rows_per_second", rps) return resultList
Sugerencia
Aunque la implementación proporciona archivos en mini lotes, este script de puntuación procesa una fila cada vez. Este es un patrón común cuando se trata de modelos de costo elevado, 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).
- Indica una función
Es necesario indicar en qué entorno vamos a ejecutar la implementación. En nuestro caso, nuestro modelo se ejecuta en
Torch
y requiere las bibliotecastransformers
,accelerate
, yoptimum
de HuggingFace. Azure Machine Learning ya tiene un entorno con compatibilidad con Torch y GPU disponible. Solo vamos a agregar un par de dependencias en un archivo deconda.yaml
.environment/torch200-conda.yaml
name: huggingface-env channels: - conda-forge dependencies: - python=3.8.5 - pip - pip: - torch==2.0 - transformers - accelerate - optimum - datasets - mlflow - azureml-mlflow - azureml-core - azureml-dataset-runtime[fuse]
Podemos usar el archivo conda mencionado antes de lo siguiente:
La definición del entorno se incluye en el archivo de implementación.
deployment.yml
compute: azureml:gpu-cluster environment: name: torch200-transformers-gpu image: mcr.microsoft.com/azureml/openmpi4.1.0-cuda11.8-cudnn8-ubuntu22.04:latest
Importante
El entorno
torch200-transformers-gpu
que hemos creado requiere un dispositivo de hardware compatible con CUDA 11.8 para ejecutar Torch 2.0 y Ubuntu 20.04. Si su GPU no admite esta versión de CUDA, puede consultar el entorno alternativotorch113-conda.yaml
conda (también disponible en el repositorio), que ejecuta Torch 1.3 sobre Ubuntu 18.04 con CUDA 10.1. Sin embargo, la aceleración mediante las bibliotecasoptimum
yaccelerate
no se admitirá en esta configuración.Cada implementación se ejecuta en clústeres de proceso. Admiten clústeres de proceso de Azure Machine Learning (AmlCompute) o clústeres de Kubernetes. En este ejemplo, nuestro modelo puede beneficiarse de la aceleración de GPU, por lo que usaremos un clúster de GPU.
az ml compute create -n gpu-cluster --type amlcompute --size STANDARD_NV6 --min-instances 0 --max-instances 2
Nota
En este momento, no se le cobra por el proceso, ya que el clúster permanece en 0 nodos hasta que se invoque un punto de conexión por lotes y se envíe un trabajo de puntuación por lotes. Más información sobre cómo administrar y optimizar el coste de AmlCompute.
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.deployment.yml
$schema: https://azuremlschemas.azureedge.net/latest/modelBatchDeployment.schema.json endpoint_name: text-summarization-batch name: text-summarization-optimum description: A text summarization deployment implemented with HuggingFace and BART architecture with GPU optimization using Optimum. type: model model: azureml:bart-text-summarization@latest compute: azureml:gpu-cluster environment: name: torch200-transformers-gpu image: mcr.microsoft.com/azureml/openmpi4.1.0-cuda11.8-cudnn8-ubuntu22.04:latest conda_file: environment/torch200-conda.yaml code_configuration: code: code scoring_script: batch_driver.py resources: instance_count: 2 settings: max_concurrency_per_instance: 1 mini_batch_size: 1 output_action: append_row output_file_name: predictions.csv retry_settings: max_retries: 1 timeout: 3000 error_threshold: -1 logging_level: info
Después, cree la implementación con el siguiente comando:
az ml batch-deployment create --file deployment.yml --endpoint-name $ENDPOINT_NAME --set-default
Importante
Observará en esta implementación un valor alto en
timeout
en el parámetroretry_settings
. Esto se debe a la naturaleza del modelo que estamos ejecutando. Este es un modelo con un costo muy elevado y la inferencia en una sola fila puede tardar hasta 60 segundos. Los parámetrostimeout
controlan cuánto tiempo debe esperar la implementación por lotes para que el script de puntuación termine de procesar cada mini lote. Dado que nuestro modelo ejecuta predicciones fila por fila, el procesamiento de un archivo largo puede tardar un tiempo. Observe también que el número de archivos por lote está establecido en 1 (mini_batch_size=1
). Esto también está relacionado con el tipo de trabajo que estamos haciendo. El procesamiento de un archivo a la vez por lote es lo suficientemente caro como para justificarlo. Observará que se trata de un patrón en el procesamiento de NLP.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:
DEPLOYMENT_NAME="text-summarization-hfbart" az ml batch-endpoint update --name $ENDPOINT_NAME --set defaults.deployment_name=$DEPLOYMENT_NAME
En este momento, nuestro punto de conexión por lotes está listo para usarse.
Prueba de la implementación
Para probar nuestro punto de conexión, vamos a utilizar una muestra del conjunto de datos BillSum: Un corpus para el resumen automático de la legislación estadounidense. Este ejemplo se incluye en el repositorio de la carpeta data
. Observe que el formato de los datos es CSV y el contenido a resumir se encuentra bajo la columna text
, tal y como espera el modelo.
Vamos a invocar el punto de conexión:
JOB_NAME=$(az ml batch-endpoint invoke --name $ENDPOINT_NAME --input data --input-type uri_folder --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
Tenga en cuenta que, al indicar una ruta de acceso local como entrada, los datos se cargan en la cuenta de almacenamiento predeterminada de Azure Machine Learning.
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
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 .
Consideraciones al implementar modelos que procesan texto
Como se mencionó en algunas de las notas de este tutorial, el texto de procesamiento puede tener algunas peculiaridades que requieren una configuración específica para las implementaciones por lotes. Tenga en cuenta lo siguiente al diseñar la implementación por lotes:
- Algunos modelos de NLP pueden tener un costo muy elevado en términos de memoria y tiempo de proceso. Si este es el caso, considere la posibilidad de reducir el número de archivos incluidos en cada mini lote. En el ejemplo anterior, el número se tomó al mínimo, 1 archivo por lote. Aunque es posible que este no sea el caso, tenga en cuenta cuántos archivos puede puntuar el modelo en cada momento. Tenga en cuenta que es posible que la relación entre el tamaño de la entrada y la superficie de memoria del modelo no sea lineal en el caso de los modelos de aprendizaje profundo.
- Si el modelo ni siquiera puede controlar un archivo a la vez (como en este ejemplo), considere la posibilidad de leer los datos de entrada en filas o fragmentos. Implemente el procesamiento por lotes en el nivel de fila si necesita lograr un mayor rendimiento o uso de hardware.
- Establezca el valor
timeout
de la implementación de acuerdo con el costo del modelo y la cantidad de datos que espera procesar. Recuerde que eltimeout
indica el tiempo que la implementación por lotes esperaría para que se ejecutara el script de puntuación para un lote determinado. Si el lote tiene muchos archivos o archivos con muchas filas, esto afectará al valor correcto de este parámetro.
Consideraciones sobre el procesamiento de texto de modelos de MLflow
Las mismas consideraciones mencionadas anteriormente se aplican a los modelos de MLflow. Sin embargo, dado que no está obligado a proporcionar un script de puntuación para la implantación de su modelo MLflow, algunas de las recomendaciones mencionadas pueden requerir un enfoque diferente.
- Los modelos MLflow en puntos de conexión por lotes admiten la lectura de datos tabulares como datos de entrada, que pueden contener largas secuencias de texto. Consulte Compatibilidad de tipos de archivo para obtener más información sobre los tipos de archivo compatibles.
- Las implementaciones de Batch llaman a la función predict del modelo de MLflow con el contenido de un archivo completo como dataframe de Pandas. Si los datos de entrada contienen muchas filas, es probable que la ejecución de un modelo complejo (como el que se presenta en este tutorial) produzca una excepción de memoria insuficiente. Si este es su caso, tenga en cuenta las indicaciones siguientes:
- Personalice la manera en que el modelo ejecuta las predicciones e implemente el procesamiento por lotes. Para aprender a personalizar la inferencia del modelo de MLflow, consulte Registro de modelos personalizados.
- Cree un script de puntuación y cargue el modelo mediante
mlflow.<flavor>.load_model()
. Consulte Uso de modelos de MLflow con un script de puntuación para obtener más información.