深入探讨在 AWS SageMaker 上运行超参数优化#

超参数优化 (HPO) 通过搜索超参数来提高模型质量。超参数通常不是在训练过程中学习的参数,而是控制学习过程本身的参数(例如,模型大小/容量)。与默认设置和非专家调优相比,这种搜索可以显著提升模型质量;然而,HPO 在非加速平台上可能需要很长时间。在本笔记本中,我们将 RAPIDS 工作流容器化,并运行 Bring-Your-Own-Container SageMaker HPO,以展示如何克服模型搜索的计算复杂度。

我们通过两种关键方式加速 HPO

  • 通过在节点内扩展(例如,多 GPU,其中每个 GPU 相对于 CPU 具有数量级更高的核心数),以及

  • 通过跨节点扩展并在云实例上运行并行 trial。

通过结合这两种能力,在 CPU 实例上感觉无法实现且可能需要多天的 HPO 实验可以在短短几小时内完成。例如,在比较 GPU 和 CPU EC2 Spot 实例上对存储在 S3 存储桶中的 10 年 Airline 数据集(约 6300 万次航班)进行 100 次 XGBoost HPO trial(使用 10 个并行 worker)时,我们发现实际运行时间加快了 12 倍 (6 小时 vs 3 天以上),成本降低了 4.5 倍 。有关更多详细信息,请参阅笔记本末尾

有了这些强大的工具,每位数据科学家都应该感到有能力在向世界提供模型之前提升其模型水平!

前言#

为了顺利开始,让我们确保能够查询 AWS SageMaker 执行角色和会话,以及我们的账户 ID 和 AWS 区域。

!docker images
%pip install --upgrade boto3
import os

import sagemaker
from helper_functions import (
    download_best_model,
    new_job_name_from_config,
    recommend_instance_type,
    summarize_choices,
    summarize_hpo_results,
    validate_dockerfile,
)
execution_role = sagemaker.get_execution_role()
session = sagemaker.Session()

account = !(aws sts get-caller-identity --query Account --output text)
region = !(aws configure get region)
account, region

关键选择#

接下来,让我们选择 HPO 运行的配置选项。

下面是两个参考配置,分别展示了小型和大规模 HPO(按实验总数/计算量衡量)。

笔记本中的默认值设置为小型 HPO 配置,但您可以根据需要进行扩展。

小型 HPO: 1_year, XGBoost, 3 CV folds, singleGPU, max_jobs = 10, max_parallel_jobs = 2

大型 HPO: 10_year, XGBoost, 10 CV folds, multiGPU, max_jobs = 100, max_parallel_jobs = 10

数据集#

我们提供了几个演示数据集的免费托管服务,您可以尝试使用它们运行 HPO,或者您也可以使用自己的数据集 (BYOD)。

默认情况下,我们利用 Airline 数据集,这是一个大型公共记录美国国内航班日志的数据集。我们提供了不同大小(1 年、3 年和 10 年)以及 Parquet(压缩列式存储)格式的版本。该数据集的机器学习目标是预测航班到达目的地是否会晚点超过 15 分钟(数据集链接,有关更多详细信息,请参阅Section 1.1)。

作为替代,我们还提供了 NYC Taxi 数据集,其中捕获了 2020 年 1 月纽约黄色出租车的行程详情,以未压缩的 CSV 格式存储。该数据集的机器学习目标是预测行程小费是否高于平均水平(>$2.20)。

我们在 us-east-1(北弗吉尼亚)或 us-west-2(俄勒冈)区域的公共 S3 演示存储桶中托管演示数据集(例如,sagemaker-rapids-hpo-us-east-1sagemaker-rapids-hpo-us-west-2)。如果您希望利用演示数据集,则应在这两个区域中的任何一个区域运行 SageMaker HPO 工作流,因为 SageMaker 要求 S3 数据集和您租用的计算资源位于同一区域。

最后,如果您计划使用自己的数据集,请参阅附录中的 BYOD 核对清单以帮助集成到工作流中。

数据集

数据存储桶

数据集目录

# 样本数

存储类型

时间跨度

Airline 统计数据(小)

演示

1 年

630 万

Parquet

2019

Airline 统计数据(中)

演示

3 年

1800 万

Parquet

2019-2017

Airline 统计数据(大)

演示

10 年

6300 万

Parquet

2019-2010

NYC Taxi

演示

NYC_taxi

630 万

CSV

2020 年 1 月

使用您自己的数据集

自定义

自定义

自定义

Parquet/CSV

自定义

# please choose dataset S3 bucket and directory
data_bucket = "sagemaker-rapids-hpo-" + region[0]
dataset_directory = "10_year"  # '1_year', '3_year', '10_year', 'NYC_taxi'

# please choose output bucket for trained model(s)
model_output_bucket = session.default_bucket()
s3_data_input = f"s3://{data_bucket}/{dataset_directory}"
s3_model_output = f"s3://{model_output_bucket}/trained-models"

best_hpo_model_local_save_directory = os.getcwd()

算法#

从 ML/算法的角度来看,我们提供 XGBoostRandomForestKMeans。您可以自由切换这些算法选择,示例中的所有内容将继续正常工作。

# please choose learning algorithm
algorithm_choice = "XGBoost"

assert algorithm_choice in ["XGBoost", "RandomForest", "KMeans"]

我们还可以选择通过重新打乱训练集和测试集分割(即 交叉验证折叠)来提高模型的鲁棒性。典型的折叠数量在 3 到 10 之间。

# please choose cross-validation folds
cv_folds = 10

assert cv_folds >= 1

ML 工作流计算选择#

我们提供了运行不同代码变体的选项,这些变体可以解锁计算工作流中越来越多的并行性。

所有这些代码路径都可以在 /workflows 目录中找到,供您参考。

**请注意,单 CPU 选项将在工作流的模型训练部分利用多个核心;然而,为了在工作流的每个阶段实现完全并行性,我们使用 Dask

# please choose code variant
ml_workflow_choice = "multiGPU"

assert ml_workflow_choice in ["singleCPU", "singleGPU", "multiCPU", "multiGPU"]

搜索范围和策略#

运行 HPO 时最重要的选择之一是选择超参数搜索过程的边界。下面我们设置了超参数的范围以允许有趣的变体,当然,您可以根据领域知识修改这些范围,特别是如果您打算插入自己的数据集。

请注意,我们支持额外的算法特定参数(请参阅 HPOConfig.py 中的 parse_hyper_parameter_inputs 函数),但出于演示目的,我们仅选择了 XGBoost 和 RandomForest 算法之间重叠的三个参数。有关更多详细信息,请参阅 XGBoost 参数RandomForest 参数的文档。由于 KMeans 使用不同的参数,我们相应地进行了调整。

# please choose HPO search ranges
hyperparameter_ranges = {
    "max_depth": sagemaker.parameter.IntegerParameter(5, 15),
    "n_estimators": sagemaker.parameter.IntegerParameter(100, 500),
    "max_features": sagemaker.parameter.ContinuousParameter(0.1, 1.0),
}  # see note above for adding additional parameters
if "XGBoost" in algorithm_choice:
    # number of trees parameter name difference b/w XGBoost and RandomForest
    hyperparameter_ranges["num_boost_round"] = hyperparameter_ranges.pop("n_estimators")
if "KMeans" in algorithm_choice:
    hyperparameter_ranges = {
        "n_clusters": sagemaker.parameter.IntegerParameter(2, 20),
        "max_iter": sagemaker.parameter.IntegerParameter(100, 500),
    }

我们还可以选择随机搜索(Random Search)或贝叶斯搜索(Bayesian Search)策略来选择参数组合。

随机搜索: 为启动的每个训练作业从其范围中选择一组随机组合的值。超参数的选择不依赖于之前的结果,因此您可以运行最大数量的并发 worker 而不影响搜索的性能。

贝叶斯搜索: 猜测哪些超参数组合可能获得最佳结果。在测试第一组超参数值后,超参数调优使用回归来选择下一组要测试的超参数值。

# please choose HPO search strategy
search_strategy = "Random"

assert search_strategy in ["Random", "Bayesian"]

实验规模#

我们还需要决定总共运行多少个实验,以及应该并行运行多少个。下面的最大作业数设置非常保守,以便您在刚开始时不会意外启动大量计算,但是对于有意义的 HPO 搜索,这个数字应该高得多(例如,在我们的实验中,我们通常运行 100 个 max_jobs)。请注意,您可能需要请求配额限制提高才能启用更多的 max_parallel_jobs 并行 worker。

# please choose total number of HPO experiments[ we have set this number very low to allow for automated CI testing ]
max_jobs = 100
# please choose number of experiments that can run in parallel
max_parallel_jobs = 10

我们还将单个作业的最大持续时间设置为 24 小时,以避免出现运行时间过长的计算作业。

max_duration_of_experiment_seconds = 60 * 60 * 24

计算平台#

根据数据集大小和计算选择,我们将尝试推荐一个实例选择*,当然您可以选择其他配置。

例如,对于 10 年数据集选项,我们建议使用 ml.p3.8xlarge 实例(4 个 GPU)和 ml.m5.24xlarge CPU 实例(在模型训练期间,我们将需要超过 200GB 的 CPU 内存)。

# we will recommend a compute instance type, feel free to modify
instance_type = recommend_instance_type(ml_workflow_choice, dataset_directory)
recommended instance type : ml.p3.8xlarge 
instance details          : 4x GPUs [ V100 ], 64GB GPU memory,  244GB CPU memory

除了选择实例类型外,我们还可以通过利用 AWS EC2 Spot 实例来实现显著的成本节省。

我们强烈推荐您将此标志设置为 True,因为它通常会节省 60-70% 的成本。但是请注意,您可能需要请求配额限制提高才能在 SageMaker 中启用 Spot 实例。

# please choose whether spot instances should be used
use_spot_instances_flag = True

验证#

summarize_choices(
    s3_data_input,
    s3_model_output,
    ml_workflow_choice,
    algorithm_choice,
    cv_folds,
    instance_type,
    use_spot_instances_flag,
    search_strategy,
    max_jobs,
    max_parallel_jobs,
    max_duration_of_experiment_seconds,
)
s3 data input    =	s3://sagemaker-rapids-hpo-us-west-2/10_year
s3 model output  =	s3://sagemaker-us-west-2-561241433344/trained-models
compute          =	multiGPU
algorithm        =	XGBoost, 10 cv-fold
instance         =	ml.p3.8xlarge
spot instances   =	True
hpo strategy     =	Random
max_experiments  =	100
max_parallel     =	10
max runtime      =	86400 sec

1. ML 工作流

数据集#

此演示的默认设置旨在利用 Airline 数据集(1987-2020 年航空公司准时性表现数据,可从交通统计局获取)。以下是关于此数据集的一些额外详细信息,我们计划提供一个配套笔记本,深入探讨此数据集背后的数据科学。请注意,如果您使用替代数据集(例如 NYC Taxi 或 BYOData),这些详细信息不相关。

公共数据集包含美国境内航班(17 家航空公司)的日志/特征,包括

  • 位置和距离( OriginDestDistance

  • 航空公司 / 承运人( Reporting_Airline

  • 计划起飞和到达时间( CRSDepTimeCRSArrTime

  • 实际起飞和到达时间( DpTimeArrTime

  • 计划时间与实际时间的差异( ArrDelayDepDelay

  • 晚点的二值编码版本,即我们的目标变量( ArrDelay15

利用这些特征,我们将构建一个分类器模型,用于预测航班在准备起飞时到达目的地是否会晚点超过 15 分钟。

Python ML 工作流#

要构建支持 RAPIDS 的 SageMaker HPO,我们首先需要构建一个 SageMaker Estimator。Estimator 是一个容器镜像,包含运行 HPO 实验所需的所有软件。容器通过入口点代码进行增强,该代码将在运行时由每个 worker 触发。入口点代码使我们能够编写自定义模型并将其连接到数据。

为了与 SageMaker HPO 协同工作,入口点逻辑应解析超参数(由 AWS SageMaker 提供),加载和分割数据,构建和训练模型,对训练好的模型进行评分/评估,并输出一个表示给定超参数设置的最终得分的结果。我们已经构建了这段代码的多个变体。

如果您想通过添加自定义模型逻辑进行更改,请随意修改 train.py 和/或 workflows 目录中的特定工作流文件。您也可以取消注释下面的单元格以加载和查看代码。

首先,让我们将工作目录切换到 Estimator 入口点和库代码所在的目录。

# %load train.py
# %load workflows/MLWorkflowSingleGPU.py

构建 Estimator#

正如我们已经提到的,SageMaker Estimator 表示 AWS SageMaker 将复制到每个工作节点上的容器化软件栈。

构建 Estimator 的第一步是使用上述 ML 工作流代码增强 RAPIDS 容器,并将此镜像推送到 Amazon Elastic Cloud Registry,以便 SageMaker 可以使用它。

容器化并推送到 ECR#

现在,让我们构建容器,使其能够与 AWS SageMaker HPO API 集成。

我们的容器可以基于最新的 RAPIDS [ nightly ] 镜像作为基础层构建,也可以基于 RAPIDS stable 镜像构建。

rapids_base_container = "nvcr.io/nvidia/rapidsai/base:25.04-cuda12.8-py3.12"

让我们也确定容器的完整名称。

image_base = "sagemaker-rapids-mnmg-100"
image_tag = rapids_base_container.split(":")[1]
ecr_fullname = (
    f"{account[0]}.dkr.ecr.{region[0]}.amazonaws.com/{image_base}:{image_tag}"
)

编写 Dockerfile#

我们将 Dockerfile 写入磁盘,并在几个单元格中执行 docker build 命令。

现在让我们将选定的 RAPDIS 镜像层作为 Dockerfile 中的第一个 FROM 语句写入。

with open("Dockerfile", "w") as dockerfile:
    dockerfile.writelines(
        f"FROM {rapids_base_container} \n\n"
        f'ENV AWS_DATASET_DIRECTORY="{dataset_directory}"\n'
        f'ENV AWS_ALGORITHM_CHOICE="{algorithm_choice}"\n'
        f'ENV AWS_ML_WORKFLOW_CHOICE="{ml_workflow_choice}"\n'
        f'ENV AWS_CV_FOLDS="{cv_folds}"\n'
    )

接下来,让我们附加 Dockerfile 的其余部分,即添加依赖项和我们的 Python 代码。

%%writefile -a Dockerfile

# ensure printed output/log-messages retain correct order
ENV PYTHONUNBUFFERED=True

# install a few more dependencies
RUN conda install --yes -n base \
    -c rapidsai -c conda-forge -c nvidia \
        cupy \
        dask-ml \
        flask \
        protobuf \
        rapids-dask-dependency=${{ rapids_version }} \
        'sagemaker-python-sdk>=2.239.0'

# path where SageMaker looks for code when container runs in the cloud
ENV CLOUD_PATH="/opt/ml/code"

# copy our latest [local] code into the container 
COPY . $CLOUD_PATH

WORKDIR $CLOUD_PATH
ENTRYPOINT ["./entrypoint.sh"]
Appending to Dockerfile

最后,让我们确保我们的 Dockerfile 正确捕获了我们选择的基础镜像。

validate_dockerfile(rapids_base_container)
!cat Dockerfile
ARG RAPIDS_IMAGE

FROM $RAPIDS_IMAGE as rapids

ENV AWS_DATASET_DIRECTORY="10_year"
ENV AWS_ALGORITHM_CHOICE="XGBoost"
ENV AWS_ML_WORKFLOW_CHOICE="multiGPU"
ENV AWS_CV_FOLDS="10"

# ensure printed output/log-messages retain correct order
ENV PYTHONUNBUFFERED=True

# install a few more dependencies
RUN conda install --yes -n base \
        cupy \
        flask \
        protobuf \
        'sagemaker-python-sdk>=2.239.0'

# path where SageMaker looks for code when container runs in the cloud
ENV CLOUD_PATH="/opt/ml/code"

# copy our latest [local] code into the container
COPY . $CLOUD_PATH

WORKDIR $CLOUD_PATH
ENTRYPOINT ["./entrypoint.sh"]

构建并标记#

构建步骤主要取决于 RAPIDS 镜像(基础层)的下载。如果已经下载,构建将花费不到 1 分钟。

!docker pull $rapids_base_container
!docker images
%%time
!docker build -t $ecr_fullname .
!docker images

发布到 Elastic Cloud Registry (ECR)#

现在我们已经构建并标记了容器,是时候将其推送到亚马逊的容器注册表 (ECR) 了。进入 ECR 后,AWS SageMaker 将能够利用我们的镜像构建 Estimator 并运行实验。

Docker 登录 ECR

docker_login_str = !(aws ecr get-login --region {region[0]} --no-include-email)
!{docker_login_str[0]}

创建 ECR 存储库 [如果它尚不存在]

repository_query = !(aws ecr describe-repositories --repository-names $image_base)
if repository_query[0] == "":
    !(aws ecr create-repository --repository-name $image_base)

现在让我们实际将容器推送到 ECR

请注意,第一次推送到 ECR 可能需要一些时间(希望不超过 10 分钟)。

!docker push $ecr_fullname

创建 Estimator#

构建了容器 [+自定义逻辑] 并将其推送到 ECR 后,最困难的部分就过去了。最终我们可以将所有的努力汇集到一个 Estimator 实例中。

!docker images
# 'volume_size' - EBS volume size in GB, default = 30
estimator_params = {
    "image_uri": ecr_fullname,
    "role": execution_role,
    "instance_type": instance_type,
    "instance_count": 2,
    "input_mode": "File",
    "output_path": s3_model_output,
    "use_spot_instances": use_spot_instances_flag,
    "max_run": max_duration_of_experiment_seconds,  # 24 hours
    "sagemaker_session": session,
}

if use_spot_instances_flag:
    estimator_params.update({"max_wait": max_duration_of_experiment_seconds + 1})
estimator = sagemaker.estimator.Estimator(**estimator_params)

测试 Estimator#

现在我们准备好测试了,通过让 SageMaker 在我们的 Estimator 中运行 BYOContainer 逻辑。如果您修改了自定义逻辑,并且想在启动大型 HPO 搜索之前确保一切正常工作,这是一个有用的步骤。

注意:此验证步骤将使用我们在自定义训练代码中声明的默认超参数值,因为 SageMaker HPO 不会为此单次运行协调搜索。

summarize_choices(
    s3_data_input,
    s3_model_output,
    ml_workflow_choice,
    algorithm_choice,
    cv_folds,
    instance_type,
    use_spot_instances_flag,
    search_strategy,
    max_jobs,
    max_parallel_jobs,
    max_duration_of_experiment_seconds,
)
s3 data input    =	s3://sagemaker-rapids-hpo-us-west-2/10_year
s3 model output  =	s3://sagemaker-us-west-2-561241433344/trained-models
compute          =	multiGPU
algorithm        =	XGBoost, 10 cv-fold
instance         =	ml.p3.8xlarge
spot instances   =	True
hpo strategy     =	Random
max_experiments  =	100
max_parallel     =	10
max runtime      =	86400 sec
job_name = new_job_name_from_config(
    dataset_directory,
    region,
    ml_workflow_choice,
    algorithm_choice,
    cv_folds,
    instance_type,
)
generated job name : air-mGPU-XGB-10cv-31d03d8b015bfc
estimator.fit(inputs=s3_data_input, job_name=job_name.lower())

运行 HPO#

手头有一个工作的 SageMaker Estimator 后,最难的部分就过去了。在关键选择部分,我们已经定义了我们的搜索策略和超参数范围,剩下的就是选择一个用于评估性能的指标。有关更多文档,请查看 AWS SageMaker Hyperparameter Tuner 文档

定义指标#

我们只关注一个指标,称为 'final-score',它捕获了模型在训练期间未见过的测试数据上的准确性。当然,您可以添加额外的指标,请参阅AWS SageMaker 指标文档。定义指标时,我们提供一个正则表达式(即字符串解析规则)以从每个 Estimator/worker 的输出中提取关键指标。

metric_definitions = [{"Name": "final-score", "Regex": "final-score: (.*);"}]
objective_metric_name = "final-score"

定义 Tuner#

最后,我们将所有构建的元素组合到 HyperparameterTuner 声明中。

hpo = sagemaker.tuner.HyperparameterTuner(
    estimator=estimator,
    metric_definitions=metric_definitions,
    objective_metric_name=objective_metric_name,
    objective_type="Maximize",
    hyperparameter_ranges=hyperparameter_ranges,
    strategy=search_strategy,
    max_jobs=max_jobs,
    max_parallel_jobs=max_parallel_jobs,
)

运行 HPO#

summarize_choices(
    s3_data_input,
    s3_model_output,
    ml_workflow_choice,
    algorithm_choice,
    cv_folds,
    instance_type,
    use_spot_instances_flag,
    search_strategy,
    max_jobs,
    max_parallel_jobs,
    max_duration_of_experiment_seconds,
)
s3 data input    =	s3://sagemaker-rapids-hpo-us-west-2/10_year
s3 model output  =	s3://sagemaker-us-west-2-561241433344/trained-models
compute          =	multiGPU
algorithm        =	XGBoost, 10 cv-fold
instance         =	ml.p3.8xlarge
spot instances   =	True
hpo strategy     =	Random
max_experiments  =	100
max_parallel     =	10
max runtime      =	86400 sec

在启动所有 HPO 实验之前,务必花点时间确认。根据您的配置选项,运行此单元格可能会启动大量的计算!

一旦此过程开始,我们建议您使用 SageMaker UI 来跟踪 HPO 进程和单个 worker 的健康状况

# tuning_job_name = new_job_name_from_config(dataset_directory, region, ml_workflow_choice,
#                                            algorithm_choice, cv_folds,
# #                                            instance_type)
# hpo.fit( inputs=s3_data_input,
#          job_name=tuning_job_name,
#          wait=True,
#          logs='All')

# hpo.wait()  # block until the .fit call above is completed

结果与摘要#

作业完成后,有多种方法可以分析结果。下面我们展示了最佳作业的性能,并将每个 HPO trial/job 作为数据框的一行打印出来。

tuning_job_name = "air-mGPU-XGB-10cv-527fd372fa4d8d"
hpo_results = summarize_hpo_results(tuning_job_name)
INFO:botocore.credentials:Found credentials from IAM Role: BaseNotebookInstanceEc2InstanceRole
best score: 0.9203665256500244
best params: {'max_depth': '7', 'max_features': '0.29751893065195945', 'num_boost_round': '346'}
best job-name: air-mGPU-XGB-10cv-527fd372fa4d8d-042-ed1ff13b
sagemaker.HyperparameterTuningJobAnalytics(tuning_job_name).dataframe()
INFO:botocore.credentials:Found credentials from IAM Role: BaseNotebookInstanceEc2InstanceRole
max_depth max_features num_boost_round TrainingJobName TrainingJobStatus FinalObjectiveValue TrainingStartTime TrainingEndTime TrainingElapsedTimeSeconds
0 5.0 0.715196 116.0 air-mGPU-XGB-10cv-527fd372fa4d8d-100-c04c691b 已完成 0.920362 2023-01-23 21:01:38+00:00 2023-01-23 21:06:21+00:00 283.0
1 12.0 0.855974 243.0 air-mGPU-XGB-10cv-527fd372fa4d8d-099-97d44628 已完成 0.920355 2023-01-23 21:17:56+00:00 2023-01-23 21:22:34+00:00 278.0
2 11.0 0.549247 395.0 air-mGPU-XGB-10cv-527fd372fa4d8d-098-e74f483f 已完成 0.920356 2023-01-23 20:56:06+00:00 2023-01-23 21:00:44+00:00 278.0
3 7.0 0.882803 179.0 air-mGPU-XGB-10cv-527fd372fa4d8d-097-50755cd6 已完成 0.920356 2023-01-23 20:54:35+00:00 2023-01-23 20:59:13+00:00 278.0
4 8.0 0.416939 267.0 air-mGPU-XGB-10cv-527fd372fa4d8d-096-5c95eb2f 已完成 0.920355 2023-01-23 20:51:24+00:00 2023-01-23 20:56:02+00:00 278.0
... ... ... ... ... ... ... ... ... ...
95 5.0 0.426204 330.0 air-mGPU-XGB-10cv-527fd372fa4d8d-005-7b755a81 已完成 0.920355 2023-01-23 18:48:35+00:00 2023-01-23 18:53:48+00:00 313.0
96 5.0 0.283752 256.0 air-mGPU-XGB-10cv-527fd372fa4d8d-004-e4d086fb 已完成 0.920356 2023-01-23 18:48:34+00:00 2023-01-23 18:53:47+00:00 313.0
97 5.0 0.137874 377.0 air-mGPU-XGB-10cv-527fd372fa4d8d-003-89cd8506 已完成 0.920355 2023-01-23 18:48:31+00:00 2023-01-23 18:53:44+00:00 313.0
98 15.0 0.934718 365.0 air-mGPU-XGB-10cv-527fd372fa4d8d-002-caf8f6c3 已完成 0.920360 2023-01-23 18:48:25+00:00 2023-01-23 18:53:48+00:00 323.0
99 15.0 0.356588 460.0 air-mGPU-XGB-10cv-527fd372fa4d8d-001-e8a6d247 已完成 0.920356 2023-01-23 18:48:29+00:00 2023-01-23 18:53:47+00:00 318.0

100 行 × 9 列

如需更深入地了解 HPO 过程,我们邀请您查看 HPO_Analyze_TuningJob_Results.ipynb 笔记本,该笔记本展示了我们如何探索每个单独超参数对性能指标的影响等有趣内容。

获取最佳模型#

接下来,让我们从 HPO 运行中下载最佳训练模型。

local_filename, s3_path_to_best_model = download_best_model(
    model_output_bucket,
    s3_model_output,
    hpo_results,
    best_hpo_model_local_save_directory,
)
INFO:botocore.credentials:Found credentials from IAM Role: BaseNotebookInstanceEc2InstanceRole
Successfully downloaded best model
> filename: /home/ec2-user/SageMaker/cloud-ml-examples/aws/best_model.tar.gz
> local directory : /home/ec2-user/SageMaker/cloud-ml-examples/aws

full S3 path : s3://sagemaker-us-west-2-561241433344/trained-models/air-mGPU-XGB-10cv-527fd372fa4d8d-042-ed1ff13b/output/model.tar.gz

模型服务#

手头有了最佳模型后,您现在可以继续在 SageMaker 上提供此模型服务了。

在下面的示例中,我们向您展示如何使用 HPO 搜索期间找到的最佳模型构建 RealTimePredictor。我们将在 RAPIDS Estimator(即容器)中添加一个轻量级 Flask 服务器,该服务器将处理传入的请求并将其传递给训练好的模型进行推理。如果您对内部工作原理感到好奇,请查看使用您自己的推理服务器文档和 serve.py 中的参考代码。

如果您对其他服务选项(例如,使用批量转换(batch-transform)处理大批量数据)感兴趣,我们计划添加一个配套笔记本,提供更多详细信息。

GPU 服务#

endpoint_model = sagemaker.model.Model(
    image_uri=ecr_fullname, role=execution_role, model_data=s3_path_to_best_model
)

启动一个用于预测的实例 [建议使用 'ml.g4dn.2xlarge' ]

DEMO_SERVING_FLAG = True

if DEMO_SERVING_FLAG:
    endpoint_model.deploy(
        initial_instance_count=1, instance_type="ml.g4dn.2xlarge"
    )  #'ml.p3.2xlarge'
INFO:sagemaker:Creating model with name: rapids-sagemaker-mnmg-100-2023-01-23-22-24-22-008
INFO:sagemaker:Creating endpoint-config with name rapids-sagemaker-mnmg-100-2023-01-23-22-24-22-498
INFO:sagemaker:Creating endpoint with name rapids-sagemaker-mnmg-100-2023-01-23-22-24-22-498
---------!

执行预测并返回结果。

下面我们编译了示例,用于在 Airline 数据集上进行训练模型的性能健全性测试。

第一个示例来自 2019 年一趟提前九分钟起飞的航班,

第二个示例来自 2018 年一趟晚点两个多小时起飞的航班。

当我们运行这些样本时,预期看到打印结果为 b'[0.0, 1.0]

我们鼓励您修改下面的查询,特别是如果您使用了自己的数据集。

if DEMO_SERVING_FLAG:
    predictor = sagemaker.predictor.Predictor(
        endpoint_name=str(endpoint_model.endpoint_name), sagemaker_session=session
    )

    if dataset_directory in ["1_year", "3_year", "10_year"]:
        on_time_example = [
            2019.0,
            4.0,
            12.0,
            2.0,
            3647.0,
            20452.0,
            30977.0,
            33244.0,
            1943.0,
            -9.0,
            0.0,
            75.0,
            491.0,
        ]  # 9 minutes early departure
        late_example = [
            2018.0,
            3.0,
            9.0,
            5.0,
            2279.0,
            20409.0,
            30721.0,
            31703.0,
            733.0,
            123.0,
            1.0,
            61.0,
            200.0,
        ]
        example_payload = str(list([on_time_example, late_example]))
    else:
        example_payload = ""  # fill in a sample payload

    result = predictor.predict(example_payload)
    print(result)
b'[0.0, 1.0]'

完成服务示例后,务必进行清理并删除终端节点。

# if DEMO_SERVING_FLAG:

#     predictor.delete_endpoint()

总结#

我们现在已经成功构建了 RAPIDS ML 工作流,将其容器化(作为 SageMaker Estimator),并启动了一系列 HPO 实验来寻找模型的最佳超参数。

如果您想进一步探索,我们邀请您插入自己的数据集并调整配置设置,以找到您的最佳模型!

HPO 实验详情

正如引言中所述,在比较 GPU 和 CPU 实例上对 10 年 Airline 数据集(约 6300 万次航班)进行 100 次 HPO trial(使用 10 个并行 worker)时,我们发现实际运行时间加快了 12 倍 ,成本降低了 4.5 倍 。在这些实验中,我们使用了 XGBoost 算法,并使用了多 GPU 对比多 CPU Dask 集群和 10 个交叉验证折叠。下表提供了更多详细信息。

在 CPU 运行中,有 12 个作业由于超过我们设定的 24 小时限制而被停止。CPU 作业摘要图片

在 GPU 运行中,没有作业被停止。GPU 作业摘要图片

请注意,在两种情况下都有 1 个作业由于 Spot 实例被终止而失败。但 100 个作业中失败 1 个作业对于显著的成本节省来说是微不足道的权衡。

附录#

使用您自己的数据集核对清单#

如果您计划使用自己的数据集 (BYOD),这里有一个核对清单帮助您集成到工作流中

  • [ ] 数据集应为 CSV 或 Parquet 格式。

  • [ ] 数据集已预处理(并且已完成所有特征工程)。

  • [ ] 数据集已上传到 S3,并且 data_bucketdataset_directory 已设置为您的数据位置。

  • [ ] 数据集特征列和目标列已在 /HPODataset.py 中列举。

RAPIDS 参考#

SageMaker 参考#

Spot 实例 文档,以及博客