Implantar modelos de idioma em pontos de extremidade em lotes
APLICA-SE A:Extensão de ML da CLI do Azure v2 (atual)SDK do Python azure-ai-ml v2 (atual)
Os pontos de extremidade em lotes podem ser usados para implantar modelos caros, como modelos de linguagem, em dados de texto. Neste tutorial, você aprenderá a implantar um modelo que pode executar a sumarização de longas sequências de texto usando um modelo do HuggingFace. Também mostram como fazer a otimização de inferência usando HuggingFace e as bibliotecas optimum
e accelerate
.
Sobre este exemplo
O modelo com o qual trabalharemos foi construído usando os populares transformadores de biblioteca do HuggingFace juntamente com um modelo pré-treinado do Facebook com a arquitetura BART. Isso foi introduzido no artigo BART: Denoising Sequence-to-Sequence Pre-training para Geração de Linguagem Natural. Esse modelo tem as seguintes restrições, o que é importante ter em mente para a implantação:
- É possível trabalhar com sequências de até 1024 tokens.
- É treinado para sumarização de texto em inglês.
- Usaremos o Torch como back-end.
O exemplo neste artigo é baseado em exemplos de códigos contidos no repositório azureml-examples . Para executar os comandos localmente sem precisar copiar ou colar YAML e outros arquivos, use os seguintes comandos para clonar o repositório e ir para a pasta do idioma de codificação:
git clone https://github.com/Azure/azureml-examples --depth 1
cd azureml-examples/cli
Os arquivos desse exemplo estão em:
cd endpoints/batch/deploy-models/huggingface-text-summarization
Acompanhar em Jupyter Notebooks
Você pode acompanhar este exemplo em um Jupyter Notebook. No repositório clonado, abra o notebook: text-summarization-batch.ipynb.
Pré-requisitos
Uma assinatura do Azure. Se você não tiver uma assinatura do Azure, crie uma conta gratuita antes de começar.
Um workspace do Azure Machine Learning. Para criar um workspace, confira Gerenciar workspaces do Azure Machine Learning.
As seguintes permissões no Workspace do Azure Machine Learning:
- Para criar ou gerenciar pontos de extremidade e implantações em lotes: use um proprietário, colaborador ou função personalizada que recebeu as permissões de
Microsoft.MachineLearningServices/workspaces/batchEndpoints/*
. - Para criar implantações do Azure Resource Manager no grupo de recursos do workspace: use um proprietário, colaborador ou função personalizada que recebeu a permissão
Microsoft.Resources/deployments/write
no grupo de recursos em que o workspace é implantado.
- Para criar ou gerenciar pontos de extremidade e implantações em lotes: use um proprietário, colaborador ou função personalizada que recebeu as permissões de
A CLI do Azure Machine Learning ou o SDK do Azure Machine Learning para Python:
Execute o seguinte comando para instalar a CLI do Azure e a extensão do Azure Machine Learning
ml
:az extension add -n ml
As implantações de componente de pipeline para pontos de extremidade em lote são introduzidas na versão 2.7 da extensão
ml
da CLI do Azure. Use o comandoaz extension update --name ml
para obter a versão mais recente.
Conectar-se ao workspace
O workspace é o recurso de nível superior do Azure Machine Learning. Ele fornece um local centralizado para trabalhar com todos os artefatos criados quando você usa o Azure Machine Learning. Nesta seção, você se conecta ao workspace em que executa as suas tarefas de implantação.
No comando a seguir, insira a ID da assinatura, o nome do workspace, o nome do grupo de recursos e o local:
az account set --subscription <subscription>
az configure --defaults workspace=<workspace> group=<resource-group> location=<location>
Registrar o modelo
Devido ao tamanho do modelo, ele não foi incluído neste repositório. Em vez disso, você pode baixar uma cópia do hub do modelo HuggingFace. Você precisa dos pacotes transformers
e torch
instalados no ambiente que está usando.
%pip install transformers torch
Use o código a seguir para baixar o modelo em uma pasta model
:
from transformers import pipeline
model = pipeline("summarization", model="facebook/bart-large-cnn")
model_local_path = 'model'
summarizer.save_pretrained(model_local_path)
Agora é possível registrar esse modelo no Registro do Azure Machine Learning:
MODEL_NAME='bart-text-summarization'
az ml model create --name $MODEL_NAME --path "model"
Criando o ponto de extremidade
Vamos criar um ponto de extremidade de lote chamado text-summarization-batch
onde implantar o modelo HuggingFace para executar o resumo de texto em arquivos de texto em inglês.
Decida o nome do ponto de extremidade. O nome do ponto de extremidade termina no URI associado ao seu ponto de extremidade. Por esse motivo, nomes de ponto de extremidade em lote devem ser exclusivos dentro de uma região do Azure. Por exemplo, pode haver apenas um ponto de extremidade em lote com o nome
mybatchendpoint
emwestus2
.Nesse caso, vamos colocar o nome do ponto de extremidade em uma variável para que possamos referenciá-lo facilmente mais tarde.
ENDPOINT_NAME="text-summarization-batch"
Configurar o ponto de extremidade em lote
O arquivo YAML a seguir define um ponto de extremidade em lote:
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
Criar o ponto de extremidade:
az ml batch-endpoint create --file endpoint.yml --name $ENDPOINT_NAME
Criar a implantação
Vamos criar a implantação que hospedará o modelo:
É necessário criar um script de pontuação que possa ler os arquivos CSV fornecidos pela implantação em lotes e retornar as pontuações do modelo com o resumo. O script a seguir executa essas ações:
- Indica uma função
init
que detecta a configuração de hardware (CPU versus GPU) e carrega o modelo adequadamente. Tanto o modelo quanto o tokenizador são carregados nas variáveis globais. Não estamos usando um objetopipeline
do HuggingFace para explicar a limitação nos comprimentos de sequência do modelo que estamos usando atualmente. - Observe que estamos realizando otimizações do modelo para aprimorar o desempenho usando as bibliotecas
optimum
eaccelerate
. Se o modelo ou o hardware não o suportarem, executaremos a implantação sem essas otimizações. - Indica uma função
run
que é executada para cada minilote fornecido pela implantação em lotes. - A função
run
lê o lote inteiro usando a bibliotecadatasets
. O texto que precisamos resumir está na colunatext
. - O método
run
itera sobre cada uma das linhas do texto e executa a previsão. Como esse é um modelo de custo muito elevado, executar a previsão em arquivos inteiros resultará em uma exceção de memória insuficiente. Observe que o modelo não executa com o objetopipeline
dotransformers
. Isso é feito para levar em conta longas sequências de texto e a limitação de 1024 tokens no modelo subjacente que estamos utilizando. - Retorna o resumo do texto fornecido.
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
Dica
Embora os arquivos sejam fornecidos em minilotes pela implantação, esse script de pontuação processará uma linha por vez. Esse é um padrão comum ao lidar com modelos caros (como transformadores), pois tentar carregar o lote inteiro e enviá-lo ao modelo de uma só vez poderá resultar em alta pressão de memória no executor do lote (exceções OOM).
- Indica uma função
É necessário indicar em qual ambiente executar a implantação. No nosso caso, nosso modelo é executado em
Torch
e exige as bibliotecastransformers
,accelerate
eoptimum
do HuggingFace. O Azure Machine Learning já tem um ambiente com suporte para Torch e GPU disponível. Vamos apenas adicionar algumas dependências em um arquivoconda.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 o arquivo conda mencionado anteriormente da seguinte forma:
A definição do ambiente está incluída no arquivo de implantação.
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
O ambiente
torch200-transformers-gpu
que criamos exige um dispositivo de hardware compatível com CUDA 11.8 para executar o Torch 2.0 e o Ubuntu 20.04. Se seu dispositivo de GPU não suportar essa versão do CUDA, você pode verificar o ambiente alternativotorch113-conda.yaml
conda (também disponível no repositório), que executa o Torch 1.3 no Ubuntu 18.04 com CUDA 10.1. No entanto, a aceleração usando as bibliotecasoptimum
eaccelerate
não será suportada nessa configuração.Cada implantação é executada em clusters de computação. Eles dão suporte a clusters de Computação do Azure Machine Learning (AmlCompute) ou a clusters do Kubernetes. Nesse exemplo, nosso modelo pode se beneficiar da aceleração da GPU, e por essa razão usamos um cluster de GPU.
az ml compute create -n gpu-cluster --type amlcompute --size STANDARD_NV6 --min-instances 0 --max-instances 2
Observação
Você não será cobrado pela computação neste momento, já que o cluster permanecerá com 0 nós até que um ponto de extremidade de lote seja invocado e um trabalho de pontuação de lote seja enviado. Saiba mais sobre gerenciar e otimizar o custo do AmlCompute.
Agora, vamos criar a implantação.
Para criar uma nova implantação no ponto de extremidade criado, crie uma configuração
YAML
semelhante à seguinte. Você pode verificar o esquema YAML do ponto de extremidade do lote completo para obter propriedades extras.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
Em seguida, crie a implantação com o seguinte comando:
az ml batch-deployment create --file deployment.yml --endpoint-name $ENDPOINT_NAME --set-default
Importante
Nessa implantação, você notará um valor alto em
timeout
no parâmetroretry_settings
. O motivo para isso é devido à natureza do modelo que estamos executando. Este é um modelo que possui um custo muito elevado e a inferência em uma única linha poderá levar até 60 segundos. Os parâmetrostimeout
controlam quanto tempo a implantação em lotes deverá aguardar até o script de pontuação concluir o processamento de cada minilote. Como nosso modelo executa previsões linha por linha, o processamento de um arquivo longo poderá demorar. Observe também que o número de arquivos por lote está definido como 1 (mini_batch_size=1
). Isso está novamente relacionado à natureza do trabalho que estamos fazendo. Processar um arquivo de cada vez por lote é caro o suficiente para justificá-lo. Você observará que esse é um padrão no processamento de NLP.Embora você possa invocar uma implantação específica dentro de um ponto de extremidade, de modo geral você irá querer invocar o ponto de extremidade propriamente dito e permitir que o ponto de extremidade decida qual implantação usar. Essa implantação é chamada de implantação "padrão". Isso permite alterar a implantação padrão e, portanto, alterar o modelo que atende à implantação sem alterar o contrato com o usuário invocando o ponto de extremidade. Use a seguinte instrução para atualizar a implantação padrão:
DEPLOYMENT_NAME="text-summarization-hfbart" az ml batch-endpoint update --name $ENDPOINT_NAME --set defaults.deployment_name=$DEPLOYMENT_NAME
Neste estágio, nosso ponto de extremidade em lotes está pronto para ser usado.
Testando a implantação
Para testar nosso ponto de extremidade, usaremos uma amostra do conjunto de dados BillSum: A Corpus for Automatic Summarization of US Legislation. Esse exemplo está incluído no repositório na pasta data
. Observe que o formato dos dados é CSV e o conteúdo a ser resumido está abaixo da coluna text
, conforme esperado pelo modelo.
Vamos invocar o ponto de extremidade:
JOB_NAME=$(az ml batch-endpoint invoke --name $ENDPOINT_NAME --input data --input-type uri_folder --query name -o tsv)
Observação
O utilitário
jq
pode não ser instalado em todas as instalações. Você pode obter instruções neste link.Dica
Observe que, quando você indica um caminho local como uma entrada, os dados são carregados para a conta de armazenamento padrão do Azure Machine Learning.
Um trabalho em lote é iniciado assim que o comando retorna. Você pode monitorar o status do trabalho até que ele seja concluído:
az ml job show -n $JOB_NAME --web
Depois que a implantação for concluída, podemos baixar as previsões:
Para baixar as previsões, use o seguinte comando:
az ml job download --name $JOB_NAME --output-name score --download-path .
Considerações ao implantar modelos que processam texto
Conforme mencionado em algumas observações ao longo deste tutorial, processar texto poderá ter algumas peculiaridades que exigirão configurações específicas para implantações em lotes. Considere o seguinte ao projetar a implantação em lotes:
- Alguns modelos de NLP poderão ter um custo muito elevado em termos de memória e tempo de computação. Se esse for o caso, considere diminuir o número de arquivos incluídos em cada minilote. No exemplo acima, o número foi executado no mínimo, 1 arquivo por lote. Embora esse possa não ser o seu caso, leve em consideração quantos arquivos seu modelo poderá pontuar em cada vez. Tenha em mente que a relação entre o tamanho da entrada e o consumo de memória do modelo poderá não ser linear para modelos de aprendizado profundo.
- Se o modelo não puder manipular um arquivo por vez (como neste exemplo), considere ler os dados de entrada em linhas/partes. Implemente o envio em lote no nível de linha se você precisar obter maior taxa de transferência ou utilização de hardware.
- Defina o valor
timeout
da implantação de acordo com o custo do seu modelo e a quantidade de dados que você espera processar. Lembre-se de que otimeout
indica o tempo que a implantação em lotes esperaria pela execução do script de pontuação para um determinado lote. Se o seu lote tiver muitos arquivos ou arquivos com muitas linhas, isso afetará o valor correto desse parâmetro.
Considerações para modelos de MLflow que processam texto
As mesmas considerações mencionadas acima se aplicam aos modelos MLflow. No entanto, como você não precisa fornecer um script de pontuação para a implantação do modelo MLFlow, algumas das recomendações mencionadas podem exigir uma abordagem diferente.
- Os modelos MLflow em Pontos de Extremidade em Lote suportam a leitura de dados tabulares como dados de entrada, que podem conter longas sequências de texto. Confira os Tipos de arquivo suportados para obter detalhes sobre quais tipos de arquivo são suportados.
- As implantações em lote irão chamar a função de previsão do modelo do MLflow com o conteúdo de um arquivo inteiro como um dataframe do Pandas. Se seus dados de entrada contiverem muitas linhas, é provável que a execução de um modelo complexo (como o apresentado neste tutorial) resulte em uma exceção de falta de memória. Se esse for o caso, você poderá considerar:
- Personalizar como o modelo executará as previsões e implementará o envio em lote. Para saber como personalizar a inferência do modelo MLflow, consulte Registrar em log os modelos personalizados.
- Criar um script de pontuação e carregar o modelo usando
mlflow.<flavor>.load_model()
. Consulte Usar modelos MLflow com um script de pontuação para obter mais detalhes.