OneRec-V1 已经完成从多级漏斗到端到端生成推荐的范式转换,并在快手主 Feed 承接了 25% 的流量。但 V1 存在两个根本性瓶颈,V2 的全部工作都是围绕解决这两个问题展开的。
2.1 设计原则:为什么不直接用 Decoder-Only?
推荐系统中一条训练样本由"历史序列(Context)+ 目标 item(Target)"构成,只对 Target 计算 Loss。标准 Naive Decoder-Only 会把 Context 和 Target 拼接成一个序列,整体通过 Self-Attention——这样 Context 的计算量和 Decoder-Only 的 Encoder-Decoder 一样多,效率并无提升(见下表)。
| 架构 | 总 FLOPs(GFLOPs) | Target 解码 FLOPs | Target 占比 |
|---|---|---|---|
| Encoder-Decoder 0.5B:0.5B(V1) | 346 | 8.1 | 2.34% |
| Naive Decoder-Only 1B | 632 | 18 | 2.85% |
| Lazy Decoder-Only 1B(V2) | 18 | 18 | ≈ 100% |
2.2 Context Processor(异构用户特征统一化)
Step 0:三路特征进来是啥样的
以 1B 模型为例($d_{model}=1792, N_{head}=14, d_{head}=128$):
| 特征路 | 来源 | 经过 | 输出形状 | 典型长度 |
|---|---|---|---|---|
| User Static | 年龄 / 性别 / 地域 / 设备 | Embedding → Linear | $N_s$ 个向量,1792 维 | $N_s=4$ |
| Short-term | 最近 10 分钟互动视频 | Embedding → Transformer | $T_{short}$ 个向量,1792 维 | $T_{short}=50$ |
| Long-term | 过去 6 个月行为摘要 | Embedding → Pooling | $T_{long}$ 个向量,1792 维 | $T_{long}=458$ |
三路 concat 成一条序列:
Context = [static_0, static_1, ..., short_0, ..., long_0, ...]
形状:(N_s + T_short + T_long) × d_model
= (4 + 50 + 458) × 1792
= 512 × 1792
Step 1:维度设计——为什么要用 $d_{\text{context}}$ 公式
Context 最终要变成 Cross-Attention 可以用的 K/V,而 Cross-Attention 的 K/V 维度必须匹配 Q 的 head 结构。公式:
以默认配置 $S_{kv}=1, L_{kv}=1, G_{kv}=14, d_{head}=128$ 为例:$d_{\text{context}} = 1 \times 1 \times 14 \times 128 = 1792 = d_{model}$。
每个 1792 维的 context 向量,沿特征维度被切分成 $S_{kv} \times L_{kv} = 1$ 份(因为所有层共享同一组 KV),每份形状为 $G_{kv} \times d_{head} = 14 \times 128$。
Step 2:RMSNorm 产出最终 K/V
# 默认配置 L_kv=1, S_kv=1 时: k_0 = RMSNorm(C_0) # 512 × 14 × 128 v_0 = k_0 # S_kv=1 → K/V 共享同一表示,不需要额外投影 # 如果 S_kv=2(K/V 独立): k_0 = RMSNorm_k(C_0 的前半) # 512 × 14 × 128 v_0 = RMSNorm_v(C_0 的后半) # 512 × 14 × 128 # 如果 L_kv=3(每 6 层共享一组 KV): # Context 沿特征维度切成 3 份 → C_0, C_1, C_2 # Layer 0-5 用 k_0/v_0, Layer 6-11 用 k_1/v_1, Layer 12-17 用 k_2/v_2
Step 3:各层如何使用这组 KV
- K/V 只计算一次:Context Processor 在进入所有 Decoder Block 之前就预计算完毕,18 层全部复用同一组 KV($L_{kv}=1$)
- 去掉 $W_K$、$W_V$ 投影层:传统 Cross-Attention 每层都有独立的 $W_K$、$W_V$ 矩阵,把 encoder 输出投影成该层的 K/V。Lazy 版本直接用预计算的 KV,完全不做投影,省掉了这部分参数和计算
- Query 仍然有 Linear:Q 来自 target item tokens(只有 BOS + s1 + s2 = 3 个),经 $W_Q$ 投影,支持 GQA
- 计算量对比:传统每个 Block 的 Cross-Attention = $W_Q$ + $W_K$ + $W_V$ 三次大矩阵乘;Lazy 版本 = $W_Q$ 一次矩阵乘(K/V 已预计算好)
❌ 传统 Encoder-Decoder(V1)
Context → Encoder(18层 Self-Attention)→ memory 每个 Decoder Block: memory × W_K → K ← 每层独立投影 memory × W_V → V ← 每层独立投影 target × W_Q → Q Attention(Q, K, V) ↑ Encoder 消耗 ~97% FLOPs ↑ 每层还有 W_K/W_V 投影,额外参数+计算
✅ Lazy Decoder-Only(V2)
Context → Linear + RMSNorm → KV(一次,极轻量) 每个 Decoder Block: 直接用预计算的 K/V ← 无投影,18层共享 target × W_Q → Q Attention(Q, K, V) ↑ Context 完全不做 Self-Attention ↑ K/V 预计算一次,省掉 18× W_K/W_V
$L_{kv}$ 和 $S_{kv}$ 的消融直觉
| 参数 | 含义 | 实验结论 | 直觉解释 |
|---|---|---|---|
| $L_{kv}=1$ | 18 层全共享同一组 KV | Loss 3.27,与 L=18 几乎一样 | 用户画像在不同 Decoder 层看起来都差不多——"年龄=25"不会因为层深就变了 |
| $L_{kv}=9$ | 相邻 2 层共享一组 KV | Loss 3.27,FLOPs 略增 | 中间值,略增灵活性但收益极小 |
| $L_{kv}=18$ | 每层独立 KV | Loss 3.27,显存 +2.3× | LLM 每层 KV 差异大(语义逐层抽象),推荐 Context 却很稳定,所以共享完全 OK |
| $S_{kv}=1$ | K/V 共享同一表示 | Loss 3.27,省一半 KV 显存 | "哪些 item 是我历史互动"和"我对这些 item 的偏好强度"在推荐 Context 中信息重叠度高 |
| $S_{kv}=2$ | K/V 各有独立 RMSNorm | Loss 3.27,略增参数 | 独立 K/V 更灵活,但对推荐 Context 无明显收益 |
2.3 Lazy Decoder Block 结构
每个 Lazy Decoder Block 包含三个子模块,按以下顺序执行:
2.4 Scaling Law 验证
首次在生成式推荐系统验证 Scaling Law,实验覆盖 0.1B 到 8B Dense 模型及 4B MoE 模型。拟合结果:
| 模型规模 | d_model | 层数 | 收敛 Loss | 备注 |
|---|---|---|---|---|
| 0.1B Dense | 640 | 12 | 3.57 | |
| 0.5B Dense | 1408 | 14 | 3.33 | |
| 1B Dense | 1792 | 18 | 3.27 | 线上部署规格 |
| 2B Dense | 2304 | 22 | 3.23 | |
| 4B Dense | 2944 | 26 | 3.20 | |
| 8B Dense | 3584 | 34 | 3.19 | |
| 4B MoE(0.5B 激活) | 1408 | 14 | 3.22 | 超越 2B Dense,仅需 0.5B 激活算力 |
- Lazy Decoder-Only 在相同 FLOPs 下与 Encoder-Decoder 收敛 Loss 持平,却节省 94% 计算量
- Loss 曲线平滑下降,与 Chinchilla Scaling Law 高度吻合,说明生成式推荐同样遵循 LLM 规律
- 4B MoE 以 0.5B 激活参数的代价,达到接近 4B Dense 的效果,是工业落地的最优配比
V2 的后训练分两阶段:① SFT(流式曝光数据,与预训练同 Loss)保持实时兴趣捕捉并防止偏离;② RL 基于真实用户反馈,取代 V1 的 Reward Model 方案。
3.1 Duration-Aware Reward Shaping
视频观看时长(play time)是最密集的反馈信号,但有时长偏差:长视频天然有更高绝对观看时长,简单用 play time 作 Reward 会让模型偏向推长视频。
- 对历史视频按时长取对数分桶:$b = \lfloor \log_{\beta}(d + \epsilon) \rfloor$($\beta$ 控制粒度,$\epsilon$ 防数值问题)
- 对目标视频,找出历史记录中相同时长桶内的所有观看时长,计算其分位数排名 $q_i$: $$q_i = \frac{|\{p_j \in P_{u,b} \mid p_j \le p_i\}|}{|P_{u,b}|}$$
- 同批次内按 $q_i$ 排序,前 25%(top quartile)为正样本($A_i=+1$),显式"不喜欢"行为为负样本($A_i=-1$),其余过滤($A_i=0$)
这样同一用户对一个 3 分钟视频完整观看,比对一个 30 秒视频只看 5 秒,reward 更高——体现了真实满意度而非绝对时长。
3.2 GBPO:Gradient-Bounded Policy Optimization
3.2.1 两类训练样本
OneRec 在 RL 阶段使用的曝光样本来自两个源:
| 来源 | $\pi_{old}$ 是什么 | ratio $r = \pi_\theta / \pi_{old}$ | 占比 |
|---|---|---|---|
| OneRec 自身曝光 | 真实记录的曝光时刻概率 | $\pi_\theta / \pi_{old}$(动态变化) | ≤ 25% 流量 |
| 传统 pipeline 曝光 | 不可知 → 简化为 $sg(\pi_\theta)$ | $\equiv 1$ 恒定 | ≥ 75% 流量 |
3.2.2 ratio=1 引发的两个连锁问题
问题 1:clipping 失效。GRPO/PPO 的损失为 $\min(r \cdot A,\ \text{clip}(r, 1-\epsilon, 1+\epsilon) \cdot A)$,当 $r \equiv 1$ 时 clip 永不触发,对这 75% 样本毫无保护。
问题 2:负样本梯度爆炸。把 $\pi_{old} = sg(\pi_\theta)$ 代入并求导:
$sg()$ 阻断对分母的求导,但分母数值 $= \pi_\theta$。所以梯度系数为 $1/\pi_\theta$。负样本时 $A_i < 0$,模型会尝试压低 $\pi_\theta$,但 $\pi_\theta$ 越小梯度系数越大——形成正反馈。
关键不在"是不是常数",而在这个常数的数值会不会随 $\pi_\theta$ 同步漂移:
- 真实 $\pi_{old}$(如 0.2)= 历史快照:写死在日志里。$\pi_\theta$ 怎么变它都是 0.2,梯度系数恒为 $1/0.2 = 5$,稳定。
- $sg(\pi_\theta)$ = 当前镜像:数值始终等于 $\pi_\theta$,$\pi_\theta$ 掉到 0.01 它也变 0.01,梯度系数变 100。"对照组"和"实验组"同步漂移,比较失去意义。
3.2.3 关键观察:BCE 梯度天然有界
对二元分类的 BCE Loss,单个负样本($y=0$)的梯度为:
| $\pi_\theta$(或 $p_\theta$) | RL 系数 $\frac{1}{\pi_\theta}$ | BCE 系数 $\frac{1}{1-p_\theta}$ | 对比 |
|---|---|---|---|
| 0.5 | 2 | 2 | 持平 |
| 0.1 | 10 | 1.11 | RL 是 BCE 的 9× |
| 0.01 | 100 | 1.01 | RL 是 BCE 的 99× |
| 0.001 | 1000 | 1.001 | RL 已经爆炸 |
BCE 的"自洽性":模型越确定一个样本是负的,梯度越小(已经学好了不再用力);而 RL 反过来,越确定越用力——这是 RL 不稳定的数学根源。
3.2.4 GBPO 的设计:用 max() 把 RL 梯度对齐到 BCE
不裁剪分子(不丢弃任何样本),只在分母引入动态下界。
为什么这个 max() 恰好等价于 BCE 梯度?对 ratio=1 的传统 pipeline 样本($\pi_{old} = \pi_\theta$),代入并讨论 $\pi_\theta < 0.5$ 时:
系数 $\frac{1}{1-\pi_\theta}$ 正好是 BCE 负样本的梯度系数!这就是"以 BCE 梯度为 RL 梯度的上界"的精确含义。$\pi_\theta \to 0$ 时系数 $\to 1$,梯度有界、稳定。
正样本同理:$\max(\pi_{old}, \pi_\theta)$ 在 $\pi_\theta$ 已经很大时取 $\pi_\theta$,对应 BCE 正样本梯度系数 $1/p_\theta$,避免"模型已经很自信"时 ratio 变大引起更新震荡。
3.2.5 GBPO vs GRPO/ECPO 三方对比
| 方法 | 核心机制 | 对 ratio=1 样本 | 对负样本梯度爆炸 | 是否丢弃样本 |
|---|---|---|---|---|
| GRPO / PPO | $\text{clip}(r, 1\!-\!\epsilon, 1\!+\!\epsilon)$ | ❌ 永不触发 | ❌ 不解决 | 是(clip 外丢弃) |
| ECPO(V1) | $\text{clip}$ 应用在 $\pi_{old}$ 而非 $r$ 负样本仅设上界 |
⚠️ 部分缓解 | ⚠️ 仍可能 | 是(部分负样本丢弃) |
| GBPO(V2) | 分母引入 $\max()$ bound 对齐 BCE 梯度 |
✅ 直接处理 | ✅ 数学可证 | 否(全样本利用) |
3.2.6 实验验证(论文图 9)
- ECPO 负样本 gradient norm:在 0–5 之间剧烈震荡,多次出现脉冲峰值,模型最终 Loss 发散。
- GBPO 正/负样本 gradient norm:均稳定在 0.04–0.14 区间内平滑波动,训练全程无发散。
- 线上 A/B(快手主 Feed)相比纯 ECPO 基线:App 停留时长 +0.467%、互动指标全线提升。
3.3 Reward Model vs 真实用户反馈 vs Hybrid
| 指标(快手主 Feed) | Reward Model | User Feedback | Hybrid |
|---|---|---|---|
| App 停留时长 | +0.269% | +0.299% | +0.283% |
| Watch Time | +0.537% | +0.610% | +0.118% |
| Video View | +0.505% | +0.647% | +0.647% |
| Like | +6.552% | +2.435% | +7.010% |
| Follow | +7.265% | +2.007% | +8.458% |
| Comment | +15.472% | +0.944% | +8.763% |
关键发现:Reward Model 更擅长提升互动指标(Like/Follow/Comment),User Feedback 更擅长提升 App 停留时长(时长类指标)。两者方向互补,Hybrid 版本兼顾了两者,但不能简单叠加(有重叠)。
最终 V2 上线规格:1B 参数、context length 3000、Beam Size 512,L20 GPU 推理,时延 36ms,MFU 62%。使用 5% 流量实验组,观测一周。
| 场景 | 指标 | OneRec-V2 vs V1 |
|---|---|---|
| 快手主 Feed | App Stay Time | +0.467% |
| LT7(7日留存) | +0.069% | |
| Watch Time | +1.367% | |
| Video View | +0.331% | |
| Like | +3.924% | |
| Follow | +4.730% | |
| Comment | +5.394% | |
| Collect | +2.112% | |
| Forward | +3.183% | |
| 快手极速版 | App Stay Time | +0.741% |
| LT7(7日留存) | +0.034% | |
| Watch Time | +0.762% | |
| Video View | +0.259% | |
| Like | +5.393% | |
| Follow | +5.627% | |
| Comment | +5.013% | |
| Collect | +3.202% | |
| Forward | +7.958% |
特别说明:论文额外报告了"关闭缓存"(Caching Disabled)的 1% 流量实验,交互指标(Like/Follow/Comment/Forward)在两个平台的涨幅达到 9.6%–29.2%,但同时观察到冷启动视频曝光减少(44.7% / 36.7%)和 cluster density 上升,说明高强度 RL 对生态系统存在影响,这是未来需要关注的方向。
| 维度 | OneRec-V1 | OneRec-V2 |
|---|---|---|
| 预训练架构 | Encoder-Decoder(0.5B:0.5B,含 MoE Decoder) | Lazy Decoder-Only(1B 上线,支持至 8B) |
| Context 处理方式 | Encoder 完整处理 → Cross-Attention 注入 | Context Processor 线性变换 → 直接作为 KV,不做 Self-Attention |
| 计算分配 | 97.66% FLOPs 用于上下文编码 | ≈ 100% FLOPs 用于 Target 解码 |
| 可扩展规模 | ~0.5B(受制于编码计算量) | 0.1B → 8B,验证 Scaling Law |
| RL 奖励来源 | Reward Model(proxy reward) | Duration-Aware 真实用户反馈 + 可选 Reward Model Hybrid |
| RL 算法 | ECPO(Early Clipped GRPO) | GBPO(Gradient-Bounded Policy Optimization) |
| On-Policy 覆盖 | 1% 用户 roll-out | 25% 流量(OneRec 自身生成样本) |
| 在线时延 / MFU | 未明确披露 | 36ms,MFU 62%(L20 GPU) |
| App 停留时长增益 | 快手 A/B +1.68%(总观看时长) | 快手 +0.467%,快手极速版 +0.741%(App Stay Time,基于 V1) |
核心洞察
- 计算效率是 Scaling 的前提:V1 的 Encoder-Decoder 架构虽然合理解决了"历史序列 vs 目标 item"异构问题,但 97% FLOPs 浪费在不参与 Loss 的 Context 编码上,根本上限制了模型规模上限。Lazy Decoder 彻底解决了这个矛盾——把 Context 降级为"静态 KV 条件",让 Decoder 专注于生成决策。
- Scaling Law 在推荐系统成立:这是该领域首次系统验证 Chinchilla 风格的 Scaling Law 曲线,从 0.1B 到 8B 平滑下降,为未来更大规模的生成式推荐提供了理论支撑和工程路线图。
- On-Policy 数据是 RL 自我进化的关键:V1 因覆盖率有限,无法使用自身生成的样本训练。V2 借助 25% 流量覆盖,用 OneRec 自身曝光样本做 on-policy RL,Video View 等全面指标均转正,体现了自我迭代的复利效应。
- Reward 偏好决定优化方向:Reward Model 更偏互动指标,真实时长 Reward 更偏停留时长,Hybrid 策略能在两者之间取得平衡而不加剧 seesaw 效应。选择 Reward 定义即选择模型优化的"北极星指标"。
- GBPO 解决了 ratio=1 时的梯度稳定问题:传统 pipeline 样本因无法获取老策略概率,$\pi_{old}=sg(\pi_\theta)$,ratio 恒为 1,GRPO/ECPO 等 clipping 方法无法截断,负样本梯度爆炸。GBPO 以 BCE 梯度为动态上界,是该问题的优雅解法。
局限与未来方向
1. 长期价值与短期信号的对齐
当前 Duration-Aware Reward 仍是基于规则的短期代理指标(观看时长分位数),并非用户长期满意度的直接信号。论文指出下一步要让模型直接优化长期价值(LT7 等),而非短期观看行为。
2. 冷启动与生态多样性
关闭缓存的实验观察到冷启动视频曝光下降 44.7%(快手)和 36.7%(极速版),cluster density 上升,说明强 RL 可能导致推荐同质化,对内容生态造成影响,需要在 Reward 设计中加入多样性约束。