CategoryResourceRepost/极客时间专栏/深度学习推荐系统实战/线上服务篇/14 | 融会贯通:Sparrow RecSys中的电影相似推荐功能是如何实现的?.md
louzefeng d3828a7aee mod
2024-07-11 05:50:32 +00:00

110 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<audio id="audio" title="14 | 融会贯通Sparrow RecSys中的电影相似推荐功能是如何实现的" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/cc/57/cc197c38ac9e8343faac60d8f9b30457.mp3"></audio>
你好,我是王喆。
课程进行到这里推荐系统架构的大部分知识点包括特征工程、Embedding模型到推荐服务的搭建线上推荐过程的实现我们都已经学习并且实践过了。如果你坚持跟着我一起学下来的话可以说已经是“武功小成”了。
为了帮你巩固所学,今天,我就带你从头到尾地实现一个完整的推荐功能,**相似电影推荐**,来帮助你打通推荐系统的“任督二脉”。
## “清点技能库”,看看我们已有的知识储备有哪些
在开始实现相似电影推荐功能之前,我想先带着你一起清点一下自己的技能库。我喜欢把推荐的过程比喻成做菜的过程,接下来,我就按照做菜的四个关键步骤,带你回顾一下前面学过的重点知识。
**第一步,准备食材。** 准备食材的过程就是我们准备推荐所需特征的过程。在特征工程篇中我们不仅学会了怎么挑选“食材”怎么处理“食材”而且还实践了“备菜”的高级技能Embedding技术。具体来说就是我们能够利用物品序列数据通过Item2vec方法训练出Embedding也能够使用Deep Walk和Node2vec把图结构数据生成Graph Embedding。
总的来说因为Embedding技术的本质就是利用了物品之间的相关性所以Embedding是做好“相似推荐”这盘菜的关键。
**第二步,食材下锅。** 备好了菜在正式开炒之前我们肯定要把食材下锅。在推荐系统中“食材下锅”的过程有两个一是把线上推荐所用的特征存储到数据库中在之前的课程中我们已经实践过使用Redis作为特征数据库的方法另一个是把模型部署到模型服务模块我们也已讲过了预训练EmbeddingEmbedding加轻量级线上模型TensorFlow Serving等多种模型服务方式这节课我们将采用预训练Embedding的方式进行模型服务。
**第三步,做菜技术。** “做菜的技术”说的是推荐服务器线上推荐的整个流程是否合理。那回到推荐系统中就是指,召回层要快速准确,模型排序部分要精确。这些具体的实现都影响着最终的推荐效果。
对于召回层来说我们已经学过单策略召回、多路召回和基于Embedding的召回。对于排序来说我们会主要利用Embedding相似度来排序后续我们还会学习基于多种推荐模型的排序。
**最后是菜品上桌的过程** 也就是把推荐的结果呈现给用户的过程。这节课我会带你一起实现这个过程。提前“剧透”一下在Sparrow Recsys中我们会先利用JavaScript异步请求推荐服务API获取推荐结果再利用JavaScript+HTML把结果展现给用户”。因为这一部分内容不是推荐系统的重点所以我们这里只要做到界面清爽、逻辑清晰就可以了。
相信到这里,各位“大厨”已经准备好了所要用到的技能,下面就让我们一起来实现**Sparrow RecSys中的相似电影推荐功能吧**
## 如何实现相似电影推荐功能?
在正式开始相似电影推荐功能之前我们先来看看我总结的Sparrow Recsys相似电影推荐功能的详细技术架构图。细心的你可能已经发现了这个架构图就是Sparrow Recsys架构的精简版。因为我们还没有学习深度学习推荐模型和模型评估的相关知识所以把重点聚焦在已经学过的知识上就可以了。
<img src="https://static001.geekbang.org/resource/image/f4/4f/f408eeeeb04bccd127a6726b8bf91d4f.jpg" alt="" title="图1 Sparrow Recsys 相似电影推荐功能的技术架构图">
接下来,我就结合这个技术架构图,带你一步步地实现其中的每一个模块。并且,我还会给你讲解一些项目中没有实现的其他业界主流方法,如果你还学有余力,希望你能抓住这个机会,来扩展一下自己的知识面。
### 1. 数据和模型部分
数据和模型部分的实现,其实和我们[第8讲](https://time.geekbang.org/column/article/296932)讲的Embedding的实战思路是一样的我们可以选用Item2vec、Deep Walk等不同的Embedding方法来生成物品Embedding向量。考虑到大数据条件下数据处理与训练的一致性在Sparrow Recsys中我们会采用Spark进行数据处理同时选择Spark MLlib进行Embedding的训练。这部分内容的代码你可以参考项目中的`_com.wzhe.sparrowrecsys.offline.spark.embedding.__Embedding_`对象它定义了所有项目中用到的Embedding方法。
对于一些比较复杂的Embedding方案比如特征种类很多网络结构也更多样化的Embedding模型业界也多采用Spark进行原始数据处理生成训练样本后交由TensorFlow、PyTorch训练的方案。
但是不论训练平台是怎样的Embedding方法的产出都是一致的就是物品ID对应的Embedding向量。那为了方便线上服务使用我们还需要在生成Embedding后把它们存入某个高可用的数据库。Sparrow Recsys选择了最主流的内存数据库Redis作为实现方案这一部分的具体实现你可以参照`com.wzhe.sparrowrecsys.offline.spark.embedding.Embedding`对象中trainItem2vec函数的Redis存储操作。当然业界也会使用Cassandra+缓存RocksDB等不同的存储方案来实现Embedding向量的高效读取但我们现阶段只要学会Redis存储和读取操作就够用了。
到这里Redis成为了连接线下和线上的关键节点那我们的线上服务部分又是怎么利用Redis中的Embedding数据进行相似电影推荐的呢
### 2. 线上服务部分
线上服务部分是直接接收并处理用户推荐请求的部分,从架构图的最左边到最右边,我们可以看到三个主要步骤:候选物品库的建立、召回层的实现、排序层的实现。我们逐个来讲一讲。
首先是候选物品库的建立。Sparrow Recsys中候选物品库的建立采用了非常简单的方式就是直接把MovieLens数据集中的物品数据载入到内存中。但对于业界比较复杂的推荐业务来说候选集的选取往往是有很多条件的 比如物品可不可用有没有过期有没有其他过滤条件等等所以工业级推荐系统往往会通过比较复杂的SQL查询或者API查询来获取候选集。
第二步是召回层的实现。我们在[第11讲](https://time.geekbang.org/column/article/299494)曾经详细学习了召回层的技术这里终于可以学以致用了。因为物品的Embedding向量已经在离线生成所以我们可以自然而然的使用Embedding召回的方法来完成召回层的实现。同时Sparrow Recsys也实现了基于物品metadata元信息的多路召回方法具体的实现你可以参照`com.wzhe.sparrowrecsys.online.recprocess.SimilarMovieProcess`类中的multipleRetrievalCandidates函数和retrievalCandidatesByEmbedding函数。
第三步是排序层的实现。根据Embedding相似度来进行“相似物品推荐”是深度学习推荐系统最主流的解决方案所以在Sparrow Recsys中我们当然也是先根据召回层过滤出候选集再从Redis中取出相应的Embedding向量然后计算目标物品和候选物品之间的相似度最后进行排序就可以了。
这里“相似度”的定义是多样的可以是余弦相似度也可以是内积相似度还可以根据你训练Embedding时定义的不同相似度指标来确定。因为在Word2vec中相似度的定义是内积相似度所以,这里我们也采用内积作为相似度的计算方法。同样具体的实现你可以参照com.wzhe.sparrowrecsys.online.recprocess.SimilarMovieProcess类中的ranker函数。
经历了这三个主要的线上服务步骤Sparrow Recsys就可以向用户返回推荐列表了。所以接下来我们要解决的问题就是怎么把这些结果通过前端页面展示给用户。
### 3. 前端部分
Sparrow Recsys的前端部分采用了最简单的HTML+AJAX请求的方式。AJAX的全称是Asynchronous JavaScript and XML异步JavaScript和XML请求。它指的是不刷新整体页面用JavaScript异步请求服务器端更新页面中部分元素的技术。当前流行的JavaScript前端框架React、Vue等等也大多是基于AJAX来进行数据交互的。
但前端毕竟不是我们课程的重点你知道我在上面提到的基本原理就可以了。如果你已经在本地的6010端口运行起了Sparrow Recsys那直接点击这个链接[http://localhost:6010/movie.html?movieId=589](http://localhost:6010/movie.html?movieId=589) 就可以看到电影《终结者2》的详情页面和相似电影推荐结果了如图2
<img src="https://static001.geekbang.org/resource/image/a3/yy/a36a1ba15f4c464c84797fc87caf85yy.jpg" alt="" title="图2 终结者2的相似电影推荐结果">
## 相似电影推荐的结果和初步分析
到这里我相信你已经串联起来了Sparrow Recsys相似电影推荐的所有实现看到了推荐结果。那么问题来了推荐结果的好坏到底是如何判断的呢关于这个问题我们也会在后面的“模型评估篇”中进行系统性的学习。不过这里我也想先跟你聊聊这个话题让你对它有一个大体认识这对你建立后续的模型评估体系是非常有帮助的。
首先提醒你的是Sparrow Recsys开源项目中自带的MovieLens数据集是经过我采样后的缩小集所以基于这个数据集训练出的模型的准确性和稳定性是比较低的。如果你有兴趣的话可以去[MovieLens官网](https://grouplens.org/datasets/movielens/)选择**MovieLens 20M Dataset**下载并重新训练,相信会得到更准确的推荐结果。
其次,针对相似物品推荐这个推荐场景,我们其实很难找到一个统一的衡量标准。比如,你能说出《功夫熊猫》这部电影是跟《玩具总动员》更相近,还是跟《飞屋环游记》更相近吗?好在,工程师们还是总结出了一些有效的评估方法。这里,我挑出了三个最常用的来给你讲讲。
**方法一人肉测试SpotCheck。** 在一种Embedding结果新鲜出炉的时候你作为创造它们的工程师应该第一时间做一个抽样测试看一看基于Embedding的相似推荐结果是不是符合你自己的常识。比如说我在Embedding训练完之后随便在Sparrow Recsys中翻了翻看到了两个页面一个是儿童电影《Free Willy》《人鱼童话》的相似电影推荐页面图3左另一个是著名动画电影《Toy Story》《玩具总动员》的相似电影推荐页面图3右
<img src="https://static001.geekbang.org/resource/image/43/87/43be7ebfd05yye98f9c432d4bb113987.jpg" alt="" title="图3 随机测试">
直观上来看《Free Willy》的推荐结果就非常不错因为你可以看到相似电影中都是适合儿童看的甚至这些电影都和动物相关。但是《玩具总动员》就不一样了它的相似电影里不仅有动画片还有《真实的谎言》《True Lies》、《阿甘正传》这类明显偏成人的电影。这明显不是一个非常好的推荐结果。
为什么会出现这样的结果呢?我们来做一个推测。事实上,《玩具总动员》本身是一部非常流行的电影,跟它近似的也都是类似《真实的谎言》、《阿甘正传》这类很热门的电影。这就说明了一个问题,热门电影其实很容易跟其他大部分电影产生相似性,因为它们会出现在大多数用户的评分序列中。
针对这个问题其实仅利用基于用户行为序列的Embedding方法是很难解决的。这需要我们引入更多内容型特征进行有针对性的改进比如电影类型、海报风格或者在训练中有意减少热门电影的样本权重增大冷门电影的样本权重等等。总的来说遇到推荐结果不合理的情况我们需要做更多的调查研究发掘这些结果出现的真实原因才能找到改进方向。
**方法二指定Ground truth可以理解为标准答案。** 虽然我们说相似影片的Ground truth因人而异。但如果只是为了进行初步评估我们也可以指定一些比较权威的验证集。比如对于相似影片来说我们可以利用IMDB的more like this的结果去做验证我们的相似电影结果。当然要补充说明的是要注意有些Ground truth数据集的可用范围不能随意在商业用途中使用未经许可的数据集。
**方法三:利用商业指标进行评估。** 既然相似影片比较难以直接衡量,那我们不如换一个角度,来思考一下做相似影片这个功能的目的是什么。对于一个商业网站来说,无非是提高点击率,播放量等等。因此,我们完全可以跃过评估相似度这样一个过程,直接去评估它的终极商业指标。
举个例子我们可以通过上线一个新的相似电影模型让相似电影这个功能模块的点击率提高假设提高了5%,那这就是一个成功的模型改进。至于相似电影到底有没有那么“相似”,我们反而不用那么纠结了。
## 小结
这节课我们使用Embedding方法准备好了食材使用Redis把食材下锅做菜的步骤稍微复杂一点分为建立候选集、实现召回层、实现排序层这3个步骤。最后我们用HTML+Ajax的方式把相似电影推荐这盘菜呈现出来。
既然有做菜的过程当然也有品菜的阶段。针对相似物品推荐这一常见的功能我们可以使用人肉测试、Ground truth和商业指标评估这三种方法对得到的结果进行评估。也希望你能够在实际的业务场景中活学活用用评估结果指导模型的下一步改进。
我希望,通过这节课的总结和实战,能让你融会贯通的厘清我们学过的知识。所以我把你需要掌握的重要知识点,总结在了一张图里,你可以利用它复习巩固。
<img src="https://static001.geekbang.org/resource/image/dc/9f/dcbb6cf20283ee362235255841b00c9f.jpg" alt="">
好了那到这里我们线上服务篇的内容就全部结束了。通过这一篇的学习我相信你已经清楚了推荐系统的全部技术架构以及深度学习核心技术Embedding的运用方法。
但盛宴还未开始,下一篇我们将进入深度推荐模型的学习和实践。我曾经说过,深度推荐模型是深度学习推荐系统这个王冠上的明珠,正是它对推荐模型的革命,让深度学习的浪潮席卷推荐系统领域。希望你再接再厉,让我们一起把这颗明珠摘下吧!
## 课后思考
刚才我说到《玩具总动员》的相似电影推荐结果并不好我认为可能是因为热门电影的头部效应造成的。你认同这一观点吗你觉得还有其他可能的原因吗如果让你去做一些Embedding方法上的改进你还有什么好的想法吗
欢迎把你的成果和优化想法分享到留言区,也欢迎你能把这节课转发出去,让更多人从我们的实践中受益,我们下节课见!