Implemente modelos de gran tamaño para realizar inferencias con TorchServe - Amazon SageMaker

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Implemente modelos de gran tamaño para realizar inferencias con TorchServe

En este tutorial se muestra cómo implementar modelos grandes y realizar inferencias en Amazon SageMaker con TorchServe onGPUs. En este ejemplo, se implementa el modelo OPT-30b en una instancia. ml.g5 Puede modificarlo para que funcione con otros modelos y tipos de instancias. En el ejemplo, sustituya italicized placeholder text por su propia información.

TorchServe es una potente plataforma abierta para la inferencia de modelos distribuidos de gran tamaño. Al ser compatible con bibliotecas populares PyTorch, como Native P y HuggingFace Accelerate iPPy DeepSpeed, ofrece un controlador uniforme APIs que mantiene la coherencia en todos los escenarios de inferencia de modelos distribuidos de gran tamaño y no distribuidos. Para obtener más información, consulte la documentación TorchServede inferencia de modelos de gran tamaño.

Contenedores de aprendizaje profundo con TorchServe

Para implementar un modelo grande con TorchServe on SageMaker, puede usar uno de los contenedores de aprendizaje SageMaker profundo (DLCs). De forma predeterminada, TorchServe está instalado en todos AWS PyTorchDLCs. Durante la carga del modelo, TorchServe puede instalar bibliotecas especializadas diseñadas para modelos grandes, como PiPPy, Deepspeed y Accelerate.

En la siguiente tabla se muestran todas las anchas SageMaker DLCs. TorchServe

DLCcategoría Marcos Hardware Ejemplo URL

SageMaker Contenedores marco

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

SageMaker Contenedores Framework Graviton

PyTorch 2.0.0+

CPU

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

Contenedores de inferencias de StabilityAI

PyTorch 2.0.0+

GPU

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

Contenedores Neuron

PyTorch 1.13.1

Neuronx

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

Introducción

Antes de implementar el modelo, complete los requisitos previos. También se pueden configurar los parámetros del modelo y personalizar el código del controlador.

Requisitos previos

Antes de comenzar, compruebe que cumple los siguientes requisitos previos:

  1. Asegúrese de tener acceso a una cuenta. AWS Configure su entorno para que AWS CLI puedan acceder a su cuenta a través de un AWS IAM usuario o un IAM rol. Recomendamos usar un IAM rol. Para realizar pruebas en tu cuenta personal, puedes adjuntar al IAM rol las siguientes políticas de permisos administrados:

    Para obtener más información sobre cómo asociar IAM políticas a un rol, consulte Añadir y eliminar permisos de IAM identidad en la Guía del AWS IAMusuario.

  2. Configure sus dependencias de forma local, como se muestra en los siguientes ejemplos.

    1. Instale la versión 2 de 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. La instalación SageMaker y el 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

Configure los ajustes y los parámetros del modelo

TorchServe se utiliza torchrunpara configurar el entorno distribuido para el procesamiento paralelo de modelos. TorchServe tiene la capacidad de admitir a varios trabajadores en un modelo grande. De forma predeterminada, TorchServe utiliza un algoritmo por turnos para asignar GPUs a un trabajador de un host. En el caso de la inferencia de modelos grandes, el número de trabajadores GPUs asignados a cada trabajador se calcula automáticamente en función del número GPUs especificado en el model_config.yaml archivo. La variable de entornoCUDA_VISIBLE_DEVICES, que especifica los GPU dispositivos IDs que están visibles en un momento dado, se establece en función de este número.

Por ejemplo, supongamos que hay 8 GPUs en un nodo y un trabajador necesita 4 GPUs en un nodo (nproc_per_node=4). En este caso, TorchServe asigna cuatro GPUs al primer trabajador (CUDA_VISIBLE_DEVICES="0,1,2,3") y cuatro GPUs al segundo trabajador (CUDA_VISIBLE_DEVICES="4,5,6,7”).

Además de este comportamiento predeterminado, TorchServe proporciona a los usuarios la flexibilidad de especificar GPUs un trabajador. Por ejemplo, si se establece la variable deviceIds: [2,3,4,5] en el YAMLarchivo de configuración del modelo y se establecenproc_per_node=2, se TorchServe asigna CUDA_VISIBLE_DEVICES=”2,3” al primer elemento de trabajo y CUDA_VISIBLE_DEVICES="4,5” al segundo elemento de trabajo.

En el siguiente model_config.yaml ejemplo, configuramos los parámetros de front-end y back-end para el modelo -30b. OPT Los parámetros de front-end configurados son parallelType, deviceType, deviceIds y torchrun. Para obtener información más detallada sobre los parámetros de interfaz que puede configurar, consulte la documentación. PyTorch GitHub La configuración de fondo se basa en un YAML mapa que permite una personalización de estilo libre. Para los parámetros de back-end, definimos la DeepSpeed configuración y los parámetros adicionales que utiliza el código de controlador 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

Personalización de controladores

TorchServe ofrece controladores básicos y utilidades de manejo para la inferencia de modelos grandes creados con bibliotecas populares. El siguiente ejemplo demuestra cómo la clase de controlador personalizada TransformersSeqClassifierHandleramplía BaseDeepSpeedHandlery utiliza las utilidades de controlador. Para ver un ejemplo de código completo, consulta el custom_handler.pycódigo de la PyTorch GitHub documentación.

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

Preparación de los artefactos de su modelo

Antes de implementar el modelo SageMaker, debe empaquetar los artefactos del modelo. Para modelos grandes, le recomendamos que utilice la PyTorch torch-model-archiverherramienta con el argumento--archive-format no-archive, ya que evita la compresión de los artefactos del modelo. El siguiente ejemplo guarda todos los artefactos del modelo en una nueva carpeta denominada 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

Una vez creada la opt/ carpeta, descargue el modelo OPT -30b a la carpeta mediante la PyTorch herramienta Download_model.

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

Por último, cargue los artefactos del modelo en un bucket de Amazon S3.

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

Ahora debería tener los artefactos del modelo almacenados en Amazon S3 que estén listos para implementarse en un SageMaker punto final.

Implemente el modelo mediante SageMaker Python SDK

Después de preparar los artefactos del modelo, puede implementarlo en un punto final de SageMaker Hosting. En esta sección se describe cómo implementar un único modelo grande en un punto de conexión y realizar predicciones de respuesta en transmisión. Para obtener más información sobre la transmisión de las respuestas desde los puntos de conexión, consulte Invocar puntos de conexión en tiempo real.

Para implementar el modelo, siga los pasos que se describen a continuación:

  1. Cree una SageMaker sesión, como se muestra en el siguiente ejemplo.

    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 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. Cree un modelo sin comprimir en SageMaker, como se muestra en el siguiente ejemplo.

    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. Implemente el modelo en una EC2 instancia de Amazon, como se muestra en el siguiente ejemplo.

    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. Inicie una clase para procesar la respuesta de transmisión, como se muestra en el siguiente ejemplo.

    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. Pruebe una predicción de respuesta de transmisión, como se muestra en el siguiente ejemplo.

    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=' ')

Ahora ha implementado su modelo en un SageMaker punto final y debería poder invocarlo para obtener respuestas. Para obtener más información sobre los puntos finales SageMaker en tiempo real, consulte. Terminales de modelo único