PROMISE: Process Reward Models Unlock Test-Time Scaling Laws in Generative Recommendations
Kuaishou
把 SID 由粗到细的逐层生成类比为 LLM 的思维链,把首层 token 走错导致后续全错的问题定义为 Semantic Drift,并引入 LLM 推理里的过程奖励模型(PRM)做逐步校验。具体是与生成主干联合训练一个轻量 path-level PRM(单 token 路径嵌入作 query、复用 encoder 输出做 cross-attention,按层 InfoNCE + 均匀负采样),推理时每步先扩到 K+ 条候选、由 PRM 打分剪回 K'=K 条。decoder 计算量不变,加大 K+ 即可做 test-time scaling;快手线上 App 使用时长 +0.12%~0.13%。
核心思路
层级 Semantic ID(SID)由粗到细:首层大致对应类目,后几层逐步细化到具体物品。生成式推荐用 teacher forcing 训练,推理时却要以自己的预测为条件(exposure bias)。论文把这个问题在 SID 上的表现命名为 Semantic Drift:首层或第二层走错之后,后面每一步都在错误的物品簇里搜索,无法回头,模型还会退回训练数据的边际分布,偏向热门物品。
作者把 SID 路径类比为 LLM 的思维链,把数学推理里的 过程奖励模型(PRM) 搬过来,对每一步的中间路径打分:
- Path-level PRM:与生成主干端到端联合训练,输入 (用户, 上下文, 长度为 b 的 SID 前缀),输出一个标量分;用正前缀和均匀采样的负前缀做逐层 InfoNCE。
- PRM-guided Beam Search:每步 decoder 先保留 K+ ≫ K 条候选,PRM 打分后只留 K’ 条进入下一步。K’ = K 时 decoder 计算量不变,于是增大 K+ 就成了一个只花少量额外算力的 test-time scaling 旋钮。
整体实现思路
- 生成主干:标准 encoder-decoder。encoder 编码用户历史序列得到 E(L);decoder 逐层预测 SID,第 b 层隐状态和第 b 层码本 C_b 做点积再 softmax,NTP 损失为 d 层负对数似然之和。
- PRM 分支:复用 encoder 输出 E(L) 作为 key/value,每条候选路径压成一个 query token,经 1 层(工业设置)cross-attention + FFN + MLP 得到分数。
- 联合训练:L_total = L_NTP + Σ_b L_InfoNCE(b)。
- 推理:Algorithm 1,每步「decoder top-K 扩展 → 按 log-prob 选 K+ → PRM 打分选 K’」,共 d 步。
- 部署:线上 K+ = 4000,K = K’ = 1000,PRM 头数为主干的 1/4,用 Radix Top-K 加速大候选集的 top-k。
子模块实现(可复现细节)
1. 正样本定义
目标物品 x_t 的 SID 为 [s_{t,1}, …, s_{t,d}]。第 b 层的正样本是其长度为 b 的前缀:S_pos(x_t, b) = [s_{t,1}, …, s_{t,b}],b ≤ d。理由是在残差量化下,要召回深度 d 的完整路径,必须先召回深度 d−1 的前缀。
2. 负采样
量化码本空间远大于物品数,不是所有 SID 组合都对应真实物品。记 V_b 为长度 b、能对应到真实物品的合法路径集合。每个正样本、每一层,从 V_b \ {S_pos} 中均匀采 N 条互不相同的负路径:
N(x_t, b) = { S_neg_i ~ Uniform(V_b \ {S_pos(x_t,b)}), i = 1..N }
正文未给出 N 的具体值。
3. PRM 结构
- 路径表示:P_S = EmbLookup([s_1, …, s_b])。每条前缀路径映射成一个独立向量,不按 token 序列编码,以减少 attention 计算。
- 交互:P_S 作 query,encoder 最终输出 E(L) 作 key/value,堆 F 层:
- P’ = P + CrossAttn(P, E(L), E(L))
- P = P’ + FFN(RMSNorm(P’))
- 输出:y_S = MLP(P_S^(F)),一个标量 logit。
- 工业设置 F = 1;线上 PRM 注意力头数为主生成模块的 1/4;所有候选 query 并行计算。
4. 训练目标
第 b 层:
L_InfoNCE(b) = −log [ exp(y_pos) / ( exp(y_pos) + Σ_{neg∈N(x_t,b)} exp(y_neg) ) ]
d 层相加,再与 NTP 直接相加:L_total = L_NTP + L_InfoNCE(无权重系数)。
5. PRM-guided Beam Search(Algorithm 1)
B(0) = {[BOS]}, S(0) = {0}
E = Encoder(history)
for b in 1..d:
C = {}
for path P in B(b-1) with score s:
p = softmax(Decoder(P, E) · C_b^T)
for top-K tokens (s_k, p_k): C += (P ⊕ s_k, s + log p_k)
C_K+ = top-K+ of C by log-prob score
Y = PRM(u, c, C_K+) # 并行打分
B(b) = top-K' of C_K+ by Y # 保留的分数仍是累计 log-prob
return B(d)
直接把传统 beam 的 K 加大,decoder 每一步的 self-/cross-attention 计算量都线性增加;而 PROMISE 中 K’ = K 时 decoder 成本不变,额外开销只有 K+ 条路径的单层 cross-attention 和更大的 top-k。
6. 关键超参
| 设置 | 公开集 (Amazon) | 工业集 (快手) |
|---|---|---|
| 量化 | RQ-VAE,3 层,M=256 | Residual K-means(多模态表征),d=3,M=8192 |
| hidden | 256 | 1024 |
| 序列长度 | 40 | 256 |
| 层数 | 未说明 | encoder 4 / decoder 4 / PRM 1 |
| 优化 | Adam lr=0.001,200 epoch,patience 20 | 在线学习 |
| beam | 未说明 | K=K’=1000,K+∈{4000, 6000} |
7. 诊断指标 HRecall@b@k
S(b) 为真值物品 SID 的 b 层前缀集合,B(b) 为第 b 步 beam 中保留的 k 条路径:
HRecall@b@k = |B(b) ∩ S(b)| / |S(b)|
b = d 时等于普通 Recall@k。用它可以看出漂移发生在哪一层。
实验设置与结果
公开集(Amazon,TIGER 划分)
| 方法 | Sports R@5 | Sports N@5 | Sports R@10 | Sports N@10 | Beauty R@5 | Beauty N@5 | Beauty R@10 | Beauty N@10 |
|---|---|---|---|---|---|---|---|---|
| SASRec | 0.0233 | 0.0154 | 0.0350 | 0.0192 | 0.0387 | 0.0249 | 0.0605 | 0.0318 |
| TIGER | 0.0264 | 0.0181 | 0.0400 | 0.0225 | 0.0454 | 0.0321 | 0.0648 | 0.0384 |
| HSTU | 0.0258 | 0.0165 | 0.0414 | 0.0215 | 0.0469 | 0.0314 | 0.0704 | 0.0389 |
| ActionPiece | 0.0316 | 0.0205 | 0.0500 | 0.0264 | 0.0511 | 0.0340 | 0.0775 | 0.0424 |
| PROMISE | 0.0450 | 0.0296 | 0.0689 | 0.0373 | 0.0536 | 0.0345 | 0.0821 | 0.0437 |
| 提升 | +42.41% | +44.39% | +37.80% | +42.19% | +4.90% | +1.47% | +5.60% | +3.07% |
两个数据集的提升差距很大(Sports 约 +40%,Beauty 约 +1.5%~5.6%),论文没有解释原因。
工业集(快手:4 亿+ DAU,日约 500 亿交互,1 亿+ 物品)
| 方法 | R@100 | N@100 | R@500 | N@500 | R@1000 | N@1000 |
|---|---|---|---|---|---|---|
| GRank | 0.1010 | 0.00472 | 0.2396 | 0.01089 | 0.3178 | 0.01422 |
| MPFormer | 0.0706 | 0.00331 | 0.1581 | 0.00694 | 0.2010 | 0.00843 |
| MISS | 0.0844 | 0.00283 | 0.2033 | 0.00741 | 0.2441 | 0.00892 |
| GPRP | 0.0414 | 0.00147 | 0.0661 | 0.00299 | 0.0929 | 0.00415 |
| Kuaiformer | 0.0622 | 0.00293 | 0.1388 | 0.00625 | 0.1761 | 0.00796 |
| CRM | 0.0409 | 0.00215 | 0.0977 | 0.00485 | 0.1437 | 0.00683 |
| PROMISE (K+=4000) | 0.1494 (+47.92%) | 0.00652 (+38.14%) | 0.2836 (+18.36%) | 0.01231 (+13.04%) | 0.3358 (+5.66%) | 0.01445 (+1.62%) |
| PROMISE (K+=6000) | 0.1609 (+59.31%) | 0.00663 (+40.47%) | 0.3017 (+25.92%) | 0.01272 (+16.80%) | 0.3637 (+14.44%) | 0.01504 (+5.77%) |
k 越小,相对提升越大;到 @1000 时,对 GRank 的优势缩小到 +5.66%(K+=4000)。
逐层消融(K=1000,PRM 层的 K+_b=4000)
| ID | PRM@1 | PRM@2 | PRM@3 | HRecall@1@1000 | HRecall@2@1000 | HRecall@3@1000 |
|---|---|---|---|---|---|---|
| (1) | - | - | - | 0.9238 | 0.3718 | 0.2296 |
| (2) | ✓ | - | - | 0.9431 | 0.3738 | 0.2322 |
| (3) | - | ✓ | - | 0.9238 | 0.4435 | 0.2544 |
| (4) | - | - | ✓ | 0.9238 | 0.3718 | 0.2650 |
| (5) | - | ✓ | ✓ | 0.9238 | 0.4435 | 0.3199 |
| (6) | ✓ | - | ✓ | 0.9431 | 0.3738 | 0.2746 |
| (7) | ✓ | ✓ | - | 0.9431 | 0.4711 | 0.2633 |
| (8) | ✓ | ✓ | ✓ | 0.9431 | 0.4711 | 0.3358 |
首层几乎都能召回(92%~94%),主要损失出现在第 2 层(降到约 37%)。第 2、3 层的 PRM 贡献最大,三层全开时最终 Recall 从 0.2296 提到 0.3358,相对 +46%。
Test-time scaling 与效率
- 扩大 K+(图 4):K = K’ = 1000,K+ 从 1000 增到 6000 时,HRecall@2@1000 从 37.18% 升到 49.88%,HRecall@3@1000 从 22.96% 升到 36.37%。直接加大全局 K 的传统做法提升小得多,decoder 计算量却明显上升。
- 对比参数扩展(图 5):从同一基座出发,在约 4.5e11 FLOPs 处,test-time scaling 的 HRecall@3@1000 为 34.37%,参数扩展为 26.67%。
- 模型规模(图 6):参数 0.4× / 1× / 2.5× / 5× 时,HRecall@3@1000 分别为 31.68% / 33.58% / 38.07% / 39.01%。
- 序列长度(图 6):128 / 256 / 1024 时,HRecall@3@1000 分别为 32.68% / 33.58% / 34.29%。
- 部署开销:总参数 +15%,推理延迟 +10%。
线上 A/B(各 5% 流量,约 2000 万用户,7 天;对照为传统 beam search 的生成式模型)
| App | 总使用时长 | CI | 人均使用时长 | CI | 总观看时长 | 单次播放观看时长 |
|---|---|---|---|---|---|---|
| 快手 | +0.121% | [+0.04%, +0.20%] | +0.120% | [+0.06%, +0.18%] | +0.431% | +0.440% |
| 快手极速版 | +0.131% | [+0.03%, +0.23%] | +0.160% | [+0.07%, +0.25%] | +0.398% | +0.296% |
思考与可参考价值
值得借鉴的地方
- 先诊断再动手:HRecall@b@k 能直接告诉你 SID 链路在哪一层丢了目标。快手数据上第 1 层约 92%,第 2 层掉到约 37%,说明真正的瓶颈在中间层。电商 SID 召回或搜索可以先跑这个指标。
- “扩宽 + 轻量剪枝”是一个通用推理旋钮:decoder 成本不变,只靠一个单层 cross-attention 打分器就能换来召回提升,适合延迟预算紧的线上场景。K+ 可以按流量分层或按时段动态调整(推断)。
- PRM 是插件:它复用 encoder 输出、与主干联合训练,不改 decoder,和前缀合法性约束、Q-Former 压缩历史、指针机制等改造是正交的,可以叠加(推断)。
需要警惕的地方
- 基线口径:同主干、传统 beam 下的 Recall@1000 只有 0.2296,明显低于 GRank 的 0.3178。PRM 的大部分收益是在补齐生成式自身的漂移损失;对 GRank 的净增益只有 +5.66%(K+=4000)。落地前要先确认自家生成式模型和现有最强召回的差距。
- 负样本分布不匹配:训练用的是从合法路径均匀采样的“容易”负例,推理时却要在 decoder 给出的高概率候选里分辨好坏。建议补做 beam 内难负例、同父节点兄弟负例的对比实验。
- 路径嵌入表:EmbLookup 给每条前缀一个独立向量。M = 8192、d = 3 时,可能的路径组合非常多,实际只能对合法路径建表(推断)。新物品带来的新路径怎么冷启动,论文没有说明。
- “Scaling law”说法偏强:证据只是 K+ 在 1000~6000 之间 6 个点的单调上升,没有拟合曲线,也没有给出饱和点。
- 线上收益偏小、配置不透明:使用时长 +0.12%~0.13%,对照组的模型规模等细节未披露,也没有开源代码。
一句话:一个工程成本很低、思路清楚的 SID 推理期补丁。适合先在自家 SID 链路上用 HRecall 诊断,再小成本试 K+ 扩宽加 PRM 剪枝;不要把论文里相对弱基线的大幅提升当成预期收益。