尽管大多数人提到 Amazon 会想到 Prime 送货和内容服务,这家公司在开发者中同样备受推崇。具体来说,Amazon Web Services(AWS)为超过 100 万活跃用户提供云技术,覆盖企业级公司以及中小型企业。
本文将聚焦 AWS 生态中的 AWS SageMaker——一个用于大规模执行端到端机器学习(ML)工作流的专用平台。读完本文后,我们将部署一个模型,可用于发送请求以生成分类任务的预测。
什么是 Amazon SageMaker?
Amazon SageMaker 是一项全托管服务,提供用于构建、训练和部署机器学习模型的工具与基础设施。它简化了机器学习工作流,使数据科学家和开发者能够快速高效地创建、训练和部署模型。
在一个典型的机器学习项目中,您会经历多个阶段:
数据摄取、清洗与探索。
特征工程与选择。
模型训练与超参数调优。
部署与模型监控。
每个阶段都需要不同的工具组合以及一支技术熟练的团队来无缝协同。Amazon SageMaker 将这一切整合到单一平台。以下是其优势:
端到端机器学习服务: 为机器学习生命周期的每个阶段提供全面工具集,从数据准备到模型部署与监控。
集成开发环境: SageMaker Studio 提供 IDE,简化整个 ML 工作流,用户可在单一界面中构建、训练和部署模型。
易用性: 借助 SageMaker Autopilot 等特性,无需编写代码也能通过几次点击生成高质量模型。
可扩展性: 自动为训练和部署扩展基础设施,无需人工干预即可确保最佳性能。
成本效益: 提供 Spot Training 和多模型端点等选项,降低训练与托管成本。
支持主流 ML 框架: 允许数据科学家使用偏好的框架,包括 TensorFlow、PyTorch 和 XGBoost。
自动化超参数调优: 通过自动调参寻找表现最佳的模型配置。
稳健的模型部署: 简化将模型部署为实时 API 或批量预测服务,便于将 ML 模型集成到应用中。
全面监控: SageMaker Model Monitor 持续跟踪模型性能,检测生产中的数据漂移与异常。
模型注册表: 管理机器学习模型的生命周期,包括版本控制、审批流程与部署历史。
无缝集成: 轻松与其他 AWS 服务集成,例如用于数据存储的 Amazon S3 、用于数据准备的 AWS Glue 、用于事件驱动处理的 AWS Lambda ,以及用于监控与日志的 Amazon CloudWatch 。
安全与合规: 通过包括 VPC 支持、加密与 IAM 策在内的强大安全功能,确保数据保护并符合行业标准。
这些优势使 Amazon SageMaker 成为在规模化场景下构建、训练与部署机器学习模型的强大而灵活的平台。
为 SageMaker 设置您的 AWS 控制台与环境
如前所述,SageMaker 是 AWS 生态的一部分,其中包含众多云计算方案,提供存储、网络、数据库、分析与机器学习能力。所有这些解决方案都可与 SageMaker 协同工作,统一您的机器学习工作流。
因此,如果您还没有 AWS 账户,SageMaker 需要您先创建一个。
1. 创建 AWS 账户
要创建账户,请访问 https://aws.amazon.com/ ,并按照流程创建新账户。
注册过程包括添加账单信息和验证您的电话号码。别担心——在您实际开始使用某些 SageMaker 功能之前(通常也较为经济),不会产生费用。
完成后,您将进入 AWS 控制台,界面通常如下图所示。请注意,您的控制台小部件可能与下图有所不同。
2. 创建 notebook 实例
现在,我们将创建一个 JupyterLab 会话,在 Amazon 云端机器上执行代码。
在 AWS 控制台顶部搜索栏中搜索 SageMaker 仪表盘:
然后向下滚动找到“Notebooks”选项卡,并在其中选择“Notebooks instances”。您将看不到任何实例,因此需要创建一个:
要创建新 notebook,请点击屏幕右上角的“Create notebook instance”。然后填写以下字段:
为您的 notebook 命名。本例中我将其命名为 sagemaker-test。
“Notebook instance type”字段指定您希望 notebook 内核使用的机器类型。我选择 ml.t3.large ,它有 8 GB 内存和 2 个 CPU 核心。撰文时费用约为每小时 $0.12(请参阅 SageMaker 价格页面 获取最新信息)。
在“Permissions and encryption”部分,选择“Create new user”选项,这将自动创建一个具有运行 notebook 实例所需权限的 IAM 用户。
填写完所有必填信息后,点击“Create notebook instance”。
当状态从“Pending”变为“inService”时,您可以点击 notebook 旁的“Open in JupyterLab”链接启动 JupyterLab:
实例进入服务后,计时和计费就开始了。如果您决定休息,请不要忘记点击“Actions”,然后点击“Stop”停止实例,以避免不必要的费用。默认闲置关机时间为两小时:
如果您停止了 notebook 实例,之后可以再次重启。您的环境会被保留。
在 AWS SageMaker 中上传要使用的数据集
本节我们将学习如何将本地文件上传到 Amazon 服务器,这是 SageMaker 的前置要求。
1. 下载示例数据集
我们将使用来自 UCI ML 仓库的Dry Bean 数据集 构建一个多分类器。它包含 1.3 万条豆类样本及其 15 个数值型测量。
任务是将其分类为七种豆类:Seker、Barbunya、Bombay、Cali、Dermosan、Horoz 和 Sira。
七种豆类:Seker、Barbunya、Bombay、Cali、Dermosan、Horoz 和 Sira。
下载后,将 ZIP 中的 Excel 文件保存到 JupyterLab 的本地 data 目录中,然后将以下代码添加到您的 notebook:
from pathlib import Path
cwd = Path. cwd( )
data_path = cwd / "data" / "Dry_Bean_Dataset.xlsx" 技术支持
接着,添加以下代码,我们可以用 pandas 读取 Excel 文件并将其保存为 CSV:
import pandas as pd
beans = pd. read_excel( data_path)
beans. to_csv( cwd / "data" / "dry_bean.csv" , index= False ) 技术支持
2. 创建 S3 存储桶并上传数据
我们的数据集必须位于 S3 存储桶中,SageMaker 才能访问。AWS S3 是一种云存储解决方案,允许您将与项目相关的对象保存在 Amazon 服务器托管的存储桶中。
要创建存储桶,请按以下步骤操作:
前往 S3 控制台。您可以在搜索栏中搜索“S3”。
点击“Create bucket”。
为您的存储桶命名。
存储桶名称必须全局唯一,因此您无法使用我所用的 dry-bean-bucket。
其余字段保持默认配置。
点击“Create bucket”。
创建完成后,点击该存储桶上传之前保存的 CSV 文件:
在存储桶中,点击“Upload”,然后点击“Add files”。
选择该 CSV 文件。
再次点击“Upload”。
之后,您可以返回 JupyterLab 界面,因为我们终于要运行一些代码了!
在 AWS SageMaker 中的端到端模型训练与部署工作流
本节我们将走一遍端到端流程:从 CSV 数据集开始,到将模型部署到端点。但在深入技术细节之前,先从高层面了解一下我们要做什么。
SageMaker 中 ML 工作流的高层概览
在 SageMaker 中进行机器学习与在本地机器上略有不同。我们已经完成了前期步骤:
创建 AWS 账户。
创建 notebook 实例。
为项目创建 S3 存储桶。
与本地 notebook 一样,SageMaker 的 notebook 实例用于探索性分析——数据清洗、探索、摄取和基础实验。
一旦进入模型训练阶段,SageMaker 期望您按其“规则”行事。具体而言,要让 SageMaker 将您的自定义模型部署为端点,它需要一个训练脚本,其功能包括:
从数据源加载数据。
在其上训练单个模型。
保存模型及其工件。
报告其指标。
脚本还必须能够动态地以命令行参数的形式接收变量。因此,将来希望在脚本内更改的任何内容(模型超参数、文件路径等)都必须设置为命令行参数。
脚本准备就绪后,会传入 SageMaker 提供的特殊估计器中。它们与主流 ML 库(如 scikit-learn 、XGBoost 、TensorFlow 、PyTorch 等)配套。借助这些估计器,SageMaker 会围绕您的脚本构建 Docker 容器,并将其部署为可大规模服务的端点。
随着我们逐步实践,上述要点将变得更加清晰。
1. 为 SageMaker 设置 notebook 实例
首先,在您先前创建的 sagemaker-test notebook 中导入必要的库:
import boto3
import numpy as np
import pandas as pd
import sagemaker
from sagemaker import get_execution_role
from sklearn. model_selection import train_test_split技术支持
部分导入说明如下:
sagemaker 是官方 Python SDK ,用于在 Amazon SageMaker 上训练和部署机器学习模型。通过该 SDK,您可以使用主流深度学习框架、Amazon 提供的算法,或内置于 SageMaker 兼容 Docker 镜像中的自定义算法来训练与部署模型。
boto3 是另一个官方 Python SDK,但它连接您的代码与所有 AWS 服务,而不仅是 SageMaker。您可以通过这门课程了解更多 boto3 。
导入完成后,创建本教程中将用到的一些资源:
sm_boto3 = boto3. client( "sagemaker" )
sess = sagemaker. Session( ) 技术支持
上述代码中,我们首先使用 boto3 创建一个 SageMaker 客户端对象。
然后创建一个 SageMaker 会话。
这两个对象都允许我们以不同方式与 SageMaker 平台交互。
现在,定义一些需要的全局变量:
region = sess. boto_session. region_name
BUCKET_URI = "s3://dry-bean-bucket"
BUCKET_NAME = "dry-bean-bucket"
DATASET_PATH = f" { BUCKET_URI} /dry_bean.csv"
TARGET_NAME = "Class" 技术支持
这些变量一目了然,我们将在整个教程中使用它们。
2. 将 S3 存储桶中的数据加载到 SageMaker
在大多数数据项目中,训练数据集会存放在云存储解决方案中,如 BigQuery、GCS 或 AWS S3 存储桶 。我们将数据存放在 S3,因此用 pandas 加载。将以下代码添加到 notebook 并执行:
dry_bean = pd. read_csv( DATASET_PATH)
dry_bean. head( ) 技术支持
在 Sagemaker notebook 中工作的一个优势是,我们可以直接用 pandas 从 S3 读取文件。所有 SageMaker 环境都已配置了您的凭证,允许 pandas 从存储桶下载 CSV。如果在本地运行,这段代码将无法工作。
3. 在 SageMaker 中进行 EDA
在每个项目中花时间进行EDA(探索性数据分析) 至关重要,本项目也不例外。不过这里我们不做深入分析,以免偏离本文主题。
我们仅打印一些概要统计和图表:
dry_bean. info( ) 技术支持
< class 'pandas.core.frame.DataFrame' >
RangeIndex: 13611 entries, 0 to 13610
Data columns (total 17 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Area 13611 non-null int64
1 Perimeter 13611 non-null float64
2 MajorAxisLength 13611 non-null float64
3 MinorAxisLength 13611 non-null float64
4 AspectRation 13611 non-null float64
5 Eccentricity 13611 non-null float64
6 ConvexArea 13611 non-null int64
7 EquivDiameter 13611 non-null float64
8 Extent 13611 non-null float64
9 Solidity 13611 non-null float64
10 roundness 13611 non-null float64
11 Compactness 13611 non-null float64
12 ShapeFactor1 13611 non-null float64
13 ShapeFactor2 13611 non-null float64
14 ShapeFactor3 13611 non-null float64
15 ShapeFactor4 13611 non-null float64
16 Class 13611 non-null object
dtypes: float64(14), int64(2), object(1)
memory usage: 1.8+ MB技术支持
上面的信息告诉我们,有 16 个数值特征和一个名为 Class 的目标列。数据集很小,只有 1.3 万条样本,因此我们不需要高性能机器或花费大量费用来训练模型。
接下来,使用 seaborn 绘制几个重要特征的配对图:
import seaborn as sns
sns. pairplot(
dry_bean,
vars = [ "Area" , "MajorAxisLength" , "MinorAxisLength" , "Eccentricity" , "roundness" ] ,
hue= "Class" ,
) ; 技术支持
上述图表显示,豆类在物理测量方面差异明显。绿色的 Bombay 豆尤其区分度高。
我们还可以绘制相关矩阵来查看特征之间的关系:
import matplotlib. pyplot as plt
correlation = dry_bean. corr( numeric_only= True )
sns. heatmap( correlation, center= 0 , square= True , cmap= "coolwarm" , vmin= - 1 , vmax= 1 )
plt. show( ) 技术支持
图中显示许多特征呈完全(正或负)相关,这很合理,因为这些特征都与物理测量相关。
此处起,我将探索的部分留给您继续进行。
4. 在 SageMaker 中为模型训练准备数据
完成探索后,您需要在训练前处理数据集中的质量或逻辑问题,并在必要时进行特征工程。
Dry Bean 数据集相当干净,所以我们的工作很简单。我们只需对目标列进行编码,因为它包含文本。我们将使用 scikit-learn 来完成:
from sklearn. preprocessing import LabelEncoder
df = dry_bean. copy( deep= True )
le = LabelEncoder( )
df[ TARGET_NAME] = le. fit_transform( df[ TARGET_NAME] ) 技术支持
预处理完成后,我们需要划分数据集:
from sklearn. model_selection import train_test_split
train, test = train_test_split( df, random_state= 1 , test_size= 0.2 ) 技术支持
如果您愿意,也可以进一步划分出第三个验证集,但这里我们先保持简单。
现在,将数据集保存为 CSV:
train. to_csv( "dry-bean-train.csv" )
test. to_csv( "dry-bean-test.csv" ) 技术支持
并将它们上传到我们的 S3 存储桶:
trainpath = sess. upload_data(
path= "dry-bean-train.csv" ,
bucket= BUCKET_NAME,
key_prefix= "sagemaker/sklearncontainer" ,
)
testpath = sess. upload_data(
path= "dry-bean-test.csv" ,
bucket= BUCKET_NAME,
key_prefix= "sagemaker/sklearncontainer" ,
) 技术支持
会话对象的 .upload_data() 函数会返回上传文件的完整路径,分别存储在 trainpath 和 testpath 变量中。后续我们会用到这些路径。
5. 为 SageMaker 编写训练脚本
在新的 notebook 单元中,粘贴以下代码:
% % writefile script. py
import argparse
import os
import joblib
import numpy as np
import pandas as pd
from sklearn. ensemble import RandomForestClassifier
from sklearn. metrics import balanced_accuracy_score
if __name__ == "__main__" :
print ( "extracting arguments" )
parser = argparse. ArgumentParser( )
parser. add_argument( "--n-estimators" , type = int , default= 10 )
parser. add_argument( "--min-samples-leaf" , type = int , default= 3 )
parser. add_argument( "--model-dir" , type = str , default= os. environ. get( "SM_MODEL_DIR" ) )
parser. add_argument( "--train" , type = str , default= os. environ. get( "SM_CHANNEL_TRAIN" ) )
parser. add_argument( "--test" , type = str , default= os. environ. get( "SM_CHANNEL_TEST" ) )
parser. add_argument( "--train-file" , type = str , default= "dry-bean-train.csv" )
parser. add_argument( "--test-file" , type = str , default= "dry-bean-test.csv" )
args, _ = parser. parse_known_args( )
print ( "reading data" )
train_df = pd. read_csv( os. path. join( args. train, args. train_file) )
test_df = pd. read_csv( os. path. join( args. test, args. test_file) )
print ( "building training and testing datasets" )
X_train = train_df. drop( "Class" , axis= 1 )
X_test = test_df. drop( "Class" , axis= 1 )
y_train = train_df[ [ "Class" ] ]
y_test = test_df[ [ "Class" ] ]
print ( "training model" )
model = RandomForestClassifier(
n_estimators= args. n_estimators,
min_samples_leaf= args. min_samples_leaf,
n_jobs= - 1 ,
)
model. fit( X_train, y_train)
print ( "validating model" )
bal_acc_train = balanced_accuracy_score( y_train, model. predict( X_train) )
bal_acc_test = balanced_accuracy_score( y_test, model. predict( X_test) )
print ( f"Train balanced accuracy: { bal_acc_train: .3f } " )
print ( f"Test balanced accuracy: { bal_acc_test: .3f } " )
path = os. path. join( args. model_dir, "model.joblib" )
joblib. dump( model, path)
print ( "model persisted at " + path) 技术支持
上述脚本中的 %%writefile script.py 魔法命令会将单元格内容写入 Python 脚本文件,而不是直接运行。
现在逐步说明脚本中发生的事情:
import argparse
import os
import joblib
import numpy as np
import pandas as pd
from sklearn. ensemble import RandomForestClassifier
from sklearn. metrics import balanced_accuracy_score技术支持
首先导入一些必要的库。
if __name__ == "__main__" :
print ( "extracting arguments" )
parser = argparse. ArgumentParser( )
parser. add_argument( "--n-estimators" , type = int , default= 10 )
parser. add_argument( "--min-samples-leaf" , type = int , default= 3 )
parser. add_argument( "--model-dir" , type = str , default= os. environ. get( "SM_MODEL_DIR" ) )
parser. add_argument( "--train" , type = str , default= os. environ. get( "SM_CHANNEL_TRAIN" ) )
parser. add_argument( "--test" , type = str , default= os. environ. get( "SM_CHANNEL_TEST" ) )
parser. add_argument( "--train-file" , type = str , default= "dry-bean-train.csv" )
parser. add_argument( "--test-file" , type = str , default= "dry-bean-test.csv" )
args, _ = parser. parse_known_args( ) 技术支持
接着,我们创建一个参数解析器对象以读取命令行参数。正如我所说,将来可能需要更新的任何值都应通过 CLI 参数传入。本节定义了这些参数:
Random Forest 分类器对象的两个超参数。
五个输入与输出文件路径,包括模型工件和数据集文件。
如果您注意到 model-dir、train 和 test 目录的默认值,会看到一些环境变量。它们来自 SageMaker SDK 文档 ,其中也提供了编写此类脚本文件的说明。
print ( "reading data" )
train_df = pd. read_csv( os. path. join( args. train, args. train_file) )
test_df = pd. read_csv( os. path. join( args. test, args. test_file) )
print ( "building training and testing datasets" )
X_train = train_df. drop( "Class" , axis= 1 )
X_test = test_df. drop( "Class" , axis= 1 )
y_train = train_df[ [ "Class" ] ]
y_test = test_df[ [ "Class" ] ] 技术支持
定义完动态值后,我们读取并构建训练与测试数据集。可以看到,我们没有传递硬编码路径,而是使用 args.argument 的值。
print ( "training model" )
model = RandomForestClassifier(
n_estimators= args. n_estimators,
min_samples_leaf= args. min_samples_leaf,
n_jobs= - 1 ,
)
model. fit( X_train, y_train)
print ( "validating model" )
bal_acc_train = balanced_accuracy_score( y_train, model. predict( X_train) )
bal_acc_test = balanced_accuracy_score( y_test, model. predict( X_test) )
print ( f"Train balanced accuracy: { bal_acc_train: .3f } " )
print ( f"Test balanced accuracy: { bal_acc_test: .3f } " ) 技术支持
我们拟合模型,并在训练集与测试集上进行评估,然后打印性能。
path = os. path. join( args. model_dir, "model.joblib" )
joblib. dump( model, path)
print ( "model persisted at " + path) 技术支持
最后,我们使用 joblib 将模型保存到模型目录。
当您在 notebook 中运行此单元时,script.py 文件会出现在 JupyterLab 环境中。您可以通过如下方式执行它来检查是否正常工作:
! python script.py --n-estimators 100 \
--min-samples-leaf 2 \
--model-dir ./ \
--train ./ \
--test ./ \ 技术支持
extracting arguments
reading data
building training and testing datasets
validating model
Train balanced accuracy: 1.000
Test balanced accuracy: 0.998
model persisted at ./modejoblib技术支持
很好,我们获得了 99% 的平衡准确率——相当出色!这意味着我们终于可以启动训练作业了。
6. 在 SageMaker 中创建自定义训练作业
现在,我们将把脚本传递给 SageMaker 的估计器对象。在 AWS 的语境中,训练作业是一个过程,即使用指定的算法、数据集和 AWS SageMaker 提供的计算资源来训练模型。与在本地机器或 notebook 上训练不同,该作业在云端可扩展基础设施上运行,提供更强算力、更快处理速度,并可处理更大的数据集。
在 notebook 的新单元中添加以下代码:
from sagemaker. sklearn. estimator import SKLearn
FRAMEWORK_VERSION = "0.23-1"
sklearn_estimator = SKLearn(
entry_point= "script.py" ,
role= get_execution_role( ) ,
instance_count= 1 ,
instance_type= "ml.c5.xlarge" ,
framework_version= FRAMEWORK_VERSION,
base_job_name= "rf-scikit" ,
hyperparameters= {
"n-estimators" : 100 ,
"min-samples-leaf" : 3 ,
} ,
) 技术支持
上述代码中,SKLearn 类用于处理 scikit-learn 脚本。它包含一些需要说明的关键参数:
entry_point:脚本的路径。
role:有权访问 SageMaker 的用户名。
instance_count:要启动的机器数量。
instance_type:机器类型。
对于超参数,只传入您在训练脚本中定义的那些。否则会出错。
现在,我们可以将该估计器拟合到数据上:
sklearn_estimator. fit( { "train" : trainpath, "test" : testpath} , wait= True ) 技术支持
回忆本教程前文,trainpath 和 testpath 是指向我们 CSV 文件的 S3 存储桶路径。
运行上述单元后,训练开始:
INFO:sagemaker:Creating training-job with name: rf-scikit-2024-06-04-10-36-31-142
2024-06-04 10:36:31 Starting - Starting the training job...
2024-06-04 10:36:46 Starting - Preparing the instances for training...
2024-06-04 10:37:13 Downloading - Downloading input data...
2024-06-04 10:37:53 Training - Training image download completed. Training in progress...技术支持
SageMaker 会下载运行 scikit-learn 代码所需的 Docker 镜像并执行您的脚本。完成后,您将看到如下消息:
2024-06-04 10:38:17 Uploading - Uploading generated training model
2024-06-04 10:38:17 Completed - Training job completed
Training seconds: 65
Billable seconds: 65技术支持
如果您进入 SageMaker 控制台的 “SageMaker” > “Traning” > “Training Jobs” 部分,也会看到该训练作业的列表。
7. 使用 Spot 实例训练以降低成本
由于数据集较小,我们可以使用低成本、低配置的机器进行训练:ml.c5.xlarge 。但在您的项目中,可能需要处理包含数百万记录或海量图像的数据集。在这种情况下,您必须选择提供更强算力和 GPU 的机器。
按需使用这些机器可能会非常昂贵 。为降低成本,Amazon 提供 Spot Training 实例。使用这些实例,您可以以较低价格选择高性能计算资源,但有一个前提——训练不会立即开始。SageMaker 会等待到需求较低且您请求的机器可用时再启动训练。
要启用 Spot Training,您只需在上一段代码中添加几行:
spot_sklearn_estimator = SKLearn(
entry_point= "script.py" ,
role= get_execution_role( ) ,
instance_count= 1 ,
instance_type= "ml.c5.xlarge" ,
framework_version= FRAMEWORK_VERSION,
base_job_name= "rf-scikit" ,
hyperparameters= {
"n-estimators" : 100 ,
"min-samples-leaf" : 3 ,
} ,
use_spot_instances= True ,
max_wait= 7200 ,
max_run= 3600 ,
) 技术支持
将 use_spot_instances 设为 True 后,spot_sklearn_estimator 将使用 Spot 训练。您还可以设置等待 Spot 实例可用的最长时间,以及训练运行的最长时间。
当您再次调用 .fit() 时,训练才会真正开始:
spot_sklearn_estimator. fit( { "train" : trainpath, "test" : testpath} , wait= True ) 技术支持
8. 使用 SageMaker 进行超参数调优
使用同一个训练脚本,我们可以通过类似流程得到一个进行过超参数调优的模型。
首先,从 sagemaker.tuner 导入 IntegerParameter 类:
from sagemaker. tuner import IntegerParameter技术支持
IntegerParameter 类允许 SageMaker 为接收整数值的参数定义调优范围。tuner 模块还包含其他类型参数的类:
CategoricalParameter:定义取离散类别值的超参数。
ContinuousParameter:为接收连续值的超参数定义调优范围。
但本教程中我们只使用 IntegerParameter,因为我们仅调 Random Forest 的两个参数:
from sagemaker. tuner import IntegerParameter
hyperparameter_ranges = {
"n-estimators" : IntegerParameter( 20 , 100 ) ,
"min-samples-leaf" : IntegerParameter( 2 , 6 ) ,
} 技术支持
然后,创建一个调优器对象:
Optimizer = sagemaker. tuner. HyperparameterTuner(
estimator= sklearn_estimator,
hyperparameter_ranges= hyperparameter_ranges,
base_tuning_job_name= "RF-tuner" ,
objective_type= "Maximize" ,
objective_metric_name= "balanced-accuracy" ,
metric_definitions= [
{ "Name" : "balanced-accuracy" , "Regex" : "Test balanced accuracy: ([0-9.]+).*$" }
] ,
max_jobs= 10 ,
max_parallel_jobs= 2 ,
) 技术支持
Optimizer 的关键参数包括:
estimator:与您的训练脚本兼容的估计器对象。
hyperparameter_ranges:使用 tuner 模块中的类定义的参数范围。
objective_type:是最大化还是最小化给定指标。平衡准确率应被最大化。
metric_definitions:要优化的指标名称,以及如何从训练日志中提取它们。
metric_definitions 参数稍微复杂一些,因为它在定义指标的方式上提供了很高的灵活性。
在训练脚本中,我们通过以下日志消息报告平衡准确率:
print ( f"Train balanced accuracy: { bal_acc_train: .3f } " )
print ( f"Test balanced accuracy: { bal_acc_test: .3f } " ) 技术支持
metric_definitions 要求我们用正则表达式捕获该消息。因此,我们提供了如下字典,为以“Test balanced accuracy”开头的捕获指标赋予一个自定义名称。
{
"Name" : "balanced-accuracy" ,
"Regex" : "Test balanced accuracy: ([0-9.]+).*$" ,
} 技术支持
其余代码就很熟悉了:
Optimizer. fit( { "train" : trainpath, "test" : testpath} ) 技术支持
INFO:sagemaker:Creating hyperparameter tuning job with name: RF-tuner-240604-1049技术支持
调优器完成后,您可以将结果以 DataFrame 展示:
results = Optimizer. analytics( ) . dataframe( )
while results. empty:
time. sleep( 1 )
results = Optimizer. analytics( ) . dataframe( )
results. head( ) 技术支持
然后,您可以获取最优估计器:
best_estimator = Optimizer. best_estimator( ) 技术支持
9. 在 SageMaker 中将模型部署到端点
一旦确定用于实验的模型,您可以将其与所有工件一起上传到 SageMaker。此任务可使用 boto3 完成:
artifact_path = sm_boto3. describe_training_job(
TrainingJobName= best_estimator. latest_training_job. name
) [ "ModelArtifacts" ] [ "S3ModelArtifacts" ]
print ( "Model artifact persisted at " + artifact) 技术支持
Model artifact persisted at s3://sagemaker-us-east-1-496320894061/RF-tuner-240604-1049-009-38d75f35/output/model.tar.gz技术支持
describe_training_job() 函数接收一个估计器对象并将其推送到 SageMaker 提供的默认 S3 位置。您可以看到,该函数在上传前将模型打包为 tarball。
上传的模型可以在 SageMaker 控制台的 “Inference” > “Models” 部分看到:
点击任意模型,您会在右上角看到“Create endpoint”按钮:
您可以通过该按钮部署模型,或返回 notebook 实例使用 .deploy() 方法通过代码部署:
from sagemaker. sklearn. model import SKLearnModel
model = SKLearnModel(
model_data= artifact_path,
role= get_execution_role( ) ,
entry_point= "script.py" ,
framework_version= FRAMEWORK_VERSION,
) 技术支持
这次我们使用 SKLearnModel 类,它用于已训练的模型。它需要存放工件的 S3 位置以及用于训练的脚本。提供这些信息后,您可以运行代码进行部署:
predictor = model.deploy(instance_type="ml.c5.large", initial_instance_count=1)
INFO:sagemaker:Creating model with name: sagemaker-scikit-learn-2024-06-04-11-03-54-465
INFO:sagemaker:Creating endpoint-config with name sagemaker-scikit-learn-2024-06-04-11-03-54-960
INFO:sagemaker:Creating endpoint with name sagemaker-scikit-learn-2024-06-04-11-03-54-960技术支持
随后,您应能在 SageMaker 控制台的 “Inference” > “Endpoints” 部分看到该端点:
要用于预测,您可以在 notebook 中使用端点对象的 .predict() 方法:
preds = predictor. predict( test. sample( 4 ) . drop( "Class" , axis= 1 ) )
preds技术支持
array([3, 0, 1, 2])技术支持
恭喜,您刚刚用 SageMaker 部署了第一个模型!
使用完毕后,请不要忘记删除端点,因为它会持续产生费用:
sm_boto3. delete_endpoint( EndpointName= predictor. endpoint) 技术支持
别忘了,您在 SageMaker 中创建的每个 notebook 实例都带有一个示例 notebook 的独立标签页,展示 SageMaker 的不同功能:
另请查看 SageMaker Python SDK 的官方文档 。
总结
今天,我们学习了如何使用最受欢迎的企业级机器学习平台之一:AWS SageMaker。我们涵盖了从创建 AWS 账户到使用 SageMaker 将 ML 模型部署为端点的全部流程。
与任何平台一样,我们目前只是浅尝辄止。如果在项目中将其与其他 AWS 技术结合,您可以做到更多。以下是一些相关资源可供参考:
尽管大多数人提到 Amazon 会想到 Prime 送货和内容服务,这家公司在开发者中同样备受推崇。具体来说,Amazon Web Services(AWS)为超过 100 万活跃用户提供云技术,覆盖企业级公司以及中小型企业。
本文将聚焦 AWS 生态中的 AWS SageMaker——一个用于大规模执行端到端机器学习(ML)工作流的专用平台。读完本文后,我们将部署一个模型,可用于发送请求以生成分类任务的预测。
什么是 Amazon SageMaker?
Amazon SageMaker 是一项全托管服务,提供用于构建、训练和部署机器学习模型的工具与基础设施。它简化了机器学习工作流,使数据科学家和开发者能够快速高效地创建、训练和部署模型。
在一个典型的机器学习项目中,您会经历多个阶段:
每个阶段都需要不同的工具组合以及一支技术熟练的团队来无缝协同。Amazon SageMaker 将这一切整合到单一平台。以下是其优势:
这些优势使 Amazon SageMaker 成为在规模化场景下构建、训练与部署机器学习模型的强大而灵活的平台。
为 SageMaker 设置您的 AWS 控制台与环境
如前所述,SageMaker 是 AWS 生态的一部分,其中包含众多云计算方案,提供存储、网络、数据库、分析与机器学习能力。所有这些解决方案都可与 SageMaker 协同工作,统一您的机器学习工作流。
因此,如果您还没有 AWS 账户,SageMaker 需要您先创建一个。
1. 创建 AWS 账户
要创建账户,请访问 https://aws.amazon.com/,并按照流程创建新账户。
注册过程包括添加账单信息和验证您的电话号码。别担心——在您实际开始使用某些 SageMaker 功能之前(通常也较为经济),不会产生费用。
完成后,您将进入 AWS 控制台,界面通常如下图所示。请注意,您的控制台小部件可能与下图有所不同。
2. 创建 notebook 实例
现在,我们将创建一个 JupyterLab 会话,在 Amazon 云端机器上执行代码。
在 AWS 控制台顶部搜索栏中搜索 SageMaker 仪表盘:
然后向下滚动找到“Notebooks”选项卡,并在其中选择“Notebooks instances”。您将看不到任何实例,因此需要创建一个:
要创建新 notebook,请点击屏幕右上角的“Create notebook instance”。然后填写以下字段:
sagemaker-test。填写完所有必填信息后,点击“Create notebook instance”。
当状态从“Pending”变为“inService”时,您可以点击 notebook 旁的“Open in JupyterLab”链接启动 JupyterLab:
实例进入服务后,计时和计费就开始了。如果您决定休息,请不要忘记点击“Actions”,然后点击“Stop”停止实例,以避免不必要的费用。默认闲置关机时间为两小时:
如果您停止了 notebook 实例,之后可以再次重启。您的环境会被保留。
在 AWS SageMaker 中上传要使用的数据集
本节我们将学习如何将本地文件上传到 Amazon 服务器,这是 SageMaker 的前置要求。
1. 下载示例数据集
我们将使用来自 UCI ML 仓库的Dry Bean 数据集构建一个多分类器。它包含 1.3 万条豆类样本及其 15 个数值型测量。
任务是将其分类为七种豆类:Seker、Barbunya、Bombay、Cali、Dermosan、Horoz 和 Sira。
七种豆类:Seker、Barbunya、Bombay、Cali、Dermosan、Horoz 和 Sira。
下载后,将 ZIP 中的 Excel 文件保存到 JupyterLab 的本地 data 目录中,然后将以下代码添加到您的 notebook:
接着,添加以下代码,我们可以用 pandas 读取 Excel 文件并将其保存为 CSV:
2. 创建 S3 存储桶并上传数据
我们的数据集必须位于 S3 存储桶中,SageMaker 才能访问。AWS S3 是一种云存储解决方案,允许您将与项目相关的对象保存在 Amazon 服务器托管的存储桶中。
要创建存储桶,请按以下步骤操作:
dry-bean-bucket。创建完成后,点击该存储桶上传之前保存的 CSV 文件:
之后,您可以返回 JupyterLab 界面,因为我们终于要运行一些代码了!
在 AWS SageMaker 中的端到端模型训练与部署工作流
本节我们将走一遍端到端流程:从 CSV 数据集开始,到将模型部署到端点。但在深入技术细节之前,先从高层面了解一下我们要做什么。
SageMaker 中 ML 工作流的高层概览
在 SageMaker 中进行机器学习与在本地机器上略有不同。我们已经完成了前期步骤:
与本地 notebook 一样,SageMaker 的 notebook 实例用于探索性分析——数据清洗、探索、摄取和基础实验。
一旦进入模型训练阶段,SageMaker 期望您按其“规则”行事。具体而言,要让 SageMaker 将您的自定义模型部署为端点,它需要一个训练脚本,其功能包括:
脚本还必须能够动态地以命令行参数的形式接收变量。因此,将来希望在脚本内更改的任何内容(模型超参数、文件路径等)都必须设置为命令行参数。
脚本准备就绪后,会传入 SageMaker 提供的特殊估计器中。它们与主流 ML 库(如 scikit-learn、XGBoost、TensorFlow、PyTorch 等)配套。借助这些估计器,SageMaker 会围绕您的脚本构建 Docker 容器,并将其部署为可大规模服务的端点。
随着我们逐步实践,上述要点将变得更加清晰。
1. 为 SageMaker 设置 notebook 实例
首先,在您先前创建的
sagemaker-testnotebook 中导入必要的库:部分导入说明如下:
sagemaker是官方 Python SDK,用于在 Amazon SageMaker 上训练和部署机器学习模型。通过该 SDK,您可以使用主流深度学习框架、Amazon 提供的算法,或内置于 SageMaker 兼容 Docker 镜像中的自定义算法来训练与部署模型。boto3是另一个官方 Python SDK,但它连接您的代码与所有 AWS 服务,而不仅是 SageMaker。您可以通过这门课程了解更多 boto3。导入完成后,创建本教程中将用到的一些资源:
boto3创建一个 SageMaker 客户端对象。这两个对象都允许我们以不同方式与 SageMaker 平台交互。
现在,定义一些需要的全局变量:
这些变量一目了然,我们将在整个教程中使用它们。
2. 将 S3 存储桶中的数据加载到 SageMaker
在大多数数据项目中,训练数据集会存放在云存储解决方案中,如 BigQuery、GCS 或 AWS S3 存储桶。我们将数据存放在 S3,因此用 pandas 加载。将以下代码添加到 notebook 并执行:
在 Sagemaker notebook 中工作的一个优势是,我们可以直接用 pandas 从 S3 读取文件。所有 SageMaker 环境都已配置了您的凭证,允许 pandas 从存储桶下载 CSV。如果在本地运行,这段代码将无法工作。
3. 在 SageMaker 中进行 EDA
在每个项目中花时间进行EDA(探索性数据分析)至关重要,本项目也不例外。不过这里我们不做深入分析,以免偏离本文主题。
我们仅打印一些概要统计和图表:
上面的信息告诉我们,有 16 个数值特征和一个名为
Class的目标列。数据集很小,只有 1.3 万条样本,因此我们不需要高性能机器或花费大量费用来训练模型。接下来,使用 seaborn 绘制几个重要特征的配对图:
上述图表显示,豆类在物理测量方面差异明显。绿色的 Bombay 豆尤其区分度高。
我们还可以绘制相关矩阵来查看特征之间的关系:
图中显示许多特征呈完全(正或负)相关,这很合理,因为这些特征都与物理测量相关。
此处起,我将探索的部分留给您继续进行。
4. 在 SageMaker 中为模型训练准备数据
完成探索后,您需要在训练前处理数据集中的质量或逻辑问题,并在必要时进行特征工程。
Dry Bean数据集相当干净,所以我们的工作很简单。我们只需对目标列进行编码,因为它包含文本。我们将使用 scikit-learn 来完成:预处理完成后,我们需要划分数据集:
如果您愿意,也可以进一步划分出第三个验证集,但这里我们先保持简单。
现在,将数据集保存为 CSV:
并将它们上传到我们的 S3 存储桶:
会话对象的
.upload_data()函数会返回上传文件的完整路径,分别存储在 trainpath 和 testpath 变量中。后续我们会用到这些路径。5. 为 SageMaker 编写训练脚本
在新的 notebook 单元中,粘贴以下代码:
上述脚本中的
%%writefile script.py魔法命令会将单元格内容写入 Python 脚本文件,而不是直接运行。现在逐步说明脚本中发生的事情:
首先导入一些必要的库。
接着,我们创建一个参数解析器对象以读取命令行参数。正如我所说,将来可能需要更新的任何值都应通过 CLI 参数传入。本节定义了这些参数:
如果您注意到
model-dir、train和test目录的默认值,会看到一些环境变量。它们来自 SageMaker SDK 文档,其中也提供了编写此类脚本文件的说明。定义完动态值后,我们读取并构建训练与测试数据集。可以看到,我们没有传递硬编码路径,而是使用
args.argument的值。我们拟合模型,并在训练集与测试集上进行评估,然后打印性能。
最后,我们使用
joblib将模型保存到模型目录。当您在 notebook 中运行此单元时,
script.py文件会出现在 JupyterLab 环境中。您可以通过如下方式执行它来检查是否正常工作:很好,我们获得了 99% 的平衡准确率——相当出色!这意味着我们终于可以启动训练作业了。
6. 在 SageMaker 中创建自定义训练作业
现在,我们将把脚本传递给 SageMaker 的估计器对象。在 AWS 的语境中,训练作业是一个过程,即使用指定的算法、数据集和 AWS SageMaker 提供的计算资源来训练模型。与在本地机器或 notebook 上训练不同,该作业在云端可扩展基础设施上运行,提供更强算力、更快处理速度,并可处理更大的数据集。
在 notebook 的新单元中添加以下代码:
上述代码中,
SKLearn类用于处理 scikit-learn 脚本。它包含一些需要说明的关键参数:entry_point:脚本的路径。role:有权访问 SageMaker 的用户名。instance_count:要启动的机器数量。instance_type:机器类型。对于超参数,只传入您在训练脚本中定义的那些。否则会出错。
现在,我们可以将该估计器拟合到数据上:
回忆本教程前文,
trainpath和testpath是指向我们 CSV 文件的 S3 存储桶路径。运行上述单元后,训练开始:
SageMaker 会下载运行 scikit-learn 代码所需的 Docker 镜像并执行您的脚本。完成后,您将看到如下消息:
如果您进入 SageMaker 控制台的 “SageMaker” > “Traning” > “Training Jobs” 部分,也会看到该训练作业的列表。
7. 使用 Spot 实例训练以降低成本
由于数据集较小,我们可以使用低成本、低配置的机器进行训练:ml.c5.xlarge。但在您的项目中,可能需要处理包含数百万记录或海量图像的数据集。在这种情况下,您必须选择提供更强算力和 GPU 的机器。
按需使用这些机器可能会非常昂贵。为降低成本,Amazon 提供 Spot Training 实例。使用这些实例,您可以以较低价格选择高性能计算资源,但有一个前提——训练不会立即开始。SageMaker 会等待到需求较低且您请求的机器可用时再启动训练。
要启用 Spot Training,您只需在上一段代码中添加几行:
将
use_spot_instances设为True后,spot_sklearn_estimator将使用 Spot 训练。您还可以设置等待 Spot 实例可用的最长时间,以及训练运行的最长时间。当您再次调用
.fit()时,训练才会真正开始:8. 使用 SageMaker 进行超参数调优
使用同一个训练脚本,我们可以通过类似流程得到一个进行过超参数调优的模型。
首先,从
sagemaker.tuner导入IntegerParameter类:IntegerParameter类允许 SageMaker 为接收整数值的参数定义调优范围。tuner模块还包含其他类型参数的类:CategoricalParameter:定义取离散类别值的超参数。ContinuousParameter:为接收连续值的超参数定义调优范围。但本教程中我们只使用
IntegerParameter,因为我们仅调 Random Forest 的两个参数:然后,创建一个调优器对象:
Optimizer的关键参数包括:estimator:与您的训练脚本兼容的估计器对象。hyperparameter_ranges:使用 tuner 模块中的类定义的参数范围。objective_type:是最大化还是最小化给定指标。平衡准确率应被最大化。metric_definitions:要优化的指标名称,以及如何从训练日志中提取它们。metric_definitions参数稍微复杂一些,因为它在定义指标的方式上提供了很高的灵活性。在训练脚本中,我们通过以下日志消息报告平衡准确率:
metric_definitions要求我们用正则表达式捕获该消息。因此,我们提供了如下字典,为以“Test balanced accuracy”开头的捕获指标赋予一个自定义名称。其余代码就很熟悉了:
调优器完成后,您可以将结果以 DataFrame 展示:
然后,您可以获取最优估计器:
9. 在 SageMaker 中将模型部署到端点
一旦确定用于实验的模型,您可以将其与所有工件一起上传到 SageMaker。此任务可使用
boto3完成:describe_training_job()函数接收一个估计器对象并将其推送到 SageMaker 提供的默认 S3 位置。您可以看到,该函数在上传前将模型打包为 tarball。上传的模型可以在 SageMaker 控制台的 “Inference” > “Models” 部分看到:
点击任意模型,您会在右上角看到“Create endpoint”按钮:
您可以通过该按钮部署模型,或返回 notebook 实例使用
.deploy()方法通过代码部署:这次我们使用
SKLearnModel类,它用于已训练的模型。它需要存放工件的 S3 位置以及用于训练的脚本。提供这些信息后,您可以运行代码进行部署:随后,您应能在 SageMaker 控制台的 “Inference” > “Endpoints” 部分看到该端点:
要用于预测,您可以在 notebook 中使用端点对象的
.predict()方法:恭喜,您刚刚用 SageMaker 部署了第一个模型!
使用完毕后,请不要忘记删除端点,因为它会持续产生费用:
别忘了,您在 SageMaker 中创建的每个 notebook 实例都带有一个示例 notebook 的独立标签页,展示 SageMaker 的不同功能:
另请查看 SageMaker Python SDK 的官方文档。
总结
今天,我们学习了如何使用最受欢迎的企业级机器学习平台之一:AWS SageMaker。我们涵盖了从创建 AWS 账户到使用 SageMaker 将 ML 模型部署为端点的全部流程。
与任何平台一样,我们目前只是浅尝辄止。如果在项目中将其与其他 AWS 技术结合,您可以做到更多。以下是一些相关资源可供参考: