Gorse 使用矩阵分解作为协同过滤算法来提供个性化推荐。矩阵分解是推荐系统中广泛使用的一种技术,它通过在共享的潜在空间中表示用户和物品来对用户-物品交互进行建模。
在矩阵分解中,物品和用户由向量表示。用户 u u u 喜欢物品 i i i 的概率由两个向量的点积预测。
y ^ u i = p u T q i \hat y_{ui}=\mathbf{p}_u^T \mathbf{q}_i y ^ u i = p u T q i
其中 p u \mathbf{p}_u p u 是用户 u u u 的嵌入向量,q i \mathbf{q}_i q i 是物品 i i i 的嵌入向量。矩阵分解的模型很简单,但有不止一种训练算法。
BPR (Bayesian Personalized Ranking) 是一种成对训练算法。BPR 的训练数据由一组三元组组成:
D s = { ( u , i , j ) ∣ i ∈ I u ∧ j ∈ I ∖ I u } D_s=\{(u,i,j)|i\in I_u\wedge j\in I \setminus I_u\} D s = {( u , i , j ) ∣ i ∈ I u ∧ j ∈ I ∖ I u }
( u , i , j ) ∈ D S (u, i, j) \in D_S ( u , i , j ) ∈ D S 的语义是假设用户 u u u 相比 j j j 更喜欢 i i i 。负例被隐式地考虑。
为所有物品找到正确的个性化排名的贝叶斯公式是最大化以下后验概率,其中 Θ \Theta Θ 表示矩阵分解模型的参数向量
p ( Θ ∣ > u ) ∝ p ( > u ∣ Θ ) p ( Θ ) p(\Theta|>_u) \propto p(>_u|\Theta)p(\Theta) p ( Θ∣ > u ) ∝ p ( > u ∣Θ ) p ( Θ )
其中 > u >_u > u 是用户 u u u 期望但潜在的偏好。所有用户被假定为彼此独立行动。BPR 还假设特定用户对每对物品 ( i , j ) (i, j) ( i , j ) 的排序独立于其他每一对的排序。因此,上述特定于用户的似然函数 p ( > u ∣ Θ ) p(>_u|\Theta) p ( > u ∣Θ ) 可以首先重写为单个密度的乘积,其次可以针对所有用户 u ∈ U u \in U u ∈ U 进行组合。
∏ u ∈ U p ( > u ∣ Θ ) = ∏ ( u , i , j ) ∈ D s p ( i > u j ∣ Θ ) \prod_{u\in U}p(>_u|\Theta)=\prod_{(u,i,j)\in D_s}p(i>_u j|\Theta) u ∈ U ∏ p ( > u ∣Θ ) = ( u , i , j ) ∈ D s ∏ p ( i > u j ∣Θ )
其中 p ( i > u j ∣ Θ ) = σ ( y ^ u i j ) p(i>_u j|\Theta)=\sigma(\hat y_{uij}) p ( i > u j ∣Θ ) = σ ( y ^ u ij ) 且 y ^ u i j = y ^ u i − y ^ u j \hat y_{uij}=\hat y_{ui} - \hat y_{uj} y ^ u ij = y ^ u i − y ^ u j 。
对于参数向量,BPR 引入了一个通用的先验密度 p ( Θ ) p(\Theta) p ( Θ ) ,它是一个均值为零且方差-协方差矩阵为 Σ Θ \Sigma_\Theta Σ Θ 的正态分布。
p ( Θ ) ∼ N ( 0 , Σ Θ ) p(\Theta) \sim N(0,\Sigma_\Theta) p ( Θ ) ∼ N ( 0 , Σ Θ )
其中 Σ Θ = λ Θ I Σ_Θ = λ_ΘI Σ Θ = λ Θ I 。那么个性化排名的优化标准是
\begin{split} \text{BPR-OPT}&=\ln p(\Theta|>_u)\\ &=\ln p(>_u|\Theta)p(\Theta)\\ &=\ln\prod_{(u,i,j)\in D_s}\sigma(\hat y_{uij})p(\Theta)\\ &=\sum_{(u,i,j)\in D_s}\ln \sigma(\hat y_{uij})+\ln p(\Theta)\\ &=\sum_{(u,i,j)\in D_s}\ln \sigma(\hat y_{uij})-\lambda_\Theta\|\Theta\|^2 \end{split
BPR-Opt 关于模型参数的梯度是:
∂ BPR-OPT ∂ Θ = ∑ ( u , i , j ) ∈ D s ∂ ∂ Θ ln σ ( x ^ u i j ) − λ Θ ∂ ∂ Θ ∥ Θ ∥ 2 ∝ ∑ ( u , i , j ) ∈ D s − e − y ^ u i j 1 + e − y ^ u i j ⋅ ∂ ∂ Θ y ^ u i j − λ Θ Θ \begin{split} \frac{\partial\text{BPR-OPT}}{\partial\Theta}&=\sum_{(u,i,j)\in D_s}\frac{\partial}{\partial\Theta}\ln\sigma(\hat x_{uij})-\lambda_\Theta\frac{\partial}{\partial\Theta}\|\Theta\|^2\\ &\propto\sum_{(u,i,j)\in D_s}\frac{-e^{-\hat y_{uij}}}{1+e^{-\hat y_{uij}}}\cdot \frac{\partial}{\partial\Theta}\hat y_{uij}-\lambda_\Theta\Theta\\ \end{split} ∂ Θ ∂ BPR-OPT = ( u , i , j ) ∈ D s ∑ ∂ Θ ∂ ln σ ( x ^ u ij ) − λ Θ ∂ Θ ∂ ∥Θ ∥ 2 ∝ ( u , i , j ) ∈ D s ∑ 1 + e − y ^ u ij − e − y ^ u ij ⋅ ∂ Θ ∂ y ^ u ij − λ Θ Θ
基于训练三元组的 bootstrap 采样的随机梯度下降算法如下:
initialize Θ \Theta Θ repeat draw ( u , i , j ) (u,i,j) ( u , i , j ) from D s D_s D s Θ ← Θ + α ( e − y ^ u i j 1 + e − y ^ u i j ⋅ ∂ ∂ Θ y ^ u i j + λ Θ Θ ) \Theta\leftarrow\Theta+\alpha\left(\frac{e^{-\hat y_{uij}}}{1+e^{-\hat y_{uij}}}\cdot \frac{\partial}{\partial\Theta}\hat y_{uij}+\lambda_\Theta\Theta\right) Θ ← Θ + α ( 1 + e − y ^ u ij e − y ^ u ij ⋅ ∂ Θ ∂ y ^ u ij + λ Θ Θ ) util convergence return Θ \Theta Θ 其中 α \alpha α 是学习率。嵌入向量的导数是
∂ ∂ θ y ^ u i j = { ( q i f − q j f ) if θ = p u f p u f if θ = q i f − p u f if θ = q j f 0 else \frac{\partial}{\partial\theta}\hat y_{uij}=\begin{cases} (q_{if}-q_{jf})&\text{if }\theta=p_{uf}\\ p_uf&\text{if }\theta=q_if\\ -p_uf&\text{if }\theta=q_{jf}\\ 0&\text{else} \end{cases} ∂ θ ∂ y ^ u ij = ⎩ ⎨ ⎧ ( q i f − q j f ) p u f − p u f 0 if θ = p u f if θ = q i f if θ = q j f else
eALS 是一种逐点训练算法。对于用户 u u u 和物品 i i i 的一对,训练的真实值是
y u i = { 1 i ∈ I u 0 i ∉ I u y_{ui}=\begin{cases} 1&i\in I_u\\ 0&i\notin I_u \end{cases} y u i = { 1 0 i ∈ I u i ∈ / I u
嵌入向量通过最小化以下成本函数[^8]来优化:
C = ∑ u ∈ U ∑ i ∈ I w u i ( y u i − y ^ u i f ) 2 + λ ( ∑ u ∈ U ∥ p ∥ 2 + ∑ i ∈ I ∥ q i ∥ 2 ) \mathcal{C} = \sum_{u\in U}\sum_{i \in I}w_{ui}(y_{ui}-\hat{y}_{ui}^f)^2 + \lambda\left(\sum_{u \in U}\|\mathcal{p}\|^2+\sum_{i \in I}\|\mathbf{q}_i\|^2\right) C = u ∈ U ∑ i ∈ I ∑ w u i ( y u i − y ^ u i f ) 2 + λ ( u ∈ U ∑ ∥ p ∥ 2 + i ∈ I ∑ ∥ q i ∥ 2 )
其中 y ^ u i f = y ^ u i − p u f q i f \hat{y}_{ui}^f=\hat{y}_{ui}-p_{uf}q_{if} y ^ u i f = y ^ u i − p u f q i f 且 w u i w_{ui} w u i 是反馈的权重
w u i = { 1 i ∈ I u α i ∉ I u w_{ui}=\begin{cases} 1&i\in I_u\\ \alpha&i\notin I_u \end{cases} w u i = { 1 α i ∈ I u i ∈ / I u
α \alpha α (α < 1 \alpha < 1 α < 1 ) 是负反馈的权重。目标函数关于 p u f p_{uf} p u f 的导数是
∂ J ∂ p u f = − 2 ∑ i ∈ I ( y u i − y ^ u i f ) w u i q u f + 2 p u f ∑ i ∈ I w u i q i f 2 + 2 λ p u f \frac{\partial J}{\partial p_{uf}}=-2\sum_{i\in I}(y_{ui}-\hat y_{ui}^f)w_{ui}q_{uf} + 2p_{uf}\sum_{i\in I}w_{ui}q_{if}^2 + 2\lambda p_{uf} ∂ p u f ∂ J = − 2 i ∈ I ∑ ( y u i − y ^ u i f ) w u i q u f + 2 p u f i ∈ I ∑ w u i q i f 2 + 2 λ p u f
通过将此导数设为 0,获得 p u f p_{uf} p u f 的解 (Eq 1):
\begin{split} p_{uf} &= \frac{\sum_{i \in I}(y_{ui}-\hat y_{ui}^f)w_{ui}q_{if}}{\sum_{i \in I}w_{ui}q^2_{if}+\lambda}\\ &=\frac{\sum_{i\in I_u}(y_{ui}-\hat{y}_{ui}^f)q_{if}-\sum_{i\in I_u}\hat{y}_{ui}^f\alpha q_{if}}{\sum_{i\in I_u}q^2_{if}+\sum_{i \in I_u}\alpha q_{if}^2+\lambda}\\ &=\frac{\sum_{i\in I_u}[y_{ui}-(1-\alpha)\hat{y}_{ui}^f]q_{if}-\sum_{k\neq f}p_{uk}s^q_{kf}}{\sum_{i\in I_u}(1-\alpha)q^2_{if}+\alpha s^q_{ff}+\lambda} \end{split
其中 s k f q s^q_{kf} s k f q 表示 S q \mathbf{S}^q S q 缓存的第 ( k , f ) (k, f) ( k , f ) 个元素,定义为 S q = Q T Q \mathbf{S}^q = \mathbf{Q}^T\mathbf{Q} S q = Q T Q 。类似地,获得物品嵌入向量的求解器 (Eq 2):
q i f = ∑ u ∈ U i ( y u i − ( 1 − α ) y ^ u i ) p u f − α ∑ k ≠ f q i k s k f p ∑ u ∈ U i ( 1 − α ) p u f 2 + α s f f p + λ q_{if} = \frac{\sum_{u \in U_i}(y_{ui}-(1-\alpha)\hat y_{ui})p_{uf}-\alpha\sum_{k\neq f}q_{ik}s^p_{kf}}{\sum_{u \in U_i}(1-\alpha)p^2_{uf} + \alpha s^p_{ff} + \lambda} q i f = ∑ u ∈ U i ( 1 − α ) p u f 2 + α s ff p + λ ∑ u ∈ U i ( y u i − ( 1 − α ) y ^ u i ) p u f − α ∑ k = f q ik s k f p
其中 s k f p s^p_{kf} s k f p 表示 S p \mathbf{S}^p S p 缓存的第 ( k , f ) (k, f) ( k , f ) 个元素,定义为 S p = P T P \mathbf{S}^p = \mathbf{P}^T\mathbf{P} S p = P T P 。学习算法总结如下
Randomly initialize P \mathbf{P} P and Q \mathbf{Q} Q for ( u , i ) ∈ R (u, i)\in R ( u , i ) ∈ R do y ^ u i = p u T q i \hat{y}_{ui}=\mathbf{p}_u^T\mathbf{q}_i y ^ u i = p u T q i while Stopping criteria is not met do S q = Q T Q \mathbf{S}^q = \mathbf{Q}^T\mathbf{Q} S q = Q T Q for u ← 1 u \leftarrow 1 u ← 1 to M M M do for f ← 1 f \leftarrow 1 f ← 1 to K K K do for i ∈ I u i \in I_u i ∈ I u do y ^ u i ← y ^ u i f − p u f q i f \hat{y}_{ui}\leftarrow\hat{y}_{ui}^f-p_{uf}q_{if} y ^ u i ← y ^ u i f − p u f q i f p u f ← p_{uf}\leftarrow p u f ← Eq 1for i ∈ I u i \in I_u i ∈ I u do y ^ u i ← y ^ u i f + p u f q i f \hat{y}_{ui}\leftarrow\hat{y}_{ui}^f+p_{uf}q_{if} y ^ u i ← y ^ u i f + p u f q i f end end S p = P T P \mathbf{S}^p=\mathbf{P}^T\mathbf{P} S p = P T P for i ← 1 i \leftarrow 1 i ← 1 to N N N do for f ← 1 f \leftarrow 1 f ← 1 to K K K do for u ∈ U i u \in U_i u ∈ U i do y ^ u i ← y ^ u i f − p u f q i f \hat{y}_{ui}\leftarrow\hat{y}_{ui}^f-p_{uf}q_{if} y ^ u i ← y ^ u i f − p u f q i f q i f ← q_{if}\leftarrow q i f ← Eq 2for u ∈ U i u \in U_i u ∈ U i do y ^ u i ← y ^ u i f + p u f q i f \hat{y}_{ui}\leftarrow\hat{y}_{ui}^f+p_{uf}q_{if} y ^ u i ← y ^ u i f + p u f q i f end end return P \mathbf{P} P and Q \mathbf{Q} Q 协同过滤的配置都是关于模型拟合和超参数优化的。
type 是协同过滤算法的类型。默认为 none。 fit_period 是模型拟合的周期。默认为 60m。fit_epoch 是模型拟合的 epoch 数。默认为 100。optimize_period 是超参数优化的周期。默认为 180m。optimize_trials 是超参数优化的试验次数。默认为 10。early_stopping.patience 是在没有改进多少个 epoch 后停止训练。默认为 10。在演示项目 GitRec 中,协同过滤配置如下:
[ recommend . collaborative ]
type = "mf"
fit_period = "60m"
fit_epoch = 100
optimize_period = "360m"
optimize_trials = 10
[ recommend . collaborative . early_stopping ]
patience = 10