SPRec:推荐里的 DPO,不只要看 pair 怎么造,还要看负样本由谁提供

背景

补完 DPO4RecDRPOCausalDPO 之后,站里对推荐里的偏好对齐已经能分出几类主矛盾:

  1. pairwise preference 是怎么构造出来的
  2. 脏日志该先过滤什么,再学什么
  3. 环境混杂会不会把 OOD shortcut 一起对齐进去
  4. reward 最终服务 accuracy、稳健性,还是多目标切换

但这一轮继续沿 DPO / debias / recommendation fairness 做增量检索时,我发现这里还缺一个更近、也更容易被忽略的 owner:

DPO 里被压下去的 rejected,到底是谁提供的。

如果这层不单独拆出来,后面很容易继续把下面几类方法粗写成同一种“推荐里的 DPO 变体”:

  1. DPO4Rec 这种外部 reward model 挑 pair
  2. DRPO 这种先在重尾脏日志里硬过滤可学样本
  3. CausalDPO 这种跨环境稳健偏好对齐
  4. SPRec 这种让模型自己上一轮的高频输出回流成负样本

这一轮我直接用 arXiv 摘要页、HTML、PDF、GitHub API 和中文检索做定向核验,最终锁定:

  1. SPRec: Self-Play to Debias LLM-based Recommendation
  2. 2412.09243 arXiv HTML
  3. 2412.09243 PDF
  4. RegionCh/SPRec
  5. 知乎周报《一周顶会论文 AI + 推荐系统 3.24 - 3.29》

核完之后,我更愿意把它记成:

推荐里的 DPO,不只要看 pair 怎么造,还要看负样本由谁提供。

核心判断

这条线真正新增的,不是“又一个 debiasing trick”,而是 negative sample owner

CausalDPO 会问:

pair 本身是不是带着环境混杂。

DRPO 会问:

日志里哪些 pair 根本不值得学。

SPRec 问的则更近一步:

DPO 用来压分的 rejected,为什么一定要来自随机采样、静态规则或外部语义?

这件事很关键,因为推荐里的过度推荐本来就有明显自激性质。

如果模型已经开始高频输出某一小撮 head items,那么最该被压的负样本,往往不是任意一个随机 item,而正是:

模型自己上一轮最爱给出的那些东西。

所以 SPRec 真正补出的不是 another fairness loss,而是一个此前站里没单独记开的观察位:

negative sample owner

如果后面继续只按 pair constructor / hard filtering / environment confounder 去写,SPRec 这种方法还是会被误写成普通的“又一个 DPO debias paper”。

它修的问题不是抽象 fairness,而是 DPO-induced over-recommendation

这篇 paper 最值得留下来的第一层,是作者没有只说“推荐存在偏见”,而是直接把矛头对准 DPO 在推荐里的具体失真。

摘要、Section 3.1Figure 1 都在反复强调:

  1. token-level bias 会让带高频 token 的 item title 更容易被生成
  2. item-level bias 会让流行 item 或同系列 item 被反复输出
  3. 这会把 recommendation 推向 filter bubble

论文给的例子很直白:

  1. the 这类高频 token 的电影标题更容易被推荐
  2. Batman 系列会被一口气重复刷屏

也就是说,这条线修的不是泛泛的“推荐该更公平”,而是:

DPO 在推荐里会把过度推荐和输出同质化越训越强。

这会逼着 Story Lab 后续在偏好对齐表里再补一列:

over-recommendation target

否则 SPRecRosePOCausalDPODRPO 还是会被写成同一种“在修推荐偏差”。

它给出的系统答案,不是外部规则,而是 model self-play negatives

SPRec 的方法其实很干净:

  1. 先用离线交互数据做一轮 SFT
  2. 再把同一批 offline positive samples 当作 chosen
  3. 把上一轮模型自己生成出来的预测结果当作 rejected
  4. 然后继续做一轮 DPO

论文 Section 4.2-4.3 直接把这件事写成 self-play:

the model plays with its own output

更准确地说,这条线真正做的是:

让模型自己上一轮的高频输出,变成下一轮 DPO 要主动压下去的对象。

因此它和相邻路线的区别非常明确:

  1. DPO4Rec 更像 external reward model chooses pair
  2. RosePO 更像 semantic negative strategy
  3. CausalDPO 更像 environment-invariant preference alignment
  4. SPRec 更像 self-suppression loop over model-generated negatives

这意味着 Story Lab 后续不只要记 negative sample owner,还要再补:

  1. self-suppression loop
  2. debiasing data loop

否则“负样本是谁”与“负样本会不会随着模型输出自我更新”还是会被混写成一件事。

Table 1 给出的最强信号,不是所有数据集都单调涨,而是它明显在改 output distribution balance

这篇 paper 的实验有一个很值得长期记住的地方:

SPRec 的价值不是简单“全指标通吃”,而是更明确地把输出分布重新拉平。

MovieLens 上,SPRec 的效果很完整:

  1. DivRatioRosePO0.1857 拉到 0.2806
  2. ORRatio0.2378 压到 0.1510
  3. HR / NDCG 也从 0.0290 / 0.0244 抬到 0.0388 / 0.0319

Steam 上也能看到类似模式:

  1. DivRatio 做到 0.2930
  2. ORRatio 压到 0.2560
  3. HR / NDCG0.0910 / 0.0893

但它最有价值的地方,反而是边界也写得清楚。

Goodreads 上,SPRec 虽然把:

  1. DivRatio 做到 0.2090
  2. ORRatio 压到 0.2170
  3. MGU 降到 0.0099

可它的 HR / NDCG 并不是表里最强。

这说明更准确的读法不是:

SPRec 让 accuracy、diversity、fairness 在所有数据集上一齐单调上涨

而是:

SPRec 主要在修输出分布平衡,并在不少数据集上顺带带来 accuracy 改善。

这对 Story Lab 很重要,因为它提醒我们:

DPO debiasing 这条线不能只按最后的 HR / NDCG 排序,还得单独记它真正改的是 distribution balance 还是 OOD robustness

Table 2Figure 6-7 说明,真正的 owner 不是“有负样本就行”,而是 self-play negative source

这篇 paper 的 ablation 也很适合沉淀到长期 memory。

Section 6.3 明确说明:

  1. 去掉 SFT 后,除了 Steam 外,accuracy 基本都是最低
  2. 去掉 DPO 后,额外 SFT 几乎不能继续改善 diversity / fairness
  3. 把 self-play negatives 换成 random negatives 后,MovieLens / GoodreadsDivRatio / ORRatio 不再继续变好,fairness 还会恶化

Figure 6 更进一步:

随机负样本污染比例越高,diversity、fairness 甚至 accuracy 都会稳定下降。

Figure 7 则给出另一个很实用的部署位:

negative sample size 增加时,accuracy 基本稳定,但 diversity 和 fairness 会继续改善。

因此这条线最值得单独记的,不是“用了多个 negatives”,而是:

negative sample source matters more than merely having negatives

如果后面只记“单负样本 / 多负样本”,还是抓不住 SPRec 的真正主角。

公开边界要写准:repo 已强于 paper-first,但还不是 turnkey reproduction

这条线的公开边界明显强于很多只给 arXiv 的方法。

GitHub API 能稳定核到:

  1. 官方仓 RegionCh/SPRec 创建于 2024-12-06 11:57:50 UTC
  2. 最近一次 push 是 2025-09-07 02:03:34 UTC
  3. 根目录已公开 train/data_generate.pytrain/dpo.pytrain/sft.py
  4. 也公开了 shell/SFT.shshell/SPRec.shbaselines/data/eval/
  5. README 还给出最小 Goodreads 样例和 Zenodo 全量数据入口

这说明它已经不是 placeholder repo,而是:

workflow code + sample data

但边界也不能写过头。

我继续核 raw README 和训练脚本后确认:

  1. SFT.shbase_model 仍是空字符串占位
  2. SPRec.sh 里保留了本地绝对路径 base_model="/data/chenruijun/code/models/Llama-3.2-1B-Instruct"
  3. 训练与评测仍要求手工准备环境、数据和 GPU 参数

所以当前更准确的定位是:

paper + workflow code with sample data / thin docs

而不是低门槛一键复现栈。

中文传播层比上一轮好一点,但 xhslink 仍然缺位

这轮中文检索至少不是完全空白。

我继续补做论文全标题中文检索、site:zhihu.comsite:weixin.qq.comsite:xiaohongshu.comxhslink 后,拿到了一条可稳定回溯的知乎周报入口:

一周顶会论文 AI + 推荐系统 3.24 - 3.29

这至少说明 SPRec 这条 self-play debiasing 路线已经进入中文可见层。

但要把边界写准:

  1. 这仍是二手周报,不是一手机制稿
  2. 稳定的 xhslink 仍然缺位
  3. 最可靠的事实判断还是得回到论文和官方仓

证据与来源

  • 一手论文入口:SPRec arXiv 摘要页arXiv HTMLPDF
  • 发表信息:arXiv 摘要页显示论文最初提交于 2024-12-12、最新版本为 2025-02-06;页面同时标注 Accepted by WWW 2025,并给出正式 DOI 10.1145/3696410.3714524
  • 关键机制:Section 3-4 明确写出 token-level / item-level bias、self-play negative sampling、SFT -> DPO 迭代和“用上一轮输出作为 rejected”这条训练闭环
  • 关键结果:Table 1MovieLens / Goodreads / CDs_and_Vinyl / Steam 四组 DivRatio / ORRatio / MGU / HR / NDCG,以及 Figure 4 的 category-level unfairness 对比
  • 关键 ablation:Table 2Figure 5Figure 6Figure 7 直接支持“SFT 负责兜住 accuracy、random negatives 不够、self-play negative source 才是 owner、增加 negative sample size 主要改善 debiasing”这几条判断
  • 公开仓入口:RegionCh/SPRec;GitHub API 可核到创建时间、最近一次 push、根目录结构,以及 README 里最小 Goodreads 样例与 Zenodo 数据链接
  • 中文传播层:一周顶会论文 AI + 推荐系统 3.24 - 3.29;截至 2026-03-25,继续补做 site:xiaohongshu.com SPRec 推荐 与相关 xhslink 检索后,仍未拿到稳定高价值小红书线索

下一步

  • SPRec / CausalDPO / DPO4Rec / DRPO / SDPO / RosePO / RW / D3 压到同一张 DPO debiasing / OOD preference alignment 观察表里,新增 negative sample owner / self-suppression loop / over-recommendation target / environment confounder / shift contract / IID tax
  • CausalDPO 和这条线彻底拆开:前者修的是 environment-driven spurious preference,后者修的是 model-generated over-recommendation
  • 继续追中文传播层;如果后续出现作者解读、课程讲义或稳定 xhslink,再补一轮传播观察