文章目录
- 1. 背景与问题
- 2. 方法
- 2.1 多视图 sid
- 2.2 Code-Guided Semantic Fusion
- 核心创新:
- 常规操作:
- 2.3 Enhanced Representation Learning via Code Masking
- 2.3.1 Masked Code Modeling (MCM)
- 2.3.2 Masked Sequence Alignment (MSA)
- 2.4 复杂度分析
- 2.4.1 训练阶段(Training)
- SFM部分
- SR部分
- 总体训练复杂度
- 2.4.2 部署阶段(Deployment)
- 3. 实验
- 3.1 主实验
- 3.2 消融实验
- 3.3 codebook 层数
- 3.4 不同 sid
- 3.5 加 item id
- 4. 总结
这里记录一下人民大学高瓴学院-KDD2025的一篇关于语义与协同对齐的文章:《Bridging Textual-Collaborative Gap through Semantic Codes for Sequential Recommendation》
论文链接:https://arxiv.org/abs/2503.12183
代码链接:https://github.com/RUCAIBox/CCFRec?tab=readme-ov-file
1. 背景与问题
序列推荐任务下,主流做法都是侧重于 ID 协同过滤(只看用户和商品的 ID,忽略内容),可以很好的捕捉用户和商品间的互动关系,但现代平台的商品文本内容(标题、品牌、描述)极为丰富,这些信息能更精准刻画商品本身,也有助于解决冷启动问题。
近年来有一些方法把文本信息和 ID 信息拼接或加权,但常常导致两种信息融合不自然,要么太依赖文本,忽略协同关系,要么文本利用不足,丢失语义信息。
本文关注如何在序列推荐任务中,通过更智能的语义融合机制,把商品文本信息和用户行为序列的信息深度结合起来,让推荐系统既懂“内容”又懂“行为”。
本文提出 CCFRec 通过 sid(semantic id)作为桥梁,sid 有两个重要特征:
- 可以理解为特殊 id,每个 id 有自己的可学习 embedding,可以像传统 id 那样建模协同语义。
- 每个 item 可以有多组 sid(每个 item 多个特征如:标题、品牌、类别,每个特征一组 sid,代码中搞了 5 套),能反应不同层次的内容语义,让相似内容的 item 自动贴近(同 RPG 文章中提到的,如果有几位相同的 sid 这两个 item 就比较相似)。
本两个创新目标:
- 用 sid 指导模型,灵活地从文本信息中抽取对推荐有用的部分,不会死板地全部用文本。
- 让商品的最终表示既有内容信息,又有协同信息,让推荐系统更精确。
2. 方法
2.1 多视图 sid
这里思想特别简单(有点大力出奇迹的意思),就是将每个 item 的多种属性,论文代码中是 5 种(title,brand,features,categories,description),经过 embedding model 得到对应的 embedding,然后搞多套 sid。
对比之前的方法都是将每个 item 的所有属性拼成一句话经过 embedding model,这样更细致了。最后将每个属性的 sid 拼在一起,组层一个大 sid 表。(每个属性 20 层 pq/rq 的 codebook,拼在一起 100 层)
每个商品有多个文本属性(如title、brand、features、categories、description):
-
Step 1:文本编码
用预训练模型分别将每个属性编码为文本embedding向量:
zit=PLM(ai),i∈{1,...,m}z_i^t = \text{PLM}(a_i), i \in \{1,...,m\} zit=PLM(ai),i∈{1,...,m} -
Step 2:向量量化成sid
对每个属性的文本embedding,用向量量化技术(PQ或RQ)转为多层语义码sid:
zit→(c1i,...,cki)z_i^t \rightarrow (c_1^i,...,c_k^i) zit→(c1i,...,cki)
比如用了5个属性,每个属性20个sid,则每个商品就有5×20=100个sid。
2.2 Code-Guided Semantic Fusion
核心创新:
这是其实比较新颖的一个点就是将经过 embedding model 得到的 embedding 作为 K/V 去增强 embedding 质量。
这个模块是本文最核心的创新:
输入两类embedding:
- 属性embedding Zt=[z1t,...,zmt]Z^t=[z_1^t,...,z_m^t]Zt=[z1t,...,zmt](内容信息)
- 语义码embedding Zc=[z1c,...,zncc]Z^c=[z_1^c,...,z_{n_c}^c]Zc=[z1c,...,zncc](协同信息)
这个模块由多层Transformer-like结构组成,每层包括:
-
Self-Attention层:
语义码之间相互融合:
H~l=MHA(Hl−1,Hl−1,Hl−1)\tilde{H}^l = \text{MHA}(H^{l-1},H^{l-1},H^{l-1}) H~l=MHA(Hl−1,Hl−1,Hl−1) -
Cross-Attention层:
以语义码embedding 为 query,以文本属性 embedding 为 key 和 value,主动抽取有用的文本信息:
Hl=FFN(MHA(H~l,Zt,Zt))H^l = \text{FFN}\left(\text{MHA}\left(\tilde{H}^l,Z^t,Z^t\right)\right) Hl=FFN(MHA(H~l,Zt,Zt)) -
最终得到商品融合表示:
-
先池化获得整体表示:e=Pool(H)e=\text{Pool}(H)e=Pool(H)
-
再加一个残差连接保留原始sid信息:
e~=e+Pool(Zc)\tilde{e}=e+\text{Pool}(Z^c) e~=e+Pool(Zc)
-
通过上述模块,每个商品得到了高质量的语义融合向量 e~\tilde{e}e~。
常规操作:
-
将用户历史序列商品的融合embedding拼成序列,加位置编码,输入Transformer网络:
h^i0=e~i+pi\hat{h}_i^0=\tilde{e}_i+p_i h^i0=e~i+pi -
Transformer多层建模序列行为关系,得到最后一层隐藏状态:
H^l=FFN(MHA(H^l−1,H^l−1,H^l−1))\hat{H}^l=\text{FFN}\left(\text{MHA}\left(\hat{H}^{l-1},\hat{H}^{l-1},\hat{H}^{l-1}\right)\right) H^l=FFN(MHA(H^l−1,H^l−1,H^l−1)) -
最后一个位置的隐藏向量表示用户当前兴趣:
r=H^L[−1]r=\hat{H}^L[-1] r=H^L[−1]
损失:
用户表示 rrr 与下一个点击商品embedding e~n+1\tilde{e}_{n+1}e~n+1 相似度最大,负样本相似度最小。 用Cross-Entropy损失:
LCE=−logexp(g(r,e~n+1)/τ)∑j∈Bexp(g(r,e~j)/τ)\mathcal{L}_{CE}=-\log\frac{\exp\left(g(r,\tilde{e}_{n+1})/\tau\right)}{\sum_{j\in\mathcal{B}}\exp\left(g(r,\tilde{e}_j)/\tau\right)} LCE=−log∑j∈Bexp(g(r,e~j)/τ)exp(g(r,e~n+1)/τ)
- 其中,B\mathcal{B}B是正负样本集合,τ\tauτ是温度系数,ggg是余弦相似度。
2.3 Enhanced Representation Learning via Code Masking
作者提出通过额外的两个训练任务(基于掩码策略)增强模型的表示学习能力,分别是:
- Masked Code Modeling (MCM, 掩码语义码建模)
- Masked Sequence Alignment (MSA, 掩码序列对齐)
2.3.1 Masked Code Modeling (MCM)
- 核心思想:
受自然语言处理中 BERT 模型的启发(通过掩码语言建模MLM学习文本表示),这里对语义码序列进行随机掩码,训练模型去恢复被掩盖的语义码,以促进语义码和文本信息更好地融合。
- 具体做法:
-
每个商品拥有一个语义码序列:
sc=(c1,c2,...,cnc)s^c = (c_1, c_2, ..., c_{n_c}) sc=(c1,c2,...,cnc) -
随机将一定比例 ρ\rhoρ 的语义码掩盖 (如 [MASK][MASK][MASK] ),得到掩盖后的序列:
s^c=(c1,...,[MASK],...,cnc)\hat{s}^c = (c_1, ..., [MASK], ..., c_{n_c}) s^c=(c1,...,[MASK],...,cnc) -
语义融合模块(SFM)接收到这个掩盖序列,要利用文本embedding和未掩盖的码,推测出被掩盖的码。
- 损失函数:
预测的目标是让模型给掩盖位置预测正确的语义码:
LMCM=1∣Mc∣∑x∈Mc−logexp(g(h^x,zxc)/τ)∑j∈Cexp(g(h^x,zjc)/τ)\mathcal{L}_{\text{MCM}} = \frac{1}{|\mathcal{M}^c|}\sum_{x\in\mathcal{M}^c}-\log\frac{\exp(g(\hat{h}_x,z_x^c)/\tau)}{\sum_{j\in C}\exp(g(\hat{h}_x,z_j^c)/\tau)} LMCM=∣Mc∣1x∈Mc∑−log∑j∈Cexp(g(h^x,zjc)/τ)exp(g(h^x,zxc)/τ)
- 其中:
- Mc\mathcal{M}^cMc 为掩盖位置的集合。
- g(h^x,zxc)g(\hat{h}_x,z_x^c)g(h^x,zxc) 为预测表示(通过融合模块输出的隐藏向量h^x\hat{h}_xh^x)和真实码embedding zxcz_x^czxc 的余弦相似度。
- 分母上的集合 CCC 表示所有语义码集合,作为分类的类别。
- τ\tauτ 是温度系数,用于softmax平滑。
- 作用与优势:
- 增强语义码之间的关联性。
- 提高文本embedding与语义码之间的对齐能力。
2.3.2 Masked Sequence Alignment (MSA)
- 核心思想:
这个任务用来增强推荐主干网络的序列建模能力,通过掩盖部分语义码产生数据增强(data augmentation),再进行对比学习(Contrastive Learning),提升模型对于序列建模的稳健性。
- 具体做法:
- 同样对输入商品序列的语义码随机掩盖部分码,获得掩盖后的序列。
- 掩盖序列经过语义融合模块(SFM)得到增强版的商品表示(augmented item representation)。
- 将增强版的序列与原始序列分别输入到推荐主干网络,得到两种用户序列表示:
- 原始表示 rrr(未掩盖序列)
- 增强表示 r^\hat{r}r^(掩盖序列)
- 希望相同序列的原始和增强版表示更相似,不同序列的表示更不同。
- 损失函数(公式7、8):
采用 InfoNCE 对比损失:
LMSA=12(InfoNCE(r^,r,Br)+InfoNCE(r,r^,Br^))\mathcal{L}_{\text{MSA}} = \frac{1}{2}\bigl(\text{InfoNCE}(\hat{r}, r, \mathcal{B}_r) + \text{InfoNCE}(r, \hat{r}, \mathcal{B}_{\hat{r}})\bigr) LMSA=21(InfoNCE(r^,r,Br)+InfoNCE(r,r^,Br^))
其中 InfoNCE定义为:
InfoNCE(x,y+,Ry)=−logexp(g(x,y+)/τ)∑y∈Ryexp(g(x,y)/τ)\text{InfoNCE}(x, y^+, \mathcal{R}_y) = -\log\frac{\exp(g(x,y^+)/\tau)}{\sum_{y\in\mathcal{R}_y}\exp(g(x,y)/\tau)} InfoNCE(x,y+,Ry)=−log∑y∈Ryexp(g(x,y)/τ)exp(g(x,y+)/τ)
- (x,y+)(x,y^+)(x,y+) 表示一对正样本(即来自同一用户序列的原始表示与增强表示)。
- 集合 Ry\mathcal{R}_yRy 包含了正样本和批次内其他序列(负样本)的表示。
- 目的是拉近同序列表示(正样本),拉开不同序列表示(负样本)。
- 作用与优势:
- 增加训练数据多样性,有效提升模型对用户序列的泛化能力和稳健性。
最后,综合起来三个优化目标(推荐预测损失、掩码语义码损失、掩码序列对齐损失),整体训练目标为:
L=LCE+αLMCM+βLMSA\mathcal{L} = \mathcal{L}_{CE} + \alpha\mathcal{L}_{MCM} + \beta\mathcal{L}_{MSA} L=LCE+αLMCM+βLMSA
- LCE\mathcal{L}_{CE}LCE:推荐任务损失(预测下一个商品)。
- LMCM\mathcal{L}_{MCM}LMCM:掩码语义码建模损失,优化SFM语义融合效果。
- LMSA\mathcal{L}_{MSA}LMSA:掩码序列对齐损失,优化序列建模的稳健性。
- α,β\alpha,\betaα,β 为超参数,调节不同任务的比重。
2.4 复杂度分析
2.4.1 训练阶段(Training)
CCFRec有两个关键模块:
- 语义融合模块(SFM, Semantic-Fusion Module)
- 序列推荐主干(SR, Sequential Recommendation backbone),比如SASRec那样的Transformer结构。
SFM部分
- 在SFM中,主要有三种操作:自注意力层(Self-Attention)、跨融合层(Cross-Fusion)、前馈网络(Feed-Forward)。
- 对于单个item,计算复杂度分别是:
- 自注意力层:O(M²d)
- 跨融合层:O(MKd)
- 前馈网络:O(Md²)
- 其中:
- d 是模型的表示维度(embedding维度)
- M 是语义code序列的长度
- K 是属性序列的长度
- **综合起来,得到一个item的SFM输出的总体复杂度:**O(M²d + MKd + Md²)
SR部分
- 主干SR一般用的是SASRec那种Transformer结构,主要消耗在自注意力层和前馈层。
- 假设用户行为序列长度为N,则总复杂度为:O(N²d + Nd²)
总体训练复杂度
- 将SFM和SR加在一起,并考虑 batch(多个item同时训练),总训练复杂度为:O(N²d + Nd² + NM²d + NMKd + NMd²)
- 这里N是用户序列的长度,M和K是item属性和code数量,d是embedding维度。
- 重点:实际应用中,M 和 K 远小于 N(通常N>50,M、K一般不超过20),所以额外的开销是可以接受的。
(代码中我看到 M=100,K=20,额。。。不过工业界数据上确实也是 K 会更大)
2.4.2 部署阶段(Deployment)
- 部署时,为了提高效率,SFM模块可以被去掉,因为训练好的语义融合表示(item embedding)是固定的。
- 我们可以提前离线计算每个item的最终embedding(用SFM提前处理好,存下来),只用主干SR进行推理。
- 这样,线上推理时的复杂度与SASRec等主流序列推荐模型完全一样,都是 O(N²d + Nd²)
- 也就是说,部署阶段CCFRec的推理速度不会比常见的序列推荐模型慢。
这里倒是没问题。
3. 实验
3.1 主实验
3.2 消融实验
感觉这些消融有点没到点上,看不出来那些是本文最重要的组件。也没有整个去掉(1)(2)的,都是去掉很小的东西,然后微降效果
3.3 codebook 层数
层数增加效果提升,这里还是有点 scaling-law 的意义:
3.4 不同 sid
这里得到比较有趣的现象:
Random code是无用但无害:模型会“忽略”它,不依赖它。
SASRec code是冗余且有害:模型会“重复利用”协同信息,导致空间浪费,降低性能。
3.5 加 item id
论文采取了一种 参数高效(parameter-efficient) 的方式,简单来说就是在保持原有文本-语义表示的基础上,再加上一份独立的 item ID embedding,并且只训练这部分参数,步骤如下:
- 先用原始的 CCFRec 进行预训练,学习出每个物品的语义融合表示(只用文本+code)。
- 引入 item ID embedding lookup table:对每个物品,分配一个随机初始化的可训练 embedding(通常与语义表征等长,比如128维)。
- 冻结原有 CCFRec 所有参数,只训练 ID embedding,即其他部分参数都不动,只让 ID embedding 随训练迭代更新。
- 最终物品表示为:
最终表示 = 语义融合表示 + ID embedding
- 两者直接相加后,作为输入传递给序列推荐器(如 Transformer/SASRec 等)。
- 继续用推荐损失(如交叉熵)finetune,直到收敛。
原本 CCFRec 只用文本和对应的 semantic code(语义码)来表达物品,不用传统的 item ID embedding。这样做的好处是更关注于文本的内容表达,便于泛化和冷启动,但有个明显的短板:无法表达“物品之间纯 collaborative(协同过滤)信息”,即没法捕捉到只有 ID 层面才有的微小区分。
4. 总结
主要是对 item embedding 与 text embedding 融合的工作,感觉设计的十分复杂(复现的时候训练相比于其他模型时间多太多),实验整体感觉差点意思,消融做的没看出哪些最关键组件,不过对于部署阶段的复杂度分析倒是感觉算是合理,相当于增加了训练阶段的算力以及存储,换准确度?