← 返回论文列表
📄 论文解读 · 生成式推荐 · 快手 · 2025

OneRec

Unifying Retrieve and Rank with Generative Recommender and Preference Alignment

机构
Kuaishou Inc. (快手)
来源
arXiv 2502.18965
年份
2025
核心命题
统一召回+排序的端到端生成式推荐
💡
一句话总结

OneRec 是首个在工业场景完全替代三级级联推荐 pipeline 的端到端生成式推荐模型:1B 参数 Encoder-Decoder + MoE 架构,一次性生成整个 session(5 个视频的 SID),Balanced K-Means 解决 codebook 不均衡问题,IPA 策略用 Reward Model 自动构造 DPO 偏好对进行迭代对齐;快手主页 A/B:总观看时长 +1.68%,人均单次观看时长 +6.56%。

📄 原文:https://arxiv.org/abs/2502.18965

🔗 前驱工作:TIGER(NeurIPS 2023)、LETTER(arXiv 2403.06361)

补充阅读:OneRec 技术报告(arXiv 2506.13695)
当前页面聚焦 2502 原论文:核心方法主线是 Balanced K-Means + Session-wise 生成 + IPA 对齐,重点回答“OneRec 为什么成立、为什么能替代三级漏斗”。

如果你想继续看“它在快手到底怎么工程化落地”,建议再读:OneRec Technical Report 解读。技术报告重点补了四类信息:
Tokenizer 前置多模态管线:caption / OCR / ASR / 图像帧 + QFormer + RQ-Kmeans;
更完整的用户建模:静态特征、短期行为、正反馈行为、终身行为四路 Encoder;
更工程化的对齐体系:P-Score、Format Reward、Industrial Reward、ECPO / RL;
更完整的工业指标:MFU、OPEX、QPS 承接比例、硬件规模等。

可以把两页配合理解为:这页讲“方法为什么成立”技术报告页讲“系统怎样真正落地、扩展并降成本”
三句话核心贡献:
① 单阶段替代三级漏斗:Encoder-Decoder + MoE,一个模型统一召回与精排,彻底消除多阶段信息损失;
② Session-wise 生成:一次输出 5 个视频的完整 session,而非逐 item 生成,捕获 session 内 item 间关联性;
③ IPA 迭代偏好对齐:Reward Model 打分 → Beam Search 采样 → DPO 构造偏好对 → 迭代优化,闭环提升推荐质量。
🌐
1. 背景与动机

快手的视频推荐系统日活用户超过 3 亿,传统架构采用三阶段级联排序:召回(Retrieval)→ 粗排(Pre-ranking)→ 精排(Ranking)。每个阶段独立训练、优化目标不同,上游的天花板限制了下游的性能上限。

根本问题:现有生成式推荐模型(如 TIGER)只能替代三阶段中的"召回"环节,其推荐精度远不及精排模型,因此无法真正替代完整的推荐 pipeline。OneRec 的目标是用一个统一的生成模型直接替代整个三阶段系统,输入用户历史,直接输出最终推荐 session。

传统级联 vs OneRec 统一架构

传统三阶段级联

  • 召回:从 $10^{10}$ 个视频筛到 $10^5$(MIPS/ANN)
  • 粗排:从 $10^5$ 筛到 $10^3$(轻量排序模型)
  • 精排:从 $10^3$ 筛到 $10^2$(复杂重排模型)
  • 各阶段独立优化,目标不一致,信息损失累积

OneRec 端到端生成

  • Encoder 处理用户历史(最长 256 个视频)
  • Decoder 直接生成 session(5 个目标视频的 SID)
  • 一个模型 = 召回 + 精排,目标统一
  • 在线 A/B:总观看时长 +1.68%,人均视频时长 +6.56%

OneRec 是快手首个在大规模工业场景中显著超越多阶段 pipeline 的端到端生成式推荐模型,具有重要的工业落地意义。

⚙️
2. 方法详解
OneRec 整体框架
Figure 2(论文原图):OneRec 完整框架。左上:平衡 K-Means 语义 ID 生成;右上:Encoder-Decoder + MoE Decoder;左下/右下:IPA 流程,基于 Reward Model 的迭代 DPO 训练。

2.1 均衡 K-Means 语义 ID(Balanced Identifier Quantization)

传统 RQ-VAE 存在"沙漏现象"(hourglass phenomenon):少数 codebook 码字被频繁使用(高频 item 全都量化到几个热门码字),而大量码字闲置,导致 ID 分布极不均匀,Decoder 难以学习。OneRec 使用平衡 K-Means(Balanced K-Means) 解决这一问题。

SID 生成全流程:残差量化 + 均衡约束

OneRec 的 SID 生成分两步:①残差量化(RQ) 决定每层的 token 是什么;②均衡 K-Means 决定每层的 codebook 如何训练。两者结合生成最终的分层 SID。

第一步:残差量化生成 SID(与 RQ-VAE 相同)

给定视频 $i$ 的多模态 embedding $\mathbf{e}_i$,依次在每一层 codebook 中找最近邻 cluster,用"残差"迭代量化:

$$\mathbf{r}_i^1 = \mathbf{e}_i$$ $$s_i^l = \arg\min_k \| \mathbf{r}_i^l - \mathbf{c}_k^l \|_2^2 \quad (\text{第}l\text{层 token = 最近 cluster 编号})$$ $$\mathbf{r}_i^{l+1} = \mathbf{r}_i^l - \mathbf{c}_{s_i^l}^l \quad (\text{残差 = 当前向量} - \text{被选中 cluster 的中心})$$

重复 $L$ 层后,视频 $i$ 的 SID 为 $(s_i^1, s_i^2, \ldots, s_i^L)$,即一个 $L$ 维的 token 序列。

第二步:均衡 K-Means 训练 codebook(OneRec 的创新)

普通 K-Means 允许各 cluster 大小不一,导致沙漏现象。均衡 K-Means 对每层 codebook 训练加入强制等分约束:

$$w = |\mathcal{V}| / K \quad (\text{每个 cluster 精确包含} w \text{个视频})$$

每轮迭代的分配过程:初始化 $K$ 个 cluster 中心 → 将所有视频按到各 cluster 的距离排序 → 每个 cluster 按距离从近到远依次认领最近的 $w$ 个未被认领的视频 → 用分配到的视频均值更新 cluster 中心 → 重复直到收敛。

💡 具体例子:5 个视频 × 2 层 codebook 如何生成 SID

设定:总视频数 $|\mathcal{V}|=6$,每层 codebook 大小 $K=3$,层数 $L=2$,则 $w = 6/3 = 2$(每个 cluster 精确包含 2 个视频)。

假设 6 个视频的 embedding(1 维,便于可视化):

  • 视频 A: 0.1  |  视频 B: 0.15  |  视频 C: 0.5  |  视频 D: 0.55  |  视频 E: 0.9  |  视频 F: 0.95

第一层均衡 K-Means($K=3$,$w=2$):
初始化 3 个 cluster 中心,假设收敛后:
Cluster 0 中心 ≈ 0.125,Cluster 1 中心 ≈ 0.525,Cluster 2 中心 ≈ 0.925
按均衡约束分配(每个 cluster 精确 2 个视频):

  • Cluster 0 ← {视频 A(0.1), 视频 B(0.15)}(最近 0.125,且恰好 2 个)
  • Cluster 1 ← {视频 C(0.5), 视频 D(0.55)}(最近 0.525)
  • Cluster 2 ← {视频 E(0.9), 视频 F(0.95)}(最近 0.925)

→ 第一层 SID token($s_i^1$):A→0, B→0, C→1, D→1, E→2, F→2

计算第一层残差($\mathbf{r}_i^2 = \mathbf{r}_i^1 - \mathbf{c}_{s_i^1}^1$):

  • 视频 A 残差:0.1 − 0.125 = −0.025
  • 视频 B 残差:0.15 − 0.125 = +0.025
  • 视频 C 残差:0.5 − 0.525 = −0.025
  • 视频 D 残差:0.55 − 0.525 = +0.025
  • 视频 E 残差:0.9 − 0.925 = −0.025
  • 视频 F 残差:0.95 − 0.925 = +0.025

第二层均衡 K-Means 作用在残差上($K=3$,$w=2$):
残差只有 ±0.025 两种,cluster 大小均衡后:

  • Cluster 0(负残差)← {视频 A, 视频 C, 视频 E},但 $w=2$,所以只能取 2 个!
  • 这里体现均衡约束的关键:普通 K-Means 会把 A/C/E 都分到同一个 cluster,而均衡 K-Means 强制每个 cluster ≤ 2 个,会把第 3 个负残差视频分到其他 cluster
  • 假设最终:Cluster 0 ← {A, C},Cluster 1 ← {E, B},Cluster 2 ← {D, F}

→ 第二层 SID token($s_i^2$):A→0, C→0, E→1, B→1, D→2, F→2

最终 2 层 SID:

  • 视频 A:(0, 0)  |  视频 B:(0, 1)  |  视频 C:(1, 0)
  • 视频 D:(1, 2)  |  视频 E:(2, 1)  |  视频 F:(2, 2)

对比普通 RQ-VAE 沙漏现象:如果不加均衡约束,极端情况下所有视频第一层都分到同一个大 cluster(比如都在 embedding 空间中某个高密度区域),导致 $s_i^1$ 对所有视频都是同一个数字,失去区分能力。均衡约束强制每个 cluster 只有 $w$ 个视频,保证 ID 空间被充分利用。

2.2 Session-wise 列表生成(Session-wise List Generation)

传统生成式推荐(如 TIGER)每次只预测"下一个 item"(Next-Item Prediction),然后再以该 item 为条件预测下下一个……这种逐点生成方式存在两个问题:

  • 每次生成只看到单个 item,无法考虑 session 内视频之间的多样性和连贯性
  • 需要人工设计规则来合并多次生成结果(如去重、强制多样性),非端到端优化

OneRec 定义 session 为一次刷新返回给用户的视频列表,通常包含 5-10 个视频。训练时直接以高质量 session 为学习目标(整体 session 而非单个视频),让模型自主学习 session 内的最优结构。

高质量 Session 筛选标准

  • 用户在该 session 内实际观看的视频数 ≥ 5
  • 用户观看总时长超过一定阈值
  • 用户有明确的交互行为(点赞、收藏、分享等)

Session-wise 生成目标的形式化定义:

$$S := \mathcal{M}(H_u)$$ $$\mathcal{L}_\text{NTP} = -\sum_{i=1}^{m}\sum_{j=1}^{L} \log P(s_i^{j+1} | [\text{BOS}, s_1^1, \ldots, s_m^j]; \Theta)$$
符号说明
  • $H_u$:用户历史行为序列(最近 256 个有效互动视频的 SID 序列)
  • $S = \{v_1, v_2, \ldots, v_m\}$:目标 session($m=5$ 个视频)
  • $s_i^j$:session 中第 $i$ 个视频第 $j$ 层的 SID token($j$ 从 1 到 $L=3$)
  • $\text{BOS}$:视频分隔符 token,每个视频前插入一个 BOS
  • $m$:session 中的视频数量(默认 5)
常见疑问:NTP 学的是旧系统推出来的 session,有意义吗?

有意义,但要理解 NTP 和 DPO 在这里各自的角色:

原因一:NTP 是"地基",不是终点
OneRec 的目标是用一个生成模型替代整个三阶段系统。第一步要做的,就是让这个生成模型至少能达到旧系统的水平——否则连基线都达不到,谈什么超越。
NTP 学旧系统的高质量 session,是在告诉模型:"历史上用户真正喜欢的是这类 session,你先学会生成这个水平的东西。"这是知识迁移,不是无意义的复制。

原因二:DPO(IPA)才是超越旧系统的关键
NTP 只能让模型复现旧系统的上限,而 DPO 的作用是让模型超越旧系统。DPO 的训练数据来自 Beam Search 生成的合成 session,Beam Search 可以探索出旧系统从来没推过的组合,RM 给这些组合打分,选出比旧系统更好的 session 作为 chosen,再用 DPO 拉高这类 session 的概率。
整体逻辑:NTP → 学会旧系统水平(地基)  →  DPO → 探索并强化旧系统未发现的更优解(超越)

原因三:99% NTP 在混合训练里起正则作用
IPA 阶段 99% 的数据仍然是 NTP,目的是防止模型在 DPO 优化偏好方向时灾难性遗忘——如果只做 DPO,模型可能过度拟合 RM 的偏好打分,忘掉"如何生成语义合法的 session token 序列"。NTP 持续提供正则,保持模型的生成能力稳定。
💡 Next-Item vs Session-wise:用训练代码对比最清晰

两者训练代码对比(Encoder-Decoder 架构):

# ── Next-Item 训练 ─────────────────────────────────────────
# target: 下一个视频的 SID,shape [3],例如 [9, 3, 1]

enc_out        = encoder(H_u)            # 用户历史,只跑一次
decoder_input  = [BOS, 9, 3]            # 长度 3,去掉最后一个 token
decoder_target = [9, 3, 1]              # 长度 3,去掉开头 BOS

logits = decoder(decoder_input, enc_out) # shape [3, vocab_size]
loss   = cross_entropy(logits, decoder_target)
# ↑ loss 只覆盖 3 个 token(1 个视频)


# ── Session-wise 训练 ──────────────────────────────────────
# target: 完整 5 个视频 session,形式化为带 BOS 分隔的序列

enc_out        = encoder(H_u)            # 完全一样,只跑一次
target_seq     = [BOS,9,3,1, BOS,4,5,4, BOS,6,1,5, BOS,2,7,2, BOS,9,1,3]  # 长度 20
decoder_input  = target_seq[:-1]         # 长度 19
decoder_target = target_seq[1:]          # 长度 19

logits = decoder(decoder_input, enc_out) # shape [19, vocab_size]
loss   = cross_entropy(logits, decoder_target)
# ↑ loss 覆盖 19 个 token(5 个视频)
          

结论一:训练方式完全相同,encoder 调用一模一样,decoder 内部也是标准 causal mask teacher forcing,唯一区别是 decoder_input 的长度(3 vs 19),即 loss 覆盖的 token 数不同。

结论二:为什么 Session-wise 能感知完整 session?
不是因为 Encoder,而是因为 5 个视频的所有 token 都在同一个 decoder_input 序列里。Decoder 的 causal self-attention 在生成视频3的 token 时,天然能"看到"视频1和视频2已经生成了什么——这是 Transformer 自回归的固有能力,与 Encoder 无关。Encoder 只负责处理用户历史 $H_u$,对 session 内部的感知没有贡献。

结论三:Next-Item 推理时的额外问题(Encoder-Decoder 架构下被放大)
推理时 Next-Item 需要循环 5 次:每次生成 1 个视频 → 把它加入 $H_u$ 重新跑 Encoder → 再生成下一个。这导致两个问题:

  • Exposure Bias:训练时 decoder_input 始终是真实视频 SID,推理时却要把模型自己生成的视频加入历史——这个模式训练中从未出现过,误差逐步累积
  • 推理代价高:需要调用 5 次 Encoder forward,而 Session-wise 只需 1 次

如果把两者都改成纯 Decoder(GPT 风格,把历史和目标拼成一条序列),则 Next-Item 推理时也不需要反馈进 Encoder,两者推理行为等价,唯一区别只剩"训练时 loss 覆盖多少个 token"。 这说明 Next-Item 的额外劣势本质上是 Encoder-Decoder 架构下"训练时序列短、推理时要迭代循环 Encoder"这一不一致带来的。

2.3 Encoder-Decoder + Sparse MoE 架构

OneRec 采用 T5 风格的 Encoder-Decoder 架构,Decoder 中的 FFN 层全部替换为 Sparse Mixture-of-Experts(MoE)层:

$$H_t^{l+1} = \sum_{i=1}^{N_\text{MoE}} g_{i,t} \cdot \text{FFN}_i(H_t^l) + H_t^l$$ $$g_{i,t} = \begin{cases} s_{i,t}, & s_{i,t} \in \text{TopK}(\{s_{j,t}\}_{j=1}^{N}, K_\text{MoE}) \\ 0, & \text{otherwise} \end{cases}$$
符号说明
  • $N_\text{MoE} = 24$:总 expert 数量(每层 24 个 FFN expert)
  • $K_\text{MoE} = 2$:每次前向只激活 2 个 expert(FFN 层稀疏性 = $2/24 \approx 8.3\%$)
  • $g_{i,t}$:第 $i$ 个 expert 对第 $t$ 个 token 的 gate 权重(仅 top-2 非零)
  • $s_{i,t} = \text{Softmax}_i(H_t^l \cdot e_i^l)$:token $t$ 对 expert $i$ 的路由分数
参数效率:OneRec 论文原文描述为 "scale model capacity without proportionally increasing computational FLOPs"。每个 MoE 层只激活 $K_\text{MoE}=2$ 个 expert,FFN 层的计算量稀疏性为 $2/24 \approx 8.3\%$。注意:这里的 8.3% 是 FFN 层的激活比例,Attention 层参数仍然 100% 激活(Attention 不是 MoE)。整体模型(Attention + FFN 合计)的参数激活比介于 8.3%~100% 之间,论文并未给出具体的整体激活率数字。MoE 的核心价值是:以较小的推理 FLOPs 代价,大幅扩展模型总参数量(专家的总知识量),从而提升模型容量。

2.4 奖励模型设计(Reward Model)

常见疑问:日志里不是已经有真实的 swt/ltr 标签了么,为什么还要另外训一个 RM?

原因一:日志给不了"对比对"(反事实问题)
DPO 需要的是:同一用户、同一历史状态 $H_u$ 下,一个 chosen session 和一个 rejected session 的对比。但历史日志中,每次刷新只有一条真实曝光记录——系统当时推了什么,就只有这一条,没有"如果推了另一个 session 用户会怎么反应"的记录。这是反事实问题,在现实中不存在。

Beam Search 的作用正是:用当前模型为同一个 $H_u$ 生成 $N$ 条不同路径,人工制造出可对比的候选集,再由 RM 从中挑出最好和最差,构成合法的 DPO pair。

原因二:直接用旧系统日志做 DPO 数据,log-ratio 会不稳定
标准 DPO 理论上可以用 off-policy 数据(提前收集好的固定数据集),但有一个实践问题:DPO loss 需要计算当前模型对 chosen/rejected session 的 log 概率。如果偏好对来自旧系统(比如一个月前的推荐系统生成的 session),当前模型对这些序列的概率可能极低甚至接近 0——当前模型根本不会生成这些 token 组合,导致 log 概率趋向 $-\infty$,log-ratio 数值爆炸,梯度噪声极大。
Beam Search 生成的候选 session 来自当前模型本身,模型对它们的概率在合理范围内,log-ratio 稳定,训练收敛正常。这是 IPA 每轮重新采样的工程动机之一。

原因三:RM 的训练数据和 DPO 的数据需求是两件不同的事
RM 用真实日志(历史session + 真实swt/ltr标签)训练,学会了"给任意 session 打分的能力"。
IPA 利用这个打分能力,给 Beam Search 产生的合成 session 评分,再选出 chosen/rejected。
不能反过来——直接把真实日志当 DPO 数据,因为真实日志根本给不了对比对(原因一),且旧 session 会导致 log-ratio 不稳定(原因二),合成 session 也没有真实用户行为标签。

类比:厨师(RM)从 10 万道顾客真实点评的菜里学会了"什么好吃"。比赛中他给自己新发明的菜(Beam Search 合成 session)打分,选最好和最差的配方来改进。真实日志给了 RM 的知识来源,但比较对象是模型自己生成的合成 session——两件事的数据需求完全不同。

RM 训练数据 IPA DPO 数据
数据来源历史真实曝光 sessionBeam Search 生成的合成 session
标签真实 swt/ltr(用户行为日志)RM 预测分数(无真实标签)
用途让 RM 学会打分构造 (chosen, rejected) 偏好对
为什么不能互换真实 session 没有可比对的"另一条路径"合成 session 没有真实用户行为标签

DPO 训练需要 preference pairs(好的 session vs 差的 session)。推荐系统中用户不会明确表示"我更喜欢这个 session",且 Beam Search 生成的合成 session 没有真实用户行为标签,因此 OneRec 训练一个多目标奖励模型(session 级别打分,非 point-wise)来模拟用户偏好。

📄 论文原文翻译(Section 3.3.1 Reward Model Training)

我们用 $R(\bm{u}, \mathcal{S})$ 表示奖励模型,它负责为不同用户选择偏好数据。其中,输出 $r$ 表示用户 $u$(通常由用户行为表示)对 session $\mathcal{S}=\{\bm{v}_1, \bm{v}_2, \ldots, \bm{v}_m\}$ 的偏好奖励值。

为了使 RM 具备对 session 进行排序的能力,我们首先对 session $\mathcal{S}$ 中每个 item $\bm{v}_i$ 提取 target-aware 表示 $\bm{e}_i = \bm{v}_i \odot \bm{u}$,其中 $\odot$ 表示 target-aware 操作(例如对用户行为做 target attention)。由此得到 session $\mathcal{S}$ 的 target-aware 表示序列 $\bm{h} = \{\bm{e}_1, \bm{e}_2, \cdots, \bm{e}_m\}$。

接着,session 内各 item 通过 self-attention 层相互交互,融合不同 item 之间的必要信息:

$$\bm{h}_f = \mathrm{SelfAttention}(\bm{h}\bm{W}^Q_s,\ \bm{h}\bm{W}^K_s,\ \bm{h}\bm{W}^V_s)$$

然后,我们使用不同的 tower 对多目标奖励进行预测,RM 使用大量推荐数据进行预训练

$$\hat{r}^{swt} = \texttt{Tower}^{swt}\big(\texttt{Sum}(\bm{h}_f)\big),\quad \hat{r}^{vtr} = \texttt{Tower}^{vtr}\big(\texttt{Sum}(\bm{h}_f)\big)$$ $$\hat{r}^{wtr} = \texttt{Tower}^{wtr}\big(\texttt{Sum}(\bm{h}_f)\big),\quad \hat{r}^{ltr} = \texttt{Tower}^{ltr}\big(\texttt{Sum}(\bm{h}_f)\big)$$ $$\text{其中}\quad \texttt{Tower}(\cdot) = \texttt{Sigmoid}\big(\texttt{MLP}(\cdot)\big)$$

在得到每个 session 的所有预测奖励 $\hat{r}^{swt}, \ldots$ 以及真实标签(ground-truth labels)$y^{swt}, \ldots$ 之后,我们直接最小化二值交叉熵损失来训练 RM:

$$\mathcal{L}_{\rm RM} = -\sum_{swt,\ldots}^{xtr}\left(y^{xtr}\log(\hat{r}^{xtr}) + (1-y^{xtr})\log(1-\hat{r}^{xtr})\right)$$

补充说明:论文未具体说明 ground-truth label 的构造方式(如 swt 是绝对时长还是归一化比例),仅说"使用大量推荐数据预训练 + binary cross-entropy loss"。RM 是 session 级别打分,而非 point-wise 对单个视频打分——通过 self-attention 让 session 内 5 个视频互相感知后 Sum 池化得到整体表示,能捕捉单视频排序做不到的多样性/连贯性信息。

💡 举例:奖励模型给 Session 打分

OneRec 用 Beam Search 为某个用户生成了 3 个不同的候选 session:

Session A:[搞笑段子①, 搞笑段子②, 搞笑段子③, 搞笑段子④, 搞笑段子⑤] → 主题重复,用户可能看了前 2 个就滑走。Reward Model 预测:swt=0.12, ltr=0.05 → 综合分低。

Session B:[搞笑段子①, 科技评测①, 美食探店①, 搞笑段子②, 健身教程①] → 多样但用户兴趣匹配度参差不齐。Reward Model 预测:swt=0.19, ltr=0.09 → 综合分中等。

Session C:[搞笑段子①, 搞笑段子②, 科技评测①, 美食探店①, 搞笑段子③] → 主题连贯 + 适度多样。Reward Model 预测:swt=0.22, ltr=0.12 → 综合分最高。

IPA 选择 Session C 为 chosen,Session A 为 rejected,构成 DPO 训练的偏好对。

2.5 迭代偏好对齐(Iterative Preference Alignment, IPA)

标准 DPO 只用一次,IPA 通过迭代自我改进的方式持续提升质量:

  1. 1
    用当前模型 $\mathcal{M}_t$ 通过 Beam Search(beam size=128)为每个用户生成 $N$ 个不同 session
  2. 2
    用 Reward Model $R(u, S)$ 对每个 session 打分
  3. 3
    选分数最高的 session 为 chosen $S^w_u$,分数最低的为 rejected $S^l_u$
  4. 4
    对每个训练样本,以概率 $r_\text{DPO}=1\%$ 进入 DPO 分支:若进入,则在线构造偏好对并计算 $\mathcal{L}_\text{NTP}+\lambda\mathcal{L}_\text{DPO}$;否则只计算 $\mathcal{L}_\text{NTP}$
  5. 5
    得到新模型 $\mathcal{M}_{t+1}$,用新模型重新生成候选 session,回到步骤 1
$$\mathcal{L}_\text{DPO} = -\log\sigma\left(\beta\log\frac{\mathcal{M}_{t+1}(S^w_u|H_u)}{\mathcal{M}_t(S^w_u|H_u)} - \beta\log\frac{\mathcal{M}_{t+1}(S^l_u|H_u)}{\mathcal{M}_t(S^l_u|H_u)}\right)$$
符号说明
  • $\mathcal{M}_{t+1}$:当前更新中的模型
  • $\mathcal{M}_t$:reference 模型(固定,用于计算 KL 惩罚基准)
  • $S^w_u$:用户 $u$ 的 chosen session(RM 分最高)
  • $S^l_u$:用户 $u$ 的 rejected session(RM 分最低)
  • $\beta$:KL 惩罚系数,防止过度偏离参考模型

总训练 loss 为:

$$\mathcal{L} = \mathcal{L}_\text{NTP} + \lambda \cdot \mathcal{L}_\text{DPO}$$
IPA 里 NTP 和 DPO 是同一训练阶段联合优化,但论文没有把实现细节写到“每个 batch 如何拼”这么细

按论文 Algorithm 2 的写法:对每个训练 sample,先按概率 $r_\text{DPO}=1\%$ 判断本次是否进入 DPO 分支。
若进入 DPO 分支:当前模型先在线生成候选 session,RM 选出 best / worst,再计算总损失 $\mathcal{L}=\mathcal{L}_\text{NTP}+\lambda\mathcal{L}_\text{DPO}$;若不进入 DPO 分支:只计算 $\mathcal{L}_\text{NTP}$。

因此,可以确定的是:
① IPA 阶段不是“先完全做完 NTP 再切到 DPO”的两阶段;
② DPO 所需的偏好对不是固定离线数据,而是由当前模型在线生成;
③ 论文明确保留了 $\mathcal{L}_\text{NTP}$,用于在偏好对齐时继续稳定生成能力。

但要注意:论文没有明确展开说明 DPO 分支中的 $\mathcal{L}_\text{NTP}$ 具体是对哪条序列计算,因此这里不能擅自写成“对 chosen 做 teacher forcing”之类超出原文的信息。
💡 怎么理解“DPO 样本”这件事

这里的“DPO 样本”不是像传统监督学习那样,提前放在离线数据集里的固定样本,而是 IPA 训练过程中由当前模型在线生成 的偏好对:

  • 先给定一个用户历史 $H_u$
  • 当前模型 $\mathcal{M}_t$ 用 Beam Search 生成 $N$ 个候选 session
  • RM 给这 $N$ 个候选打分
  • 最高分作为 chosen $S^w_u$,最低分作为 rejected $S^l_u$

于是得到一个在线构造的偏好对 $(H_u, S^w_u, S^l_u)$,再用于计算 $\mathcal{L}_{\text{DPO}}$。因此,DPO 数据不是“事先标好的训练集”,而是“训练过程中当前模型自己生成、RM 再筛出来的 pair”。

注意:论文确认了进入 DPO 分支时总损失写作 $\mathcal{L}_{\text{NTP}} + \lambda \mathcal{L}_{\text{DPO}}$,但没有展开说明这个分支里 $\mathcal{L}_{\text{NTP}}$ 的监督对象具体是哪条序列,因此这里不再额外假设实现细节。

💡 举例:为什么要"迭代"而非一次 DPO

第 1 轮:模型质量较弱,Beam Search 生成的最优 session 也只能打 0.22 分(勉强好),rejected 打 0.08 分(明显差)。DPO 能学到一些偏好信号,但 chosen session 本身不够好。

第 2 轮(用第 1 轮模型):模型稍强,现在 Beam Search 的最优 session 能打 0.28 分,rejected 还是 0.09 分。DPO 能从更高质量的 chosen 学习更强的偏好信号。

第 3 轮:最优 session 打 0.31 分……如此迭代,每轮的"自我生成的 hard negative"都是当前模型能力边界上的挑战性样本,比一次性用固定负样本训练效果好得多——这就是"自我改进"的本质。

2.6 在线部署架构

OneRec 的在线服务由三个核心组件构成:

OneRec 在线部署架构
Figure 3(论文原图):OneRec 在线部署全景。离线训练 → 参数同步 → 在线推理;同时 DPO Sample Server 从在线流量中采样偏好数据,反馈给训练系统形成持续学习闭环。
  • 离线训练系统:1B 参数模型,使用 XLA + bfloat16 混合精度,支持大规模分布式训练
  • 在线推理服务:KV Cache 加速 + float16 量化减少内存,Beam Search beam_size=128(平衡质量与延迟)
  • DPO Sample Server:仅对 1% 请求进行 DPO 采样(用 Reward Model 打分生成偏好对),供持续在线学习使用
这个模型在线上到底怎么用?

论文给出的核心思路很明确:OneRec 在线上不是当“召回器”或“打分器”用,而是直接充当完整的推荐生成器。也就是说,它一次性完成传统系统里“召回 + 排序 + 列表组织”三件事。

在线请求到来时,大致流程是:
① 取用户最近的行为历史,编码成语义 ID 序列,送入 Encoder;
② Decoder 以自回归方式生成目标 session 的语义 ID 序列(例如 5 个视频,每个视频 3 个 SID token,中间用 BOS 分隔);
③ 在线服务使用 Beam Search 在 SID 空间搜索多个候选序列,beam size = 128;
④ 得到最终的 SID 序列后,再映射回真实视频 ID,作为这一屏的推荐结果返回给用户。

所以从线上 serving 角度看,它不是“先召回一堆候选视频,再用模型逐个打分重排”,而是直接生成最终的推荐列表
💡 举例:一次线上请求是怎么走的

假设某用户最近看过的历史是:[搞笑A, 搞笑B, 科技C, 美食D, 搞笑E, 健身F, ...]。

  • Step 1:Encoder 读历史
    系统先把这些历史视频转成语义 ID token 序列,Encoder 对整段历史做编码,得到用户当前兴趣状态的表示。
  • Step 2:Decoder 生成 session
    Decoder 从 [BOS] 开始,自回归生成一整屏推荐的 SID 序列,比如:
    [BOS, a9, b3, c1, BOS, a4, b5, c4, BOS, a6, b1, c5, BOS, a2, b7, c2, BOS, a9, b1, c3]
  • Step 3:Beam Search 选最优序列
    在线推理不是只保留一条贪心路径,而是保留 beam size = 128 条候选路径,在 SID 空间中比较哪条完整 session 概率最高。
  • Step 4:SID → 视频
    最终把生成出的 5 组 SID 映射回真实视频,得到这一屏真正展示给用户的 5 个视频。

这就是 OneRec 在线 serving 的本质:用户历史 → 生成语义 ID 列表 → 映射回视频 → 直接展示

论文明确写了哪些,没写哪些?

论文明确写了:
  • 在线推理用 KV Cache 加速自回归解码
  • 使用 float16 量化 降低显存/内存开销
  • 在线搜索使用 Beam Search,beam size = 128
  • 单独有一个 DPO Sample Server,只采样 1% 在线流量,用于构造偏好对回流训练
但论文没有展开实现细节,例如:SID 到真实视频 ID 的索引服务怎么做、在线缓存怎么组织、服务拆分成多少个微服务、延迟预算是多少、是否还有额外的规则后处理等。这些都属于工程落地细节,论文图里只给了高层结构,没有写源码级实现。
📊
3. 实验结果

离线对比(vs 传统方法 + TIGER)

模型swt↑ (mean)swt↑ (max)ltr↑ (mean)ltr↑ (max)
SASRec(传统判别式)0.03750.08030.03140.0604
TIGER-1B(逐点生成)0.08730.13680.03230.0579
OneRec-1B(session 生成)0.09910.15290.03600.0660
OneRec-1B+IPA(+偏好对齐)0.10250.19330.03970.1203

OneRec-1B 在 session watch time 的 max 指标上比 TIGER-1B 提升 +41.3%,加上 IPA 后 ltr (max) 提升 +107.8%(0.0579 → 0.1203),说明 IPA 对交互类指标的提升尤其显著。

模型规模消融(Scaling Law)

从 0.05B 到 1B 持续提升性能,具有稳定的 scaling 特性:

  • 0.05B → 0.1B:max swt 提升 +14.45%
  • 0.1B → 0.2B:+5.09%;→ 0.5B:+5.70%;→ 1B:+5.69%

DPO 采样比例消融

在 1% 到 5% 的 DPO 采样比例范围内,1% 比例已能获得约 95% 的最优性能,而 5% 需要 5 倍 GPU 资源。论文选择 1% 作为在线部署的工程平衡点。

在线 A/B 测试(快手主页信息流,1% 流量,1 个月)

模型总观看时长人均视频时长
OneRec-0.1B+0.57%+4.26%
OneRec-1B+1.21%+5.01%
OneRec-1B+IPA+1.68%+6.56%

在快手这样的超大规模平台上,1.68% 的观看时长提升代表着极大的商业价值(对应数亿用户每天数百万小时的增量观看时长)。

💡
4. 个人理解与启发

最重要的贡献

  • Session-wise 生成是核心创新:不是"生成单个推荐"而是"生成推荐列表",让模型能感知多视频之间的关系,这是 OneRec 超越 TIGER 的关键。
  • IPA = 自我博弈式提升:用当前模型的 beam search 结果构造 hard negative,再 DPO 训练,形成正向循环。这是 AlphaGo 自对弈思想在推荐系统的应用。
  • 1% DPO 是工程智慧:论文中仔细分析了计算资源与性能的权衡,最终选择 1% 而非更大比例,这种工程意识在工业论文中非常难得。

潜在不足

  • Session-wise 生成要求训练数据中有高质量 session 标注,数据集构建成本高(需要满足 3 个以上筛选条件的真实 session)。
  • Reward Model 本身的质量直接影响 IPA 的上限——如果 RM 不准,chosen/rejected 的区分就会有噪声,DPO 效果打折。
  • MoE 推理需要 All-to-All 通信,分布式部署时可能成为延迟瓶颈(尤其是 expert 跨卡分布时)。

对我的启发

OneRec 给了我一个重要信号:生成式推荐的潜力不仅在于"好的 item tokenization",更在于"好的生成目标"。Session-wise 生成让模型优化的目标更接近线上真实场景(用户不是孤立地接受每个推荐,而是整体评价这一屏内容的质量),这种"任务定义的优化"往往比"模型架构的优化"带来更大的收益。

论文链接:arXiv 2502.18965

关键词:生成式推荐 · Session-wise 生成 · MoE · DPO · 偏好对齐 · 端到端推荐

对比基线:SASRec, BERT4Rec, TIGER, DPO/IPO/cDPO 等多种变体