🏠 总目录📚 本教程 18 · 进阶专题
📑 本页目录(点开跳转)

18 · 进阶专题:GNN、蒸馏、去偏与强化学习

35 分钟 | 🎁 进阶选修 | 建议至少学完第 8、12 节再来

这一节是五个独立的小专题,可以只挑感兴趣的看,互相不依赖。


🎯 一句话

这五个专题是「从会用到精通」的分水岭:图神经网络(换个视角看数据)、知识蒸馏(让大模型的能力装进小模型)、因果去偏(对抗数据里的谎言)、强化学习(优化长期而非单次)、LLM 特征工厂(2026 年性价比之王)


专题一:图神经网络召回(LightGCN)

换个视角:交互矩阵其实是一张图

   用户-物品交互,除了看成矩阵,还可以看成二部图:

      u1 ─────── i1
      u1 ─────── i2          用户和物品是两类节点
      u2 ─────── i2          交互是边
      u2 ─────── i3
      u3 ─────── i3

   图视角的红利:可以看「多跳」关系
      u1 → i2 → u2 → i3
      (u1 没看过 i3,但通过 2 跳连到了它 → 潜在兴趣!)

协同过滤只用了 1 跳信息(直接交互)。GNN 把 2 跳、3 跳的「间接协同信号」也显式地用上了。

LightGCN:把 GCN 里没用的东西全砍掉

何向南团队 2020 年的经典工作。做了一个大胆的实验:把标准 GCN 的特征变换矩阵 W非线性激活都删掉,效果反而更好。

为什么? 推荐场景的输入只有 ID Embedding(没有丰富的节点特征),复杂的变换只会过拟合。

剩下的唯一操作:邻居平均(消息传递)

$$e_u^{(k+1)} = \sum_{i \in N(u)} \frac{1}{\sqrt{|N(u)|}\sqrt{|N(i)|}} e_i^{(k)}$$

💡 人话翻译

第 k+1 层的用户向量 = 他交互过的所有物品的第 k 层向量的加权平均。 物品同理。做 K 层,就吸收了 K 跳以内的邻居信息。 最终表示 = 各层的平均(既有自己,也有 1 跳、2 跳邻居的信息)。

import torch, torch.nn as nn

class LightGCN(nn.Module):
    def __init__(self, n_users, n_items, k=64, n_layers=3):
        super().__init__()
        self.n_users, self.n_items, self.n_layers = n_users, n_items, n_layers
        self.emb = nn.Embedding(n_users + n_items, k)
        nn.init.normal_(self.emb.weight, std=0.1)

    def propagate(self, norm_adj):
        """norm_adj: 归一化的邻接稀疏矩阵 (U+I, U+I)"""
        x = self.emb.weight
        outs = [x]
        for _ in range(self.n_layers):
            x = torch.sparse.mm(norm_adj, x)   # 一层 = 一次邻居平均
            outs.append(x)
        final = torch.stack(outs, dim=0).mean(0)     # 各层取平均
        return final[:self.n_users], final[self.n_users:]

    # 训练:用第 5 节的 BPR loss,users/items 向量点积打分

什么时候值得用 GNN

情况 建议
数据极稀疏(每用户交互 < 10 次) ✅ 多跳信息收益大
有社交关系(好友、关注) ✅ 图天然表达这种结构
数据充足、行为丰富 ⚠️ 收益不明显,SASRec/双塔通常更划算
物品每天大量更新 ❌ 图要频繁重建,工程代价大

📌 现实定位:LightGCN 是学术界最强的 CF baseline 之一;工业界通常把它当召回的其中一路,而不是主力。


专题二:Swing —— 工业界最强的 i2i 算法之一

第 4 节的 ItemCF 有个弱点:共现统计容易被「巧合」污染。 两个物品被同一批人点过,可能只是因为它们都在同一个活动页上。

阿里 Swing 的洞察:如果多对用户都同时点了物品 i 和 j,且这些用户之间的重合度低(来自不同圈子),那 i 和 j 才是真的相关。

$$\text{sim}(i,j) = \sum_{u \in U_i \cap U_j} \sum_{v \in U_i \cap U_j} \frac{1}{\alpha + |I_u \cap I_v|}$$

💡 人话翻译

对每一同时点过 i、j 的用户 (u, v): 如果 u 和 v 的整体行为很像($|I_u \cap I_v|$ 大)→ 他们可能只是同一个小圈子,证据打折; 如果 u 和 v 八竿子打不着却都点了 i 和 j → 强证据,i 和 j 是真相关。

名字的由来:u、i、v、j 四个节点构成一个「秋千(Swing)」形状的结构。

from itertools import combinations
from collections import defaultdict

def swing(user_items, alpha=1.0, top_k=20):
    # 反向索引:物品 → 点过它的用户集合
    item_users = defaultdict(set)
    for u, items in user_items.items():
        for i in items:
            item_users[i].add(u)
    user_set = {u: set(items) for u, items in user_items.items()}

    sim = defaultdict(lambda: defaultdict(float))
    for i, j in combinations(item_users, 2):
        common = item_users[i] & item_users[j]
        if len(common) < 2:
            continue
        for u, v in combinations(common, 2):
            overlap = len(user_set[u] & user_set[v])
            w = 1.0 / (alpha + overlap)
            sim[i][j] += w
            sim[j][i] += w
    return {i: dict(sorted(s.items(), key=lambda x: -x[1])[:top_k])
            for i, s in sim.items()}

⚠️ 复杂度是 O(物品对 × 用户对),全量算不动。工业实现要做用户采样(每个物品对最多采 N 对用户)+ 分布式计算。

📌 Swing 在阿里系产品长期是「买了又买」「看了又看」的主力算法,鲁棒性显著好于朴素 ItemCF。


专题三:知识蒸馏 —— 大模型的能力装进小模型

为什么推荐系统特别需要蒸馏

第 6 节说过:粗排必须比精排快 10 倍,但要「尽可能像精排」。 第 15 节说过:推理延迟是生命线。

蒸馏就是同时满足这两者的标准答案。

离线【教师】精排大模型(几亿参数,几百特征)用教师的"打分"当学习目标(而不只是 0/1 标签)线上【学生】粗排小模型(双塔/小 MLP,快 10-50 倍)线上只跑学生模型 —— 教师只在离线训练时出现
蒸馏的全部形状就是这一根箭头:大模型把自己的打分往下传给小模型。⭐ 该看的是这根箭头只存在于离线 —— 线上真正被调用的只有底下那个学生模型,教师再大也不占线上的延迟预算。这正是「粗排既要比精排快 10 倍、又要尽可能像精排」这个矛盾要求的标准解法。

为什么学「教师的分数」比学「真实标签」好?

真实标签只有 0 和 1,信息量很少。教师的打分是连续的、带排序信息的

   真实标签:   A=1   B=0   C=0     ← B 和 C 看起来一样差
   教师打分:   A=0.9 B=0.4 C=0.05  ← 其实 B 远比 C 好!

   学生从教师那里学到了"B 和 C 的差别"——这是标签里没有的暗知识 (Dark Knowledge)

推荐系统蒸馏的三种姿势

姿势 做法 用在哪
分数蒸馏 (pointwise) 学生拟合教师的 logit(MSE) 最简单,粗排蒸馏的起点
排序蒸馏 (listwise) 学生学教师对候选列表的排序,而不是绝对分 更符合粗排职责(一致性)
特征/表示蒸馏 学生的中间层向学教师的中间层 Embedding 压缩
import torch
import torch.nn.functional as F

def ranking_distill_loss(student_logits, teacher_logits, temperature=2.0):
    """
    Listwise 蒸馏:把两边的打分都 softmax 成"列表上的分布",
    然后让学生的分布逼近教师的分布(KL 散度)
    student_logits/teacher_logits: (B, N) 同一批候选在两个模型下的分
    """
    t = F.softmax(teacher_logits / temperature, dim=-1)
    s = F.log_softmax(student_logits / temperature, dim=-1)
    return F.kl_div(s, t, reduction="batchmean") * temperature ** 2

# 总损失 = 真实标签损失 + λ × 蒸馏损失
# loss = bce(student_logits, labels) + 0.5 * ranking_distill_loss(student_logits, teacher_logits)

🔮 2026 视角:蒸馏正在变得更重要——生成式大模型(第 14 节)效果好但太贵, 「大模型离线打分 → 蒸馏成轻量模型上线」是当前最现实的落地路径之一(如 MLP 蒸馏生成式推荐的研究方向)。


专题四:因果与去偏 —— 对抗数据里的谎言

第 12 节讲了曝光偏差的存在,这里讲怎么定量地纠正它

核心工具:IPS(逆倾向得分加权)

问题:热门物品被曝光的机会大 → 训练数据里它们的样本多 → 模型进一步偏向它们。

IPS 的思路:每条样本除以「它被观测到的概率」。

$$\mathcal{L}_{IPS} = \frac{1}{N}\sum_{(u,i)\in D} \frac{\delta(u,i)}{P(o_{ui}=1)}$$

💡 人话翻译

一个冷门物品的样本能进训练集,是小概率事件——所以它代表了一大批没被观测到的同类,要放大它的权重。 一个热门物品的样本随处可见——权重缩小。 就像民意调查:如果你的受访者里城市人口占 90%(实际只占 60%),就要给农村受访者加权。

# 最简单的实现:用物品的曝光频率估计倾向得分
propensity = item_exposure_count / item_exposure_count.sum()
propensity = np.clip(propensity, 1e-4, None)     # ⭐ 必须截断!

sample_weight = 1.0 / propensity[item_ids]
loss = (sample_weight * bce_per_sample).mean()

⚠️ IPS 的致命弱点:方差爆炸。倾向得分接近 0 的样本权重会大到离谱,一条样本能掀翻整个模型。 ✅ 缓解:截断(clipping)自归一化(SNIPS)、或升级到 Doubly Robust(IPS + 一个预估模型互为保险,其中一个准就行)。

无偏数据:最贵但最干净的解法

第 13 节说的「1-5% 随机流量」,在去偏语境下的正式用法:

有偏大数据(99%)+无偏小数据(1% 随机曝光)联合训练大数据学表示,小数据校准偏差(代表方法:CausE、KD-Debias 等)
两份数据分工完全不同:99% 的有偏大数据负责学表示,1% 的随机曝光小数据负责校准偏差。⭐ 关键在中间那个「联合训练」—— 只用小数据量不够,只用大数据偏差消不掉,必须一起上。

📌 实用主义总结:中小团队优先做「位置偏差建模」(第 12 节,收益大成本低), IPS 类方法在评估(Off-Policy Evaluation)里比在训练里更常用。


专题五:强化学习 —— 优化长期价值

为什么点击率模型天然短视

   精排优化的是:这一次曝光的点击概率
   产品要的是:  用户三个月后还在不在

   两者可能冲突:
     标题党 → 这次点击率高 ✅ → 用户长期反感流失 ❌
     深度长文 → 这次点击率低 ❌ → 用户长期信任留存 ✅

强化学习的视角:推荐是序列决策——每次推荐是一个动作,用户的长期活跃是累计奖励。

   状态 s   = 用户当前的兴趣状态(历史行为、疲劳度、会话上下文)
   动作 a   = 推荐哪批内容
   奖励 r   = 即时反馈(点击/时长)+ 折扣后的未来反馈
   目标     = max E[ Σ γᵗ·rₜ ]   ← 不是 max 单次 r!

现实中的三大拦路虎

难题 说明
不能在线试错 游戏可以死一万次重来,推荐每次坏动作都伤害真实用户 → 只能离线 RL(Off-Policy),从历史日志学
动作空间巨大 从 1 亿物品里选 10 个 = 天文数字的组合动作
奖励稀疏且延迟 「三个月后还留存」这个奖励信号要等三个月

工业界实际在用的形态(务实版)

  1. YouTube 的 Top-K REINFORCE(2019):策略梯度 + 重要性采样纠偏,用于召回。是最著名的成功案例
  2. 奖励塑形:不等三个月,用「会话深度」「次日回访」这类中期代理指标当奖励
  3. 保守离线 RL:限制新策略不能离旧策略(日志策略)太远(类似 PPO 的约束思想)
  4. RLHF/DPO 进推荐(2025+):生成式推荐(第 14 节的 OneRec)直接借用 LLM 的偏好对齐技术——把「用户真实选了 A 没选 B」当偏好对,做 DPO

🔑 给初学者的定位:RL 推荐是「效果上限最高、落地难度也最高」的方向。 面试中能讲清「为什么点击率模型短视 + 离线 RL 为什么难」就已经超过大多数人。


专题六(彩蛋):LLM 特征工厂 —— 2026 年性价比之王

第 14 节提过「LLM 四种用法里最实用的是当特征工厂」。这里给出能直接抄的操作流程

物品原始信息(标题 / 描述 / 图片)批量调 LLM(离线,每个物品只算一次)Prompt 示例:「给这个商品打标签,输出 JSON:{类目层级, 风格标签[], 适用人群[],价格感知档位, 情感调性, 一句话卖点}」结构化标签 + 文本 Embedding内容召回倒排索引新物品发布即可被检索精排模型的特征类目 / 风格 / 人群 → EmbSemantic ID 的输入第 14 节的生成式推荐离线算一次 → 在线只查表:这就是 LLM 在推荐里性价比最高的用法
重点在那个「离线」二字:LLM 只在物品入库时跑一次,线上全程不调用大模型,所以成本和延迟都可控,一次产出还能同时喂给召回、精排和语义 ID。

为什么它性价比高: - 离线计算,不影响线上延迟;每个物品只算一次 - 直接命中推荐系统最大的痛点之一:物品冷启动(第 13 节) - 不用改任何架构,标签当普通类别特征喂进现有模型 - 比人工运营打标签便宜几个数量级,且覆盖率 100%

三个实操注意: 1. 让 LLM 输出受控词表(在 prompt 里给出候选标签列表让它选),否则标签会发散到无法当特征用 2. 抽样人工审核(1%),LLM 会有系统性的偏差(如把所有东西都标「高性价比」) 3. 用 Embedding 时注意降维(768 维太大,PCA/SVD 到 64 维再入模型)


🔗 这一章连到哪里

去哪为什么
强化学习 14专题五的展开版:离线 RL 为什么难、动作空间怎么压、什么时候真的该上 RL
上线之后 13专题四的完整版:倾向得分怎么估、SNIPS / Doubly Robust 为什么能压住方差
上线之后 18专题三的落地账:蒸馏在降本清单里排最后一位——先 profile、缓存、请求分级,那三步就能拿 70% 收益

✅ 检查点

  1. LightGCN 相比标准 GCN 删掉了什么?为什么删掉反而更好?
  2. Swing 比 ItemCF 强在哪?「秋千结构」指什么?
  3. 为什么蒸馏时学「教师的分数」比学「真实标签」信息量大?
  4. IPS 的直觉是什么?它的致命弱点和缓解方法?
  5. 为什么推荐里的强化学习只能用离线 RL?
  6. LLM 特征工厂为什么是「性价比之王」?(说出三个理由)
👀 答案 1. 删掉了特征变换矩阵 W 和非线性激活,只留邻居平均。因为推荐输入只有 ID Embedding,没有丰富节点特征,复杂变换只会过拟合。 2. Swing 检查「同时点过 i、j 的用户对」之间的重合度:来自不同圈子的用户对是强证据,同一小圈子的证据打折。u-i-v-j 四节点构成秋千形状。它对「碰巧被同一批人点过」的噪声更鲁棒。 3. 真实标签只有 0/1;教师的连续打分包含「负样本之间谁更好」的排序信息(暗知识)。 4. 每条样本按「被观测到的概率」的倒数加权,让冷门样本代表它背后没被观测的同类。弱点是倾向得分接近 0 时权重爆炸(方差大);缓解:截断、自归一化 SNIPS、Doubly Robust。 5. 在线试错会伤害真实用户,不能像游戏一样死一万次重来,只能从历史日志(旧策略产生的数据)学习。 6. 离线计算不碰线上延迟、直接解决物品冷启动、不改架构即可接入现有系统(外加:比人工标注便宜且全覆盖)。

🛑 可以停在这里

走神救援

五个进阶专题:LightGCN(图视角,多跳协同信号,只做邻居平均)、Swing(用户对重合度打折,鲁棒 i2i)、蒸馏(学教师的连续打分=暗知识,listwise 蒸馏最适合粗排)、去偏(IPS 逆倾向加权,弱点方差爆炸,要截断)、RL(优化长期价值,只能离线 RL,YouTube Top-K REINFORCE 是标杆)+ 彩蛋 LLM 特征工厂(离线打标签,治冷启动,性价比之王)。每个专题一句话定位,记这个就够:LightGCN —— 学术界最强 CF baseline,工业界只当召回的其中一路数据极稀疏或有社交关系才值得上;行为丰富时 SASRec/双塔更划算,物品天天大换血就别碰(图要频繁重建)。Swing —— 「买了又买 / 看了又看」的主力 i2i,⚠️ 复杂度 O(物品对 × 用户对) 全量算不动,工业实现必须对用户采样 + 分布式。蒸馏 —— 教师的连续打分带的是暗知识(「这个负样本其实有点像正的」),真实标签只有 0/1;粗排用 listwise 蒸馏对齐精排的,比对齐分数更管用。IPS —— 评估(Off-Policy Evaluation)里比训练里更常用;中小团队优先做位置偏差建模,收益大成本低。RL —— 效果上限最高、落地难度也最高,⚠️ 三座大山是不能在线试错(只能离线 RL)、动作空间天文数字、奖励稀疏且延迟;务实解法是用「会话深度、次日回访」这类中期代理指标当奖励。⚠️ LLM 特征工厂有三个实操细节别漏:让 LLM 在给定候选词表里选标签(不然标签发散到没法当特征)、抽 1% 人工审核(LLM 有系统性偏差,比如什么都标「高性价比」)、Embedding 先 PCA/SVD 降到 64 维再入模型。

下一步 👉 挑战项目:19-挑战项目A-新闻推荐-时效性生死时速.md

打卡记录保存在你的浏览器里,首页能看到总进度