28、自动化机器学习工作流:AWS CloudFormation 实战指南

自动化机器学习工作流:AWS CloudFormation 实战指南

1. 自动化机器学习工作流的必要性

在机器学习模型部署中,使用 SageMaker SDK 和 boto3 SDK 在 Jupyter Notebooks 中进行实验和快速迭代是常见的做法。然而,将笔记本用于生产任务并非良策。即使代码经过了仔细测试,在监控、日志记录、创建其他 AWS 资源、错误处理和回滚等方面,仍需要大量额外的工作和代码,这也增加了出现更多错误的可能性。因此,需要一种更具工业化的方法。

2. 本章涵盖的主题
  • 利用 AWS CloudFormation 进行自动化
  • 利用 AWS CDK 进行自动化
  • 使用 AWS Step Functions 构建端到端工作流
  • 使用 Amazon SageMaker Pipelines 构建端到端工作流
3. 技术要求
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 服务进行自动化机器学习工作流的搭建。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值