矩阵分解算法的求解 随机梯度下降SGD和交替最小二乘ALS

1 优化时为何选择偏导数的负方向?

首先假设目标函数为 m i n f ( x ) min f(x) minf(x)
那么我们的关注点就是如何找到当前状态 x k x^k xk后的下一个状态点 x k + 1 x^{k+1} xk+1
x k + 1 = x k + t k ⋅ p k x^{k+1}=x^k+t_k\cdot p_k xk+1=xk+tkpk
其中, t k t_k tk表示步长, p k p_k pk表示方向

1.1 使用泰勒展开进行解释

依据泰勒展开式
f ( x ) = f ( a ) + f ′ ( a ) 1 ! ( x − a ) + f ′ ′ ( a ) 2 ! ( x − a ) 2 + ⋯ + f ( n ) ( a ) n ! ( x − a ) n + R n ( x ) f(x)=f(a)+\frac{f^{'}(a)}{1!}(x-a)+\frac{f^{''}(a)}{2!}(x-a)^2+\cdots+\frac{f^{(n)}(a)}{n!}(x-a)^n+R_n(x) f(x)=f(a)+1!f(a)(xa)+2!f(a)(xa)2++n!f(n)(a)(xa)n+Rn(x)
因此
f ( x k + t k p k ) = f ( x k ) + t k ⋅ ∇ f ( x k ) T ⋅ p k + o ( ∥ t k ⋅ p k ∥ ) f(x^k+t_kp_k)=f(x^k)+t^k\cdot \nabla f(x^k)^T\cdot p^k+o(\Vert t^k \cdot p^k \Vert) f(xk+tkpk)=f(xk)+tkf(xk)Tpk+o(tkpk)
于是
f ( x k ) − f ( x k + t k p k ) = − t k ⋅ ∇ f ( x k ) T ⋅ p k + o ( ∥ t k ⋅ p k ∥ ) f(x^k)-f(x^k+t_kp_k)=-t^k\cdot \nabla f(x^k)^T\cdot p^k+o(\Vert t^k \cdot p^k \Vert) f(xk)f(xk+tkpk)=tkf(xk)Tpk+o(tkpk)
由于 o ( ∥ t k ⋅ p k ∥ ) o(\Vert t^k \cdot p^k \Vert) o(tkpk)是高阶无穷小量,可以不考虑
若要使 f ( x k ) − f ( x k + t k p k ) f(x^k)-f(x^k+t_kp_k) f(xk)f(xk+tkpk)最大,即下降的最多,又因为 t k t^k tk是不变的参数,因此就要使
p k = − ∇ f ( x k ) T p^k=-\nabla f(x^k)^T pk=f(xk)T
即方向向量等于(偏)导数的负方向

1.2 使用图像进行解释

在这里插入图片描述
在适合的 t k t_k tk的情况下,x(k)点右侧的x(k+1)点可以使得函数值变小,那么如何找到x(k+1)点呢?答案是找f(x)在x(k)点处下降最快的方向,显然这个方向与f(x)在x(k)处的斜率有关系,但从图中可以看出 ∇ f ( x ( k ) ) \nabla f(x(k)) f(x(k))的方向是左上方,但显然我们需要的是到右下方去找下一个状态点。因此,方向向量等于(偏)导数的负方向。

2 随机梯度下降算法(Stochastic Gradient Descent, SGD)

SGD的思路就是让训练集中的每一条数据依次进入模型,不断优化变量。
要注意的是,因为是一条条进入模型,因此数据的顺序会对实验结果产生影响,
对于考虑时间因素的数据集,应按照时间顺序依次进入模型

以最基本的矩阵分解模型 r u i = q i T p u r_{ui}=q_i^Tp_u rui=qiTpu为例
损失函数可以定义为 J ( p u , q i ) = 1 2 ( ∑ ( r u i − q i T p u ) 2 + λ ( ∥ q i ∥ 2 + ∥ p u ∥ 2 ) ) J(p_u,q_i) =\frac{1}{2}\left( \sum (r_{ui}-q_i^Tp_u)^2 + \lambda(\Vert q_i \Vert^2 + \Vert p_u \Vert^2 ) \right) J(pu,qi)=21((ruiqiTpu)2+λ(qi2+pu2))
其中 λ \lambda λ是正则化系数,这里把对 p u p_u pu q i q_i qi的正则化系数设置为相同值,也可以为不同值,不使用括号即可
下面求损失函数对 p u p_u pu的偏导
∂ J ( p u ) ∂ p u = ( r u i − q i T p u ) ( − q i T ) + λ p u \frac{\partial J(p_u)}{\partial p_u} = (r_{ui}-q_i^Tp_u)(-q_i^T) + \lambda p_u puJ(pu)=(ruiqiTpu)(qiT)+λpu
常令
e u i = r u i − q i T p u e_{ui} = r_{ui}-q_i^Tp_u eui=ruiqiTpu
因此
p u = p u − η ⋅ ∂ J ( p u ) ∂ p u = p u + η ( e u i ⋅ q i − λ ⋅ p u ) p_u = p_u - \eta \cdot \frac{\partial J(p_u)}{\partial p_u}= p_u+\eta(e_{ui}\cdot q_i - \lambda \cdot p_u) pu=puηpuJ(pu)=pu+η(euiqiλpu)
其中, η \eta η表示学习速率
同理
q i = q i − η ⋅ ∂ J ( q i ) ∂ q i = q i + η ( e u i ⋅ p u − λ ⋅ q i ) q_i = q_i - \eta \cdot \frac{\partial J(q_i)}{\partial q_i}= q_i+\eta(e_{ui}\cdot p_u - \lambda \cdot q_i) qi=qiηqiJ(qi)=qi+η(euipuλqi)

3 交替最小二乘算法(Alternating Least Squares, ALS)

因为p和q两个变量未知,因此损失函数不是凸函数,无法使用凸优化求解。
但是,如果固定p,那么损失函数是只关于q的二次函数,用解二次函数方法。
因此,可固定p,求q;再固定q,求p,这样迭代下去,此即为交替一词出处。

∂ J ( p u ) ∂ p u = ( r u i − q i T p u ) ( − q i T ) + λ p u = ( q i T q i + λ ) p u − r u i q i T \frac{\partial J(p_u)}{\partial p_u} = (r_{ui}-q_i^Tp_u)(-q_i^T) + \lambda p_u=(q_i^T q_i + \lambda)p_u - r_{ui}q_i^T puJ(pu)=(ruiqiTpu)(qiT)+λpu=(qiTqi+λ)puruiqiT
下面令 ∂ J ( p u ) ∂ p u = 0 \frac{\partial J(p_u)}{\partial p_u}=0 puJ(pu)=0
写成矩阵形式
( Q Q T + λ E ) P = R j Q T (QQ^T+\lambda E)P=R_jQ^T (QQT+λE)P=RjQT
P = ( Q Q T + λ E ) − 1 R j P=(QQ^T+\lambda E)^{-1}R_j P=(QQT+λE)1Rj
同理
Q = ( P P T + λ E ) − 1 R i Q=(PP^T+\lambda E)^{-1}R_i Q=(PPT+λE)1Ri

### 基于矩阵分解的协同过滤算法原理 在基于矩阵分解的协同过滤算法中,主要目标是对原始用户-项目评分矩阵 \( R \) 进行低秩近似。该过程涉及将大而稀疏的评分矩阵分解成两个较小维度的隐含特征矩阵:一个是代表用户的隐向量矩阵 \( U \),另一个是项目的隐向量矩阵 \( M \)[^1]。 #### 隐向量生成与优化 为了获得这些隐向量,首先需要人为设定潜在因子的数量 \( k \),即希望提取出来的隐藏特征数目。接着随机初始化用户物品各自的特征矩阵,并通过迭代更新的方式逐步逼近最优解,使得重构后的矩阵能够尽可能好地拟合已知数据中的评分记录[^2]。 #### 推荐机制 一旦获得了用户商品之间相对应的隐向量之后,便可以通过计算两者间内积或其他形式的距离度量(如余弦相似度),从而评估未被观测到的部分可能存在的偏好程度并据此做出个性化推荐[^4]。 ### Python 实现示例 下面给出一段简单的Python代码片段用于展示如何应用交替最小二乘法(Alternating Least Squares, ALS)来进行显式的矩阵分解: ```python import numpy as np from scipy.sparse import csr_matrix from implicit.als import AlternatingLeastSquares def matrix_factorization(R, P, Q, K, steps=5000, alpha=0.0002, beta=0.02): ''' :param R: 用户-项评分矩阵 (m*n) :param P: 初始化后的用户特征矩阵(m*k) :param Q: 初始化后的项特征矩阵(n*k) :param K: 特征数/纬度 :return: 训练好的P,Q矩阵 ''' for step in range(steps): for i in range(len(R)): for j in range(len(R[i])): if R[i][j] > 0: eij = R[i][j] - np.dot(P[i,:],Q[j,:]) for k in range(K): P[i][k] = P[i][k] + alpha * (2 * eij * Q[j][k] - beta * P[i][k]) Q[j][k] = Q[j][k] + alpha * (2 * eij * P[i][k] - beta * Q[j][k]) error = 0 for i in range(len(R)): for j in range(len(R[i])): if R[i][j] > 0: error += pow(R[i][j] - np.dot(P[i,:],Q[j,:]), 2) if error < 0.001: break return P, Q R = [ [5,3,0,1], [4,0,0,1], [1,1,0,5], [1,0,0,4], [0,1,5,4], ] R = np.array(R) N = len(R) M = len(R[0]) K = 2 P = np.random.rand(N,K) Q = np.random.rand(M,K) n_P, n_Q = matrix_factorization(R, P, Q, K) print(np.round_(np.dot(n_P,n_Q.T), decimals=2)) ``` 这段代码展示了基本的ALS训练流程以及最终得到的新评分预测表。注意这里采用的是梯度下降方式调整参数;实际工程实践中可能会选用更高效的求解器比如SGD或Adam等[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值