谷歌-PCR-CA-联合训练并行小码本引入语义特征
这里分享一篇谷歌的文章《PCR-CA: Parallel Codebook Representations with Contrastive Alignment for Multiple-Category App Recommendation》,在谷歌应用商店场景中,构建端到端 CTR 预测架构,用更紧凑、可解释的离散语义表示刻画多类应用的多维属性;将内容语义与协同 ID 表示对齐,让冷启/长尾也能受益…
论文地址:https://arxiv.org/pdf/2508.18166
文章目录
- 1. 背景
- 2. 方法
- 2.1 多模态 embedding 抽取
- 2.2 PC-AE(Parallel Codebook Auto-Encoder)
- 2.3 Contrastive Alignment Module
- 2.4 双注意力融合
- 3. 实验
- 3.1 主实验
- 3.2 消融实验
- 3.2.1 对比对齐 与 Codebook
- 3.2.2 注意力融合模块
- 3.3 AB
- 4. 总结
1. 背景
-
现实是多维叠加,而不是树形里的一片叶子:很多 App 同时属于多种类别:比如游戏 Mafia 同时是 “犯罪、射击、动作”, Wolfenstein 是 “射击、动作、血腥”;非游戏 微信主打“消息”,但也有“短视频、电商”,TikTok 是 “娱乐” 覆盖 “短视频、电商”。这些都是交叠的语义集合,不符合传统“树形类别、单一路径”的假设。
-
为什么老办法不行:传统 CTR 往往把 “类别” 当做固定的离散特征(比如只给 Wolfenstein 贴一个 “射击”),这样会过渡简化真实语义;用户可能更喜欢 “射击 + 动作 + 犯罪” 的组合,但只保留特征 “射击” 这一面,学出来的物品表征就会失真,后续 MLP/Attention 再怎么学也难把丢失的信息补回来。结果就是:不准确的表征 --> 次优的推荐效果。
- 长尾问题严重:谷歌商店 8万+ 个 App,前 100 个就拿走了 63.6% 的所有点击,剩下的几万个只能分剩下的四成不大,越往后越稀疏。马太效应–>放大流行度偏置、降低推荐多样性。
引入 “内容信号” 是缓解 冷启动、长尾 的常规思路(即便长尾几乎没交互,内容仍在),但直接把高维内容信息拼进 CTR 有坑:1、dim 大但是信噪比低 2、 与协同空间不对齐。
作者采用:①用 “离散、可组合” 的并行 codebook 学语义;②用 “对比式对齐” 把内容语义空间 <–> 协同 id 空间拉到一起;③用 “双路注意力”稳妥融合。
2. 方法
2.1 多模态 embedding 抽取
这里作者只用了 “应用标题 + 描述” 拼成一段文本,喂入 微软的 text-embedding 模型给每个 App 一个 256 维的向量 eie_iei ,这就是后续 PC-AE 的输入。
- 不微调,直接冻结。理由:预训练模型自带海量语义知识,直接用能省训练成本、也更稳;他们的预实验发现,即时不微调,后面的 PC-AE 与 CTR 联合学习也能自适应把表示调到合适。
- 不加图片。理由:在 “应用推荐” 里,图片相对信息增量有限,而文本已经覆盖了大部分有用语义,大模型的背景知识能从很短的标题里推理出丰富语义,原始图片不如模型能推出来的知识重要。
2.2 PC-AE(Parallel Codebook Auto-Encoder)
① 输入与编码(Encoder):
把每个 App 的文本向量 ei∈R256e_i\in\mathbb{R}^{256}ei∈R256 先经过一个两层 MLP,得到低维潜向量
zenc,i∈R16.z_{\text{enc},i}\in\mathbb{R}^{16}. zenc,i∈R16.
MLP 之后接 LayerNorm 稳定训练;这一步相当于把与“重建与 CTR 预测”相关的成分提炼出来,作为后续量化的输入。
② 并行码本量化(Parallel Codebooks, Top-K 取码):
设有 NNN 本码本 {C(1),…,C(N)}\{\,\mathcal C^{(1)},\ldots,\mathcal C^{(N)}\,\}{C(1),…,C(N)}。对每一本码本 jjj,在欧氏距离下,从其码字集合里挑选 Top-K(实现里 K=2K=2K=2)个最近的码字向量并相加,得到该本的量化结果:
qi(j)=∑k∈TopK(zenc,i,C(j))ck(j)\mathbf q_i^{(j)} \;=\; \sum_{k\in \mathrm{TopK}\big(z_{\text{enc},i},\,\mathcal C^{(j)}\big)} \mathbf c^{(j)}_{k} qi(j)=k∈TopK(zenc,i,C(j))∑ck(j)
Top-K 允许同一本里同时“点亮”多个子语义(例如同属 射击 与 动作),而多本并行让不同码本各自负责不同方面(如“玩法”“画风”“功能”等)。图里的红色虚框就是在每本码本上挑 K 个码字,底部的 Sum Pooling 表示把这 K 个码字相加。
③ 拼接成离散语义向量(Concatenate):
把 NNN 本的量化结果按通道拼接,得到该物品的离散语义向量:
si=[qi(1)∥⋯∥qi(N)].\mathbf s_i \;=\; \big[\,\mathbf q_i^{(1)} \;\Vert\; \cdots \;\Vert\; \mathbf q_i^{(N)}\,\big]. si=[qi(1)∥⋯∥qi(N)].
需要注意,si\mathbf s_isi 完全由码字索引决定,因此线下/线上只需保存每本码本被选中的索引 (c(1),…,c(N))(c^{(1)},\ldots,c^{(N)})(c(1),…,c(N)),存储极其紧凑;图中右侧“concatenate → Output”对应的就是这一步。
④ 解码与重建损失(Decoder & LreconL_{\text{recon}}Lrecon):
把 si\mathbf s_isi 送入另一端两层 MLP 解码器,重建出 e^i≈ei\hat{\mathbf e}_i\approx \mathbf e_ie^i≈ei。用 L2L_2L2 重建误差约束离散语义要“像原文那样说话”:
Lrecon=∥e^i−ei∥22.L_{\text{recon}} \;=\; \big\|\, \hat{\mathbf e}_i - \mathbf e_i \,\big\|_2^2 . Lrecon=e^i−ei22.
这保证了学到的离散码并不是随便凑出来的,而是能忠实保留文本语义。
⑤ VQ 承诺损失(稳定、避免塌缩):
为每本码本再加一项 VQ(向量量化)承诺损失,既把编码器输出拉向选中码字,又把码字拉向编码器输出,从而稳定训练、提升码本利用率、避免“所有样本挤同一码字”的塌缩:
Lvq(j)=∥zenc,i−sg(qi(j))∥22+β∥qi(j)−sg(zenc,i)∥22,β=0.25,L_{\text{vq}}^{(j)} \;=\; \big\|\, z_{\text{enc},i} - \mathrm{sg}(\mathbf q_i^{(j)}) \,\big\|_2^2 \;+\; \beta \,\big\|\, \mathbf q_i^{(j)} - \mathrm{sg}(z_{\text{enc},i}) \,\big\|_2^2, \quad \beta=0.25, Lvq(j)=zenc,i−sg(qi(j))22+βqi(j)−sg(zenc,i)22,β=0.25,
其中 sg(⋅)\mathrm{sg}(\cdot)sg(⋅) 是 stop-gradient 运算符,第一项主要更新编码器,第二项主要更新码字向量。
⑥ 与 CTR/对齐联合训练(Joint Training):
PC-AE 不是单独训完再接入,而是与主干 CTR 网络、以及后续的对比式对齐(把语义空间与协同 ID 空间对齐)端到端联合优化。总损失为:
Ltotal=LCTR+Lrecon+∑j=1NLvq(j)+LalignL_{\text{total}} \;=\; L_{\text{CTR}} \;+\; L_{\text{recon}} \;+\; \sum_{j=1}^{N} L_{\text{vq}}^{(j)} \;+\; L_{\text{align}} Ltotal=LCTR+Lrecon+j=1∑NLvq(j)+Lalign
这样学到的语义码既保内容、又贴协同、还能直接利于点击预测;图 3 下半部分“Encoder → 多码本并行 → Concatenate → Decoder”与上半部分的对齐/CTR 就对应着这条端到端链路。
2.3 Contrastive Alignment Module
① 物品级(Item-level)对齐:
正样本(positives)
- 同一物品:(si,vi)(s_i,\, v_i)(si,vi)。
- 以及“同一用户在短时间窗口内共同安装”的两物品的交叉配对:若 p,qp,qp,q 被同一用户近时共装,则 (sp,vq)(s_p,\, v_q)(sp,vq) 与 (sq,vp)(s_q,\, v_p)(sq,vp) 也视为正样本。
负样本(negatives)
- 与 iii 无关的同一 batch 中的其它物品(不在正样本集合中的都算负)。
损失(InfoNCE,对称计算)
以 sis_isi 为 anchor、{vj}\{v_j\}{vj} 为对照集,余弦相似 sim(⋅,⋅)\mathrm{sim}(\cdot,\cdot)sim(⋅,⋅),温度 τ\tauτ:
Litem(i)=−log∑j∈P(i)exp(sim(si,vj)/τ)∑j∈P(i)∪N(i)exp(sim(si,vj)/τ).L_{\text{item}}^{(i)} \;=\; -\log \frac{\sum_{j\in \mathcal P(i)} \exp\!\big(\mathrm{sim}(s_i, v_j)/\tau\big)} {\sum_{j\in \mathcal P(i)\cup \mathcal N(i)} \exp\!\big(\mathrm{sim}(s_i, v_j)/\tau\big)} . Litem(i)=−log∑j∈P(i)∪N(i)exp(sim(si,vj)/τ)∑j∈P(i)exp(sim(si,vj)/τ).
作者还做对称项(以 viv_ivi 为 anchor、{sj}\{s_j\}{sj} 为对照),实践中对两种 anchor 的损失求和作为物品级对齐损失。
② 用户级(User-level)对齐:
先以历史的简单均值(非注意力)得到两份“用户画像”:
uuID=mean{vi∣i∈user u的历史},uuSEM=mean{si∣i∈user u的历史}.u_u^{\text{ID}}=\mathrm{mean}\{\,v_i\,|\,i\in\text{user }u\text{ 的历史}\,\},\qquad u_u^{\text{SEM}}=\mathrm{mean}\{\,s_i\,|\,i\in\text{user }u\text{ 的历史}\,\}. uuID=mean{vi∣i∈user u 的历史},uuSEM=mean{si∣i∈user u 的历史}.
同一用户的 (uuID,uuSEM)(u_u^{\text{ID}},\,u_u^{\text{SEM}})(uuID,uuSEM) 为正样本;不同用户交叉 (uuID,uvSEM),u≠v(u_u^{\text{ID}},\,u_v^{\text{SEM}}),\,u\neq v(uuID,uvSEM),u=v 为负样本。对应的 InfoNCE:
Luser(u)=−logexp(sim(uuID,uuSEM)/τ)∑vexp(sim(uuID,uvSEM)/τ).L_{\text{user}}^{(u)} \;=\; -\log \frac{\exp\!\big(\mathrm{sim}(u_u^{\text{ID}},\,u_u^{\text{SEM}})/\tau\big)} {\sum_{v}\exp\!\big(\mathrm{sim}(u_u^{\text{ID}},\,u_v^{\text{SEM}})/\tau\big)} . Luser(u)=−log∑vexp(sim(uuID,uvSEM)/τ)exp(sim(uuID,uuSEM)/τ).
注意:这里没有经过双路注意力;注意力只用于 CTR 打分阶段。
③ 总对齐损失与作用:
把两部分加权求和,得到整体对齐目标:
Lalign=λi∑iLitem(i)+λu∑uLuser(u),L_{\text{align}} \;=\; \lambda_i \sum_i L_{\text{item}}^{(i)} \;+\; \lambda_u \sum_u L_{\text{user}}^{(u)} , Lalign=λii∑Litem(i)+λuu∑Luser(u),
其中 λi,λu\lambda_i,\lambda_uλi,λu 控制两层面对齐的权重;该损失与 CTR、重建、VQ 一起端到端优化。效果是:新/长尾应用的语义嵌入 sss 会落在相似老应用的 ID 嵌入 vvv 附近,即便没有协同数据也能被正确关联到相关用户与物品,相当于把协同知识迁入内容空间
2.4 双注意力融合
① 为什么要两套注意力:
用户都有一串历史交互。打分一个候选 app 时,需要从历史里“挑关键”。作者选用 MLP-式注意力(而不是 Transformer),因为虽然 Transformer 能把 AUC 继续抬约 0.033%,但会显著拖慢线上时延,所以最终使用更轻的 MLP;同时保留两条注意力通道:一条只看协同的 ID 表示,另一条只看语义(代码本得到的离散语义)表示。这样可以分别捕捉协同与内容的相关性,再做稳健融合。
记号与输入:
给定用户 UUU 的历史序列 HU=[i1,…,iT]H_U=[i_1,\ldots,i_T]HU=[i1,…,iT],评估候选 app ccc。
- vijv_{ij}vij:历史项 iji_jij 的 ID embedding,vcv_cvc:候选的 ID embedding。
- sijs_{ij}sij:历史项 iji_jij 的 语义 embedding(来自 PC-AE 代码本),scs_csc:候选的语义 embedding。
② ID-通道注意力:
对每个历史项 iji_jij,把 (vij,vc,vij∘vc)(v_{ij},\, v_c,\, v_{ij}\circ v_c)(vij,vc,vij∘vc) 送入两层 MLP 得到打分 ejIDe^{ID}_jejID(∘\circ∘ 为逐元素乘,模仿 DIN 把交互特征显式乘进去)。然后做 softmax 得到权重:
αjID=exp(ejID)∑k=1Texp(ekID)\alpha^{ID}_j \;=\; \frac{\exp(e^{ID}_j)}{\sum_{k=1}^T \exp(e^{ID}_k)} αjID=∑k=1Texp(ekID)exp(ejID)
③ 语义-通道注意力:
做同样的事,但把特征换成 (sij,sc,sij∘sc)(s_{ij},\, s_c,\, s_{ij}\circ s_c)(sij,sc,sij∘sc),经另一套 MLP 得分 ejSEMe^{SEM}_jejSEM,再 softmax 得到 αjSEM\alpha^{SEM}_jαjSEM。
④ 融合两套注意力:
把两路注意力权重做一个简单平均(作者把它视作 bagging,稳且降方差):
αj=g(αjID,αjSEM)=αjID+αjSEM2\alpha_j \;=\; g(\alpha^{ID}_j,\alpha^{SEM}_j) \;=\; \frac{\alpha^{ID}_j+\alpha^{SEM}_j}{2} αj=g(αjID,αjSEM)=2αjID+αjSEM
用这组最终权重分别汇总两种空间的历史表示:
hUID=∑j=1Tαjvij,hUSEM=∑j=1Tαjsijh^{ID}_U \;=\; \sum_{j=1}^{T}\alpha_j\,v_{ij},\qquad h^{SEM}_U \;=\; \sum_{j=1}^{T}\alpha_j\,s_{ij} hUID=j=1∑Tαjvij,hUSEM=j=1∑Tαjsij
直觉上,hUIDh^{ID}_UhUID 是“和候选在协同上最相关的历史摘要”,hUSEMh^{SEM}_UhUSEM 是“和候选在内容语义上最相关的历史摘要”。
⑤ 预测层输入与 CTR 损失:
把候选的两种表示 (vc,sc)(v_c, s_c)(vc,sc) 与汇总后的历史 (hUID,hUSEM)(h^{ID}_U, h^{SEM}_U)(hUID,hUSEM)(以及可选的用户 ID 向量)拼起来,喂入预测 MLP,输出点击/安装概率 y^Uc\hat{y}_{Uc}y^Uc。CTR 的训练目标是标准二元交叉熵:
LCTR=−[yUclogy^Uc+(1−yUc)log(1−y^Uc)].L_{\text{CTR}} = -\big[y_{Uc}\log \hat{y}_{Uc} + (1-y_{Uc})\log(1-\hat{y}_{Uc})\big]. LCTR=−[yUclogy^Uc+(1−yUc)log(1−y^Uc)].
⑥ 总损失(把四块学在一起):
整套模型端到端联合训练。总损失把四部分相加:
L=LCTR+λrecLrecon+λvq∑j=1NLvq(j)+λalignLalignL \;=\; L_{\text{CTR}} \;+\; \lambda_{\text{rec}}\, L_{\text{recon}} \;+\; \lambda_{\text{vq}} \sum_{j=1}^{N} L^{(j)}_{\text{vq}} \;+\; \lambda_{\text{align}}\, L_{\text{align}} L=LCTR+λrecLrecon+λvqj=1∑NLvq(j)+λalignLalign
这里 LreconL_{\text{recon}}Lrecon 和 ∑Lvq(j)\sum L^{(j)}_{\text{vq}}∑Lvq(j) 来自 PC-AE(重建 + VQ 承诺损失),LalignL_{\text{align}}Lalign 是前一节的对比对齐损失(含 item-level 与 user-level 两部分,用 InfoNCE 形式),用于把语义空间和协同 ID 空间拉到一起,提升冷启动/长尾。作者给了一个典型权重设定:λrec≈1\lambda_{\text{rec}}\approx 1λrec≈1、λvq=0.25\lambda_{\text{vq}}=0.25λvq=0.25,而 λalign\lambda_{\text{align}}λalign 取 0.010.010.01 左右——因为对齐项的绝对值通常比 CTR 损失大两个数量级,需要较小权重防止“喧宾夺主”。
3. 实验
3.1 主实验
3.2 消融实验
3.2.1 对比对齐 与 Codebook
3.2.2 注意力融合模块
这里整体指的是 ”历史如何做注意力选择“:
疑问:把简单的加权平均换成 MoE 门控效果反而变差很多?
作者的解释是:平均=方差降低;门控=方差增大。简单平均本质是 bagging(多个不完全相同的模型 + 简单聚合 --> 更稳、更不容易被噪声带偏),能稳定降低两路注意力的方差和噪声。门控是在学习”偏向谁“,容易随着样本/批次波动,高方差导致泛化差。
3.3 AB
投放位置:Microsoft Store 首页的“Games/Apps we think you Love”版块(一个召回+排序的推荐位)。
实验方式:持续 2 周、覆盖 50% 全量流量、面向 4 个主要市场。也就是把一半用户随机分到实验组(PCR-CA),另一半是对照组(现网 Base)。
4. 总结
PCR-CA 是一套把内容特征“离散化 + 对齐 + 稳健融合”的 CTR 排序框架:用并行码本把文本向量压成少量离散码,再用对比学习把这些“语义码”与协同 ID 空间对齐,并用双路注意力稳健融合到用户历史中,从而在长尾上显著增益。
与我们目前 sid 的利用有所不同,我们可能只是把它放在生成式推荐的第一阶段,而这里是专门设计用来加特征用的,codebook 更小(4*32),也不需要考虑冲突问题。