使用Amazon SageMaker轻松打包和部署经典ML和LLMs,第一部分:PySDK的改进

使用Amazon SageMaker轻松打包和部署经典ML和LLMs:PySDK改进系列之一

Amazon SageMaker 是一项全面托管的服务,使开发人员和数据科学家能够快速轻松地构建、训练和部署任何规模的机器学习(ML)模型。SageMaker通过API调用直接将模型部署到生产环境中,使部署模型变得简单直接。模型被打包成容器,以实现稳健且可扩展的部署。虽然它提供了多种入口,如SageMaker Python SDK、AWS SDK、SageMaker控制台以及Amazon SageMaker Studio笔记本,以简化大规模训练和部署ML模型的过程,但客户仍然寻求更好的方法来为操场测试部署他们的模型并优化生产环境中的部署。

我们正在推出两种新方法来简化使用SageMaker打包和部署模型的过程。

在本文中,我们介绍了新的SageMaker Python SDK ModelBuilder体验,旨在降低像数据科学家这样的新SageMaker用户的学习曲线,同时帮助经验丰富的MLOps工程师最大程度地利用SageMaker托管服务。该体验降低了初始设置和部署的复杂性,并通过提供关于充分利用SageMaker功能的最佳实践指导。我们为这种新的SageMaker功能提供了详细的信息和GitHub示例。

另一项新推出是使用SageMaker Studio中的新互动部署体验。我们将在第二部分中讨论此内容。

将模型部署到SageMaker端点需要一系列步骤,以使模型准备好在SageMaker端点上托管。这包括以正确的格式和结构获取模型工件、创建推断代码以及指定模型镜像URL、亚马逊简单存储服务(Amazon S3)模型工件位置、序列化和反序列化步骤以及必要的AWS身份和访问管理(IAM)角色以便提供适当的访问权限。在此之后,端点配置需要确定推断类型并配置相应的参数,如实例类型、数量和模型变体之间的流量分配。

为了帮助客户在使用SageMaker托管时进一步提高效率,我们在SageMaker Python SDK中引入了新的ModelBuilder类,它在将模型部署到SageMaker端点时提供了以下关键优势:

  • 统一跨框架的部署体验 – 新的体验为使用不同框架(如PyTorch、TensorFlow和XGBoost)构建的模型提供了一致的工作流程。这简化了部署过程。
  • 自动化模型部署 – 选择适当的容器、捕获依赖关系和处理序列化/反序列化等任务被自动化,减少了部署所需的手动工作。
  • 平稳过渡从本地到SageMaker托管端点 – 通过最小的代码更改,模型可以轻松地从本地测试过渡到SageMaker端点上的部署。实时日志使调试变得无缝。

总的来说,SageMakerModelBuilder通过处理底层细节并提供测试、验证和优化端点的工具,简化和优化了SageMaker推理的模型打包过程。这提高了开发人员的生产力并减少了错误。

在接下来的章节中,我们将深入探讨这一新功能的细节。我们还讨论了如何使用ModelBuilder将模型部署到SageMaker托管环境中,从而简化了该过程。然后我们将为不同的框架演示一些示例,以部署传统的ML模型和支持生成式AI用例的基础模型。

了解SageMaker ModelBuilder

新的ModelBuilder是一个专注于将使用XGBoost或PyTorch等框架构建的ML模型转换为可在SageMaker上部署的模型的Python类。 ModelBuilder提供了一个build()函数,根据模型服务器生成工件,并提供一个deploy()函数,用于本地部署或部署到SageMaker端点。这一功能的引入简化了模型与SageMaker环境的集成,优化了它们的性能和可伸缩性。下图显示了ModelBuilder在高级别上的工作原理。

ModelBuilder类

ModelBuilder类提供不同的自定义选项。 但是,要部署框架模型,模型构建器只需要模型,输入,输出和角色:

  class ModelBuilder(model,#模型ID或模型对象role_arn,#IAM角色schema_builder,#定义输入和输出mode,#选择本地部署和局域网之间…) 

Schema Builder

SchemaBuilder类使您能够为终端定义输入和输出。 它允许模式生成器生成用于序列化和反序列化输入和输出的相应封送函数。 以下类文件提供了所有自定义选项:

  class SchemaBuilder (sample_input:Any,sample_output:Any,input_translator:CustomPayloadTranslator = None,output_translator:CustomPayloadTranslator = None) 

但是,在大多数情况下,只需样本输入和输出即可。 例如:

  input =“演示进行得如何?”output =“Comment la démo va-t-elle?”schema = SchemaBuilder(input,output) 

通过提供样本输入和输出, SchemaBuilder 可以自动确定所需的转换,使集成过程更加简单。 对于更高级的用例,还可以灵活地提供自定义的输入和输出翻译函数,以确保更复杂的数据结构也可以高效处理。 我们在以下部分中通过使用 ModelBuilder 使用不同的框架部署不同的模型来演示这一点。

本地模式体验

在此示例中,我们使用 ModelBuilder 在本地部署XGBoost模型。您可以使用Mode在本地测试和部署到SageMaker端点之间切换。我们首先训练XGBoost模型(在本地或在SageMaker中)并将模型工件存储在工作目录中:

 #训练模型model = XGBClassifier()model.fit(X_train,y_train)model.save_model(model_dir +“/ my_model.xgb”) 

然后,通过传递实际模型对象,使用使用示例测试输入和输出对象的 SchemaBuilder 创建一个ModelBuilder对象(与我们在训练和测试模型时使用的相同输入和输出)来推断所需的序列化。请注意,我们使用 Mode.LOCAL_CONTAINER 来指定本地部署。之后,我们调用构建函数,以自动识别支持的框架容器映像以及扫描依赖项。请参见以下代码:

  model_builder_local = ModelBuilder(model = model,schema_builder = SchemaBuilder(X_test,y_pred),role_arn = execution_role,mode = Model.LOCAL_CONTAINER)
xgb_local_builder = model_builder_local.build() 

最后,我们可以在模型对象中调用 deploy 函数,该函数还提供实时日志记录以便更容易进行调试。您无需指定实例类型或计数,因为模型将在本地部署。如果您提供了这些参数,它们将被忽略。此功能将返回我们可以用来处理测试数据的预测器对象:

 #注意:所有序列化和反序列化都由模型构建器处理。predictor_local = xgb_local_builder.deploy(# instance_type ='ml.c5.xlarge',# initial_instance_count = 1)#对测试数据进行预测。预测器_local.predict(X_test) 

另外,您还可以使用 InferenceSpec 控制模型的加载以及预处理和后处理。我们稍后在此帖子中提供更多详细信息。使用 LOCAL_CONTAINER 是在部署到SageMaker端点之前在本地测试脚本的好方法。

有关使用 ModelBuilder 在本地和SageMaker端点上进行部署的测试,请参阅 model-builder-xgboost.ipynb 示例。

部署传统模型到SageMaker端点

在以下示例中,我们展示如何使用ModelBuilder来部署传统的机器学习模型。

XGBoost模型

与前面的部分类似,您可以通过在创建ModelBuilder对象时更改mode参数来将XGBoost模型部署到SageMaker端点:

model_builder = ModelBuilder(    model=model,      schema_builder=SchemaBuilder(sample_input=sample_input, sample_output=sample_output),     role_arn=execution_role,     mode=Mode.SAGEMAKER_ENDPOINT)xgb_builder = model_builder.build()predictor = xgb_builder.deploy(    instance_type='ml.c5.xlarge',    initial_instance_count=1)

请注意,在部署到SageMaker端点时,您需要在调用deploy函数时指定实例类型和实例数量。

请参阅model-builder-xgboost.ipynb示例以部署XGBoost模型。

Triton模型

您可以使用ModelBuilderTriton Inference Server上提供PyTorch模型的服务。为此,您需要将model_server参数指定为ModelServer.TRITON,传递一个模型,并使用SchemaBuilder对象,该对象需要来自模型的示例输入和输出。ModelBuilder将为您处理其余的工作。

model_builder = ModelBuilder(    model=model,      schema_builder=SchemaBuilder(sample_input=sample_input, sample_output=sample_output),     role_arn=execution_role,    model_server=ModelServer.TRITON,     mode=Mode.SAGEMAKER_ENDPOINT)triton_builder = model_builder.build()predictor = triton_builder.deploy(    instance_type='ml.g4dn.xlarge',    initial_instance_count=1)

请参阅model-builder-triton.ipynb以部署Triton模型。

Hugging Face模型

在此示例中,我们展示如何将Hugging Face提供的预训练transformer模型部署到SageMaker。我们想要使用Hugging Face的pipeline加载模型,因此我们为ModelBuilder创建了一个自定义的推断规范:

# 使用Hugging Face 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()

我们还通过基于模型输入和输出定义SchemaBuilder对象来定义推断工作负载的输入和输出:

schema = SchemaBuilder(value,output)

然后,我们创建ModelBuilder对象,并按照其他示例中显示的相同逻辑将模型部署到SageMaker端点:

builder = ModelBuilder(    inference_spec=inf_spec,    mode=Mode.SAGEMAKER_ENDPOINT,  # 您可以将其更改为Mode.LOCAL_CONTAINER进行本地测试    schema_builder=schema,    image_uri=image,)model = builder.build(    role_arn=execution_role,    sagemaker_session=sagemaker_session,)predictor = model.deploy(    initial_instance_count=1,    instance_type='ml.g5.2xlarge')

请参阅model-builder-huggingface.ipynb以部署Hugging Face pipeline模型。

部署基础模型到SageMaker端点

在以下示例中,我们展示了如何使用ModelBuilder部署基础模型。与之前提到的模型一样,所需的只是模型ID。

Hugging Face Hub

如果您想从Hugging Face Hub部署基础模型,您只需要传递预训练的模型ID。例如,以下代码片段在本地部署了meta-llama/Llama-2-7b-hf模型。您可以将模式更改为Mode.SAGEMAKER_ENDPOINT以部署到SageMaker端点。

model_builder = ModelBuilder(    model="meta-llama/Llama-2-7b-hf",    schema_builder=SchemaBuilder(sample_input, sample_output),    model_path="/home/ec2-user/SageMaker/LoadTestResources/meta-llama2-7b", #本地保存工件的路径    mode=Mode.LOCAL_CONTAINER,    env_vars={        # Llama 2是一个受保护的模型,需要一个Hugging Face Hub令牌。        "HUGGING_FACE_HUB_TOKEN": "<YourHuggingFaceToken>"     })model = model_builder.build()local_predictor = model.deploy()

对于Hugging Face Hub上的受保护模型,您需要通过Hugging Face Hub请求访问并使用关联键将其作为环境变量HUGGING_FACE_HUB_TOKEN传递。一些Hugging Face模型可能需要信任远程代码。也可以使用HF_TRUST_REMOTE_CODE将其设置为环境变量。默认情况下,ModelBuilder将使用Hugging Face文本生成推断(TGI)容器作为Hugging Face模型的底层容器。如果要使用AWS大型模型推断(LMI)容器,您可以在配置ModelBuilder对象时将model_server参数设置为ModelServer.DJL_SERVING

ModelBuilder的一个很棒的功能是在使用LOCAL_CONTAINER模式时可以运行容器参数的本地调优。只需运行tuned_model = model.tune()即可使用此功能。

请参阅demo-model-builder-huggingface-llama2.ipynb以部署Hugging Face Hub模型。

SageMaker JumpStart

Amazon SageMaker JumpStart还提供了许多预训练的基础模型。与从Hugging Face Hub部署模型的过程类似,需要模型ID。将SageMaker JumpStart模型部署到SageMaker端点就像运行以下代码一样简单:

model_builder = ModelBuilder(    model="huggingface-llm-falcon-7b-bf16",    schema_builder=SchemaBuilder(sample_input, sample_output),    role_arn=execution_role)sm_ep_model = model_builder.build()predictor = sm_ep_model.deploy()

有关所有可用的SageMaker JumpStart模型ID,请参阅内置算法与预训练模型表。请参阅model-builder-jumpstart-falcon.ipynb以部署SageMaker JumpStart模型。

推理组件

ModelBuilder允许您使用SageMaker中的新推理组件功能部署模型。有关推理组件的更多信息,请参阅使用SageMaker的最新功能平均减少50%的模型部署成本。您可以通过在deploy()方法中指定endpoint_type=EndpointType.INFERENCE_COMPONENT_BASED来将推理组件用于ModelBuilder的部署。您还可以使用tune()方法,该方法会获取最佳加速器数量,并在需要时进行修改。

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

请参阅model-builder-inference-component.ipynb以将模型部署为推理组件。

自定义ModelBuilder类

ModelBuilder类允许您使用InferenceSpec自定义模型加载。

此外,您可以使用CustomPayloadTranslator来控制有效负载和响应的序列化和反序列化,并自定义预处理和后处理。此外,当您需要扩展我们预先构建的用于SageMaker模型部署的容器时,可以使用ModelBuilder来处理模型打包过程。在以下部分,我们提供了更多关于这些功能的详细信息。

InferenceSpec

InferenceSpec提供了额外的自定义层。它允许您定义模型的加载方式以及如何处理传入的推理请求。通过InferenceSpec,您可以为您的模型定义自定义加载过程,绕过默认的加载机制。当处理非标准模型或自定义推理流程时,这种灵活性尤为有益。可以自定义invoke方法,以精确地处理传入请求的模型过程(预处理和后处理)。定制化对于确保推理过程与模型的特定需求相符合非常重要。参见以下代码:

class InferenceSpec(abc.ABC):    @abc.abstractmethod    def load(self, model_dir: str):        pass    @abc.abstractmethod    def invoke(self, input_object: object, model: object):        pass

以下代码显示了使用此类的示例:

class MyInferenceSpec(InferenceSpec):    def load(self, model_dir: str):        return // model object    def invoke(self, input, model):        return model(input)

CustomPayloadTranslator

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

  1. 推理请求序列化(由客户端处理)
  2. 推理请求反序列化(由服务器或算法处理)
  3. 针对有效负载调用模型
  4. 发送响应有效负载
  5. 推理响应序列化(由服务器或算法处理)
  6. 推理响应反序列化(由客户端处理)

以下图示说明了在调用过程中进行序列化和反序列化的过程。

在下面的代码片段中,我们展示了CustomPayloadTranslator的一个示例,当需要额外的自定义处理来处理客户端和服务器端的序列化和反序列化时:

from sagemaker.serve import CustomPayloadTranslator# 请求翻译类class MyRequestTranslator(CustomPayloadTranslator):    # 此函数将有效负载序列化为字节 - 发生在客户端    def serialize_payload_to_bytes(self, payload: object) -> bytes:        # 将输入有效负载转换为字节        ... ...        return  //以字节形式返回对象            # 此函数将字节反序列化为有效负载 - 发生在服务器端    def deserialize_payload_from_stream(self, stream) -> object:        # 将字节转换为内存中的对象        ... ...        return //以内存对象返回        # 响应翻译类class MyResponseTranslator(CustomPayloadTranslator):    # 此函数将有效负载序列化为字节 - 发生在服务器端    def serialize_payload_to_bytes(self, payload: object) -> bytes:        # 将响应有效负载转换为字节        ... ...        return //以字节形式返回对象        # 此函数将字节反序列化为有效负载 - 发生在客户端    def deserialize_payload_from_stream(self, stream) -> object:        # 将字节转换为内存中的对象        ... ...        return //以内存对象返回

demo-model-builder-pytorch.ipynb笔记本中,我们演示了如何使用ModelBuilderCustomPayloadTranslatorInferenceSpec类轻松部署PyTorch模型到SageMaker端点。

为部署准备模型

如果您想要将模型进行分析或在模型注册表中进行分析,您可以使用model.create()model.register()

model_builder = ModelBuilder(    model=model,      schema_builder=SchemaBuilder(X_test, y_pred),     role_arn=execution_role, )deployable_model = model_builder.build()deployable_model.create() # 可以使用deployable_model.register()来进行模型注册

使用自定义容器

SageMaker为其内置算法和用于训练和推理的支持深度学习框架提供预构建的Docker镜像。如果预构建的SageMaker容器无法满足您的所有需求,您可以扩展现有镜像以满足您的需求。通过扩展预构建镜像,您可以使用其中包含的深度学习库和设置,而无需从头创建镜像。有关如何扩展预构建容器的详细信息,请参阅SageMaker文档。ModelBuilder支持使用自定义容器的用例,这些容器是从我们预构建的Docker容器扩展的。

在这种情况下,要使用自己的容器镜像,您需要在定义ModelBuilder时设置image_urimodel_server字段:

model_builder = ModelBuilder(    model=model,  # 传入实际的模型对象。在端点中将调用其"predict"方法。    schema_builder=SchemaBuilder(X_test, y_pred), # 传入一个"SchemaBuilder",它将使用示例测试输入和输出对象来推断所需的序列化。    role_arn=execution_role,     image_uri=image_uri, # BYOC所需:传入个人ECR Repo中托管的镜像    model_server=ModelServer.TORCHSERVE, # BYOC所需:传入所选的模型服务器    mode=Mode.SAGEMAKER_ENDPOINT,    dependencies={"auto": True, "custom": ["protobuf==3.20.2"]})

这里,image_uri将是存储在您账户的Amazon Elastic Container Registry(Amazon ECR)仓库中的容器镜像ARN。以下是一个示例:

# 拉取了 xgboost:1.7-1 DLC,并推送到个人 ECR 仓库image_uri = "<your_account_id>.dkr.ecr.us-west-2.amazonaws.com/my-byoc:xgb"

当设置了image_uri时,在ModelBuilder构建过程中,它将跳过图像的自动检测,因为提供了图像 URI。如果model_server在 ModelBuilder 中未设置,则将收到验证错误消息,例如:

ValueError: 当设置 image_uri 时,必须设置 model_server。支持的模型服务器:{<ModelServer.TRITON: 5>, <ModelServer.DJL_SERVING: 4>, <ModelServer.TORCHSERVE: 1>}

截至本贴文发布时,ModelBuilder支持使用我们的预构建 DLC 容器镜像扩展您自己的容器,或者使用Deep Java Library (DJL)Text Generation Inference (TGI)TorchServeTriton inference server 构建的模型服务器容器。

自定义依赖

当运行ModelBuilder.build()时,默认情况下它会自动将您的 Python 环境捕获到一个requirements.txt文件中,并在容器中安装相同的依赖项。然而,有时您的本地 Python 环境与容器中的环境发生冲突。ModelBuilder允许您提供自定义配置来修复此类依赖冲突,为您修改捕获的依赖项提供了一种简单的方式。请注意,这仅适用于 TorchServe 和 Triton 与InferenceSpec。例如,您可以在 ModelBuilder 中指定输入参数依赖项,这是一个 Python 字典,如下所示:

dependency_config = {   "auto" = True,   "requirements" = "/path/to/your/requirements.txt"   "custom" = ["module>=1.2.3,<1.5", "boto3==1.16.*", "some_module@http://some/url"]}  ModelBuilder(    # Other params    dependencies=dependency_config,).build()

我们定义了以下字段:

  • auto – 是否尝试自动捕获环境中的依赖项。
  • requirements – 到您自己的requirements.txt文件的路径字符串。(这是可选的。)
  • custom – 任何其他您想添加或修改的自定义依赖项的列表。(这是可选的。)

如果在多个位置指定了同一模块,custom将具有最高优先级,然后是requirementsauto将具有最低优先级。例如,假设在自动检测期间,ModelBuilder检测到numpy==1.25,并提供了一个指定numpy>=1.24,<1.26requirements.txt文件。另外,还有一个自定义依赖项:custom = ["numpy==1.26.1"]。在这种情况下,我们在容器中安装依赖项时将选择numpy==1.26.1

清理

当完成模型测试后,作为一项最佳实践,如果不再需要该端点,请删除端点以节省成本。您可以按照每个演示笔记本中的清理部分进行操作,或者使用以下代码删除演示创建的模型和端点:

predictor.delete_model()predictor.delete_endpoint()

结论

新的SageMaker ModelBuilder功能简化了在SageMaker上将机器学习模型部署到生产环境的过程。通过在幕后处理许多复杂的细节,ModelBuilder降低了新用户的学习曲线,并最大程度地利用了经验丰富的用户的能力。只需几行代码,您就可以将内置的XGBoost、PyTorch、Triton和Hugging Face等框架以及SageMaker JumpStart提供的模型部署到SageMaker上的稳健、可伸缩的终端。

我们鼓励所有的SageMaker用户通过参考ModelBuilder文档页面来尝试这个新的功能。ModelBuilder现已向所有SageMaker用户免费提供。利用这个简化的工作流程来加快您的模型部署速度。我们期待听到ModelBuilder如何加速您的模型开发生命周期的消息!

特别感谢Sirisha Upadhyayala、Raymond Liu、Gary Wang、Dhawal Patel、Deepak Garg和Ram Vegiraju。