Implantar modelos de linguagem em pontos de extremidade em lote

APLICA-SE A:Azure CLI ml extension v2 (current)Python SDK azure-ai-ml v2 (current)

Os pontos de extremidade em lote podem ser usados para implantar modelos caros, como modelos de linguagem, sobre dados de texto. Neste tutorial, você aprenderá a implantar um modelo que pode executar o resumo de texto de longas sequências de texto usando um modelo do HuggingFace. Ele também mostra como fazer otimização de inferência usando HuggingFace optimum e accelerate bibliotecas.

Sobre este exemplo

O modelo com o qual vamos trabalhar foi construído usando os populares transformadores de biblioteca da HuggingFace, juntamente com um modelo pré-treinado do Facebook com a arquitetura BART. Foi introduzido no artigo BART: Denoising Sequence-to-Sequence Pre-training for Natural Language Generation. Este modelo tem as seguintes restrições, que são importantes ter em mente para a implantação:

  • Pode trabalhar com sequências de até 1024 tokens.
  • É treinado para resumir texto em inglês.
  • Vamos usar a Tocha como backend.

O exemplo neste artigo é baseado em exemplos de código contidos no repositório azureml-examples . Para executar os comandos localmente sem ter que copiar/colar YAML e outros arquivos, primeiro clone o repositório e, em seguida, altere os diretórios para a pasta:

git clone https://github.com/Azure/azureml-examples --depth 1
cd azureml-examples/cli

Os arquivos para este exemplo estão em:

cd endpoints/batch/deploy-models/huggingface-text-summarization

Acompanhe em Jupyter Notebooks

Você pode acompanhar este exemplo em um Caderno Jupyter. No repositório clonado, abra o bloco de anotações: text-summarization-batch.ipynb.

Pré-requisitos

  • Uma subscrição do Azure. Se não tiver uma subscrição do Azure, crie uma conta gratuita antes de começar. Experimente a versão gratuita ou paga do Azure Machine Learning.

  • Uma área de trabalho do Azure Machine Learning. Para criar um espaço de trabalho, consulte Gerenciar espaços de trabalho do Azure Machine Learning.

  • Verifique se você tem as seguintes permissões no espaço de trabalho Aprendizado de Máquina:

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

    Execute o seguinte comando para instalar a CLI do Azure e a extensão para o ml Azure Machine Learning:

    az extension add -n ml
    

    As implantações de componentes de pipeline para pontos de extremidade em lote são introduzidas na versão 2.7 da ml extensão para a CLI do Azure. Use o az extension update --name ml comando para obter a versão mais recente.


Ligar à sua área de trabalho

O espaço de trabalho é o recurso de nível superior para Machine Learning. Ele fornece um local centralizado para trabalhar com todos os artefatos que você cria quando usa o Machine Learning. Nesta seção, você se conecta ao espaço de trabalho onde executa suas tarefas de implantação.

No comando a seguir, insira os valores para sua ID de assinatura, espaço de trabalho, local e grupo de recursos:

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

Registo do 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 para 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 podemos 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 em 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 isso, os nomes de ponto de extremidade em lote precisam 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 facilmente consultá-lo mais tarde.

    ENDPOINT_NAME="text-summarization-batch"
    
  2. Configurar seu ponto de extremidade em lote

    O seguinte arquivo YAML 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. Crie o ponto de extremidade:

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

Criando a implantação

Vamos criar a implantação que hospeda o modelo:

  1. Precisamos criar um script de pontuação que possa ler os arquivos CSV fornecidos pela implantação em lote e retornar as pontuações do modelo com o resumo. O script a seguir executa essas ações:

    • Indica uma init função que deteta a configuração de hardware (CPU vs GPU) e carrega o modelo de acordo. Tanto o modelo quanto o tokenizador são carregados em variáveis globais. Não estamos usando um pipeline objeto do HuggingFace para explicar a limitação nos comprimentos de sequência do modelo que estamos usando atualmente.
    • Observe que estamos realizando otimizações de modelo para melhorar o desempenho usando optimum e accelerate bibliotecas. Se o modelo ou hardware não oferecer suporte a ele, executaremos a implantação sem essas otimizações.
    • Indica uma run função que é executada para cada minilote fornecido pela implantação em lote.
    • A run função lê todo o lote usando a datasets biblioteca. O texto que precisamos resumir está na coluna text.
    • O run método itera sobre cada uma das linhas do texto e executa a previsão. Como este é um modelo muito caro, executar a previsão em arquivos inteiros resultará em uma exceção de falta de memória. Observe que o modelo não é executado com o pipeline objeto de transformers. Isso é feito para levar em conta longas sequências de texto e a limitação de 1024 tokens no modelo subjacente que estamos usando.
    • Ele retorna o resumo do texto fornecido.

    código/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
    

    Gorjeta

    Embora os arquivos sejam fornecidos em minilotes pela implantação, esse script de pontuação processa uma linha de cada vez. Este é um padrão comum ao lidar com modelos caros (como transformadores), pois tentar carregar o lote inteiro e enviá-lo para o modelo de uma só vez pode resultar em alta pressão de memória no executor de lote (exepções OOM).

  2. Precisamos indicar em qual ambiente vamos executar a implantação. No nosso caso, o nosso modelo funciona Torch e requer as bibliotecas transformers, acceleratee optimum do HuggingFace. O Azure Machine Learning já tem um ambiente com suporte a Tocha e GPU disponível. Vamos apenas adicionar algumas dependências em um conda.yaml arquivo.

    ambiente/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 de 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 requer um dispositivo de hardware compatível com CUDA 11.8 para executar o Torch 2.0 e o Ubuntu 20.04. Se o seu dispositivo GPU não suporta esta versão do CUDA, você pode verificar o ambiente conda alternativo torch113-conda.yaml (também disponível no repositório), que executa o Torch 1.3 sobre o Ubuntu 18.04 com CUDA 10.1. No entanto, a aceleração usando as bibliotecas e accelerate não será suportada optimum 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 clusters Kubernetes. Neste exemplo, nosso modelo pode se beneficiar da aceleração da GPU, e é por isso que usamos um cluster de GPU.

    az ml compute create -n gpu-cluster --type amlcompute --size STANDARD_NV6 --min-instances 0 --max-instances 2
    

    Nota

    Você não será cobrado pela computação neste momento, pois o cluster permanece em 0 nós até que um ponto de extremidade em lote seja invocado e um trabalho de pontuação em lote seja enviado. Saiba mais sobre como gerenciar e otimizar custos para AmlCompute.

  5. Agora, vamos criar a implantação.

    Para criar uma nova implantação sob o ponto de extremidade criado, crie uma YAML configuração como a seguinte. Você pode verificar o esquema YAML do ponto de extremidade de 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

    Você notará nesta implantação um alto valor no timeout parâmetro retry_settings. A razão para isso deve-se à natureza do modelo que estamos a executar. Este é um modelo muito caro e a inferência em uma única linha pode levar até 60 segundos. Os timeout parâmetros controlam quanto tempo a implantação em lote deve aguardar até que o script de pontuação termine o processamento de cada minilote. Como nosso modelo executa previsões linha por linha, o processamento de um arquivo longo pode levar tempo. Observe também que o número de arquivos por lote está definido como 1 (mini_batch_size=1). Isto está, mais uma vez, relacionado com a natureza do trabalho que estamos a realizar. Processar um arquivo de cada vez por lote é caro o suficiente para justificá-lo. Você notará que este é um padrão no processamento de PNL.

  6. Embora você possa invocar uma implantação específica dentro de um ponto de extremidade, geralmente deseja invocar o próprio ponto de extremidade e deixar que o ponto de extremidade decida qual implantação usar. Essa implantação é chamada de implantação "padrão". Isso lhe dá a possibilidade de alterar a implantação padrão e, portanto, alterar o modelo que serve a implantação sem alterar o contrato com o usuário invocando o ponto de extremidade. Use as seguintes instruções 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 ponto, nosso ponto de extremidade em lote está pronto para ser usado.

Testando a implantação

Para testar nosso endpoint, vamos usar uma amostra do conjunto de dados BillSum: A Corpus for Automatic Summarization of US Legislation. Este 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á sob a 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)
    

    Nota

    O utilitário jq pode não ser instalado em todas as instalações. Você pode obter instruções neste link.

    Gorjeta

    Observe que, ao indicar um caminho local como entrada, os dados são carregados na 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 termine:

    az ml job show -n $JOB_NAME --web
    
  3. Quando a implantação estiver 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

Como mencionado em algumas das notas ao longo deste tutorial, o processamento de texto pode ter algumas peculiaridades que exigem configuração específica para implantações em lote. Leve a seguinte consideração ao projetar a implantação em lote:

  • Alguns modelos de PNL podem ser muito caros em termos de memória e tempo de computação. Se for esse o caso, considere diminuir o número de arquivos incluídos em cada minilote. No exemplo acima, o número foi levado ao mínimo, 1 arquivo por lote. Embora este possa não ser o seu caso, leve em consideração quantos arquivos seu modelo pode pontuar em cada vez. Tenha em mente que a relação entre o tamanho da entrada e a pegada de memória do seu modelo pode não ser linear para modelos de aprendizagem profunda.
  • Se o seu modelo não conseguir lidar com um arquivo de cada vez (como neste exemplo), considere ler os dados de entrada em linhas/partes. Implemente o processamento em lote no nível da linha se precisar obter uma taxa de transferência ou utilização de hardware mais alta.
  • Defina o timeout valor da sua implantação de acordo com o quão caro é o 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 lote esperaria que o script de pontuação fosse executado para um determinado lote. Se o lote tiver muitos arquivos ou arquivos com muitas linhas, isso afetará o valor correto desse parâmetro.

Considerações para modelos MLflow que processam texto

As mesmas considerações mencionadas acima aplicam-se aos modelos MLflow. No entanto, como você não é obrigado a 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 Batch Endpoints suportam a leitura de dados tabulares como dados de entrada, que podem conter longas sequências de texto. Consulte Suporte a tipos de arquivo para obter detalhes sobre quais tipos de arquivo são suportados.
  • As implantações em lote chamam a função de previsão do seu modelo MLflow com o conteúdo de um arquivo inteiro como dataframe Pandas. Se os 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 este for o seu caso, pode considerar:
    • Personalize como seu modelo executa previsões e implemente lotes. Para saber como personalizar a inferência do modelo MLflow, consulte Registrando modelos personalizados.
    • Crie um script de pontuação e carregue seu modelo usando mlflow.<flavor>.load_model()o . Consulte Usando modelos MLflow com um script de pontuação para obter detalhes.