21.5. 推荐系统的个性化排名
在 Colab 中打开 Notebook
在 Colab 中打开 Notebook
在 Colab 中打开 Notebook
在 Colab 中打开 Notebook
在 SageMaker Studio Lab 中打开 Notebook

在前面的章节中,我们只考虑了显式反馈,并在观察到的评分上训练和测试模型。这种方法有两个缺点:首先,在现实世界的场景中,大多数反馈不是显式的,而是隐式的,而显式反馈的收集成本可能更高。其次,那些可能预测用户兴趣的未观察到的“用户-商品”对被完全忽略,这使得这些方法不适用于评分不是随机缺失,而是因为用户偏好的情况。未观察到的“用户-商品”对是真实负面反馈(用户对这些商品不感兴趣)和缺失值(用户将来可能会与这些商品互动)的混合体。在矩阵分解和AutoRec中,我们简单地忽略了未观察到的“用户-商品”对。显然,这些模型无法区分已观察和未观察到的“用户-商品”对,因此通常不适合个性化排名任务。

为此,一类旨在从隐式反馈中生成排名推荐列表的推荐模型越来越受欢迎。总的来说,个性化排名模型可以通过单点(pointwise)、成对(pairwise)或列表(listwise)方法进行优化。单点方法一次只考虑单个交互,并训练一个分类器或回归器来预测个体偏好。矩阵分解和AutoRec就是使用单点目标进行优化的。成对方法为每个用户考虑一对商品,并旨在为该对商品近似最优排序。通常,成对方法更适合排名任务,因为预测相对顺序与排名的本质更为相似。列表方法则近似整个商品列表的排序,例如,直接优化排名指标,如归一化折损累计增益(NDCG)。然而,列表方法比单点或成对方法更复杂,计算量也更大。在本节中,我们将介绍两个成对目标/损失:贝叶斯个性化排名损失和Hinge损失,以及它们各自的实现。

21.5.1. 贝叶斯个性化排名损失及其实现

贝叶斯个性化排名(BPR) (Rendle et al., 2009) 是一种成对的个性化排名损失,它源于最大后验估计。它已被广泛用于许多现有的推荐模型中。BPR的训练数据包括正样本对和负样本对(缺失值)。它假设用户相对于所有其他未观察到的商品更喜欢正样本商品。

形式上,训练数据由 \((u, i, j)\) 形式的元组构成,表示用户 \(u\) 相对于商品 \(j\) 更喜欢商品 \(i\)。BPR旨在最大化后验概率的贝叶斯公式如下所示

(21.5.1)\[p(\Theta \mid >_u ) \propto p(>_u \mid \Theta) p(\Theta)\]

其中 \(\Theta\) 表示任意推荐模型的参数, \(>_u\) 表示用户 \(u\) 对所有商品的期望个性化总排序。我们可以构建最大后验估计来推导个性化排名任务的通用优化准则。

(21.5.2)\[\begin{split}\begin{aligned} \textrm{BPR-OPT} : &= \ln p(\Theta \mid >_u) \\ & \propto \ln p(>_u \mid \Theta) p(\Theta) \\ &= \ln \prod_{(u, i, j \in D)} \sigma(\hat{y}_{ui} - \hat{y}_{uj}) p(\Theta) \\ &= \sum_{(u, i, j \in D)} \ln \sigma(\hat{y}_{ui} - \hat{y}_{uj}) + \ln p(\Theta) \\ &= \sum_{(u, i, j \in D)} \ln \sigma(\hat{y}_{ui} - \hat{y}_{uj}) - \lambda_\Theta \|\Theta \|^2 \end{aligned}\end{split}\]

其中 \(D \stackrel{\textrm{def}}{=} \{(u, i, j) \mid i \in I^+_u \wedge j \in I \backslash I^+_u \}\) 是训练集, \(I^+_u\) 表示用户 \(u\) 喜欢的商品集合, \(I\) 表示所有商品,而 \(I \backslash I^+_u\) 表示除用户喜欢的商品外的所有其他商品。 \(\hat{y}_{ui}\)\(\hat{y}_{uj}\) 分别是用户 \(u\) 对商品 \(i\) 和商品 \(j\) 的预测得分。先验 \(p(\Theta)\) 是一个均值为零,协方差矩阵为 \(\Sigma_\Theta\) 的正态分布。这里,我们令 \(\Sigma_\Theta = \lambda_\Theta I\)

贝叶斯个性化排名示意图 我们将实现基类 mxnet.gluon.loss.Loss 并重写 forward 方法来构建贝叶斯个性化排名损失。我们首先导入Loss类和np模块。

from mxnet import gluon, np, npx

npx.set_np()

BPR损失的实现如下。

#@save
class BPRLoss(gluon.loss.Loss):
    def __init__(self, weight=None, batch_axis=0, **kwargs):
        super(BPRLoss, self).__init__(weight=None, batch_axis=0, **kwargs)

    def forward(self, positive, negative):
        distances = positive - negative
        loss = - np.sum(np.log(npx.sigmoid(distances)), 0, keepdims=True)
        return loss

21.5.2. Hinge损失及其实现

用于排名的Hinge损失与gluon库中提供的通常用于分类器(如SVM)的Hinge损失形式不同。在推荐系统中用于排名的损失具有以下形式。

(21.5.3)\[\sum_{(u, i, j \in D)} \max( m - \hat{y}_{ui} + \hat{y}_{uj}, 0)\]

其中 \(m\) 是安全边界大小。它旨在将负样本商品推离正样本商品。与BPR类似,它的目标是优化正负样本之间的相对距离,而不是绝对输出,这使其非常适合推荐系统。

#@save
class HingeLossbRec(gluon.loss.Loss):
    def __init__(self, weight=None, batch_axis=0, **kwargs):
        super(HingeLossbRec, self).__init__(weight=None, batch_axis=0,
                                            **kwargs)

    def forward(self, positive, negative, margin=1):
        distances = positive - negative
        loss = np.sum(np.maximum(- distances + margin, 0))
        return loss

这两种损失在推荐中的个性化排名任务中可以互换使用。

21.5.3. 小结

  • 对于推荐系统中的个性化排名任务,有三种可用的排名损失,即单点法、成对法和列表法。

  • 贝叶斯个性化排名损失和Hinge损失这两种成对损失可以互换使用。

21.5.4. 练习

  • BPR和Hinge损失是否有任何变体?

  • 你能找到任何使用BPR或Hinge损失的推荐模型吗?

讨论