写点什么

使用 AWS Sagemaker 训练因子分解机模型并应用于推荐系统

  • 2019-10-08
  • 本文字数:6554 字

    阅读完需:约 22 分钟

使用AWS Sagemaker训练因子分解机模型并应用于推荐系统

使用 AWS Sagemaker 系列文章:

第一篇:使用 AWS Sagemaker 训练因子分解机模型并应用于推荐系统(本博文)


第二篇:使用 AWS Sagemaker 部署的终端节点进行推荐预测的常用场景


————


在线服务和应用中,经常遇到需要对用户历史行为进行分析并预测,典型的案例如页面点击预测及推荐系统。这些案例的特点是历史数据集非常庞大,而且大多数情况,数据集是稀疏的。让我们以电影点评网站为例来理解稀疏数据集。在电影点评网站中,拥有大量的用户以及大量的电影,然而几乎不可能实现每个用户对每个电影都进行点评或打分。因此如果我们以用户为行,以电影为列,构建一个表格,对该用户点评过的电影单元格置 1,未点评过的置 0,我们可以发现,该表格中绝大部分数据都将是 0。这就是稀疏数据集的典型例子。


针对稀疏数据集,因子分解机(Factorization Machines,FM)是比较有效的算法模型。



直观来说因子分解机可以考虑为由用户(User)为行、电影(Movie)为列构成的矩阵 R 可以表示为一个用户(User)为行、K 列特征构成的矩阵 P 与电影(Movie)为行、K 列特征构成的矩阵 Q 的转置的乘积。其中的 K 即潜藏特征值,可以将他理解为用户与电影之间的关系。在因子分解机中,这一值是可以自行设定的。算法的主要目的就是计算出 P 和 Q 矩阵,并使 P 与 QT 的乘积尽可能与 R 一致。


本次实验采用国内用户对大量国内外电影的评论作为训练数据集,利用 AWS SageMaker 自带的因子分解机算法构建模型,通过 SageMaker 的超参调优服务观察参数调整对模型表现的影响。最后,以实际应用中经常会遇到的用法演示模型的预测结果。本次实验全部使用 Python3.6 完成,在 SageMaker 中选用 conda_python3 的 Kernel。

数据准备阶段

本次数据总量大约为 396 万条,用户数 49 万,电影数 3 万多。考虑到演示的目的和运算的效率,训练模型时使用其中 10 万条数据的采样。


In [3]:


df_all = pd.read_csv('all_movie_rates_noblank.csv')print(df_all.shape)print(df_all['UserId'].nunique())print(df_all['MovieID'].nunique())
复制代码


(3963891, 3)


490790


33345


首先我们对数据进行基本的观察。可以看到这 10 万条数据包含 53902 个用户和 26004 部电影。随后我们对数据集进行训练集和测试集的拆分,这里采用训练数据:测试数据 = 4:1 的比例进行拆分。


In [4]:


df=pd.read_csv('all_movie_rates_100k.csv')print(df.shape)print(df['UserId'].nunique())print(df['MovieID'].nunique())
df_train, df_test = train_test_split(df, test_size=0.2, random_state=42)print(df_train.shape, df_test.shape)
print(df_train.head(10))print(df_test.head(10))(107029, 3)
复制代码


53902


26004


(85623, 3) (21406, 3)


MovieID Rate UserId


63287 1296827 10 BloodzBoi


73804 3564327 6 LadyHoney


76527 6874441 8 49886917


71411 3152563 8 feathercat


64499 2004250 6 jingtianwst83


42130 3230459 6 funni


88502 3313801 6 chrisocean


79349 3072140 0 lala1123


21431 2053746 6 145992805


39240 1464338 8 HeroineDaode


MovieID Rate UserId


44496 26304167 8 152833029


11855 1299900 8 leonah


13955 26085750 2 49298107


27112 4202982 8 Kylin-2015


28103 4739952 10 likong


53598 3443393 4 3832465


65338 2052363 6 1926472


1116 6129707 8 vero_nicat


38854 26841337 2 158039357


78721 1307026 8 TowaErio

为用户和电影分别建立字典(Python Dictionary)

数据集中的用户 ID 和电影 ID 均为随机字符串,为了方便我们后续建立有序矩阵以及模型训练后预测结果的数据对应,我们首先为用户和电影分别建立由 0 开始的 index 序列,并使其与 ID 字符串对应。


In [5]:


filename = 'all_movie_rates_100k.csv'user_number = 53902movie_number = 26004
def createIDtoIndexDict(filename, user_number, movie_number): u_Dict = {} m_Dict = {} i = 0 m = 0 with open(filename, 'r') as f: sample = csv.reader(f, delimiter=',') for MovieID, Rate, UserId in sample: if UserId == 'UserId': continue else: if UserId not in u_Dict.keys(): u_Dict[UserId] = i i = i+1 if MovieID not in m_Dict.keys(): m_Dict[MovieID] = m m = m+1 return u_Dict, m_Dict u_Dict, m_Dict = createIDtoIndexDict(filename, user_number, movie_number)
复制代码

建立稀疏矩阵(Sparse Matrix)和标签向量(Label Vector)

因子分解机的训练是针对稀疏矩阵的,因此我们要将数据集中电影、评分、用户的序列转为稀疏矩阵,并根据用户评分的结果生成标签向量。我们使用 Python Scipy 模块中的 lil_matrix 来构建。


生成的矩阵应当是每一个用户 ID 作为单独一列、每一部电影在所有用户列之后也作为单独一列,针对原数据集中每行的数据,在对应的用户列和电影列置 1。标签向量以用户评分为基准,我们设定用户评分大于等于 6 的为“喜爱”,并在对应的标签向量位置置 1,反之为“不喜爱”,标签向量相应位置置 0。


训练集和测试集均进行同样的操作。


df_train.to_csv('100k_train.csv', index=False, encoding="utf_8_sig")df_test.to_csv('100k_test.csv', index=False, encoding="utf_8_sig")
columns = user_number+movie_numberdef loadDataset(filename, lines, columns): X = scipy.sparse.lil_matrix((lines, columns)).astype('float32') Y = [] line = 0 with open (filename, 'r') as f: sample = csv.reader(f, delimiter=',') for MovieID, Rate, UserId in sample: if UserId == 'UserId': continue else: X[line, u_Dict[UserId]] = 1 X[line, user_number+m_Dict[MovieID]] = 1 if Rate == 'Rate' or int(Rate) < 6: Y.append(0) else: Y.append(1) line=line+1
Y=np.array(Y).astype('float32') print(X.shape) print(Y.shape) return X, Y
复制代码


In [222]:


X_train, Y_train = loadDataset('100k_train.csv', df_train.shape[0], columns)X_test, Y_test = loadDataset('100k_test.csv', df_test.shape[0], columns)print(X_train.shape, X_test.shape)print(Y_train.shape, Y_test.shape)
复制代码


(85623, 79906)


(85623,)


(21406, 79906)


(21406,)


(85623, 79906) (21406, 79906)


(85623,) (21406,)


我们获得了训练集为 85623✖️79906 的矩阵,训练标签向量为 85263 元素;测试集为 21406✖️79906 矩阵,其标签向量为 21406 元素。

转换稀疏矩阵为 protobuf 格式,并保存到 S3

稀疏矩阵中绝大多数元素均为 0,如果直接保存稀疏矩阵,会占用大量的存储空间,因此我们将其转为 protobuf 格式的数据,并保存到 S3。


In [224]:


bucket = 'movie-recommendation-demo-raw-data'prefix = 'sagemaker/movie-recommendation'train_key      = 'train.protobuf'train_prefix   = '{}/{}'.format(prefix, 'train')test_key       = 'test.protobuf'test_prefix    = '{}/{}'.format(prefix, 'test')output_prefix  = 's3://{}/{}/output'.format(bucket, prefix)
def writeDatasetToProtobuf(X, Y, bucket, prefix, key): import io,boto3 import sagemaker.amazon.common as smac buf = io.BytesIO() smac.write_spmatrix_to_sparse_tensor(buf, X, Y) buf.seek(0) print(buf) obj = '{}/{}'.format(prefix, key) boto3.resource('s3').Bucket(bucket).Object(obj).upload_fileobj(buf) print('Wrote dataset: {}/{}'.format(bucket,obj)) return 's3://{}/{}'.format(bucket,obj) train_data = writeDatasetToProtobuf(X_train, Y_train, bucket, train_prefix, train_key) test_data = writeDatasetToProtobuf(X_test, Y_test, bucket, test_prefix, test_key)
print(train_data)print(test_data)print('Output: {}'.format(output_prefix))<_io.BytesIO object at 0x7f99a8b8e1a8>
Wrote dataset: movie-recommendation-demo-raw-data/sagemaker/movie-recommendation/train/train.protobuf
<_io.BytesIO object at 0x7f99a8b8e1a8>
Wrote dataset: movie-recommendation-demo-raw-data/sagemaker/movie-recommendation/test/test.protobuf
s3://movie-recommendation-demo-raw-data/sagemaker/movie-recommendation/train/train.protobuf
s3://movie-recommendation-demo-raw-data/sagemaker/movie-recommendation/test/test.protobuf
Output: s3://movie-recommendation-demo-raw-data/sagemaker/movie-recommendation/output
复制代码


程序输出中 Output 的内容是模型训练完成后,保存模型代码的位置。

FM 模型训练

FM 是 SageMaker 自带的算法之一,因此通过 SageMaker 训练模型非常容易。首先我们需要引入 SageMaker 的 SDK,并建立 SageMaker 的 session、定义位于该 Region 的因子分解机算法 Container 以及获取 SageMaker 的运行角色。


In [225]:


from sagemaker import get_execution_rolefrom sagemaker.amazon.amazon_estimator import get_image_uriimport sagemakersess = sagemaker.Session()
role = get_execution_role()container = get_image_uri(boto3.Session().region_name, 'factorization-machines')
复制代码


随后我们定义 FM 训练需要的一些参数。首先是环境参数,包括之前定义好的 Container、角色、输出位置和 session、还包括训练使用的 EC2 实例,本例中采用“ml.c4.xlarge”来训练。


之后,我们需要定义 FM 算法的超参(Hyperparameters)。在本例中特征列为用户数与电影数的总和 79906、预测方式为二分类(即结果为判断“喜爱”或是“不喜爱”)、最小批量为 1000、epoch 时期为 50 次。其中 num_factors 即为在算法介绍中提到的潜藏特征 K 的数量,根据 SageMaker 官方文档的说明,建议在 2-1000 之间,通常 64 为最优值,因此,我们也设为 64。


最后为模型提供训练集和测试集在 S3 中的位置,训练就开始了。


In [226]:


fm = sagemaker.estimator.Estimator(container,                                   role,                                    train_instance_count=1,                                    train_instance_type='ml.c4.xlarge',                                   output_path=output_prefix,                                   sagemaker_session=sess)fm.set_hyperparameters(feature_dim=79906,                      predictor_type='binary_classifier',                      mini_batch_size=1000,                      num_factors=64,                      epochs=50)
fm.fit({'train': train_data, 'test':test_data})
复制代码


INFO:sagemaker:Creating training-job with name: factorization-machines-2018-12-18-03-18-50-388


2018-12-18 03:18:50 Starting – Starting the training job…


2018-12-18 03:18:56 Starting – Launching requested ML instances……


2018-12-18 03:19:58 Starting – Preparing the instances for training…


2018-12-18 03:20:45 Downloading – Downloading input data…


2018-12-18 03:20:55 Training – Downloading the training image…


Docker entrypoint called with argument(s): train


[12/18/2018 03:22:09 INFO 139830159329088] #quality_metric: host=algo-1, test binary_classification_accuracy=0.736288890965


[12/18/2018 03:22:09 INFO 139830159329088] #quality_metric: host=algo-1, test binary_classification_cross_entropy=0.548373071499


[12/18/2018 03:22:09 INFO 139830159329088] #quality_metric: host=algo-1, test binary_f_1.000=0.84806072188


[2018-12-18 03:22:09.767] [tensorio] [info] data_pipeline_stats={“name”: “/opt/ml/input/data/test”, “epoch”: 1, “duration”: 366, “num_examples”: 22}


[2018-12-18 03:22:09.767] [tensorio] [info] data_pipeline_stats={“name”: “/opt/ml/input/data/test”, “duration”: 40228, “num_epochs”: 2, “num_examples”: 23}


#metrics {“Metrics”: {“totaltime”: {“count”: 1, “max”: 40280.484199523926, “sum”: 40280.484199523926, “min”: 40280.484199523926}, “setuptime”: {“count”: 1, “max”: 39.59202766418457, “sum”: 39.59202766418457, “min”: 39.59202766418457}}, “EndTime”: 1545103329.767301, “Dimensions”: {“Host”: “algo-1”, “Operation”: “training”, “Algorithm”: “factorization-machines”}, “StartTime”: 1545103329.299489}
复制代码


[2018-12-18 03:22:09.784] [tensorio] [info] data_pipeline_stats={“name”: “/opt/ml/input/data/train”, “epoch”: 50, “duration”: 1287, “num_examples”: 86}


[2018-12-18 03:22:09.784] [tensorio] [info] data_pipeline_stats={“name”: “/opt/ml/input/data/train”, “duration”: 39923, “num_epochs”: 51, “num_examples”: 4301}


Billable seconds: 92


模型训练完成了。在模型训练结束后的总结中,我们可以看到几个重要的指标:


  • 模型训练计费时间 92 秒,所以并不会花很多钱;

  • 模型的二分准确度为 73.62%

  • 接下来,我们考虑一下应用 SageMaker 的超参调优(Hyperparameters Tuning)来尝试其他的超参设置是否可以获得更好的二分准确度。SageMaker 的超参调优可以通过 SageMaker 的 Console 直接配置完成。简单来讲,就是首先设定目标,本例中我们希望最大化(Maximize)模型二分准确度。之后给予可调参数的变动范围,本例中我们希望测试 mini batch size 和 epochs 的设置是否可以提升结果表现。最后定义训练集、测试集、算法的相应位置,以及优化任务运行的次数(最大为 100),即可开始。


当优化任务全部运行完成后,我们可以获得表现最好的模型的数据,如图



在这一参数配置下,模型的二分准确度提升为 76.2%。应用这一超参配置训练模型,并部署为 Endpoint。Endpoint 可以理解为模型基于 http 访问的 API 接口,有了 Endpoint 就可以进行预测服务了。


In [227]:


fm.set_hyperparameters(feature_dim=79906,                      predictor_type='binary_classifier',                      mini_batch_size=200,                      num_factors=64,                      epochs=134)In [228]:
fm_predictor = fm.deploy(initial_instance_count=1, instance_type='ml.t2.medium')INFO:sagemaker:Creating model with name: factorization-machines-2018-12-18-05-56-31-040
INFO:sagemaker:Creating endpoint with name factorization-machines-2018-12-18-05-47-26-108
—————————————————————–!
复制代码


我们的模型部署完成,Endpoint 名称为“factorization-machines-2018-12-18-05-47-26-108”。之后我们可以通过这个名称来调用 Endpoint 完成预测任务。


后续我们会继续利用已部署的终端节点 Endpoint 对常见的应用场景进行预测。


使用 AWS Sagemaker 系列文章:


第一篇:使用AWS Sagemaker训练因子分解机模型并应用于推荐系统(本博文)


第二篇:使用AWS Sagemaker部署的终端节点进行推荐预测的常用场景


————


作者介绍:


崔辰


AWS 大中华区创新中心技术业务拓展经理。加入 AWS 之前,崔辰在中国惠普、IBM、微软以及海航科技等公司担任过售前技术顾问、市场经理和战略合作经理等职务。在 10 多年的科技领域工作经历中,崔辰服务过众多企业级客户。


本文转载自 AWS 技术博客。


原文链接:


https://amazonaws-china.com/cn/blogs/china/aws-sagemaker-system-recommend-use/


2019-10-08 10:03738
用户头像

发布了 1849 篇内容, 共 114.7 次阅读, 收获喜欢 78 次。

关注

评论

发布
暂无评论
发现更多内容

Python开发游戏?也太好用了吧!

Jackpop

大数据培训工作就业前景怎么样

小谷哥

声网管浩森:元宇宙派对场景的最佳实践

声网

实践 元宇宙 RTE2022

下一个AI舞台,名叫煤矿

脑极体

2022-12-16:给你一个长度为n的数组,并询问q次 每次询问区间[l,r]之间是否存在小于等于k个数的和大于等于x 每条查询返回true或者false。 1 <= n, q <= 10^5 k

福大大架构师每日一题

golang 算法 福大大

华为云12·12直播EI专场即将开始,满足电商行业全场景搜索需求

科技怪授

华为云

场景 | 大型电商企业运营管理数字化解决方案

九科Ninetech

Chrome浏览器竟然可以用ChatGPT了!

Jackpop

SpringBoot整合Swagger2,再也不用维护接口文档了!

@下一站

12月日更 12月月更 springboot整合 swagger2

来聊一聊 ElasticSearch 最新版的 Java 客户端

江南一点雨

Java elasticsearch springboot ES

云渲染是什么?云渲染和自己渲染有什么区别?

Renderbus瑞云渲染农场

云渲染 渲染农场 云渲染平台

多名网络主播因恶意炒作被列入警示名单,如何打击这种违规行为

石头IT视角

ZBC陆续在主要CEX开启Staking,锁定市场大部分流通量成大利好

BlockChain先知

C++开发,这些GUI库一定不要错过!

Jackpop

终于被我发现了这个推特视频下载的方法!超级简单!支持苹果安卓双系统!

frank

推特视频下载

大数据培训出来就业前景如何

小谷哥

浪潮 KaiwuDB 陈磊:布局数字能源,创新助力 “双碳”

KaiwuDB

java自学好还是培训好?

小谷哥

架构实战模块1作业

Geek_e3a35c

打造算力新引擎!安擎上海智能制造基地正式运营

科技热闻

横空出世!阿里巴巴Spring全家桶实战笔记真香

Java永远的神

spring 源码 架构师 springboot SpringCloud

相见恨晚!Git这些功能太好用了!

Jackpop

凭借这份Java面试复盘笔记,我在2022寒冬之际也斩获了多张Offer!

程序员小毕

spring 程序员 后端 架构师 java面试

关于K8s集群环境工作组隔离配置多集群切换的一些笔记

山河已无恙

k8s管理 K8s 多集群管理 12月月更

Verilog的语句块

梦笔生花

Verilog Verilog语法 Verilog语句块

极客时间运维进阶训练营第八周作业

好吃不贵

ZBC陆续在主要CEX开启Staking,锁定市场大部分流通量成大利好

股市老人

直播继续!华为云Solution as Code一键高效上云,解决方案开箱即用

科技怪授

华为云

模块二 -- 朋友圈高性能复杂度分析

陈实

「架构实战营」

选取数据的原则

穿过生命散发芬芳

数据分析 12月月更

使用AWS Sagemaker训练因子分解机模型并应用于推荐系统_语言 & 开发_亚马逊云科技 (Amazon Web Services)_InfoQ精选文章