亚马逊AWS官方博客

通过 SageMaker 与 Step Functions 实现机器学习的 CI/CD 方案

在传统的机器学习工作流程当中,经常会面临两个问题:(1)数据迭代迅速,需要定期对模型进行重新训练,每次训练完成后,都需要重新部署模型,如何实现训练与部署过程的的自动化,从而提升工作效率;(2)算法团队不断地对算法进行开发与变更,并且需要尝试不同的特征工程,每次变更都需要做单元测试,如何将SageMaker与CI/CD工具整合,在提升开发效率的同时减少运维团队的工作负担。本文会介绍通过SageMaker与Step Functions进行模型自动训练与部署的方法,并会与CodeCommit、CodeBuild、Jenkins集成,实现机器学习的CI/CD方案。

1. 相关技术介绍

在开始之前,请先对以下技术进行简单了解。

1.1 Amazon SageMaker

Amazon SageMaker 是一项完全托管的机器学习PaaS平台,它提供的功能完整的覆盖了整个机器学习生命周期。并且您不需要对用于训练和推理的实例进行维护,只需要根据工作负载指定相应的机型与数量即可,通过简单的API进行模型的一键训练与部署。

1.2 Step Functions

Step Functions是一项云原生的workflow编排工具,在创建时不需要配置基础设施,只需要在工作流程当中指定要执行的步骤即可。Step Functions为开发者提供了数据科学开发工具包,并且已经与SageMaker进行了集成,开发者可以通过面向对象编程的方式在workflow中定义SageMaker的步骤,因此可以将模型训练与部署的过程自动化。

1.3 CodeCommit与CodeBuild

CodeCommit与CodeBuild是AWS CI/CD系列当中的两个重要服务,CodeCommit是一项完全托管的代码仓库服务,可以提供给用户近乎无限的代码存储空间,在使用习惯上和标准的git工具没有差异。 CodeBuild 可编译源代码,运行单元测试,并构建可供部署的项目,并且也无需预置、管理和扩展自己的构建服务器,可以在构建请求高峰时实现自动扩展。

1.4 Jenkins

Jenkins是一个自包含的开源自动化服务器,可用于自动化与构建,测试以及交付或部署软件有关的各种任务。它的开源社区非常活跃,整合了1000多种插件,为CI/CD的过程提供了极大的灵活性,并且也可以与AWS Code系列集成,使得开发者可以轻松的集成两者的优势。

2. 演练

2.1 流程架构图与过程简介

(1)在一台EC2上安装Jenkins,配置好与CodeCommit、CodeBuild集成的插件;
(2)开发人员push代码到CodeCommit后触发Jenkins pipeline,代码在CodeBuild中封装成docker image,并推送到ECR当中(注:在本实验中,为了方便在CI/CD过程中对代码版本进行控制,会通过BYOC的方式在SageMaker中使用自定义算法,该方式需要自己编写Dockerfile并将算法build为docker image,然后上传到ECR当中,详细介绍可参考将您的算法或模型与Amazon SageMaker结合使用);
(3)触发Step Functions执行SageMaker训练与部署的步骤;
(4)SageMaker从ECR中加载docker image与S3中的数据进行训练;
(5)训练完成后对模型进行部署,暴露供推理使用的endpoint。

2.2 前提条件

(1)本文示例所使用的区域为us-east-1;
(2)在该区域使用Ubuntu 18.04的AMI创建一台EC2,并确保与其绑定的IAM Role有AdministratorAccess权限,安全组放开8080端口供Jenkins web使用,后续章节有安装Jenkins的具体步骤;
(3)为了模拟用户的开发环境,请先在本地或远程服务器配置好git工具与aws的credentials,并确定其拥有AdministratorAccess权限。

2.3 实现过程

2.3.1 在Step Functions中定义使用SageMaker训练与部署模型的步骤

(1)在SageMaker中创建一台笔记本实例,输入名称并保持其他默认配置,待创建完成后打开JupterLab,在初始界面下拉找到Terminal,点击进入执行cd SageMaker命令;

(2)打开IAM console,找到SageMaker自动创建的新角色,添加AdministratorAccess权限;
(3)在Terminal中执行命令:
curl https://shawnyj.s3-ap-northeast-1.amazonaws.com/package.zip --output package.zip
(4)压缩包下载完成后,执行unzip package.zip命令进行解压,待解压完成后在Jupyter notebook左侧的工作目录中打开sfn_deploy_byoc.ipynb文件;
(5)按照该notebook中的步骤执行一遍即可;
(6)执行完成后,打开Step Functions控制台,会看到多出一个状态机,如下图所示:

(7)选中该状态机,点击定义,可以看到如下所示的工作流,其中定义了SageMaker从训练到部署所需的步骤:

2.3.2 在EC2上安装Jenkins

在本实验中,Jenkins只用来提供pipeline的作用,构建编译的步骤全部会由CodeBuild来完成。
(1)登陆EC2,安装Java环境;
sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get install openjdk-8-jdk -y

(2)根据Jenkins官方文档安装Jenkins 2.235版本;
(3)安装完成后,执行下列命令,记下初始密码;
sudo cat /var/lib/jenkins/secrets/initialAdminPassword

(4)在浏览器输入Jenkins server的URL,输入上一步的初始密码并点击Continue;

(5)选择Install suggested plugins并等待插件安装完成;

(6)配置Admin User并选择Save and Continue,接下来的步骤保持默认并点击继续完成配置;




(7)在Jenkins服务器上切换到jenkins用户,并配置后续实验所需的依赖包。
sudo su -
sudo vim /etc/sudoers
# 在文件中的User privilege specification下添加一行:jenkins ALL=(ALL) NOPASSWD: ALL,然后保存并关闭文件
su jenkins
sudo apt install python3-pip
pip3 install awscli --upgrade --user
vim ~/.bashrc
# 在文件中添加一行python路径:export PATH=$HOME/.local/bin:$PATH,然后保存并关闭文件
source ~/.bashrc
# 命令行输入aws configure,不需要设置access id与access key,在Default region name配置中输入us-east-1即可

2.3.3 创建CodeCommit与CodeBuild

(1)打开CodeCommit控制台,点击创建存储库;

(2)输入存储库名称并点击创建;

(3)进入到IAM控制台中,选择并配置本地环境使用的iam user的CodeCommit HTTPS Git凭证;

点击生成凭证后将凭证下载到本地,供实验后续使用

(4)回到CodeCommit控制台,选择第二步中创建好的存储库,克隆HTTPS URL,在本地执行git clone;


一般第一次执行git clone会要求用户输入CodeCommit HTTPS Git的凭证,打开上一步下载好的凭证,输入用户名与密码即可,如果有报错,请查询CodeCommit问题排查
(5)从github上下载实验所需代码到本地,并上传到CodeCommit的代码仓库;
git clone https://github.com/micxyj/ml-ops.git
cp -r ml-ops/* ml-ops-codecommit
cd ml-ops-codecommit
git add .
git commit -m 'update'
git push

push成功之后,回到CodeCommit控制台,打开存储库,发现代码已经上传完成;

在cifar10文件夹中包含了使用tensorflow对cifar-10数据集进行训练与创建tersorflow serving的代码,会通过Dockerfile文件与build_and_push.sh打包封装成docker image并上传到ECR当中,上传完成后会执行invoke_sfn.py脚本,运行已经定义好的Step Functions状态机,从而完成SageMaker训练与部署的过程。
(6)打开CodeBuild控制台,按照下述信息创建项目;





Buildspec中定义的代码即为在构建编译过程中所需要执行的命令,可以把该过程理解为:1)下载执行脚本所需的依赖包boto3;2)执行build_and_push.sh脚本将算法封装成docker image并上传到ECR;3)执行invoke_sfn.py脚本,触发Step Functions状态机进行模型的训练与部署。在build commands下复制粘贴以下代码:
- pip install boto3
- chmod 777 build_and_push.sh
- ./build_and_push.sh sagemaker-tf-cifar10-example
- python invoke_sfn.py


其他配置保持默认即可,点击创建构建项目。
(7)打开iam role的控制台,赋予codebuild-ml-ops-service-role角色AmazonEC2ContainerRegistryFullAccess与AWSStepFunctionsFullAccess的权限;

2.3.4 将CodeCommit、CodeBuild与Jenkins集成

(1)打开jenkins web页面,下载与CodeCommit、CodeBuild集成的相关插件;

(2)搜索AWS CodeCommit Trigger与AWS CodeBuild插件并安装,安装完成之后点击restart;

(3)配置AWS CodeCommit Trigger插件;
AWS CodeCommit Trigger插件需要通过SQS与SNS来实现webhook的功能(即push代码到CodeCommit之后,触发Jenkins Pipeline),因此需要先对SQS与SNS进行配置。
创建一个新的SNS主题并输入名称。


将以下json代码复制到访问策略当中,将your_account_id与your_sns_name替换为你的账户id和SNS名称,其他配置保持不变并点击创建主题。

{

  "Version": "2008-10-17",

  "Id": "__default_policy_ID",

  "Statement": [

    {

      "Sid": "__default_statement_ID",

      "Effect": "Allow",

      "Principal": {

        "AWS": "*"

      },

      "Action": [

        "SNS:Publish",

        "SNS:RemovePermission",

        "SNS:SetTopicAttributes",

        "SNS:DeleteTopic",

        "SNS:ListSubscriptionsByTopic",

        "SNS:GetTopicAttributes",

        "SNS:Receive",

        "SNS:AddPermission",

        "SNS:Subscribe"

      ],

      "Resource": "arn:aws:sns:us-east-1:your_account_id:your_sns_name",

      "Condition": {

        "StringEquals": {

          "AWS:SourceOwner": "your_account_id"

        }

      }

    }

  ]

}


打开CodeCommit控制台,配置触发器,按图中信息进行配置,选择刚刚创建好的SNS主题后点击创建触发器。


打开SQS控制台,创建SQS队列并输入名称。


复制以下json代码到访问策略当中,将your_account_id、your_sqs_name、your_sns_name替换为相应的信息,其他配置保持不变并点击创建。

{

  "Version": "2012-10-17",

  "Id": "arn:aws:sqs:us-east-1:your_account_id:your_sqs_name/SQSDefaultPolicy",

  "Statement": [

    {

      "Effect": "Allow",

      "Principal": {

        "Service": "sns.amazonaws.com"

      },

      "Action": "sqs:SendMessage",

      "Resource": "arn:aws:sqs:us-east-1:your_account_id:your_sqs_name",

      "Condition": {

        "ArnEquals": {

          "aws:SourceArn": "arn:aws:sns:us-east-1:your_account_id:your_sns_name"

        }

      }

    }

  ]

}


点击订阅SNS主题,选择之前创建好的SNS主题ARN后保存即可。


打开Jenkins web页面,点击系统配置。

下拉到AWS Code Commit Trigger SQS Plugin栏目,首先添加aws的credentials,使用具有AdministratorAccess权限的iam user即可。


添加完成credentials之后,选择刚创建好的credentials、正确的region(us-east-1)与之前创建好的sqs队列,点击Test access,返回successful则表示配置正确,最后点击save。

(4)创建Jenkins Item;
输入名称ml-ops-pipeline并选择Pipeline。

在Pipeline中的Build Triggers栏目,勾选“Build when a CodeCommit repository is updated and notifies a SQS queue”,点击 “Manually enter CodeCommit URL and branches”,在“Code commit repository URL”处输入CodeCommit代码仓库的Git URL。

下拉到Pipeline栏目,在“Definition”中选择“Pipeline script from SCM”,在“SCM”中选择“Git”。

点击“Credentials”旁的“add”按钮,选择Jenkins,将弹出如下页面,输入为CodeCommit的Git credentials(其中Username与Password都在2.3.3章节提到的Git凭证中):

添加完成之后,输入CodeCommit代码仓库的Git URL与刚创建好的Credentials。

其他配置保持默认选项,点击Save。

3. 展示

(1)打开下载到本地的CodeCommit远程仓库代码文件夹,打开invoke_sfn.py文件,将your_account_id与your_step_functions_name分别替换为你的账户id与之前执行notebook后生成的Step Functions状态机的名称;

(2)打开Jenkinsfile,将your_project_name替换为你的CodeBuild项目名称,从代码中可以看出,Jenkins安装完成AWS CodeBuild插件之后,就可以以常见的Groovy语法定义需要执行的step,触发CodeBuild执行相应的构建编译的过程,因此,Jenkins在这里只起到调度的作用,编译构建的负载全部交给CodeBuild来完成,用户并不需要预置底层资源;

(3)此时代码已经发生了变更,push代码到Codecommit当中,触发整个CI/CD的流程;

(4)查看CodeBuild的构建日志,任务正在执行,由于Jenkins安装了CodeBuild的插件,也可以在Jenkins的console上看到相同的日志输出,可以利用这一机制,在Jenkins上对构建过程的输出进行统一监控管理;


(5)待CodeBuild将docker image上传到ECR之后,会执行buildspec中第二个步骤,触发Step Functions,打开Step Functions与SageMaker训练任务的界面,可以看到SageMaker训练过程正在执行;



(6)待状态机中部署的过程执行完成,打开SageMaker的终端节点界面,可以看到终端节点正在创建过程当中,待创建完成之后,就可以用于推理。

4. 总结

本文介绍了如何利用Step Functions定义SageMaker中训练与部署的过程,当模型需要重新训练时,可以直接触发Step Functions中定义好的状态机,从而减少运维人员重复工作;当算法或特征工程代码发生变更时,需要考虑如何实现MLOps,AWS的Code系列可以轻松和开源的工具集成,开发者可以利用到两者的优势,比如可以使用Jenkins提供的多种插件,并且在编译构建的过程中使用CodeBuild,将任务高峰期扩展资源的任务交给AWS自动完成。本文通过上述两个场景实现机器学习的CI/CD过程,从而进一步提升算法工程师的开发效率,减少运维团队的工作负担。

5. 参考资料

[1] Automating model retraining and deployment using the AWS Step Functions Data Science SDK for Amazon SageMaker
[2] Automated and continuous deployment of Amazon SageMaker models with AWS Step Functions
[3] 将 AWS CodeBuild 与 Jenkins 结合使用
[4] Building your own TensorFlow container
[5] Continuous Delivery for Machine Learning

本篇作者

肖元君

AWS解决方案架构师,负责基于AWS云计算方案的架构咨询和设计实现,同时致力于数据分析与AI的研究与应用。

金忠敏

AWS解决方案架构师,现在专注于云计算解决方案和架构的工作。具有超过15年的IT从业经验,曾从事软件开发,售后支持,系统交付,售前等工作。参与过很多大型项目架构设计和实施交付。