隐语义模型 LFM 推导

算法应用场景

在推荐系统中,要根据用户的历史行为(点击、收藏、评分等),挖掘用户感兴趣的物品进行推荐(一般用作推荐系统里面的召回算法,来召回候选集)。这个问题就可以转换成:给定 用户-物品 的评分矩阵(稀疏矩阵),根据评分矩阵里面已有的评分,预测评分矩阵里面空缺的评分,然后对于每个用户,为其对应的物品向量的评分进行排序找出 Top-N,即可完成推荐。

问题分析

这里的中心问题是:如何根据 用户-物品 评分矩阵里面的非空值,预测出该矩阵里面空缺位置应该填的值?我们可以进行矩阵分解,将 user-item 矩阵分解成 2 个矩阵相乘的形式,那么这两个矩阵怎么表示呢?假设要将 user-item 矩阵(mn)(m*n) 分解成 P(mk)P(m*k)Q(kn)Q(k*n)矩阵,根据矩阵相乘的性质,mn=(mk)(kn)m*n = (m*k) * (k*n),所以这里的问题转化为求出 矩阵 PPQQ,求出了 PPQQ 之后,PQP*Q 就可以将 user-item 矩阵空缺的地方填满,即得到未知的用户-物品对的预测评分

算法推导

推导损失函数

设 user-item 矩阵为 RR,用户特征矩阵为 PP,物品特征矩阵为 QQ
R^=PQ \hat{R} = P*Q
要计算的损失就是 user-item 矩阵里面的预测评分已知评分的偏离程度,故损失函数用平方损失函数(u,i)(u,i) 是已知的 user-item 对
loss=(u,i)R(RuiRui^)2 loss = \sum_{(u,i)\in{R}}(R_{ui} - \hat{R_{ui}})^2
加入正则项
loss=(u,i)R(RuiPuTQi)2+λuPu2+λiQi2 loss = \sum_{(u,i)\in{R}}(R_{ui} - P^T_u*Q_i)^2 + \lambda\sum_u||P_u||^2 + \lambda \sum_i||Q_i||^2
这里 PuP_u(1k)(1*k)维,QiQ_i(1k)(1*k)维,代表 用户u物品i 对应的 kk 个隐因子组成的向量,由于隐因子的数量越多,模型越复杂,为减少过拟合,加入 L2 正则项


求解损失函数

梯度下降法

到这里其实就可以用梯度下降法来求解损失函数取得最小值时对应的参数矩阵了,当然不是一下子得到整个矩阵,是逐行求解在拼接即可, 故可以化简损失函数,以求 lossPu\frac{\partial{loss}}{\partial{P_u}} 为例,此时 QiQ_i 可以看成常量
loss=(u,i)R(RuiPuTQi)2+λuPu2+λiQi2=u(i(RuiPuTQi)2+λPu2) \begin{aligned} loss &= \sum_{(u,i)\in{R}}(R_{ui} - P^T_u*Q_i)^2 + \lambda\sum_u||P_u||^2 + \lambda \sum_i||Q_i||^2\\ &=\sum_u \Big(\sum_i(R_{ui} - P^T_u*Q_i)^2 +\lambda||P_u||^2 \Big) \end{aligned}
此时就相当于,对于每个物品,求出对应的用户评分向量了,所以遍历每一个物品,得到的用户评分向量拼接起来,就是 QQ,求 PP 同理。


L(Pu)=i(RuiPuTQi)2+λPu2L(Qi)=u(RuiPuTQi)2+λPu2 L(P_u) = \sum_i(R_{ui} - P^T_u*Q_i)^2 +\lambda||P_u||^2\\ L(Q_i) = \sum_u(R_{ui} - P^T_u*Q_i)^2 +\lambda||P_u||^2

计算梯度
LPu=2i(RuiPuTQi)(Qi)+2λPuLQi=2u(RuiPuTQi)(Pu)+2λQi \frac{\partial{L}}{\partial{P_u}} = 2\sum_i(R_{ui} - P^T_{u}*Q_i)*(-Q_i) + 2\lambda P_u \\ \frac{\partial{L}}{\partial{Q_i}} = 2\sum_u(R_{ui} - P^T_{u}*Q_i)*(-P_u) + 2\lambda Q_i
每次迭代
Pu=PuηlossPuQi=QiηlossQi P_u = P_u - \eta\frac{\partial{loss}}{\partial{P_u}}\\ Q_i = Q_i - \eta\frac{\partial{loss}}{\partial{Q_i}}
直到 loss 达到阈值,或者达到最大迭代次数,此时的 PuP_uQiQ_i

交替最小二乘法

先回顾一下线性回归模型里面求解损失函数的最小二乘法,本质上就是令损失函数的偏导等于0,求出对应的参数


回顾最小二乘法求解线性回归
令要求解的回归方程表达式为:y=wTx+by = w^Tx + b
损失函数:J(w,b)=i=1m(yiwTxib)2J(w,b) = \sum_{i=1}^m(y_i - w^Tx_i - b)^2,m为样本个数
这里以 J(w,b)b=0\frac{\partial{J(w, b)}}{\partial{b}} = 0 求解 bb 为例

J(w,b)b=i=1m2(yiwTxib)=0\frac{\partial{J(w, b)}}{\partial{b}} = \sum^m_{i=1}2(y_i-w^Tx_i - b) =0

i=1myiwTi=1mxii=1mb=0\sum^m_{i=1}y_i-w^T\sum^m_{i=1}x_i-\sum^m_{i=1}b = 0

mb=i=1myiwTi=1mximb = \sum^m_{i=1}y_i-w^T\sum^m_{i=1}x_i

解得:b=ywTxˉb = \overline{y} - w^T\bar{x}


那么交替最小二乘法呢?

对于损失函数
loss=(u,i)R(RuiPuTQi)2+λuPu2+λiQi2 loss = \sum_{(u,i)\in{R}}(R_{ui} - P^T_u*Q_i)^2 + \lambda\sum_u||P_u||^2 + \lambda \sum_i||Q_i||^2
PuP_uQiQ_i 是通过矩阵乘法耦合在一起的,我们可以先以 PuP_u 为常量,求解 QiQ_i,在以QiQ_i 为常量,求解 PuP_u,如此反复,知道达到迭代次数上限,或 loss 小于阈值。

这里以固定 QiQ_iPuP_u 为例,进行推导
loss=(u,i)R(RuiPuTQi)2+λuPu2+λiQi2=u(i(RuiPuTQi)2+λPu2) \begin{aligned} loss &= \sum_{(u,i)\in{R}}(R_{ui} - P^T_u*Q_i)^2 + \lambda\sum_u||P_u||^2 + \lambda \sum_i||Q_i||^2\\ &=\sum_u \Big(\sum_i(R_{ui} - P^T_u*Q_i)^2 +\lambda||P_u||^2 \Big) \end{aligned}
L(Pu)=i(RuiPuTQi)2+λPu2L(P_u) = \sum_i(R_{ui} - P^T_u*Q_i)^2 +\lambda||P_u||^2

求偏导,令其=0:

LPu=2i(RuiPuTQi)(Qi)+2λPu=0\frac{\partial{L}}{\partial{P_u}} = 2\sum_i(R_{ui} - P^T_{u}*Q_i)*(-Q_i) + 2\lambda P_u=0

iPuTQiQiiRuiQi+λPu=0\sum_iP^T_uQ_iQ_i - \sum_iR_{ui}Q_i + \lambda P_u =0

PuTQi=QiTPuP_u^TQ_i = Q_i^TP_u(ATB=(BTA)T)(A^TB = (B^TA)^T)

iPuTQiQiiRuiQi+λPu=iQiTPuQiiRuiQi+λPu=0\sum_iP^T_uQ_iQ_i - \sum_iR_{ui}Q_i + \lambda P_u\\=\sum_iQ_i^TP_uQ_i - \sum_iR_{ui}Q_i + \lambda P_u=0

(iQiTQi+λE)Pu=iRuiQi(\sum_iQ_i^TQ_i + \lambda E)P_u=\sum_iR_{ui}Q_i

(QTQ+λE)Pu=RuQi(Q^TQ+ \lambda E)P_u=R_{u}Q_i
最终得到:
Pu=(QiQiT+λE)1RuQP_u = (Q_iQ_i^T+\lambda E)^{-1}R_uQ
同理得:
Qi=(PPT+λE)1PRiQ_i = (PP^T+\lambda E)^{-1}PR_i


开源库

implicit
pyspark.mllib.recommendation.ALS



这篇真的码了很久,累死了。。

笔记:
隐语义模型 LFM 推导