Implante grandes modelos com o TorchServe. - SageMaker IA da Amazon

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Implante grandes modelos com o TorchServe.

Este tutorial demonstra como implantar grandes modelos e oferecer inferência no Amazon SageMaker AI com o TorchServe em GPUs. Este exemplo implanta o modelo OPT-30b em uma instância ml.g5. Você pode modificar isso para funcionar com outros modelos e tipos de instância. Nos exemplos, substitua italicized placeholder text com suas próprias informações.

O TorchServe é uma plataforma aberta poderosa para inferência de modelos distribuídos de grande porte. Ao oferecer compatibilidade com bibliotecas mais conhecidas como PyTorch, PiPPy nativo, DeepSpeed e HuggingFace Accelerate, ele oferece APIs de manipulador uniformes que permanecem consistentes em cenários de modelos grandes distribuídos e cenários de inferência de modelos não distribuídos. Para obter mais informações, consulte a documentação de inferência de modelos grandes do TorchServe.

Contêineres de deep learning com o TorchServe

Para implantar um grande modelo com o TorchServe no SageMaker AI, você pode usar um dos contêineres de deep learning (DLCs) do SageMaker AI. Por padrão, o TorchServe é instalado em todos os DLCs da AWS para PyTorch. Durante o carregamento do modelo, o TorchServe pode instalar bibliotecas especializadas e personalizadas para grandes modelos, como PiPPy, Deepspeed e Accelerate.

A tabela a seguir lista todos os DLCs do SageMaker AI com o TorchServe.

Categoria DLC Framework Hardware Exemplo de URL

Contêineres de framework do SageMaker AI

PyTorch 2.0.0+

CPU, GPU

763104351884.dkr.ecr.us-east-1.amazonaws.com/PyTorch-inference:2.0.1-gpu-py310-cu118-ubuntu20.04-sagemaker

Contêineres de framework Graviton do SageMaker AI

PyTorch 2.0.0+

CPU

763104351884.dkr.ecr.us-east-1.amazonaws.com/PyTorch-inference-graviton:2.0.1-cpu-py310-ubuntu20.04-sagemaker

Contêineres de inferência StabilityAI

PyTorch 2.0.0+

GPU

763104351884.dkr.ecr.us-east-1.amazonaws.com/stabilityai-PyTorch-inference:2.0.1-sgm0.1.0-gpu-py310-cu118-ubuntu20.04-sagemaker

Contêineres de neurônios

PyTorch 1.3.1

Neuronx

763104351884.dkr.ecr.us-west-2.amazonaws.com/PyTorch-inference-neuron:1.13.1-neuron-py310-sdk2.12.0-ubuntu20.04

Começar

Antes de implantar seu modelo, preencha os pré-requisitos. Você também pode configurar os parâmetros do modelo e personalizar o código do manipulador.

Pré-requisitos

Para começar, verifique se você tem os seguintes pré-requisitos:

  1. Certifique-se de ter acesso a uma conta AWS. Configure seu ambiente para que a AWS CLI possa acessar sua conta por meio de um usuário do IAM da AWS ou de um perfil do IAM. Recomendamos usar uma perfil do IAM. Para fins de teste em sua conta pessoal, você pode anexar as seguintes políticas de permissões gerenciadas à perfil do IAM:

    Para obter informações sobre como anexar políticas a identidades do IAM, consulte Adicionar e remover permissões de identidade do IAM no Guia do usuário do IAM AWS.

  2. Configure suas dependências localmente, conforme mostrado nos exemplos a seguir.

    1. Instale a versão 2 do AWS CLI:

      # Install the latest AWS CLI v2 if it is not installed !curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" !unzip awscliv2.zip #Follow the instructions to install v2 on the terminal !cat aws/README.md
    2. Instale o SageMaker AI e o cliente Boto3:

      # If already installed, update your client #%pip install sagemaker pip --upgrade --quiet !pip install -U sagemaker !pip install -U boto !pip install -U botocore !pip install -U boto3

Configurar parâmetros e configurações do modelo

O TorchServe usa o torchrun para configurar o ambiente distribuído para processar o paralelismo do modelo. O TorchServe tem a capacidade de oferecer compatibilidade com vários operadores em um modelo grande. Por padrão, o TorchServe usa um algoritmo de ida e volta para atribuir GPUs a um operador em um host. No caso de inferência de modelos grandes, o número de GPUs atribuídas a cada operador é calculado automaticamente com base no número de GPUs especificado no arquivo model_config.yaml. A variável de ambiente CUDA_VISIBLE_DEVICES, que especifica as IDs dos dispositivos da GPU que estão visíveis em um determinado momento é definida com base nesse número.

Por exemplo, suponha que haja oito GPUs em um nó, e um operador precise de quatro GPUs em um nó (nproc_per_node=4). Nesse caso, o TorchServe atribui quatro GPUs ao primeiro operador (CUDA_VISIBLE_DEVICES="0,1,2,3") e quatro GPUs ao segundo operador (CUDA_VISIBLE_DEVICES="4,5,6,7”).

Além desse comportamento padrão, o TorchServe oferece flexibilidade para os usuários especificarem GPUs para um operador. Por exemplo, se você definir a variável deviceIds: [2,3,4,5] no arquivo YAML de configuração do modelo e definir nproc_per_node=2, o TorchServe atribuirá CUDA_VISIBLE_DEVICES=”2,3” ao primeiro operador e CUDA_VISIBLE_DEVICES="4,5” ao segundo operador.

No exemplo model_config.yaml a seguir, configuramos os parâmetros front-end e backend para o modelo OPT-30b. Os parâmetros de front-end configurados são parallelType, deviceType, deviceIds e torchrun. Para obter mais informações detalhadas sobre os parâmetros de front-end que você pode configurar, consulte a documentação do PyTorch no GitHub. A configuração de backend é baseada em um mapa YAML que permite a personalização em estilo livre. Para os parâmetros de backend, definimos a configuração do DeepSpeed e os parâmetros adicionais usados pelo código do manipulador personalizado.

# TorchServe front-end parameters minWorkers: 1 maxWorkers: 1 maxBatchDelay: 100 responseTimeout: 1200 parallelType: "tp" deviceType: "gpu" # example of user specified GPU deviceIds deviceIds: [0,1,2,3] # sets CUDA_VISIBLE_DEVICES torchrun: nproc-per-node: 4 # TorchServe back-end parameters deepspeed: config: ds-config.json checkpoint: checkpoints.json handler: # parameters for custom handler code model_name: "facebook/opt-30b" model_path: "model/models--facebook--opt-30b/snapshots/ceea0a90ac0f6fae7c2c34bcb40477438c152546" max_length: 50 max_new_tokens: 10 manual_seed: 40

Personalizar manipuladores

O TorchServe oferece manipuladores básicos e utilitários de manipulador para inferência de modelos grandes criados com bibliotecas conhecidas. O exemplo a seguir demonstra como a classe de manipulador personalizada TransformersSeqClassifierHandler estende BaseDeepSpeedHandler e usa os utilitários do manipulador. Para ver um exemplo de código completo, consulte o código custom_handler.py na documentação do PyTorch no GitHub.

class TransformersSeqClassifierHandler(BaseDeepSpeedHandler, ABC): """ Transformers handler class for sequence, token classification and question answering. """ def __init__(self): super(TransformersSeqClassifierHandler, self).__init__() self.max_length = None self.max_new_tokens = None self.tokenizer = None self.initialized = False def initialize(self, ctx: Context): """In this initialize function, the HF large model is loaded and partitioned using DeepSpeed. Args: ctx (context): It is a JSON Object containing information pertaining to the model artifacts parameters. """ super().initialize(ctx) model_dir = ctx.system_properties.get("model_dir") self.max_length = int(ctx.model_yaml_config["handler"]["max_length"]) self.max_new_tokens = int(ctx.model_yaml_config["handler"]["max_new_tokens"]) model_name = ctx.model_yaml_config["handler"]["model_name"] model_path = ctx.model_yaml_config["handler"]["model_path"] seed = int(ctx.model_yaml_config["handler"]["manual_seed"]) torch.manual_seed(seed) logger.info("Model %s loading tokenizer", ctx.model_name) self.tokenizer = AutoTokenizer.from_pretrained(model_name) self.tokenizer.pad_token = self.tokenizer.eos_token config = AutoConfig.from_pretrained(model_name) with torch.device("meta"): self.model = AutoModelForCausalLM.from_config( config, torch_dtype=torch.float16 ) self.model = self.model.eval() ds_engine = get_ds_engine(self.model, ctx) self.model = ds_engine.module logger.info("Model %s loaded successfully", ctx.model_name) self.initialized = True def preprocess(self, requests): """ Basic text preprocessing, based on the user's choice of application mode. Args: requests (list): A list of dictionaries with a "data" or "body" field, each containing the input text to be processed. Returns: tuple: A tuple with two tensors: the batch of input ids and the batch of attention masks. """ def inference(self, input_batch): """ Predicts the class (or classes) of the received text using the serialized transformers checkpoint. Args: input_batch (tuple): A tuple with two tensors: the batch of input ids and the batch of attention masks, as returned by the preprocess function. Returns: list: A list of strings with the predicted values for each input text in the batch. """ def postprocess(self, inference_output): """Post Process Function converts the predicted response into Torchserve readable format. Args: inference_output (list): It contains the predicted response of the input text. Returns: (list): Returns a list of the Predictions and Explanations. """

Prepare seus artefatos de modelo

Antes de implantar seu modelo no SageMaker AI, você deve empacotar os artefatos do modelo. Para modelos grandes, recomendamos que você use a ferramenta torch-model-archiver do PyTorch com o argumento --archive-format no-archive, que ignora a compactação de artefatos do modelo. O exemplo a seguir salva todos os artefatos do modelo em uma nova pasta chamada opt/.

torch-model-archiver --model-name opt --version 1.0 --handler custom_handler.py --extra-files ds-config.json -r requirements.txt --config-file opt/model-config.yaml --archive-format no-archive

Depois que a pasta opt/ for criada, baixe o modelo Opt-30b para a pasta usando a ferramenta Download_model do PyTorch.

cd opt python path_to/Download_model.py --model_path model --model_name facebook/opt-30b --revision main

Por fim, faça upload dos artefatos do modelo para um bucket do Amazon S3.

aws s3 cp opt {your_s3_bucket}/opt --recursive

Agora você deve ter artefatos de modelo armazenados no Amazon S3 prontos para implantação em um endpoint do SageMaker AI.

Implante o modelo usando o SageMaker Python SDK

Depois de preparar os artefatos do modelo, você pode implantar o modelo em um endpoint de hospedagem do SageMaker AI. Esta seção descreve como implantar um único modelo grande em um endpoint e fazer predições de resposta de streaming. Para obter mais informações sobre streaming de respostas de endpoints, consulte Invocar endpoints em tempo real.

Para implantar seu modelo, conclua as seguintes etapas:

  1. Crie uma sessão do SageMaker AI, conforme mostrado no exemplo a seguir.

    import boto3 import sagemaker from sagemaker import Model, image_uris, serializers, deserializers boto3_session=boto3.session.Session(region_name="us-west-2") smr = boto3.client('sagemaker-runtime-demo') sm = boto3.client('sagemaker') role = sagemaker.get_execution_role() # execution role for the endpoint sess= sagemaker.session.Session(boto3_session, sagemaker_client=sm, sagemaker_runtime_client=smr) # SageMaker AI session for interacting with different AWS APIs region = sess._region_name # region name of the current SageMaker Studio Classic environment account = sess.account_id() # account_id of the current SageMaker Studio Classic environment # Configuration: bucket_name = sess.default_bucket() prefix = "torchserve" output_path = f"s3://{bucket_name}/{prefix}" print(f'account={account}, region={region}, role={role}, output_path={output_path}')
  2. Crie um modelo descompactado no SageMaker AI, conforme mostrado no exemplo a seguir.

    from datetime import datetime instance_type = "ml.g5.24xlarge" endpoint_name = sagemaker.utils.name_from_base("ts-opt-30b") s3_uri = {your_s3_bucket}/opt model = Model( name="torchserve-opt-30b" + datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), # Enable SageMaker uncompressed model artifacts model_data={ "S3DataSource": { "S3Uri": s3_uri, "S3DataType": "S3Prefix", "CompressionType": "None", } }, image_uri=container, role=role, sagemaker_session=sess, env={"TS_INSTALL_PY_DEP_PER_MODEL": "true"}, ) print(model)
  3. Implante o modelo em uma instância do Amazon EC2, conforme mostrado no exemplo a seguir.

    model.deploy( initial_instance_count=1, instance_type=instance_type, endpoint_name=endpoint_name, volume_size=512, # increase the size to store large model model_data_download_timeout=3600, # increase the timeout to download large model container_startup_health_check_timeout=600, # increase the timeout to load large model )
  4. Inicialize uma classe para processar a resposta de streaming, conforme mostrado no exemplo a seguir.

    import io class Parser: """ A helper class for parsing the byte stream input. The output of the model will be in the following format: ``` b'{"outputs": [" a"]}\n' b'{"outputs": [" challenging"]}\n' b'{"outputs": [" problem"]}\n' ... ``` While usually each PayloadPart event from the event stream will contain a byte array with a full json, this is not guaranteed and some of the json objects may be split across PayloadPart events. For example: ``` {'PayloadPart': {'Bytes': b'{"outputs": '}} {'PayloadPart': {'Bytes': b'[" problem"]}\n'}} ``` This class accounts for this by concatenating bytes written via the 'write' function and then exposing a method which will return lines (ending with a '\n' character) within the buffer via the 'scan_lines' function. It maintains the position of the last read position to ensure that previous bytes are not exposed again. """ def __init__(self): self.buff = io.BytesIO() self.read_pos = 0 def write(self, content): self.buff.seek(0, io.SEEK_END) self.buff.write(content) data = self.buff.getvalue() def scan_lines(self): self.buff.seek(self.read_pos) for line in self.buff.readlines(): if line[-1] != b'\n': self.read_pos += len(line) yield line[:-1] def reset(self): self.read_pos = 0
  5. Teste uma predição de resposta de streaming, conforme mostrado no exemplo a seguir.

    import json body = "Today the weather is really nice and I am planning on".encode('utf-8') resp = smr.invoke_endpoint_with_response_stream(EndpointName=endpoint_name, Body=body, ContentType="application/json") event_stream = resp['Body'] parser = Parser() for event in event_stream: parser.write(event['PayloadPart']['Bytes']) for line in parser.scan_lines(): print(line.decode("utf-8"), end=' ')

Agora você já implantou o modelo em um endpoint do SageMaker AI e certamente conseguirá invocá-lo para obter respostas. Para ter mais informações sobre os endpoints em tempo real do SageMaker AI, consulte Endpoints de modelo único.