使用在 Amazon SageMaker 中创建模型 ModelBuilder - Amazon SageMaker

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

使用在 Amazon SageMaker 中创建模型 ModelBuilder

准备模型以在 SageMaker 终端节点上部署需要多个步骤,包括选择模型映像、设置终端节点配置、对序列化和反序列化函数进行编码以在服务器和客户端之间传输数据、识别模型依赖关系以及将其上传到 Amazon S3。 ModelBuilder可以降低初始设置和部署的复杂性,帮助您通过一个步骤创建可部署的模型。

ModelBuilder为您执行以下任务:

  • 只需一步即可将使用各种框架(如XGBoost或 PyTorch )训练的机器学习模型转换为可部署的模型。

  • 根据模型框架自动选择容器,因此您不必手动指定容器。您仍然可以通过将自己的集装箱传递给来带上自己的URI集装箱ModelBuilder

  • 在将数据发送到服务器以进行推断和反序列化服务器返回的结果之前,先在客户端处理数据的序列化。无需手动处理即可正确格式化数据。

  • 启用自动捕获依赖关系并根据模型服务器的期望对模型进行打包。 ModelBuilder自动捕获依赖关系是一种尽力动态加载依赖关系的方法。(我们建议您在本地测试自动捕获并更新依赖关系以满足您的需求。)

  • 对于大型语言模型 (LLM) 用例,可以选择对服务属性执行本地参数调整,这些属性可以在 SageMaker 端点上托管时部署以提高性能。

  • 支持大多数流行的模型服务器和容器 TorchServe,例如 Triton DJLServing 和TGI容器。

使用以下方法构建您的模型 ModelBuilder

ModelBuilder是一个 Python 类,它采用框架模型(例如XGBoost或 PyTorch)或用户指定的推理规范,并将其转换为可部署的模型。 ModelBuilder提供了生成要部署的工件的生成函数。生成的模型对象特定于模型服务器,您也可以将其指定为输入之一。有关该ModelBuilder课程的更多详细信息,请参阅ModelBuilder

下图说明了使用时的整个模型创建工作流程ModelBuilderModelBuilder接受模型或推理规范以及您的架构,以创建可在部署之前在本地测试的可部署模型。

使用创建模型和部署流程ModelBuilder。

ModelBuilder可以处理您要应用的任何自定义。但是,要部署框架模型,模型开发者至少需要模型、样本输入和输出以及角色。在下面的代码示例中,ModelBuilder使用框架模型和SchemaBuilder具有最少参数的实例进行调用(以推断出用于序列化和反序列化端点输入和输出的相应函数)。未指定容器,也未传递任何打包的依赖关系,在构建模型时SageMaker 会自动推断出这些资源。

from sagemaker.serve.builder.model_builder import ModelBuilder from sagemaker.serve.builder.schema_builder import SchemaBuilder model_builder = ModelBuilder( model=model, schema_builder=SchemaBuilder(input, output), role_arn="execution-role", )

以下代码示例ModelBuilder使用推理规范(作为InferenceSpec实例)而不是模型进行调用,并进行了额外的自定义。在这种情况下,对模型构建器的调用包括存储模型工件的路径,还会启用所有可用依赖项的自动捕获。有关的其他详细信息InferenceSpec,请参阅自定义模型加载和请求处理

model_builder = ModelBuilder( mode=Mode.LOCAL_CONTAINER, model_path=model-artifact-directory, inference_spec=your-inference-spec, schema_builder=SchemaBuilder(input, output), role_arn=execution-role, dependencies={"auto": True} )

定义序列化和反序列化方法

调用 SageMaker 端点时,数据通过不同类型的HTTPMIME负载发送。例如,发送到端点进行推理的图像需要在客户端转换为字节,然后通过HTTP有效载荷发送到端点。当端点收到有效负载时,它需要将字节字符串反序列化为模型所期望的数据类型(也称为服务器端反序列化)。模型完成预测后,还需要将结果序列化为字节,这些字节可以通过HTTP有效载荷发送回给用户或客户端。客户端收到响应字节数据后,需要执行客户端反序列化以将字节数据转换回预期的数据格式,例如。JSON您至少需要为以下任务转换数据:

  1. 推理请求序列化(由客户端处理)

  2. 推理请求反序列化(由服务器或算法处理)

  3. 针对有效载荷调用模型并发送回响应有效负载

  4. 推理响应序列化(由服务器或算法处理)

  5. 推理响应反序列化(由客户端处理)

下图显示了调用端点时发生的序列化和反序列化过程。

客户端到服务器的数据序列化和反序列化示意图。

当您向提供示例输入和输出时SchemaBuilder,架构生成器会生成相应的编组函数,用于序列化和反序列化输入和输出。您可以使用进一步自定义序列化函数。CustomPayloadTranslator但是在大多数情况下,像下面这样的简单序列化器是可以工作的:

input = "How is the demo going?" output = "Comment la démo va-t-elle?" schema = SchemaBuilder(input, output)

有关的更多详细信息SchemaBuilder,请参阅SchemaBuilder

以下代码片段概述了一个示例,您希望在客户端和服务器端同时自定义序列化和反序列化函数。您可以定义自己的请求和响应翻译器,CustomPayloadTranslator并将这些翻译器传递给SchemaBuilder

通过在转换器中包含输入和输出,模型构建器可以提取模型期望的数据格式。例如,假设样本输入是原始图像,您的自定义翻译器会裁剪图像并将裁剪后的图像作为张量发送到服务器。 ModelBuilder需要原始输入和任何自定义的预处理或后处理代码,才能得出一种在客户端和服务器端转换数据的方法。

from sagemaker.serve import CustomPayloadTranslator # request translator class MyRequestTranslator(CustomPayloadTranslator): # This function converts the payload to bytes - happens on client side def serialize_payload_to_bytes(self, payload: object) -> bytes: # converts the input payload to bytes ... ... return //return object as bytes # This function converts the bytes to payload - happens on server side def deserialize_payload_from_stream(self, stream) -> object: # convert bytes to in-memory object ... ... return //return in-memory object # response translator class MyResponseTranslator(CustomPayloadTranslator): # This function converts the payload to bytes - happens on server side def serialize_payload_to_bytes(self, payload: object) -> bytes: # converts the response payload to bytes ... ... return //return object as bytes # This function converts the bytes to payload - happens on client side def deserialize_payload_from_stream(self, stream) -> object: # convert bytes to in-memory object ... ... return //return in-memory object

创建SchemaBuilder对象时,您可以将示例输入和输出以及先前定义的自定义转换器一起传入,如以下示例所示:

my_schema = SchemaBuilder( sample_input=image, sample_output=output, input_translator=MyRequestTranslator(), output_translator=MyResponseTranslator() )

然后,将示例输入和输出以及先前定义的自定义转换器传递给SchemaBuilder对象。

my_schema = SchemaBuilder( sample_input=image, sample_output=output, input_translator=MyRequestTranslator(), output_translator=MyResponseTranslator() )

以下各节详细说明了如何使用模型构建模型,ModelBuilder以及如何使用其支持类为您的用例自定义体验。

自定义模型加载和请求处理

通过提供自己的推理代码InferenceSpec可以提供额外的自定义层。使用InferenceSpec,您可以绕过模型的默认加载和推理处理机制,自定义模型的加载方式以及如何处理传入的推理请求。在使用非标准模型或自定义推理管道时,这种灵活性特别有益。您可以自定义invoke方法来控制模型如何预处理和后处理传入的请求。该invoke方法可确保模型正确处理推理请求。以下示例InferenceSpec使用 HuggingFace 管道生成模型。有关的更多详细信息InferenceSpec,请参阅InferenceSpec

from sagemaker.serve.spec.inference_spec import InferenceSpec from transformers import pipeline class MyInferenceSpec(InferenceSpec): def load(self, model_dir: str): return pipeline("translation_en_to_fr", model="t5-small") def invoke(self, input, model): return model(input) inf_spec = MyInferenceSpec() model_builder = ModelBuilder( inference_spec=your-inference-spec, schema_builder=SchemaBuilder(X_test, y_pred) )

以下示例说明了前一个示例中更具自定义性的变体。模型是用具有依赖关系的推理规范定义的。在这种情况下,推理规范中的代码依赖于 l ang-seg ment 包。的参数dependencies包含一条语句,该语句指示生成器使用 Git 安装 lang-segmen t。由于用户指示模型构建器自定义安装依赖项,因此auto关键是False关闭依赖项的自动捕获。

model_builder = ModelBuilder( mode=Mode.LOCAL_CONTAINER, model_path=model-artifact-directory, inference_spec=your-inference-spec, schema_builder=SchemaBuilder(input, output), role_arn=execution-role, dependencies={"auto": False, "custom": ["-e git+https://github.com/luca-medeiros/lang-segment-anything.git#egg=lang-sam"],} )

构建您的模型并部署

调用该build函数来创建您的可部署模型。此步骤在您的工作目录中创建推理代码(如inference.py),其中包含创建架构、运行输入和输出的序列化和反序列化以及运行其他用户指定的自定义逻辑所需的代码。

作为完整性检查,作为ModelBuilder构建功能的一部分,打 SageMaker 包和封存部署所需的文件。在此过程中, SageMaker 还会为 pickle 文件创建HMAC签名,并在deploy(或create)期间将密钥CreateModelAPI作为环境变量添加到中。端点启动使用环境变量来验证 pickle 文件的完整性。

# Build the model according to the model server specification and save it as files in the working directory model = model_builder.build()

使用模型的现有deploy方法部署模型。在此步骤中,在模型开始预测传入请求时, SageMaker 设置一个端点来托管模型。尽管可以ModelBuilder推断出部署模型所需的端点资源,但您可以使用自己的参数值覆盖这些估计值。以下示例指示 SageMaker 在单个ml.c6i.xlarge实例上部署模型。通过构建的模型ModelBuilder支持在部署期间进行实时记录,这是一项附加功能。

predictor = model.deploy( initial_instance_count=1, instance_type="ml.c6i.xlarge" )

如果您想更精细地控制分配给模型的端点资源,则ResourceRequirements可以使用对象。使用该ResourceRequirements对象,您可以请求要部署的最少数量的模型CPUs、加速器和副本。您也可以请求内存的最小和最大限制(以 MB 为单位)。要使用此功能,您需要将终端节点类型指定为EndpointType.INFERENCE_COMPONENT_BASED。以下示例请求将四个加速器、最小内存大小为 1024 MB 和一个模型副本部署到类型的EndpointType.INFERENCE_COMPONENT_BASED终端节点。

resource_requirements = ResourceRequirements( requests={ "num_accelerators": 4, "memory": 1024, "copies": 1, }, limits={}, ) predictor = model.deploy( mode=Mode.SAGEMAKER_ENDPOINT, endpoint_type=EndpointType.INFERENCE_COMPONENT_BASED, resources=resource_requirements, role="role" )

自带容器 (BYOC)

如果您想自带容器(从容 SageMaker 器扩展),也可以指定图片,URI如以下示例所示。您还需要识别与图像对应的模型服务器,ModelBuilder以生成特定于模型服务器的工件。

model_builder = ModelBuilder( model=model, model_server=ModelServer.TORCHSERVE, schema_builder=SchemaBuilder(X_test, y_pred), image_uri="123123123123.dkr.ecr.ap-southeast-2.amazonaws.com/byoc-image:xgb-1.7-1") )

ModelBuilder 在本地模式下使用

您可以使用mode参数在本地测试和部署到端点之间切换,从而在本地部署模型。您需要将模型工件存储在工作目录中,如以下代码段所示:

model = XGBClassifier() model.fit(X_train, y_train) model.save_model(model_dir + "/my_model.xgb")

传递模型对象、SchemaBuilder实例,并将模式设置为Mode.LOCAL_CONTAINER。当您调用该build函数时,ModelBuilder会自动识别支持的框架容器并扫描依赖关系。以下示例演示了在局部模式下使用XGBoost模型创建模型。

model_builder_local = ModelBuilder( model=model, schema_builder=SchemaBuilder(X_test, y_pred), role_arn=execution-role, mode=Mode.LOCAL_CONTAINER ) xgb_local_builder = model_builder_local.build()

调用deploy函数进行本地部署,如以下代码段所示。如果您为实例类型或计数指定参数,则会忽略这些参数。

predictor_local = xgb_local_builder.deploy()

本地模式疑难解答

根据您的个人本地设置,在您的环境中ModelBuilder平稳运行可能会遇到困难。有关您可能面临的一些问题以及如何解决这些问题,请参阅以下列表。

  • 已在使用:您可能会遇到Address already in use错误。在这种情况下,可能有一个 Docker 容器正在该端口上运行,或者其他进程正在使用它。您可以按照 Linux 文档中概述的方法来识别进程,并优雅地将本地进程从端口 8080 重定向到另一个端口,或者清理 Docker 实例。

  • IAM权限问题:在尝试提取亚马逊ECR图片或访问 Amazon S3 时,您可能会遇到权限问题。在这种情况下,请导航到笔记本或 Studio Classic 实例的执行角色以验证策略SageMakerFullAccess或相应的API权限。

  • EBS卷容量问题:如果您部署大型语言模型 (LLM),则在本地模式下运行 Docker 时可能会耗尽空间,或者遇到 Docker 缓存的空间限制。在这种情况下,你可以尝试将 Docker 卷移到有足够空间的文件系统中。要移动 Docker 音量,请完成以下步骤:

    1. 打开终端并运行df以显示磁盘使用情况,如以下输出所示:

      (python3) sh-4.2$ df Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 195928700 0 195928700 0% /dev tmpfs 195939296 0 195939296 0% /dev/shm tmpfs 195939296 1048 195938248 1% /run tmpfs 195939296 0 195939296 0% /sys/fs/cgroup /dev/nvme0n1p1 141545452 135242112 6303340 96% / tmpfs 39187860 0 39187860 0% /run/user/0 /dev/nvme2n1 264055236 76594068 176644712 31% /home/ec2-user/SageMaker tmpfs 39187860 0 39187860 0% /run/user/1002 tmpfs 39187860 0 39187860 0% /run/user/1001 tmpfs 39187860 0 39187860 0% /run/user/1000
    2. 将默认 Docker 目录从移/dev/nvme0n1p1至,/dev/nvme2n1这样您就可以充分利用 256 GB 的 SageMaker 容量。有关更多详细信息,请参阅有关如何移动 Docker 目录的文档。

    3. 使用以下命令停止 Docker:

      sudo service docker stop
    4. 在现有的 blob 中添加/etc/docker或将daemon.json以下 JSON blob 附加到现有的 blob 中。

      { "data-root": "/home/ec2-user/SageMaker/{created_docker_folder}" }
    5. /home/ec2-user/SageMaker使用以下命令将 Docker 目录移入:/var/lib/docker

      sudo rsync -aP /var/lib/docker/ /home/ec2-user/SageMaker/{created_docker_folder}
    6. 使用以下命令启动 Docker:

      sudo service docker start
    7. 使用以下命令清理垃圾:

      cd /home/ec2-user/SageMaker/.Trash-1000/files/* sudo rm -r *
    8. 如果您使用的是 SageMaker 笔记本实例,则可以按照 Docker 准备文件中的步骤为本地模式准备 Docker。

ModelBuilder 例子

有关使用ModelBuilder构建模型的更多示例,请参阅ModelBuilder示例笔记本