Déployez de grands modèles à des fins d'inférence avec TorchServe - Amazon SageMaker

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Déployez de grands modèles à des fins d'inférence avec TorchServe

Ce didacticiel explique comment déployer de grands modèles et utiliser l'inférence dans Amazon SageMaker avec TorchServe onGPUs. Cet exemple déploie le modèle OPT-30b sur une instance. ml.g5 Vous pouvez le modifier pour l'adapter à d'autres modèles et types d'instance. Remplacez les informations figurant italicized placeholder text dans les exemples par vos propres informations.

TorchServe est une puissante plateforme ouverte pour l'inférence de modèles distribués à grande échelle. En prenant en charge les bibliothèques populaires telles que PyTorch Native P iPPy et HuggingFace Accelerate, il offre un gestionnaire uniforme APIs qui reste cohérent entre les scénarios d'inférence de grands modèles distribués et de modèles non distribués. DeepSpeed Pour plus d'informations, consultez TorchServela documentation sur l'inférence de grands modèles.

Conteneurs de deep learning avec TorchServe

Pour déployer un modèle de grande taille avec TorchServe on SageMaker, vous pouvez utiliser l'un des conteneurs de SageMaker deep learning (DLCs). Par défaut, TorchServe est installé dans tous AWS PyTorchDLCs. Pendant le chargement du modèle, TorchServe vous pouvez installer des bibliothèques spécialisées adaptées aux grands modèles tels que PiPPy, Deepspeed et Accelerate.

Le tableau suivant répertorie tous les SageMaker DLCsavec TorchServe.

DLCcatégorie Framework Matériel Exemple URL

SageMaker Contenants Framework

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 Conteneurs 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

Conteneurs d'inférence 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

Conteneurs Neuron

PyTorch 1.13.1

Neurones

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

Premiers pas

Avant de déployer votre modèle, remplissez les conditions préalables. Vous pouvez également configurer les paramètres de votre modèle et personnaliser le code du gestionnaire.

Prérequis

Avant de démarrer, vérifiez que les conditions préalables suivantes sont respectées :

  1. Assurez-vous d'avoir accès à un AWS compte. Configurez votre environnement de manière à ce qu' AWS CLI ils puissent accéder à votre compte par le biais d'un AWS IAM utilisateur ou d'un IAM rôle. Nous vous recommandons d'utiliser un IAM rôle. À des fins de test dans votre compte personnel, vous pouvez associer les politiques d'autorisations gérées suivantes au IAM rôle :

    Pour plus d'informations sur IAM l'attachement de politiques à un rôle, consultez la section Ajouter et supprimer des autorisations IAM d'identité dans le Guide de AWS IAM l'utilisateur.

  2. Configurez vos dépendances localement, comme indiqué dans les exemples suivants.

    1. Installez la version 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. Installez SageMaker et le client 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

Configuration des paramètres et des paramètres du modèle

TorchServe permet torchrunde configurer l'environnement distribué pour le traitement parallèle des modèles. TorchServe a la capacité de prendre en charge plusieurs travailleurs pour un modèle de grande taille. TorchServe Utilise par défaut un algorithme circulaire pour l'attribuer GPUs à un travailleur sur un hôte. Dans le cas d'une inférence de modèle à grande échelle, le nombre de travailleurs GPUs affectés à chaque travailleur est automatiquement calculé en fonction du nombre GPUs spécifié dans le model_config.yaml fichier. La variable d'environnementCUDA_VISIBLE_DEVICES, qui spécifie les GPU appareils IDs visibles à un moment donné, est définie en fonction de ce nombre.

Par exemple, supposons qu'il y en ait 8 GPUs sur un nœud et qu'un travailleur en ait besoin de 4 GPUs sur un nœud (nproc_per_node=4). Dans ce cas, en TorchServe attribue quatre GPUs au premier travailleur (CUDA_VISIBLE_DEVICES="0,1,2,3") et quatre GPUs au second travailleur (CUDA_VISIBLE_DEVICES="4,5,6,7”).

Outre ce comportement par défaut, TorchServe offre aux utilisateurs la flexibilité de spécifier GPUs pour un travailleur. Par exemple, si vous définissez la variable deviceIds: [2,3,4,5] dans le YAMLfichier de configuration du modèle, puis que vous la définisseznproc_per_node=2, puis que vous TorchServe l'CUDA_VISIBLE_DEVICES=”2,3”assignez au premier et CUDA_VISIBLE_DEVICES="4,5” au second programme de travail.

Dans l'model_config.yamlexemple suivant, nous configurons les paramètres frontaux et principaux pour le modèle OPT-30b. Les paramètres frontaux configurés sont parallelTypedeviceType, deviceIds ettorchrun. Pour des informations plus détaillées sur les paramètres frontaux que vous pouvez configurer, consultez la PyTorch GitHub documentation. La configuration du back-end est basée sur une YAML carte qui permet une personnalisation de style libre. Pour les paramètres du back-end, nous définissons la DeepSpeed configuration et les paramètres supplémentaires utilisés par le code du gestionnaire personnalisé.

# 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

Personnaliser les gestionnaires

TorchServe propose des gestionnaires de base et des utilitaires de gestion pour l'inférence de grands modèles conçus à l'aide de bibliothèques populaires. L'exemple suivant montre comment la classe de gestionnaire personnalisée TransformersSeqClassifierHandlerétend BaseDeepSpeedHandleret utilise les utilitaires de gestion. Pour un exemple de code complet, consultez le custom_handler.pycode figurant dans la PyTorch GitHub documentation.

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

Préparation des artefacts de votre modèle

Avant de déployer votre modèle sur SageMaker, vous devez empaqueter les artefacts de votre modèle. Pour les modèles de grande taille, nous vous recommandons d'utiliser l' PyTorch torch-model-archiveroutil avec l'argument--archive-format no-archive, qui ignore la compression des artefacts du modèle. L'exemple suivant enregistre tous les artefacts du modèle dans un nouveau dossier nommé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

Une fois le opt/ dossier créé, téléchargez le modèle OPT -30b dans le dossier à l'aide de l'outil PyTorch Download_model.

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

Enfin, téléchargez les artefacts du modèle dans un compartiment Amazon S3.

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

Vous devriez désormais disposer d'artefacts de modèle stockés dans Amazon S3 prêts à être déployés sur un SageMaker point de terminaison.

Déployez le modèle à l'aide du SageMaker Python SDK

Après avoir préparé les artefacts de votre modèle, vous pouvez déployer votre modèle sur un point de terminaison SageMaker d'hébergement. Cette section explique comment déployer un seul grand modèle sur un point de terminaison et établir des prévisions de réponse au streaming. Pour plus d'informations sur le streaming des réponses provenant des points de terminaison, consultez la section Invoquer des points de terminaison en temps réel.

Pour déployer votre modèle, procédez comme suit :

  1. Créez une SageMaker session, comme indiqué dans l'exemple suivant.

    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. Créez un modèle non compressé dans SageMaker, comme indiqué dans l'exemple suivant.

    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. Déployez le modèle sur une EC2 instance Amazon, comme illustré dans l'exemple suivant.

    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. Initialisez une classe pour traiter la réponse de streaming, comme indiqué dans l'exemple suivant.

    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. Testez une prédiction de réponse au streaming, comme illustré dans l'exemple suivant.

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

Vous avez maintenant déployé votre modèle sur un SageMaker point de terminaison et vous devriez pouvoir l'invoquer pour obtenir des réponses. Pour plus d'informations sur les points de terminaison SageMaker en temps réel, consultezPoints de terminaison à modèle unique.