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/colar o YAML e outros arquivos, primeiro clone o repositório e altere os diretórios para a pasta:

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. Caso não tenha uma assinatura do Azure, crie uma conta gratuita antes de começar. Experimente a versão gratuita ou paga do Azure Machine Learning.

  • Um workspace do Azure Machine Learning. Para criar um workspace, confira Gerenciar workspaces do Azure Machine Learning.

  • Certifique-se de que você tenha as seguintes permissões no espaço de trabalho do Machine Learning:

    • Criar ou gerenciar implantações e pontos de extremidade em lote: use uma função de Proprietário, Colaborador ou Personalizada que permita Microsoft.MachineLearningServices/workspaces/batchEndpoints/*.
    • Crie implantações do Azure Resource Manager no grupo de recursos do espaço de trabalho: use uma função de Proprietário, Colaborador ou Personalizada que permita Microsoft.Resources/deployments/write no grupo de recursos onde o espaço de trabalho está implantado.
  • Instale o seguinte software para trabalhar com o Machine Learning:

    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 do Lote são introduzidas na versão 2.7 da extensão ml da CLI do Azure. Use o comando az extension update --name ml para obter a versão mais recente.


Conectar-se ao workspace

O workspace é o recurso de nível superior do Machine Learning. Ele fornece um local centralizado para trabalhar com todos os artefatos criados ao usar o Machine Learning. Nesta seção, você se conecta ao workspace em que executa as suas tarefas de implantação.

No comando a seguir, insira os valores para a sua ID de assinatura, workspace, local e grupo de recursos:

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.

  1. 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 em westus2.

    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"
    
  2. 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
    
  3. 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:

  1. É 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 objeto pipeline 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 e accelerate. 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 biblioteca datasets. O texto que precisamos resumir está na coluna text.
    • 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 objeto pipeline do transformers. 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).

  2. É necessário indicar em qual ambiente executar a implantação. No nosso caso, nosso modelo é executado em Torch e exige as bibliotecas transformers, accelerate e optimum 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 arquivo conda.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]
    
  3. 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 alternativo torch113-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 bibliotecas optimum e accelerate não será suportada nessa configuração.

  4. 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.

  5. 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âmetro retry_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âmetros timeout 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.

  6. 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
    
  7. 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.

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

  2. 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
    
  3. 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 o timeout 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: