作者:时晴
推荐系统内容实在太丰富了,以至于刚开始学的人都无从下手,当年时晴无意中翻到谷歌这篇教程,然后就开启了入"坑"推荐系统的神奇旅程,极力推荐给大家,大家也可以推荐给想学推荐系统的童鞋们。该课程标明预估学完要用4个小时,那这篇的重点就是带大家15分钟内学完。(本篇内容较为基础,大牛们略过)
大规模推荐系统
YouTube是怎么知道你要看的下个视频是啥的呢?Google应用商店又是如何选择哪款app展示给你的呢?为什么要有推荐系统呢?谷歌应用商店有上百万app,YouTube有上亿视频,然后app和视频数每天还会增加,我们不可能指望给一个搜索框,让用户自己搜视频或者app,有些用户可能根本不知道自己想看什么或者下载什么,值得注意的是,谷歌应用商店40%的app安装都是来自于推荐系统,YouTube 60%视频观看时间都是来自于推荐系统。
相关术语:
Items(documents)
推荐系统推荐的实体,对于YouTube就是视频,对于Google应用商店就是app。
Query(context)
推荐系统用query的信息进行推荐,query信息包括用户信息(用户id,用户交互特征)和上下文信息(时间,设备)。
Embedding
离散值到向量空间的隐射,大部分的推荐系统都是基于学到的item和query的向量表达来做推荐的。
推荐系统概述
推荐系统主要由3个部分组成,候选集生成(召回),粗排,精排。
召回可以天马行空,从各个角度召回不同items集合取并集,最后召回的items数量是远远小于所有items数量的。因为召回数目已经被限定了,所以可以使用更加精确的模型对items进行排序。精排要考虑的内容比较多,要除了排序还要考虑多样性,新鲜度,公平性。
候选集生成
两个常用的方法就是基于内容推荐和协同过滤。基于内容推荐就是用items的相似度,推荐用户喜欢什么。比如用户A喜欢看可爱的猫相关视频,那就可以给他推可爱的动物相关视频。协同过滤是同时考虑queries和items的相似度进行推荐,比如用户A和用户B相似,推荐系统可以推荐某个视频给用户A因为用户B喜欢看这个视频。
因为我们已经把queries和items映射到了向量空间,并且需要获得相似度,这就牵涉到了相似度计算公式。目前推荐系统常用的相似度计算公式如下:
Cosine
Dot product
Euclidean distance
需要注意的是,如果向量被归一化,这3种度量方式就等效了,因为:
使用不同的度量公式,最终推荐结果区别也是很大的,比如下图1个query向量和3个item向量
如果采用不同的度量方式,排序如下:
所以应该选择什么样的度量方式呢?从公式,我们可以知道,dot product对embedding的长度比较敏感,如果embedding长度越长,则该item更容易被推荐。如果一个items在训练级出现的频率较高,并行用dot来度量,那么热门的items的embedding相比较冷门items就会很大,所以dot学到了items的流行度,如果你不想让流行度主导推荐结果,可以对相似度做缩放,如下所示:
值得注意的是,一些冷门item由于在训练过程中出现较少,很容易受随机初始化的影响,如果你初始化一个长度很大的值,那这个冷门item更容易被错误推荐,所以我们需要用适当的初始化方法,并使用正则化。
两种常用推荐方法
基于内容的协同过滤,如下图所示,需要专家人工挖掘出大量特征,如果user和item有这个特征,就标为1,如下图所示。然后就可以dot计算相似度,我们可以知道,如果一个user和一个item在某一个特征都是1,那最终dot就会累计1,如下图女孩和第一个app 都有Education和Science R Us特征,所以它们点积为2,所以图中app推荐第一个app给她。
优点:模型不需要知道其他用户的任何数据,这样可扩展性比较高。
缺点: 模型只能理解用户特定的兴趣,且完全不利于冷启动。
协同过滤同时使用了users和items的相似度,基于用户之间相似兴趣做推荐,不像基于内容需要人工特征,users和items的embedding可以自主学习。用电影推荐系统举例,训练数据是一个反馈矩阵,每行表示一个user,每列表示一个电影。每个反馈有两种情况,一种是显式的,即user对item有打分的,一种种隐式的,需要系统推断该打分。为了简化,我们假设打分就两种,0表示不感兴趣,1表示感兴趣。基于这份数据,推荐系统会推荐两种情况的电影。1是用户以往看过的电影相似的电影;2是相似用户喜欢的电影。
假设user和item的embedding是1维的,对于user而言,向量接近1表示他喜欢成人电影,向量接近-1表示他喜欢儿童电影,对于电影而言,越接近1表示是成人电影,越接近-1是儿童电影,每个user和item的向量如下图:
然后我们按dot计算相似度,dot越接近1表示越感兴趣,然后我们看下这4个人真实看电影的情况。
我们看下上图中最后两个人,如果按照dot推荐前两部电影,推荐是准确的,但是对于上面两个人,就完全错了。所以1维向量有泛化能力,但是泛化能力很弱。
于是我们增加特征,变成2维向量,增加了一个特征表示是大片还是艺术片,如下图:
同样,我们用dot方式,计算user和item的分数表示用户对电影的偏好。如下图中的问号,就是0.1 * 1 1 * -1 = -0.9,表示该用户对该电影没兴趣。这里是直接指定user和item的embedding的,实际是自动学习到的,接下来就说到矩阵分解。
给定一个反馈矩阵Rm*n,m是user数量,n是item数量,要学到user向量Um*d,和item向量Vn*d,最后使得UV约等于Ai,j即可,如下图:
我们希望UV约等于Ai,j,所以这里需要制定目标还是,最简单的就是计算UV与Ai,j有值部分之间的mse了,如下式:
但是这种方式,只计算了有值部分的误差,我们知道Ai,j是非常稀疏的,因此用上述公式优化可能导致模型泛化能力较弱,所以又有了各种优化目标:
如果把未观测的都填成0,也是有问题的,这样UV就会解决0矩阵,导致模型泛化能力弱。所以给未观测的损失,给一个权重w0,调整这个w0对最终模型泛化能力影响比较大。
解决上述优化问题大致有两种,一种是SGD(随机梯度下降)。另一种是WALS,随机初始化embedding后,先固定U,求V,再固定V求U,如此反复,这种方式一定会收敛,因为每一步loss一定会降低。
SGD vs WALS
SGD:
1、非常灵活,可以用其他目标函数
2、可以并行
3、收敛慢
4、很难处理未观测的部分(需要负采样)
WALS:
1、只能用平方误差
2、可以并行
3、比SGD收敛快
4、处理未观测数据较快
矩阵分解相比较基于内容推荐,不需要领域知识,推荐更具探索性,只需要一个反馈矩阵即可训练推荐模型,操作简单。缺陷也比较明显,有明显的冷启动问题,同时也很难加入其它特征提高模型泛化性。当然,矩阵分解可以通过某种方式解决上述问题,比如冷启动,可以通过WALS更新最新的user和item向量,而不需要重train模型,再简单些,直接把相同类目item的embedding平均后作为新的item的embedding。
后续还有实战部分,放在下一篇介绍。
参考资料
https://developers.google.com/machine-learning/recommendation/overview