End-To-End 之于推荐-kuaishou OneRec 笔记

核心思想

OneRec 提出了一种统一的生成式推荐系统架构,打破了传统“召回-粗排-精排”级联式推荐流程,使用单一生成模型同时完成召回与排序任务。该系统由快手团队研发,并成功部署于短视频主场景。

Online A/B Test 表现:

模型 总观看时长 平均观看时长
OneRec-1B + IPA +1.68% +6.56%

一 Input 处理

User positive action sequence,将短视频的多模态表征,通过量化的方式离散化成token序列
End-To-End 之于推荐-kuaishou OneRec 笔记_第1张图片

多模态特征处理流程

1. 原始输入:多模态视频内容

对于每个视频 v i \mathbf{v}_i vi,会包含:

  • 文本:标题、标签(title, tags)
  • 图像:封面图(cover image)
  • 音频:背景音乐(BGM embedding)
  • 用户行为:点赞、评论、分享数(可作为辅助特征)

2. 多模态嵌入&对齐

这一部分是图中最左边部分,主要作用如下:

模块 功能
嵌入(Embedding) 把视频的文本、图像、音频等模态编码为 dense 向量 e ∈ R d \mathbf{e} \in \mathbb{R}^d eRd
对齐(Alignment) 把不同模态编码结果投射到统一推荐语义空间,通过对比学习构建语义一致性

嵌入部分快手使用的是自己的多模态LLM, 这个没有公开,我们可以用自己知道的猜下:

2.1 输入层(多模态原始数据)

模态 内容
文本 标题、描述、标签(可用 BERT 编码)
图像 封面图、视频首帧(可用 CLIP/VIT 编码)
音频 BGM 音频或音素(可用 Wav2Vec、YAMNet)
结构化特征 视频长度、发布时间、作者等级等(dense vector)

2.2 单模态编码器(数据嵌入)(可能 frozen)

  • 文本 → RoBERTa/BERT → h text ∈ R 768 h^{\text{text}} \in \mathbb{R}^{768} htextR768
  • 图像 → ViT-Base or CLIP-Vision → h img ∈ R 512 h^{\text{img}} \in \mathbb{R}^{512} himgR512
  • 音频 → YAMNet/Wav2Vec → h audio ∈ R 128 h^{\text{audio}} \in \mathbb{R}^{128} haudioR128
  • 结构化特征 → MLP → h struct ∈ R 64 h^{\text{struct}} \in \mathbb{R}^{64} hstructR64

这些 encoder 可能是 frozen,或者微调部分参数(如 projection head)

2.3 多模态融合模块(快手的关键)

可能使用以下融合机制之一:

✅ 方法 1:MLP Concatenation
h_concat = concat([h_text, h_img, h_audio, h_struct])  # → ℝ^1472
h_fused = MLP(h_concat)  # → ℝ^1024
✅ 方法 2:Cross-Attention Fusion

将文本为 query,图像/音频为 key/value 做一次 cross-attention:

h_text = BERT(text)
h_img = ViT(image)
h_audio = Wav2Vec(audio)

h_fused = MultiModalAttention(query=h_text, key=[h_img, h_audio], value=[h_img, h_audio])
h_fused = Pooling(h_fused) → ℝ^1024

2.4. Item Tower(共享结构)

到这里就是论文公开的部分了。

  • 模型结构:MLP / Transformer encoder(N层 self-attention + FFN)
  • 功能:进一步压缩 & 对齐语义空间
  • 输出:Trigger item 和 Target item 的语义嵌入向量 e ∈ R 1024 e \in \mathbb{R}^{1024} eR1024

2.5. 训练目标:Batch Contrastive Loss

采用 InfoNCE 对比学习:

  • 正样本对:用户历史点击 + 当前正样本(Trigger–Target)

  • 负样本对:同 batch 中其他 item

  • 损失形式:
    L contrastive = − log ⁡ exp ⁡ ( sim ( e trig , e tgt ) / τ ) ∑ j exp ⁡ ( sim ( e trig , e j ) / τ ) \mathcal{L}_{\text{contrastive}} = -\log \frac{\exp(\text{sim}(e_{\text{trig}}, e_{\text{tgt}})/\tau)}{\sum_{j} \exp(\text{sim}(e_{\text{trig}}, e_j)/\tau)} Lcontrastive=logjexp(sim(etrig,ej)/τ)exp(sim(etrig,etgt)/τ)

2.6 最终输出

所有多模态输入 → 一个统一语义空间下的向量 e i ∈ R 1024 e_i \in \mathbb{R}^{1024} eiR1024

所有模态嵌入向量会被拼接或加权融合为一个统一的 e i ∈ R d \mathbf{e}_i \in \mathbb{R}^d eiRd,如 d = 1024 d=1024 d=1024

3. Tokenizer

这一部分是图中中间部分,将嵌入 e i \mathbf{e}_i ei 编码为离散语义 token 序列(例如 ),具体的每一个item会生成3个token,item之间使用Sep分隔

主要思想是利用之前的文章QARM: Quantitative Alignment Multi-Modal Recommendation at Kuaishou 进行序列化编码,主要的原理叫Residual Vector Quantization(RVQ),核心原理是通过几个离散化token序列代表原来稠密的dense向量。

我们来看个实际例子

输入向量:

x = [4.1, 2.8]

三层聚类中心(简化示意):

  • 第1层 codebook:4 个中心点
    [[0,0], [3,2], [6,1], [5,5]]
  • 第2层 codebook:
    [[0,0], [1,1], [-1,-1], [2,-2]]
  • 第3层 codebook:
    [[0,0], [0.5,0.5], [-0.5,-0.5], [1,1]]

Tokenizer 运行过程:

  1. 第一层:
    • 找到 [3,2] 最接近 x
    • token₁ = 1
    • 残差 = [4.1, 2.8] - [3,2] = [1.1, 0.8]
  2. 第二层:
    • 对残差 [1.1, 0.8],找到 [1,1] 最近
    • token₂ = 1
    • 新残差 = [0.1, -0.2]
  3. 第三层:
    • 对残差 [0.1, -0.2],找到 [0,0] 最近
    • token₃ = 0

最终输出:

token(x) = [1, 1, 0]

表示:

x ≈ codebook_1[1] + codebook_2[1] + codebook_3[0]
  = [3,2] + [1,1] + [0,0] = [4, 3]

对比原始向量:

  • 原始:[4.1, 2.8]
  • 重构:[4.0, 3.0]

下面讲快手的优化

Balanced KMeans

快手采用了Balanced KMeans对聚类进行了优化,因为传统的聚类会有token collapse问题(有些中心被大量item占据,但是有些中心却没有人是用,这样的话模型就学不到token)

想法(注意,这段文章中没有出现)

给定:

  • N N N 个向量
  • K K K 个聚类中心(token)
  • 我们希望每个聚类获得约 N / K N/K N/K 个样本

实现方式一:容量限制型 KMeans(Hard Balanced)

每个聚类最多分配 N / K + δ N/K + \delta N/K+δ 个样本:

  1. 初始化中心点(随机/前几轮结果)
  2. 遍历样本:
    • 按距离挑选最近中心
    • 如果该中心容量未满,就分配进去
    • 否则选择次近的中心
  3. 每轮迭代后更新中心,重复

这样可确保最终每个中心分配样本数近似相等。

⚙️ 实现方式二:Soft Balanced with Penalty

加入“频次惩罚项”,例如每个中心在选样本时加上一个 penalty:
effective_dist i , j = ∥ x i − c j ∥ 2 + λ ⋅ f j \text{effective\_dist}_{i,j} = \|x_i - c_j\|^2 + \lambda \cdot f_j effective_disti,j=xicj2+λfj
其中:

  • f j f_j fj 是当前聚类中心 c j c_j cj 被使用的频次(或软频率)
  • λ \lambda λ 是惩罚强度

这种方式在训练中平滑惩罚热门中心,促使样本选择更冷门的 token。

二 Model 细节

End-To-End 之于推荐-kuaishou OneRec 笔记_第2张图片
模型整体结构由一个Transformer Encoder和Transformer Decoder组合而成。

训练目标:NTP(Next Token Prediction)

类似语言模型:

  • 输入:用户历史 + 高价值目标序列的 token 序列
  • Decoder 自回归地预测下一个 token:
    • P( | )
    • P( | , )

✅ Encoder:用户行为建模器

输入

用户历史行为序列,tokenized 后变成一串 token(每个 item = 3 tokens):

[SEP] <a_6> <b_1> <c_5> [SEP] <a_2> <b_1> <c_7> ...

编码流程结构

  1. Embedding Layer

    • 查 token embedding:每个 token 映射为 d_model 维(如 768/1024)向量
    • 加入 position embedding(绝对或相对)
  2. ×N/2 层 Encoder Block(如 N=12,共用 6 层)

    • 每层包括:
      • Fully Visible Multi-head Self-Attention(全 token 可见)
      • Residual + RMS Norm
      • Feed Forward 层
  3. 输出

    • 对应每个 token 的 contextual 表示:

      E_output = [e₁, e₂, ..., e_L],L = token 序列长度,eᵢ ∈ ℝ^{d_model}
      

这些 token-level 表达作为 decoder cross-attn 的 key/value。

✅ Decoder:高价值推荐目标生成器

输入

Decoder 从 [BOS] 开始生成推荐目标 token 序列, 每次预测一个token,直到生成特殊token[EOS]为止,所生成组合成一个Session,:

Session = [BOS] <a_9> <b_7> <c_1> [BOS] <a_4> <b_5> <c_4> [BOS] ...[EOS]

每一步预测当前 token,前面 token 已知。


解码流程结构

  1. Embedding Layer

    • 和 encoder 共享 token embedding
    • 加入 decoder position embedding
  2. ×N/2 层 Decoder Block(MoE支持)

    • 每层包括:
      • Causal Self-Attention(mask 未来 token)
      • Residual + RMS Norm
      • Cross-Attention(使用 encoder 的输出作为 key/value)
      • MoE Feed Forward Layer(gated expert × Router)
  3. 输出

    • 对每个输入 token,输出下一 token 的概率分布:

      D_output = [p₁, p₂, ..., p_L],pᵢ ∈ ℝ^{V}(V 为 token vocabulary size)
      
    • 用于计算 token-level cross-entropy loss(Next Token Prediction)

三 强化学习偏好对齐

未完待续

你可能感兴趣的:(RecSys,笔记)