推荐系统基础(三):矩阵分解和FM

1. 隐语义模型与矩阵分解

协同过滤算法的特点就是完全没有利用到物品本身或者是用户自身的属性, 仅仅利用了用户与物品的交互信息就可以实现推荐,是一个可解释性很强, 非常直观的模型, 但是也存在一些问题, 第一个就是处理稀疏矩阵的能力比较弱, 所以为了使得协同过滤更好处理稀疏矩阵问题, 增强泛化能力, 从协同过滤中衍生出矩阵分解模型(Matrix Factorization,MF)或者叫隐语义模型, 两者差不多说的一个意思, 就是在协同过滤共现矩阵的基础上, 使用更稠密的隐向量表示用户和物品, 挖掘用户和物品的隐含兴趣和隐含特征, 在一定程度上弥补协同过滤模型处理稀疏矩阵能力不足的问题。

2. 隐语义模型

隐语义模型最早在文本领域被提出,用于找到文本的隐含语义。在2006年, 被用于推荐中, 它的核心思想是通过隐含特征(latent factor)联系用户兴趣和物品(item), 基于用户的行为找出潜在的主题和分类, 然后对item进行自动聚类,划分到不同类别/主题(用户的兴趣)。

这么说可能有点抽象,所以下面拿项亮老师《推荐系统实践》里面的那个例子看一下:

如果我们知道了用户A和用户B两个用户在豆瓣的读书列表, 从他们的阅读列表可以看出,用户A的兴趣涉及侦探小说、科普图书以及一些计算机技术书, 而用户B的兴趣比较集中在数学和机器学习方面。 那么如何给A和B推荐图书呢?

先说说协同过滤算法, 这样好对比不同:

对于UserCF,首先需要找到和他们看了同样书的其他用户(兴趣相似的用户),然后给他们推荐那些用户喜欢的其他书。
对于ItemCF,需要给他们推荐和他们已经看的书相似的书,比如作者B看了很多关于数据挖掘的书,可以给他推荐机器学习或者模式识别方面的书。

而如果是隐语义模型的话, 它会先通过一些角度把用户兴趣和这些书归一下类, 当来了用户之后, 首先得到他的兴趣分类, 然后从这个分类中挑选他可能喜欢的书籍。

这里就看到了隐语义模型和协同过滤的不同, 这里说的角度其实就是这个隐含特征, 比如书籍的话它的内容, 作者, 年份, 主题等都可以算隐含特征,如果这个例子还不是很清晰的话, 那么下面再举个更为具体的例子, 看看是如何通过隐含特征来划分开用户兴趣和物品的。但是在这之前, 相信通过上面这个例子, 我们已经隐隐约约感受到了协同过滤和隐语义模型的区别了, 下面放上王喆老师《深度学习推荐系统》的一个原理图作为对比, 区别简直一目了然:

在这里插入图片描述

矩阵分解算法原理

在矩阵分解的算法框架下, 我们就可以通过分解协同过滤的共现矩阵来得到用户和物品的隐向量, 就是上面的用户矩阵Q和物品矩阵P, 这也是“矩阵分解”名字的由来。
在这里插入图片描述

矩阵分解算法将 m×n 维的共享矩阵 R 分解成 m×k 维的用户矩阵 U 和 k×n 维的物品矩阵 V 相乘的形式。 其中 m 是用户数量, n 是物品数量, k 是隐向量维度, 也就是隐含特征个数, 只不过这里的隐含特征变得不可解释了, 即我们不知道具体含义了, 要模型自己去学。 k 的大小决定了隐向量表达能力的强弱, k 越大, 表达信息就越强, 理解起来就是把用户的兴趣和物品的分类划分的越具体。

那么如果有了用户矩阵和物品矩阵的话, 我们就知道了如果想计算用户 u 对物品 i 的评分, 只需要

Preference(u,i)=rui=pTuqi=F∑f=1pu,kqk,i

这里的 pu 就是用户 u 的隐向量, 就类似与上面的张三向量, 注意这是列向量, qi 是物品 i 的隐向量, 就类似于上面的音乐A向量, 这个也是列向量, 所以才用了 pTuqi 得到了一个数, 也就是用户的最终评分, 计算过程其实和上面例子中一样。 这里的 pu,k 和 qi,k 是模型的参数, 也正是我们想办法要计算的, pu,k 度量的是用户 u 的兴趣和第 k 个隐类的关系, 而 qi,k 度量了第 k 个隐类和物品 i 之间的关系。

  1. 矩阵分解算法的求解
    谈到矩阵分解, 最常用的方法是特征值分解(EVD)或者奇异值分解(SVD), 关于这两个的具体原理可以参考下面的链接奇异值分解(SVD)的原理详解及推导 2,但是这两种方式在这里不适用。

首先是EVD, 它要求分解的矩阵是方阵, 显然用户-物品矩阵不满足这个要求, 而传统的SVD分解, 会要求原始矩阵是稠密的, 而我们这里的这种矩阵一般情况下是非常稀疏的, 如果想用奇异值分解, 就必须对缺失的元素进行填充, 而一旦补全, 空间复杂度就会非常高, 且补的不一定对。 然后就是SVD分解计算复杂度非常高, 而我们的用户-物品矩阵非常大, 所以基本上无法使用。

  1. Basic SVD
    2006年的Netflix Prize之后, Simon Funk公布了一个矩阵分解算法叫做Funk-SVD, 后来被Netflix Prize的冠军Koren称为Latent Factor Model(LFM)。 Funk-SVD的思想很简单: 把求解上面两个矩阵的参数问题转换成一个最优化问题, 可以通过训练集里面的观察值利用最小化来学习用户矩阵和物品矩阵。

我们上面已经知道了, 如果有了用户矩阵和物品矩阵的话, 我们就知道了如果想计算用户 u 对物品 i i i的评分, 只需要

Preference(u,i)=rui=pTuqi=F∑f=1pu,kqk,i

而现在, 我们有真实的 ru,i , 但是没有 pTuqi , 那么我们可以初始化一个啊, 随机初始化一个用户矩阵 U 和一个物品矩阵 V , 然后不就有 pTuqi 了? 当然你说, 随机初始化的肯定不准啊, 但是, 有了 pTuqi 之后, 我们就可以计算一个猜测的 ^rui , 即

^rui=pTuqi

这时候, 肯定是不准, 那么这个猜测的和真实值之间就会有一个误差:

eui=rui−^rui

有了误差, 我们就可以计算出总的误差平方和:

SSE=∑u,ie2ui=∑u,i(rui−K∑k=1pu,kqk,i)2

有了损失, 我们就可以想办法进行训练, 把SSE降到最小, 那么我们的两个矩阵参数就可以算出来。所以就把这个问题转成了最优化的的问题, 而我们的目标函数就是:

minq∗,p∗∑(u,i)∈K(rui−pTuqi)2

这里的 K 表示所有用户评分样本的集合。

有了目标函数, 那么我们就可以使用梯度下降算法来降低损失。 那么我们需要对目标函数求偏导, 得到梯度。 我们的目标函数如果是上面的SSE, 我们下面来推导一下最后的导数:

SSE=∑u,ie2ui=∑u,i(rui−K∑k=1pu,kqk,i)2

首先我们求SSE在 pu,k (也就是Q矩阵的第 u 行 k 列)的梯度:

∂∂pu,kSSE=∂∂pu,k(e2ui)=2eui∂∂pu,keui=2eui∂∂pu,k(rui−K∑k=1pu,kqk,i)=−2euiqk,i

然后求SSE在 qk,i 处(也就是V矩阵的第 k 行 i 列)的梯度:

∂∂qk,iSSE=∂∂pk,i(e2ui)=2eui∂∂pk,ieui=2eui∂∂pk,i(rui−K∑k=1pu,kqk,i)=−2euipu,k

为了让公式更为简单, 把前面的2给他越掉, 即可以令SSE等于:

SSE=12∑u,ie2ui=12∑u,i(rui−K∑k=1pukqki)2

这时候, 梯度就没有前面的系数了, 有了梯度, 接下来我们就可以用梯度下降算法更新梯度了:

pu,k=pu,k−η(−euiqk,i)=pu,k+ηeuiqk,iqk,i=qk,i−η(−euipu,k)=qk,i+ηeuipu,k

这里的 η 是学习率, 控制步长用的, 但上面这个有个问题就是当参数很多的时候, 就是两个矩阵很大的时候, 往往容易陷入过拟合的困境, 这时候, 就需要在目标函数上面加上正则化的损失, 就变成了RSVD, 关于RSVD的详细内容, 可以参考下面给出的链接, 由于篇幅原因, 这里不再过多的赘述。

但在实际中, 单纯的 ^rui=pTuqi 也是不够的, 还要考虑其他的一些因素, 比如一个评分系统, 有些固有的属性和用户物品无关, 而用户也有些属性和物品无关, 物品也有些属性和用户无关。 因此, Netfix Prize中提出了另一种LFM, 在原来的基础上加了偏置项, 来消除用户和物品打分的偏差, 即预测公式如下:

^rui=μ+bu+bi+pTu⋅qi

这个预测公式加入了3项偏置 μ,bu,bi , 作用如下:

μ : 训练集中所有记录的评分的全局平均数。 在不同网站中, 因为网站定位和销售物品不同, 网站的整体评分分布也会显示差异。 比如有的网站中用户就喜欢打高分, 有的网站中用户就喜欢打低分。 而全局平均数可以表示网站本身对用户评分的影响。
bu : 用户偏差系数, 可以使用用户 u 给出的所有评分的均值, 也可以当做训练参数。 这一项表示了用户的评分习惯中和物品没有关系的那种因素。 比如有些用户比较苛刻, 对什么东西要求很高, 那么他评分就会偏低, 而有些用户比较宽容, 对什么东西都觉得不错, 那么评分就偏高
bi : 物品偏差系数, 可以使用物品 i 收到的所有评分的均值, 也可以当做训练参数。 这一项表示了物品接受的评分中和用户没有关系的因素。 比如有些物品本身质量就很高, 因此获得的评分相对比较高, 有的物品本身质量很差, 因此获得的评分相对较低。
加了用户和物品的打分偏差之后, 矩阵分解得到的隐向量更能反映不同用户对不同物品的“真实”态度差异, 也就更容易捕捉评价数据中有价值的信息, 从而避免推荐结果有偏。 注意此时的 S S E SSE SSE会发生变化:

SSE=12∑u,ie2ui+12λ∑u|pu|2+12λ∑i|qi|2+12λ∑ub2u+12λ∑ub2i=12∑u,i(rui−μ−bu−bi−∑Kk=1pukqki)2+12λ∑u|pu|2+12λ∑i|qi|2+12λ∑ub2u+12λ∑ub2i

此时如果把 bu 和 bi 当做训练参数的话, 那么它俩的梯度是:

∂∂buSSE=−eui+λbu∂∂biSSE=−eui+λbi

更新公式为:

bu=bu+η(eui−λbu)bi=bi+η(eui−λbi)

而对于 pu,k 和 pk,i , 导数没有变化, 更新公式也没有变化。

  1. 编程实现
    我们这里用代码实现一下上面的算法来预测上一篇文章里面的那个预测Alice对物品5的评分, 看看矩阵分解到底是怎么进行预测或者是推荐的。 我把之前的例子拿过来:

image-20201017195217637

任务就是根据这个评分矩阵, 猜测Alice对物品5的打分。

在实现SVD之前, 先来回忆一下ItemCF和UserCF对于这个问题的做法, 首先ItemCF的做法, 根据已有的用户打分计算物品之间的相似度, 得到物品的相似度矩阵, 根据这个相似度矩阵, 选择出前K个与物品5最相似的物品, 然后基于Alice对这K个物品的得分, 猜测Alice对物品5的得分, 有一个加权的计算公式。 UserCF的做法是根据用户对其他物品的打分, 计算用户之间的相似度, 选择出与Alice最相近的K个用户, 然后基于那K个用户对物品5的打分计算出Alice对物品5的打分。 但是, 这两种方式有个问题, 就是如果矩阵非常稀疏的话, 当然这个例子是个特例, 一般矩阵都是非常稀疏的, 那么预测效果就不好, 因为两个相似用户对同一物品打分的概率以及Alice同时对两个相似物品打分的概率可能都比较小。 另外, 这两种方法显然没有考虑到全局的物品或者用户, 只是基于了最相似的例子, 很可能有偏。

那么SVD在解决这个问题上是这么做的:

首先, 它会先初始化用户矩阵P和物品矩阵Q, P的维度是[users_num, F], Q的维度是[item_nums, F], 这个F是隐向量的维度。 也就是把通过隐向量的方式把用户的兴趣和F的特点关联了起来。 初始化这两个矩阵的方式很多, 但根据经验, 随机数需要和 1/√F 成正比。 下面代码中会发现。
有了两个矩阵之后, 我就可以根据用户已经打分的数据去更新参数, 这就是训练模型的过程, 方法很简单, 就是遍历用户, 对于每个用户, 遍历它打分的物品, 这样就拿到了该用户和物品的隐向量, 然后两者相乘加上偏置就是预测的评分, 这时候与真实评分有个差距, 根据上面的梯度下降就可以进行参数的更新
这样训练完之后, 我们就可以得到用户Alice和物品5的隐向量, 根据这个就可以预测Alice对物品5的打分。 下面的代码的逻辑就是上面这两步, 这里使用带有偏置项和正则项的那个SVD算法:

  1. FM公式的理解
    从公式来看,模型前半部分就是普通的LR线性组合,后半部分的交叉项:特征组合。首先,单从模型表达能力上来看,FM是要强于LR的,至少它不会比LR弱,当交叉项参数 wij 全为0的时候,整个模型就退化为普通的LR模型。对于有 n 个特征的模型,特征组合的参数数量共有 1+2+3+⋯+n−1=n(n−1)2 个,并且任意两个参数之间是独立的。所以说特征数量比较多的时候,特征组合之后,维度自然而然就高了。

定理:任意一个实对称矩阵(正定矩阵) W 都存在一个矩阵 V ,使得 W=V.VT 成立。

类似地,所有二次项参数 ωij 可以组成一个对称阵 W (为了方便说明FM的由来,对角元素可以设置为正实数),那么这个矩阵就可以分解为 W=VTV , V 的第 j 列( vj )便是第 j 维特征( xj )的隐向量。

^y(X)=ω0+n∑i=1ωixi+n−1∑i=1n∑j=i+1<vi,vj>xixj

需要估计的参数有 ω0∈R , ωi∈R , V∈R , <⋅,⋅> 是长度为 k 的两个向量的点乘,公式如下:

<vi,vj>=k∑f=1vi,f⋅vj,f

上面的公式中:

ω0 为全局偏置;
ωi 是模型第 i 个变量的权重;
ωij=<vi,vj> 特征 i 和 j 的交叉权重;
vi 是第 i 维特征的隐向量;
<⋅,⋅> 代表向量点积;
k(k<<n) 为隐向量的长度,包含 k 个描述特征的因子。
FM模型中二次项的参数数量减少为 kn 个,远少于多项式模型的参数数量。另外,参数因子化使得
xhxi 的参数和 xixj 的参数不再是相互独立的,因此我们可以在样本稀疏的情况下相对合理地估计FM的二次项参数。具体来说, xhxi 和 xixj 的系数分别为 <vh,vi> 和 <vi,vj> ,它们之间有共同项 vi 。也就是说,所有包含“ xi 的非零组合特征”(存在某个 j≠i ,使得 xixj≠0 )的样本都可以用来学习隐向量 vi ,这很大程度上避免了数据稀疏性造成的影响。而在多项式模型中, whi 和 wij 是相互独立的。

显而易见,FM的公式是一个通用的拟合方程,可以采用不同的损失函数用于解决regression、classification等问题,比如可以采用MSE(Mean Square Error)loss function来求解回归问题,也可以采用Hinge/Cross-Entropy loss来求解分类问题。当然,在进行二元分类时,FM的输出需要使用sigmoid函数进行变换,该原理与LR是一样的。直观上看,FM的复杂度是 O(kn2) 。但是FM的二次项可以化简,其复杂度可以优化到 O(kn) 。由此可见,FM可以在线性时间对新样本作出预测。

证明:

n−1∑i=1n∑j=i+1<vi,vj>xixj=12n∑i=1n∑j=1<vi,vj>xixj−12n∑i=1<vi,vi>xixi=12⎛⎝n∑i=1n∑j=1k∑f=1vi,fvj,fxixj−n∑i=1k∑f=1vi,fvi,fxixi⎞⎠=12k∑f=1[(n∑i=1vi,fxi)⋅(n∑j=1vj,fxj)−n∑i=1v2i,fx2i]=12k∑f=1⎡⎣(n∑i=1vi,fxi)2−n∑i=1v2i,fx2i⎤⎦

解释:

vi,f 是一个具体的值;
第1个等号:对称矩阵 W 对角线上半部分;
第2个等号:把向量内积 vi , vj 展开成累加和的形式;
第3个等号:提出公共部分;
第4个等号: i 和 j 相当于是一样的,表示成平方过程。

猜你喜欢

转载自blog.csdn.net/qq_45019698/article/details/109280094