自动化机器学习工作流:AWS CloudFormation 实战指南
1. 自动化机器学习工作流的必要性
在机器学习模型部署中,使用 SageMaker SDK 和 boto3 SDK 在 Jupyter Notebooks 中进行实验和快速迭代是常见的做法。然而,将笔记本用于生产任务并非良策。即使代码经过了仔细测试,在监控、日志记录、创建其他 AWS 资源、错误处理和回滚等方面,仍需要大量额外的工作和代码,这也增加了出现更多错误的可能性。因此,需要一种更具工业化的方法。
2. 本章涵盖的主题
- 利用 AWS CloudFormation 进行自动化
- 利用 AWS CDK 进行自动化
- 使用 AWS Step Functions 构建端到端工作流
- 使用 Amazon SageMaker Pipelines 构建端到端工作流
3. 技术要求
- AWS 账户 :若没有,请访问 https://aws.amazon.com/getting-started/ 创建。同时,建议熟悉 AWS 免费套餐 。
- AWS 命令行界面(CLI) :需安装并配置,可参考 https://aws.amazon.com/cli/ 。
- Python 3.x 环境 :安装 Anaconda 发行版( https://www.anaconda.com/ )虽非强制,但强烈推荐,因为它包含了许多所需的项目(如 Jupyter、pandas、numpy 等)。
- Git 客户端 :用于访问代码示例,可从 https://git-scm.com/ 安装。代码示例可在 GitHub 上获取。
4. 利用 AWS CloudFormation 进行自动化
AWS CloudFormation 长期以来一直是在 AWS 上自动化基础设施构建和操作的首选方式。使用 CloudFormation 的第一步是编写模板,即一个 JSON 或 YAML 文本文件,用于描述要构建的资源,如 EC2 实例或 S3 存储桶。几乎所有 AWS 服务都有对应的资源,SageMaker 也不例外。
模板可以(并且应该)包含参数和输出。参数有助于使模板尽可能通用,输出则提供可由下游应用程序使用的信息,如端点 URL 或存储桶名称。
编写好模板文件后,将其传递给 CloudFormation 以创建堆栈,即一组 AWS 资源。CloudFormation 会解析模板并自动创建所有资源,同时自动管理依赖关系,确保资源按正确顺序创建。如果堆栈无法正确创建,CloudFormation 会回滚并删除已构建的资源。
堆栈可以通过应用较新的模板修订进行更新。CloudFormation 会分析更改,并相应地创建、删除、更新或替换资源。借助变更集,可在执行更改之前验证更改,然后决定是否继续。
当然,堆栈可以删除,CloudFormation 会自动拆除其所有资源,这是清理构建而不留下任何残余的好方法。
5. 部署模型到实时端点示例
5.1 编写模板
以下是一个 YAML 文件 endpoint-one-model.yml 的示例,定义了部署模型所需的参数和资源:
AWSTemplateFormatVersion: 2010-09-09
Parameters:
ModelName:
Description: Model name
Type: String
ModelDataUrl:
Description: Location of model artifact
Type: String
ContainerImage:
Description: Container used to deploy the model
Type: String
InstanceType:
Description: Instance type
Type: String
Default: ml.m5.large
InstanceCount:
Description: Instance count
Type: String
Default: 1
RoleArn:
Description: Execution Role ARN
Type: String
Resources:
Model:
Type: "AWS::SageMaker::Model"
Properties:
Containers:
-
Image: !Ref ContainerImage
ModelDataUrl: !Ref ModelDataUrl
ExecutionRoleArn: !Ref RoleArn
ModelName: !Ref ModelName
EndpointConfig:
Type: "AWS::SageMaker::EndpointConfig"
Properties:
ProductionVariants:
-
ModelName: !GetAtt Model.ModelName
VariantName: variant-1
InitialInstanceCount: !Ref InstanceCount
InstanceType: !Ref InstanceType
InitialVariantWeight: 1.0
Endpoint:
Type: "AWS::SageMaker::Endpoint"
Properties:
EndpointConfigName: !GetAtt EndpointConfig.EndpointConfigName
Outputs:
EndpointId:
Value: !Ref Endpoint
EndpointName:
Value: !GetAtt Endpoint.EndpointName
5.2 部署模型到实时端点
以下是使用 boto3 API 创建堆栈部署 TensorFlow 模型的代码示例:
import boto3
import time
# 创建 SageMaker 和 CloudFormation 客户端
sm = boto3.client('sagemaker')
cf = boto3.client('cloudformation')
# 描述训练作业以获取模型工件位置和执行角色
training_job = 'tensorflow-training-2021-05-28-14-25-57-394'
job = sm.describe_training_job(TrainingJobName=training_job)
model_data_url = job['ModelArtifacts']['S3ModelArtifacts']
role_arn = job['RoleArn']
# 设置部署使用的容器
container_image = '763104351884.dkr.ecr.us-east-1.amazonaws.com/tensorflow-inference:2.1.0-cpu-py36-ubuntu18.04'
# 读取模板,创建新堆栈并传递所需参数
timestamp = time.strftime("%Y-%m-%d-%H-%M-%S", time.gmtime())
stack_name = 'endpoint-one-model-' + timestamp
with open('endpoint-one-model.yml', 'r') as f:
response = cf.create_stack(
StackName=stack_name,
TemplateBody=f.read(),
Parameters=[
{"ParameterKey": "ModelName", "ParameterValue": training_job + '-' + timestamp},
{"ParameterKey": "ContainerImage", "ParameterValue": container_image},
{"ParameterKey": "ModelDataUrl", "ParameterValue": model_data_url},
{"ParameterKey": "RoleArn", "ParameterValue": role_arn}
]
)
# 获取堆栈创建完成后的端点名称
response = cf.describe_stacks(StackName=stack_name)
print(response['Stacks'][0]['StackStatus'])
for o in response['Stacks'][0]['Outputs']:
if o['OutputKey'] == 'EndpointName':
endpoint_name = o['OutputValue']
print(endpoint_name)
5.3 修改堆栈
可以使用变更集来修改堆栈。例如,更新支持端点的实例数量:
response = cf.create_change_set(
StackName=stack_name,
ChangeSetName='add-instance',
UsePreviousTemplate=True,
Parameters=[
{"ParameterKey": "InstanceCount", "ParameterValue": "2"},
{"ParameterKey": "ModelName", "UsePreviousValue": True},
{"ParameterKey": "ContainerImage", "UsePreviousValue": True},
{"ParameterKey": "ModelDataUrl", "UsePreviousValue": True},
{"ParameterKey": "RoleArn", "UsePreviousValue": True}
]
)
然后在 CloudFormation 控制台查看变更集详细信息,确认无误后执行变更集:
# 执行变更集
# 可通过控制台点击 Execute 按钮或使用以下 API
# cf.execute_change_set(ChangeSetName='add-instance', StackName=stack_name)
变更完成后,可检查端点现在是否由两个实例支持:
r = sm.describe_endpoint(EndpointName=endpoint_name)
print(r['ProductionVariants'][0]['CurrentInstanceCount'])
5.4 添加第二个生产变体
若要为端点添加第二个生产变体,需更新模板 endpoint-two-models.yml :
# 在 Parameters 部分添加第二个模型的条目
Parameters:
ModelName2:
Description: Second model name
Type: String
ModelDataUrl2:
Description: Location of second model artifact
Type: String
VariantWeight2:
Description: Weight of second model
Type: String
Default: 0.0
# 在 Resources 部分添加第二个模型资源
Resources:
Model2:
Type: "AWS::SageMaker::Model"
Properties:
Containers:
-
Image: !Ref ContainerImage
ModelDataUrl: !Ref ModelDataUrl2
ExecutionRoleArn: !Ref RoleArn
ModelName: !Ref ModelName2
然后在笔记本中创建变更集:
training_job_2 = 'tensorflow-training-2020-06-08-07-32-18-734'
job_2 = sm.describe_training_job(TrainingJobName=training_job_2)
model_data_url_2 = job_2['ModelArtifacts']['S3ModelArtifacts']
with open('endpoint-two-models.yml', 'r') as f:
response = cf.create_change_set(
StackName=stack_name,
ChangeSetName='add-model',
TemplateBody=f.read(),
Parameters=[
{"ParameterKey": "ModelName", "UsePreviousValue": True},
{"ParameterKey": "ModelDataUrl", "UsePreviousValue": True},
{"ParameterKey": "ContainerImage", "UsePreviousValue": True},
{"ParameterKey": "RoleArn", "UsePreviousValue": True},
{"ParameterKey": "ModelName2", "ParameterValue": training_job_2 + '-' + timestamp},
{"ParameterKey": "ModelDataUrl2", "ParameterValue": model_data_url_2}
]
)
执行变更集后,端点将支持两个生产变体。
6. 金丝雀部署
金丝雀部署是一种流行的渐进式应用部署技术,也可用于机器学习模型。具体做法是通过一系列堆栈更新,以 10% 的增量逐步增加第二个生产变体的权重,直到它完全取代第一个生产变体。同时,创建一个 CloudWatch 警报来监控第二个生产变体的延迟,如果警报触发,变更集将回滚。
import boto3
# 创建 CloudWatch 警报
cw = boto3.client('cloudwatch')
alarm_name = 'My_endpoint_latency'
response = cw.put_metric_alarm(
AlarmName=alarm_name,
ComparisonOperator='GreaterThanThreshold',
EvaluationPeriods=1,
MetricName='ModelLatency',
Namespace='AWS/SageMaker',
Period=60,
Statistic='Average',
Threshold=500000.0,
AlarmDescription='1-minute average latency exceeds 500ms',
Dimensions=[
{'Name': 'EndpointName', 'Value': endpoint_name},
{'Name': 'VariantName', 'Value': 'variant-2'}
],
Unit='Microseconds'
)
# 查找警报的 ARN
response = cw.describe_alarms(AlarmNames=[alarm_name])
for a in response['MetricAlarms']:
if a['AlarmName'] == alarm_name:
alarm_arn = a['AlarmArn']
# 循环更新堆栈
for w in list(range(10, 110, 10)):
response = cf.update_stack(
StackName=stack_name,
UsePreviousTemplate=True,
Parameters=[
{"ParameterKey": "ModelName", "UsePreviousValue": True},
{"ParameterKey": "ModelDataUrl", "UsePreviousValue": True},
{"ParameterKey": "ContainerImage", "UsePreviousValue": True},
{"ParameterKey": "RoleArn", "UsePreviousValue": True},
{"ParameterKey": "ModelName2", "UsePreviousValue": True},
{"ParameterKey": "ModelDataUrl2", "UsePreviousValue": True},
{"ParameterKey": "VariantWeight", "ParameterValue": str(100 - w)},
{"ParameterKey": "VariantWeight2", "ParameterValue": str(w)}
],
RollbackConfiguration={
'RollbackTriggers': [
{'Arn': alarm_arn, 'Type': 'AWS::CloudWatch::Alarm'}
],
'MonitoringTimeInMinutes': 5
}
)
waiter = cf.get_waiter('stack_update_complete')
waiter.wait(StackName=stack_name)
print("Sending %d%% of traffic to new model" % w)
7. 蓝绿部署
蓝绿部署需要两个生产环境:
- 运行版本 n 的实时生产环境(蓝色)
- 运行版本 n + 1 的此环境副本(绿色)
7.1 单端点实现蓝绿部署
从运行当前模型版本的现有端点开始,执行以下步骤:
1. 创建一个包含两个生产变体的新端点配置:一个用于当前模型,一个用于新模型。初始权重分别设置为 1 和 0。
2. 将其应用于端点。
3. 在新生产变体上运行测试,通过 invoke_endpoint() 中的 TargetVariant 参数显式选择它。
4. 测试满意后,将权重更新为 0 和 1,这将无缝切换流量到新模型。若出现问题,将权重恢复为 1 和 0。
5. 部署完成后,更新端点以删除第一个生产变体。
7.2 双端点实现蓝绿部署
从运行当前模型版本的现有端点开始,执行以下步骤:
1. 创建一个运行新模型版本的第二个端点。
2. 在这个新端点上运行测试。
3. 测试满意后,将所有流量切换到新端点。可以通过多种方式实现,例如更新业务应用程序中的参数或更新私有 DNS 条目。若出现问题,恢复到先前设置。
4. 部署完成后,删除旧端点。
这种设置稍微复杂一些,但可以让你在部署和回滚时立即从一个模型版本切换到另一个版本。
综上所述,CloudFormation 是一个出色的自动化工具,学习它的时间将会带来回报。不过,一些 AWS 用户更喜欢编写代码而不是编写模板,这也是引入 CDK 的原因。
以下是一个简单的 mermaid 流程图,展示了使用 AWS CloudFormation 部署模型的主要步骤:
graph LR
A[编写模板] --> B[创建堆栈]
B --> C[部署模型到端点]
C --> D[修改堆栈(可选)]
D --> E[添加生产变体(可选)]
E --> F[金丝雀部署(可选)]
F --> G[蓝绿部署(可选)]
G --> H[删除堆栈]
通过上述步骤和示例,你可以利用 AWS CloudFormation 实现自动化的机器学习模型部署。
自动化机器学习工作流:AWS CloudFormation 实战指南
8. 不同部署方式对比
| 部署方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 金丝雀部署 | 可渐进式部署,降低风险;可实时监控新模型性能,出现问题可及时回滚 | 部署时间较长;需要额外设置监控和回滚机制 | 对新模型稳定性不确定,希望逐步验证的场景 |
| 蓝绿部署 - 单端点 | 简单易实现;可无缝切换流量 | 端点更新时间长,可能影响业务连续性 | 对业务连续性要求不高,且希望尽量简化部署流程的场景 |
| 蓝绿部署 - 双端点 | 可快速切换模型版本;部署和回滚迅速 | 部署复杂度较高,需要维护两个端点 | 对业务连续性要求高,需要快速响应模型更新的场景 |
9. 利用 AWS CDK 自动化
虽然 CloudFormation 功能强大,但有些 AWS 用户更喜欢编写代码来实现自动化,AWS CDK 应运而生。AWS CDK 允许使用熟悉的编程语言(如 Python、TypeScript 等)来定义云基础设施。
以下是一个使用 Python 和 AWS CDK 部署 SageMaker 模型的简单示例:
from aws_cdk import (
aws_sagemaker as sagemaker,
core
)
class SageMakerStack(core.Stack):
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
# 定义模型
model = sagemaker.CfnModel(self, "MyModel",
execution_role_arn="arn:aws:iam::123456789012:role/MyExecutionRole",
primary_container=sagemaker.CfnModel.ContainerDefinitionProperty(
image="763104351884.dkr.ecr.us-east-1.amazonaws.com/tensorflow-inference:2.1.0-cpu-py36-ubuntu18.04",
model_data_url="s3://my-bucket/my-model.tar.gz"
)
)
# 定义端点配置
endpoint_config = sagemaker.CfnEndpointConfig(self, "MyEndpointConfig",
production_variants=[
sagemaker.CfnEndpointConfig.ProductionVariantProperty(
model_name=model.ref,
variant_name="variant-1",
initial_instance_count=1,
instance_type="ml.m5.large"
)
]
)
# 定义端点
endpoint = sagemaker.CfnEndpoint(self, "MyEndpoint",
endpoint_config_name=endpoint_config.ref
)
10. 使用 AWS Step Functions 构建端到端工作流
AWS Step Functions 可用于协调多个 AWS 服务,构建复杂的工作流。以下是一个使用 AWS Step Functions 构建机器学习工作流的示例,包含训练、部署和监控步骤:
graph LR
A[开始] --> B[训练模型]
B --> C[部署模型到端点]
C --> D[监控端点数据]
D --> E{数据质量是否达标}
E -- 是 --> F[继续运行]
E -- 否 --> G[调整模型]
G --> B
以下是一个简单的 AWS Step Functions 状态机定义示例(JSON 格式):
{
"Comment": "A simple machine learning workflow",
"StartAt": "TrainModel",
"States": {
"TrainModel": {
"Type": "Task",
"Resource": "arn:aws:states:::sagemaker:createTrainingJob.sync",
"Parameters": {
"TrainingJobName": "my-training-job",
"AlgorithmSpecification": {
"TrainingImage": "763104351884.dkr.ecr.us-east-1.amazonaws.com/tensorflow-training:2.1.0-cpu-py36-ubuntu18.04",
"TrainingInputMode": "File"
},
"RoleArn": "arn:aws:iam::123456789012:role/MyExecutionRole",
"InputDataConfig": [
{
"ChannelName": "train",
"DataSource": {
"S3DataSource": {
"S3DataType": "S3Prefix",
"S3Uri": "s3://my-bucket/train-data"
}
}
}
],
"OutputDataConfig": {
"S3OutputPath": "s3://my-bucket/output"
}
},
"Next": "DeployModel"
},
"DeployModel": {
"Type": "Task",
"Resource": "arn:aws:states:::sagemaker:createEndpoint.sync",
"Parameters": {
"EndpointName": "my-endpoint",
"EndpointConfigName": "my-endpoint-config"
},
"Next": "MonitorData"
},
"MonitorData": {
"Type": "Task",
"Resource": "arn:aws:states:::sagemaker:createMonitoringSchedule.sync",
"Parameters": {
"MonitoringScheduleName": "my-monitoring-schedule",
"MonitoringScheduleConfig": {
"MonitoringJobDefinition": {
"BaselineConfig": {
"ConstraintsResource": {
"S3Uri": "s3://my-bucket/baseline/constraints.json"
}
},
"MonitoringInputs": [
{
"EndpointInput": {
"EndpointName": "my-endpoint",
"LocalPath": "/opt/ml/processing/input"
}
}
],
"MonitoringOutputConfig": {
"MonitoringOutputs": [
{
"S3Output": {
"S3Uri": "s3://my-bucket/monitoring-output",
"LocalPath": "/opt/ml/processing/output"
}
}
]
},
"MonitoringResources": {
"ClusterConfig": {
"InstanceCount": 1,
"InstanceType": "ml.m5.large",
"VolumeSizeInGB": 30
}
},
"MonitoringAppSpecification": {
"ImageUri": "763104351884.dkr.ecr.us-east-1.amazonaws.com/sagemaker-model-monitor:latest"
},
"RoleArn": "arn:aws:iam::123456789012:role/MyExecutionRole"
}
}
},
"End": true
}
}
}
11. 使用 Amazon SageMaker Pipelines 构建端到端工作流
Amazon SageMaker Pipelines 提供了一种简单的方式来构建、自动化和管理机器学习工作流。以下是一个使用 SageMaker Pipelines 的示例代码:
import sagemaker
from sagemaker.workflow.pipeline import Pipeline
from sagemaker.workflow.steps import TrainingStep
from sagemaker.estimator import Estimator
# 定义 estimator
estimator = Estimator(
image_uri="763104351884.dkr.ecr.us-east-1.amazonaws.com/tensorflow-training:2.1.0-cpu-py36-ubuntu18.04",
role="arn:aws:iam::123456789012:role/MyExecutionRole",
instance_count=1,
instance_type="ml.m5.large",
output_path="s3://my-bucket/output"
)
# 定义训练步骤
training_step = TrainingStep(
name="MyTrainingStep",
estimator=estimator,
inputs={
"train": sagemaker.inputs.TrainingInput(s3_data="s3://my-bucket/train-data")
}
)
# 定义管道
pipeline = Pipeline(
name="MyPipeline",
steps=[training_step]
)
# 创建管道
pipeline.create(role_arn="arn:aws:iam::123456789012:role/MyExecutionRole")
# 启动管道执行
execution = pipeline.start()
12. 总结
通过本文,我们深入探讨了利用 AWS 服务实现自动化机器学习工作流的多种方式:
- AWS CloudFormation 提供了强大的模板化基础设施管理能力,适用于需要精确控制资源创建和更新的场景。
- AWS CDK 允许使用代码定义云基础设施,为喜欢编程的用户提供了便利。
- AWS Step Functions 和 Amazon SageMaker Pipelines 则专注于构建端到端的机器学习工作流,提高工作效率和可管理性。
在实际应用中,可根据项目需求和团队技术栈选择合适的工具和方法,实现高效、稳定的机器学习模型部署和管理。
以下是一个 mermaid 流程图,展示了不同 AWS 服务在自动化机器学习工作流中的应用:
graph LR
A[AWS CloudFormation] --> B[自动化基础设施管理]
C[AWS CDK] --> B
B --> D[构建机器学习工作流]
E[AWS Step Functions] --> D
F[Amazon SageMaker Pipelines] --> D
D --> G[模型训练]
D --> H[模型部署]
D --> I[模型监控]
希望本文能帮助你更好地理解和应用 AWS 服务进行自动化机器学习工作流的搭建。
超级会员免费看
43

被折叠的 条评论
为什么被折叠?



