← All writing生成式推荐 · 01

推荐系统原本是一台打分机|生成式推荐 01:BPR

用户从不告诉系统自己讨厌什么。BPR 把点击与沉默改写成成对比较,让推荐第一次直接学习“谁应该排在谁前面”。

Read the English edition →

小林点击了攀岩鞋,却没有点击泳镜。

这是否意味着她不喜欢泳镜?

未必。她可能根本没有看到泳镜,可能今天只想买攀岩装备,也可能已经在别处买过。推荐系统最常见的数据恰恰是这种隐式反馈(implicit feedback):点击、停留、加购、购买,以及大量无法解释的沉默。

如果把点击记为 1、没点击记为 0,再训练一个二分类器,模型会被迫相信所有沉默都是真正的负反馈。但 BPR: Bayesian Personalized Ranking from Implicit Feedback 换了一个问题:

我们不必知道小林给每件商品打几分。只要她看过 i$、没有看过 $j,能否先学会让 排在 前面?

这是整个系列的第一块地基。后面无论模型使用 GRU、Transformer、LLM 还是 Semantic ID,最终都绕不开同一个问题:什么样的训练信号,能让正确商品排到错误商品前面?

30 秒看懂本文

  1. 上一代的问题:隐式反馈只有“发生过”,没有可靠的负评分;逐点拟合点击值与最终 Top-K 排序并不完全一致。
  2. BPR 的答案:从“已观察商品 i$”和“未观察商品 $j$”构造三元组 $(u,i,j),最大化用户更偏好 的概率
  3. 最重要的证据:论文把同一个 BPR 优化准则分别装到矩阵分解和 adaptive kNN 上,都得到更好的个性化排序;贡献首先是目标函数与采样算法,而不是一种新的神经网络。

BPR 把逐点预测改写成成对排序

图 1:BPR 的关键迁移不是“换了一个更大的模型”,而是从拟合绝对值转向学习同一用户的相对顺序。

上一代留下了什么问题

显式反馈很好理解:小林给网球拍 5 星、给瑜伽垫 2 星,我们可以用平方误差拟合评分。

现实里的大多数推荐日志没有星级。设用户集合为 ,商品集合为 ,观测到的交互为

只表示用户 对商品 做过某个行为。它没有告诉我们:

  • 点击是否真的代表喜欢;
  • 未点击是因为不喜欢,还是没有曝光;
  • 两件都点击过的商品谁更喜欢;
  • 两件都没点击过的商品谁应该更靠前。

一个常见做法是把 当正样本,把其他组合当负样本,再回归 0/1。但商品库可能有百万件:对每个正样本,小林都有近百万个“未观察商品”。这些负例不仅数量悬殊,而且语义含糊。

BPR 接受这种不确定性,却把结论收窄:

  • 已观察 与未观察 比较:假设 $i \succ_u j$;
  • 两件都已观察:不推断顺序;
  • 两件都未观察:也不推断顺序。

所以它不是宣布“没点就是讨厌”,而是说:

在当前日志能提供的弱证据下,先让用户做过行为的商品排在沉默商品之前。

用八件商品理解训练数据

沿用全系列的小林与八件运动商品。假设她点击了 I03 攀岩鞋,没有与 I06 泳镜 交互。

一次隐式行为怎样变成 BPR 三元组

图 2:BPR 从一条 observed 记录和一个 unobserved 商品构造 。图中的“偏好”是训练假设,不是用户亲口表达的事实。

对每个用户 ,已观察集合记为

训练三元组集合是

三元组 (小林, I03, I06) 的含义不是“攀岩鞋得 1 分、泳镜得 0 分”,而是一个二元命题:

这个区别看似细小,却改变了梯度在做什么。

  • Pointwise loss 分别推动 接近 1、$s(u,I06)$ 接近 0;
  • Pairwise loss 只关心差值 是否足够大。

如果两个分数分别是 101 和 100,绝对值很奇怪,但排序是对的;如果分别是 0.8 和 0.9,两个值都看似合理,顺序却错了。BPR 优化的是后者。

模型从输入到输出发生了什么

BPR 不是一个固定的打分器,而是一层可以套在不同模型上的优化框架。论文展示了矩阵分解和 adaptive kNN。最经典的组合是 BPR-MF

给用户与商品各分配一个 维向量:

用户—商品分数是点积:

同一用户对两件商品的分差则是

BPR-MF 的数据流、张量和核心目标

图 3:一次更新只读取一个用户向量和两个商品向量。训练直接放大正负商品的分差;推理阶段仍然需要对候选商品计算分数。

如果 mini-batch 包含 个三元组,实现里常见的 shape 是:

张量 Shape 含义
user_ids 用户索引
pos_item_ids 已观察商品
neg_item_ids 采样的未观察商品
user_emb 用户向量
pos_emb, neg_emb 正负商品向量
margin

矩阵分解的一次三元组更新大约是 。这使训练可以在巨大且没有显式展开的 上进行。

但请注意:BPR 仍属于“打分机”。

推理时它为候选商品计算 ,再取 Top-K。它没有生成商品 token,也没有让列表第二件依赖第一件。我们把它放在生成式推荐故事的起点,是因为它建立了后面所有排序监督的原型。

核心公式逐项拆解

BPR 把“用户真的更喜欢 $i$”的概率写成:

然后为参数 加一个零均值高斯先验,得到最大后验目标:

逐项看:

  • :正商品与负商品的分差;
  • :把分差转成 内的偏好概率;
  • :当顺序错得越离谱,惩罚越大;已经明显排对后,边际收益变小;
  • :来自参数先验,防止只靠放大向量范数制造巨大分差。

负号形式更像我们熟悉的 loss:

举个数值例子:

  • 如果攀岩鞋分数 1.2、泳镜 0.2,$\Delta=1.0$,偏好概率约为 0.731;
  • 如果顺序颠倒,$\Delta=-1.0$,概率约为 0.269,梯度会强烈推动两者分开;
  • 如果 ,概率已接近 1,继续拉开差距的收益很小。

这也是 BPR 与 AUC 的联系:AUC 统计正样本能否排在负样本之前;BPR 用可微的 近似这种成对正确性。

训练和推理分别怎么做

完整 的规模约为 ,不可能真的枚举。论文提出 LearnBPR:每一步随机抽用户、正商品与未观察商品,立即做一次 SGD 更新。

initialize user and item vectors
repeat:
    sample user u
    sample observed item i from I_u+
    sample unobserved item j from I \ I_u+

    delta = score(u, i) - score(u, j)
    loss  = -log sigmoid(delta) + regularization
    update only w_u, h_i, h_j
until validation ranking stops improving

“随机抽三元组”不只是工程小技巧。论文指出,如果按用户或商品顺序遍历,连续梯度会反复击中同一组参数;热门正商品还会形成大量相似比较,收敛很差。带放回的 bootstrap sampling 打散了这种偏斜。

推理则完全不同:

user_vector = W[u]
for candidate item i:
    score[i] = dot(user_vector, H[i])
return top_k(score)

如果对全量商品暴力打分,复杂度约为 $O(|\mathcal I|d)$;工业系统通常会用候选召回、向量索引或缓存缩小范围。因此 BPR 解决的是“怎样学排序”,没有解决“怎样从百万商品里高效找出来”。

实验究竟证明了什么

原论文 做了两个重要控制:

  1. 底层模型固定为矩阵分解,比较 BPR 优化与其他训练方式;
  2. 再把 BPR 套到 adaptive kNN,检查收益是否只属于 MF。

论文在多个隐式反馈数据上以 AUC 衡量个性化排序,并报告 BPR-MF 与 BPR-kNN 相对相应基线的优势。更有价值的结论不是某一根柱子高了多少,而是:

同样的表示模型,仅仅把训练目标从数值重建改成 pairwise ranking,就可以显著改变最终排序质量。

BPR 论文的证据链与结论边界

图 4:原论文 Figure 5–6 的核心证据方向。为避免从曲线中制造伪精确数字,本图只重绘实验逻辑与被支持的结论。

今天回看这组实验,还要加三条限制:

  • 论文主要使用离线 AUC,不等价于在线点击、转化或长期满意度;
  • 数据来自旧系统的曝光与交互,未观察集合不是随机抽样;
  • 结果证明 BPR 适合这些模型与设置,不代表 pairwise loss 永远优于更强的 listwise 或 counterfactual 方法。

它失败在哪里

1. 把“没看见”和“不喜欢”混在一起

BPR 的核心假设是 i\in\mathcal I_u^+$、$j\notin\mathcal I_u^+ 时,$i\succ_u j$。如果 I06 泳镜 从未曝光,模型却把它当负例,就会把旧推荐系统的盲区继续学下去。

这就是曝光偏差(exposure bias):日志记录的是“旧策略展示了什么之后发生的行为”,不是用户在完整商品库上的自然偏好。

2. 负采样决定了模型学到的边界

均匀采样容易抽到大量显然无关的简单负例;按热门度采样会得到更难的比较,却可能过度压制热门商品;从同类目抽 hard negatives 更有信息,但也更容易出现“其实用户会喜欢两件”的假负例。

Loss 公式只写了一行,采样分布却可能决定大部分训练效果。

3. 一个用户只有一个静态向量

BPR-MF 把小林压成 。她过去一年喜欢网球、今天突然开始攀岩,这些事件的先后顺序都被折叠进同一个坐标。模型知道“她总体像哪类人”,却不知道“她此刻正在做什么”。

4. 独立打分不能自然表达列表关系

I03 攀岩鞋I04 粉袋 可以各自获得高分,但模型不会因为第一位已经放了攀岩鞋,就主动改变第二位对多样性、互补性或重复度的判断。这些依赖通常由后续重排承担。

5. 排序正确不代表因果上更好

BPR 学的是历史行为顺序,不是“展示这件商品会让用户更满意”的因果效应。流行度、位置、价格、库存和旧策略都会进入日志。

下一篇为什么会出现

BPR 让推荐系统学会了第一件事:

对同一个用户,正商品的分数应该高于一个采样负商品。

但它仍然把用户当成一个静止的点。

如果小林先看网球拍,再看攀岩鞋,和先看攀岩鞋、再看网球拍,BPR-MF 得到的用户—商品集合几乎相同。可真实意图可能完全不同:前者像是在随意浏览运动用品,后者可能正在为今晚的抱石做准备。

于是下一篇论文把“用户是谁”改写成“这段 session 正在怎样展开”。

下一篇:GRU4Rec——用户不是一个点,而是一段正在发生的故事。

原始论文

返回完整路线图 →