9

image

对数据科学家来说,R语言无异于一个利器,可以非常方便直观地解决大量与数据分析有关的挑战。这样一个神器与SageMaker的机器学习能力相结合又能产生多大的威力?目前,已经有不少亚马逊云科技 (Amazon Web Services)客户开始将流行的开源统计计算与图形软件R全面引入大数据分析与数据科学领域。

Amazon SageMaker是一项全托管服务,可帮助用户快速完成机器学习(ML)模型的构建、训练与部署。Amazon SageMaker消除了机器学习流程中各个步骤带来的繁重负担,显著降低了高质量模型的开发门槛。2019年8月,Amazon SageMaker宣布在所有区域都预装R内核。这项功能开箱即用,且预先安装有reticulate库,负责为Amazon SageMaker Python SDK提供R接口,帮助用户直接从R脚本中调用Python模块。

在本文中,我们将了解如何在Amazon SageMaker notebook实例上使用R实现机器学习模型的训练、部署与预测结果检索。此模型将根据鲍鱼贝壳上的圈纹数量预测鲍鱼的年龄。大家可以使用reticulate工具包实现R与Python对象之间的翻译,Amazon SageMaker则提供无服务器环境,用于机器学习模型的大规模训练与部署。

要完成本篇文章,大家需要对R拥有基本了解,并熟悉以下tidyverse软件包:dplyr、readr、stringr以及ggplot2。

创建一个带有R内核的Amazon SageMaker notebook实例

要创建一个预装R内核的Amazon SageMaker notebook实例,需要完成以下操作步骤:

我们可以根据需要选择实例类型与存储大小创建一个Notebook实例。此外,请注意选择身份与访问管理(Identity and Access Management,简称IAM)角色,保证能够运行Amazon SageMaker并拥有对项目中使用的Amazon Simple Storage Service(Amazon S3)存储桶的访问权限。另外,大家也可以选择VPC、子网以及Git库(如果需要的话)。关于更多详细信息,请参阅创建IAM角色

  • 在确认Notebook的当前状态为InService后,选择Open Jupyter。

image

  • 在Jupyter环境中,通过New下拉菜单选择R。

image

Amazon SageMaker中的R内核使用IRKernel软件包,并包含140多个标准工具包。关于为Amazon SageMaker Jupyter notebook实例创建自定义R环境的更多信息,请参阅为Amazon SageMaker创建持久自定义R环境

在创建新Notebook时,大家应该会在Notebook环境的右上角看到R徽标,徽标下方则为R内核。这表明Amazon SageMaker已经成功为当前Notebook启动R内核。
image

在Amazon SageMaker上通过R实现端到端机器学习

本文中的示例Notebook可通过Using R with Amazon SageMaker GitHub repo获取。

接下来加载reticulate库并导入sagemaker Python模块。详见以下代码:

library(reticulate)

sagemaker <- import('sagemaker')

在模块加载完成后,使用R中的$替代Python中的.。

创建并访问数据存储

Session类负责通过Amazon SageMaker对以下boto3资源进行操作:

在本用例中,我们为Amazon SageMaker创建一个默认S3存储桶。使用default_bucket函数创建一个名为sagemaker-_<aws-region-name>_-_<aws account number>_的S3存储桶,详见以下代码:

session <- sagemaker$Session()
bucket <- session$default_bucket()

指定IAM角色的ARN,以允许Amazon SageMaker访问该S3存储桶。大家可以选择创建Notebook时使用过的同一IAM角色,详见以下代码:

role_arn <- sagemaker$get_execution_role()

下载并处理数据集

我们的模型使用来自UCI机器学习库的Abalone数据集。下载相关数据并开始探索性数据分析。使用tidyverse软件包读取数据、绘制数据并将其转换为适用于Amazon SageMaker的ML格式,详见以下代码。

library(readr)
data_file <- 'http://archive.ics.uci.edu/ml/machine-learning-databases/abalone/abalone.data'
abalone <- read_csv(file = data_file, col_names = FALSE)
names(abalone) <- c('sex', 'length', 'diameter', 'height', 'whole_weight', 'shucked_weight', 'viscera_weight', 'shell_weight', 'rings')
head(abalone)

下表为输出结果。
image

输出结果中的sex属于一种因子数据类型,但其目前属于字符数据类型(F为雌性、M为雄性、I为幼体)。将变量sex转换为一个因子数据类型,并使用以下代码查看数据集的统计摘要:

abalone$sex <- as.factor(abalone$sex)
summary(abalone)

以下截屏为上述代码片段的输出结果,此代码片段提供了abalone数据框的统计摘要。
image

摘要中显示,height的最小值为0。大家可以使用以下代码与库绘制不同性别值的rings(即文章开头提到的贝壳圈数)与height之间的关系,从而直观了解哪些鲍鱼的height值为0。

library(ggplot2)
options(repr.plot.width = 5, repr.plot.height = 4)
ggplot(abalone, aes(x = height, y = rings, color = sex)) + geom_point() + geom_jitter()

下图为数据绘出的图。
image

图中显示出多个异常值:2个height为0的幼体鲍鱼,以及数个height远超平均水平的雌性与雄性鲍鱼。要过滤掉这2个height为0的幼体鲍鱼,请使用以下代码:

library(dplyr)
abalone <- abalone %>%
 filter(height != 0)

为模型训练准备数据集

本模型需要3个数据集:训练数据集、测试数据集以及验证数据集。大家需要完成以下操作步骤:

l 将变量sex转换为虚拟变量(Dummy Variable)),而后将目标rings移动至第一列:

abalone <- abalone %>%
 mutate(female = as.integer(ifelse(sex == 'F', 1, 0)),
 male = as.integer(ifelse(sex == 'M', 1, 0)),
 infant = as.integer(ifelse(sex == 'I', 1, 0))) %>%
 select(-sex)
abalone <- abalone %>%
 select(rings:infant, length:shell_weight)
head(abalone)

Amazon SageMaker算法要求目标位于数据集的第一列。下表是输出结果。
image

l 全部数据样本中,有70%被用于进行ML算法训练,其余30%则被进一步拆分成两个部分,一部分用于测试、一部分用于验证:

abalone_train <- abalone %>%
 sample_frac(size = 0.7)
abalone <- anti_join(abalone, abalone_train)
abalone_test <- abalone %>%
 sample_frac(size = 0.5)
abalone_valid <- anti_join(abalone, abalone_test)

现在,我们可以将训练与验证数据上传至Amazon S3,从而进行模型训练。请注意,对于CSV文件训练时,XGBoost算法会假定目标变量位于第一列中,且CSV没有列名称。对于CSV文件推理时,该算法则假定CSV输入中不存在列名称。以下代码不会将列名称保存在CSV文件中。

  • 以.csv格式将训练与验证数据集写入至本地文件系统当中:
write_csv(abalone_train, 'abalone_train.csv', col_names = FALSE)
write_csv(abalone_valid, 'abalone_valid.csv', col_names = FALSE)
  • 将2套数据集上传至S3存储桶中的data “目录”内:
s3_train <- session$upload_data(path = 'abalone_train.csv',
 bucket = bucket,
 key_prefix = 'data')
s3_valid <- session$upload_data(path = 'abalone_valid.csv',
 bucket = bucket,
 key_prefix = 'data')
  • 为Amazon SageMaker算法定义Amazon S3输入类型:
s3_train_input <- sagemaker$s3_input(s3_data = s3_train, content_type = 'csv')
s3_valid_input <- sagemaker$s3_input(s3_data = s3_valid, content_type = 'csv')

训练模型

Amazon SageMaker使用容器Docker来进行训练。要训练XGBoost模型,请完成以下操作步骤:

registry <- sagemaker$amazon$amazon_estimator$registry(session$boto_region_name, algorithm='xgboost')
container <- paste(registry, '/xgboost:latest', sep='')
container
'811284229777.dkr.ecr.us-east-1.amazonaws.com/xgboost:latest'
  • 定义一个Amazon SageMaker Estimator,它可以训练容器化的任意算法。在创建Estimator时,请使用以下参数:
  • image_name – 在训练中使用的容器镜像
  • role – Amazon SageMaker服务角色
  • train_instance_count – 在训练中使用的EC2实例数量
  • train_instance_type – 在训练中使用的EC2实例类型
  • train_volume_size – 在训练过程中用于存储输入数据的Amazon Elastic Block Store (Amazon EBS)存储卷的容量大小(单位为GB)
  • train_max_run – 训练超时(单位为秒)
  • input_mode – 算法支持的输入模式
  • output_path – 用于保存训练结果(包括模型工件与输出文件)的Amazon S3位置
  • output_kms_key – 用于加密训练输出结果的Amazon Key Management Service (Amazon KMS)密钥
  • base_job_name – 训练作业的名称前缀
  • sagemaker_session – 负责管理与Amazon SageMaker API间交互的Session对象
s3_output <- paste0('s3://', bucket, '/output')
estimator <- sagemaker$estimator$Estimator(image_name = container,
 role = role_arn,
 train_instance_count = 1L,
 train_instance_type = 'ml.m5.large',
 train_volume_size = 30L,
 train_max_run = 3600L,
 input_mode = 'File',
 output_path = s3_output,
 output_kms_key = NULL,
 base_job_name = NULL,
 sagemaker_session = NULL)

Python中的None相当于R中的NULL。

  • 指定XGBoost超参数并进行模型拟合
  • 将训练轮数设置为100,这也是在Amazon SageMaker之外使用XGBoost库时的默认值。
  • 根据当前时间戳指定输入数据与作业名称。
estimator$set_hyperparameters(num_round = 100L)
job_name <- paste('sagemaker-train-xgboost', format(Sys.time(), '%H-%M-%S'), sep = '-')
input_data <- list('train' = s3_train_input,
 'validation' = s3_valid_input)
estimator$fit(inputs = input_data,
 job_name = job_name)

在训练完成之后,Amazon SageMaker会将模型的二进制文件(gzip压缩文件)复制至指定的Amazon S3输出位置。使用以下代码以获取完整的Amazon S3路径:

estimator$model_data

部署模型

Amazon SageMaker为用户提供一个预测入口(Endpoint),我们可以使用HTTPS请求通过安全、简单API调用以完成模型部署。要将训练完成的模型部署在ml.t2.medium实例上,请输入以下代码:

model_endpoint <- estimator$deploy(initial_instance_count = 1L,
 instance_type = 'ml.t2.medium')

使用模型进行预测

现在,大家可以使用测试数据进行预测。请完成以下操作步骤:

  • 通过为预测入口(Endpoint)指定text/csv与csv_serializer,将以逗号分隔的文本传递为JSON格式,具体参见以下代码:

model_endpoint$content_type <- 'text/csv'
model_endpoint$serializer <- sagemaker$predictor$csv_serializer
  • 删除目标列,并将前500个行数据转换为没有列名称的矩阵:
abalone_test <- abalone_test[-1]
num_predict_rows <- 500
test_sample <- as.matrix(abalone_test[1:num_predict_rows, ])
dimnames(test_sample)[[2]] <- NULL

本文只使用500行数据,以避免超出预测入口(Endpoint)上限。

  • 预测并将其转换成以逗号分隔的字符串:
library(stringr)
predictions <- model_endpoint$predict(test_sample)
predictions <- str_split(predictions, pattern = ',', simplify = TRUE)
predictions <- as.numeric(predictions)
  • 将预测出的圈数与测试数据集的列绑定:

把预测值转换成整数

  • abalone_test <- cbind(predicted_rings = as.integer(predictions),
  • abalone_test[1:num_predict_rows, ])
  • head(abalone_test)

下表所示为代码的输出结果,其将predicted_rings添加至abalone_test表当中。请注意,实际代码输出可能与此不同,因为步骤2中“为模型训练准备数据集”阶段内的数据集训练/验证/测试拆分属于随机拆分,所以拆分结果很可能与本示例有所区别。
![image](/img/bVcLpwT

删除预测入口(Endpoint

在模型使用完成之后,请删除预测入口(Endpoint)以避免产生不必要的部署成本。具体参见以下代码:

session$delete_endpoint(model_endpoint$endpoint)

总结

本文引导大家完成了一个端到端机器学习项目,全面涵盖数据收集、数据处理、模型训练、将模型部署为端点、使用所部署模型进行推理等各个步骤。关于为Amazon SageMaker Jupyter notebook实例创建自定义R环境的更多信息,请参阅为Amazon SageMaker创建持久自定义R环境。关于Amazon SageMaker上的R notebook示例,请参阅Amazon SageMaker示例GitHub repo

大家也可以参考开发者指南上的《Amazon SageMaker R用户指南》以了解关于通过R使用Amazon SageMaker 各项功能的详细信息。

image


亚马逊云开发者
2.9k 声望9.6k 粉丝

亚马逊云开发者社区是面向开发者交流与互动的平台。在这里,你可以分享和获取有关云计算、人工智能、IoT、区块链等相关技术和前沿知识,也可以与同行或爱好者们交流探讨,共同成长。