推荐系统自动研究知识库
RecSys Auto Research KB · 从级联架构到生成式范式的推荐与广告知识库
一个面向推荐系统与计算广告的知识库:判别式推荐、生成式推荐、计算广告专题,为人类读者与 AI agent 的 auto research 提供结构化、可精确引用的技术知识。
这是什么?
《推荐系统自动研究知识库》 是一个面向推荐系统 auto research 的知识库,内容重写并扩展自 Datawhale 开源项目 fun-rec。
📖 在线阅读:访问 https://haozhe-xing.github.io/fun-rec-mdbook/ 阅读最新版本。
本书围绕推荐系统的两条核心主线展开:
- 判别式推荐 :召回、排序、重排、多目标、多场景、去偏、冷启动等工业级推荐系统基础能力。
- 生成式推荐 :语义 ID、生成式排序、端到端推荐、推荐推理、扩散模型与生成式推荐系统实战。
如果你希望从「算法原理」走到「系统实践」,并理解推荐系统从经典架构走向生成式范式的完整脉络,这本书就是为你准备的。
内容地图
本书共 12 个 Part ,建议按顺序阅读;如果你已有推荐系统基础,也可以直接跳到感兴趣的主题。
| 篇章 | 主题 | 你将学到什么 |
|---|---|---|
| Part 1 | 推荐系统全景 | 推荐系统基本问题、技术地图、特征与 Embedding 基础 |
| Part 2 | 快速候选召回 | 协同过滤、向量召回、双塔、序列召回、流式索引 |
| Part 3 | 精准偏好预测 | Wide&Deep、特征交叉、序列建模、多目标、多场景 |
| Part 4 | 重排多样性建模 | MMR、DPP、个性化重排与列表级优化 |
| Part 5 | 前沿趋势 | 去偏、冷启动、生成式推荐范式演进 |
| Part 6 | 生成式推荐基础 | 生成式范式、LLM 基础、Codebook、语义 ID |
| Part 7 | Scaling 生成式排序 | HSTU、生成式排序、MTGR、RankMixer、OneTrans |
| Part 8 | 端到端生成式应用 | 推荐、搜索、广告中的端到端生成式建模 |
| Part 9 | 推荐中的思考与推理 | 语义对齐、推理框架、自主推理探索 |
| Part 10 | 扩散模型推荐 | 扩散基础、数据增强、推荐应用 |
| Part 11 | 生成式推荐系统实战 | 系统架构、离线管线、在线管线、前端与部署 |
| Part 12 | 计算广告专题 | 拍卖机制、智能出价、合约与竞价广告、定向、数据交易、实验与反作弊 |
完整目录见 SUMMARY.md。
1. 安装依赖
cargo install mdbook
cargo install mdbook-katex
2. 本地预览(中英双语一键启动)
./serve.sh
默认在 http://localhost:3000 启动,中文版在 /zh/、英文版在 /en/,根路径按浏览器语言自动跳转。
3. 构建静态站点
mdbook build # 中文版 → book/zh/
cp book-en.toml book.toml && mdbook build # 英文版 → book/en/(构建后恢复 book.toml)
项目结构
本项目提供 中英双语 版本,结构与 agent_learning 一致:
.
├── src/
│ ├── zh/ # 中文源(当前目录)
│ │ ├── SUMMARY.md # mdBook 目录结构
│ │ ├── part1-introduction/ … part11-project/
│ │ ├── appendix/ # 附录
│ │ ├── images/ # SVG 图表资源
│ │ └── viz/ # 交互式可视化资源
│ └── en/ # 英文源(与 zh 1:1 对齐)
├── book.toml # 中文版配置 → book/zh/
├── book-en.toml # 英文版配置 → book/en/
├── root-index.html # 语言选择首页(按浏览器语言自动跳转)
├── serve.sh # 一键构建并本地预览
├── styles/ # 自定义样式
└── scripts/ # 自定义交互脚本
推荐阅读路径
初学者路径
适合刚接触推荐系统、希望建立完整知识框架的读者:
Part 1 → Part 2 → Part 3 → Part 4 → Part 5
你会先掌握推荐系统的经典级联架构,再理解召回、排序、重排各模块如何协同工作。
进阶工程路径
适合已经做过推荐算法或推荐工程,希望补齐系统设计能力的读者:
Part 2 → Part 3 → Part 4 → Part 11
你会重点理解工业推荐链路中的候选生成、偏好预测、列表优化和线上服务架构。
生成式推荐路径
适合关注大模型、生成式排序、语义 ID 与下一代推荐系统的读者:
Part 5 → Part 6 → Part 7 → Part 8 → Part 9 → Part 10 → Part 11
你会从范式迁移开始,逐步进入生成式推荐的建模、推理和系统落地。
适合谁读?
- 推荐算法学习者 :希望系统学习推荐系统核心模型与技术路线。
- 机器学习工程师 :希望理解推荐系统从离线训练到在线服务的工程链路。
- 推荐系统从业者 :希望补齐生成式推荐、语义 ID、端到端推荐等新方向。
- 技术面试准备者 :希望建立清晰的推荐系统知识地图与表达框架。
写作约定
- 章节顶部使用徽章标注 章节编号、预计阅读时间、难度级别。
- 数学公式使用
$行内公式$与$$独立公式$$,由mdbook-katex渲染。 - 图表统一放在
images/,交互式可视化放在viz/。 - 每章尽量包含 常见错误、核心要点、FAQ、章节关联与分层练习。
参与贡献
欢迎通过 Issue 或 Pull Request 参与改进:
- 修正错别字、公式、图表或链接问题。
- 补充推荐系统论文、工业案例或工程实践经验。
- 改进章节结构、示例代码、练习题与可视化内容。
- 提出你希望新增的推荐系统主题。
在提交内容时,建议保持:
- 术语统一 :优先参考 GLOSSARY.md。
- 结构一致 :遵循已有章节的组织方式。
- 解释清晰 :优先说明直觉、边界条件和工程取舍。
致谢
本书重写自 Datawhale 开源项目 fun-rec,感谢原项目作者与社区贡献者为推荐系统学习资料建设做出的贡献。
也感谢推荐系统、信息检索、机器学习与大模型社区中的研究者和工程师。本书中的许多内容都受益于公开论文、工业实践分享和开源社区讨论。
推荐系统是现代互联网最核心的基础设施之一,但其内部逻辑远比「帮用户找内容」复杂。本部分先帮你建立 立体的认知框架 :从微观的两种范式,到工业的两条技术路线,再到宏观的生态平衡;最后再落到工程底座,理解业务字段如何变成模型可用的特征与 Embedding。
本章涵盖
| 章节 | Topic | The Big Idea |
|---|---|---|
| 1.1 | 推荐系统是什么 | 从「判别式 vs 生成式」双范式、三阶段流水线、生态三角三个层次理解推荐 |
| 1.2 | 本书概览与技术地图 | 沿判别式与生成式两条主线,串起从记忆·泛化到理解·推理的能力演进 |
| 1.3 | 特征与 Embedding 入门 | 从 slotId / featureSign / value 出发,打通业务字段、特征表达、Embedding 与线上工程边界 |
What You'll Be Able to Do After This Part
- 🟢 描述 推荐问题的两种根本范式(判别式打分 vs 生成式序列生成)及其核心公式
- 🟢 解释 工业级推荐为何采用「召回—排序—重排」三阶段漏斗,以及各阶段的职责
- 🟡 辨析 端到端生成式架构如何消解级联架构的目标不一致、信息损失与计算碎片化
- 🟡 对照 本书的技术地图,定位后续每一章在「能力演进」曲线上的位置
- 🟡 解释 业务字段如何经
slotId / featureSign / value进入模型,并区分 Sparse、Dense、分桶与 Embedding
核心概念
| Concept | 章节 | Relevance |
|---|---|---|
| 判别式推荐 / 生成式推荐 | 1.1 | 贯穿全书的两条主线,决定架构与优化目标 |
| 三阶段流水线(召回/排序/重排) | 1.1 | 判别式推荐的工业骨架 |
| 端到端生成 | 1.1 | 生成式推荐对级联架构的替代 |
| 生态三角(用户/创作者·内容·平台) | 1.1 | 跳出技术指标,理解系统的长期价值 |
| 特征三元组 / Feature Hashing | 1.3 | 连接业务字段与模型输入的工程协议 |
| Sparse / Dense / 分桶 / Embedding | 1.3 | 后续召回、排序与特征交叉模型的表示基础 |
前置知识
- 具备基础机器学习概念(监督学习、概率、向量表示)
- 了解基本的 Python 与神经网络常识
无需推荐系统前置知识——本部分正是为初学者建立的起点。
Tips for This Part
- 先建立框架,再抠细节。 前两节重在「认知地图」,具体算法在后续 Part 逐步展开。
- 对比着读两种范式。 每遇到一个新模型,先判断它属于判别式还是生成式。
- 记住三阶段漏斗。 它是后续 Part 2–4 的组织线索。
- 把 1.3 当作表示基础。 后续看到 Embedding、特征交叉或向量拼接时,随时回到
slotId / featureSign / value检查信息究竟放在哪里。
Let's dive in! 🚀
推荐系统是什么
📝 Before You Continue: 本章是基础起点,不需要任何推荐系统前置知识。你只需要知道「机器学习是让模型从数据中学习规律」这一基本事实即可。
当你早晨打开手机刷新闻,或在电商 App 里闲逛时,可能并未意识到:有一套精密的系统正在毫秒之间做出成千上万个判断,决定你看到什么、错过什么。这就是 推荐系统——现代互联网最底层的基础设施之一。
但「帮用户找到感兴趣的内容」只是表面描述。要真正理解它,我们需要从三个层次去观察:从最微观的 单个预测 ,到工业级的 规模流程 ,再到宏观的 生态平衡。只有层层递进,才能把握推荐系统的核心逻辑。
读完本章,你将能够:
- 用 一句话 说清推荐系统要解决的微观问题,并区分其两种根本范式
- 写出 判别式 与 生成式 的核心公式,并解释二者「问的问题」有何不同
- 解释工业级推荐为何采用「召回—排序—重排」三阶段漏斗 ,以及各阶段职责
- 说明 端到端生成式架构 如何消解级联架构的三大痛点
- 从 生态三角 (用户/创作者·内容·平台)理解推荐系统的长期价值
- 完成 4 道分层练习题,巩固三种视角
1.1.0 三种视角:从微观到宏观
理解推荐系统,最忌「只看到算法」。同样一套系统,放在不同尺度下看到的东西完全不同:
| 视角 | 观察对象 | 核心问题 |
|---|---|---|
| 🔬 微观 | 一次「用户—物品」判断 | 两种根本范式如何定义推荐? |
| 🏭 工业 | 亿级物品 → 一份列表 | 如何在毫秒内完成规模化筛选? |
| 🌍 宏观 | 多方参与的生态 | 技术上「准确」的系统就是好系统吗? |
接下来我们逐一拆解。
1.1.1 微观视角:推荐问题的两种根本范式
让我们从最基本的单元想起。推荐系统面临的核心问题看似简单——如何为用户找到最有价值的内容? 但对这个问题的回答,存在两种截然不同的思路。
无论哪种思路,系统都需要先深入理解三个关键要素:
- 理解用户(User)——你是谁、兴趣如何。历史行为是最重要的信号;显式反馈(如「不感兴趣」按钮)和画像信息(年龄、地域)提供线索;实时意图(刚搜了什么)同样关键。
- 理解物品(Item)——它的内容属性(品类、时长、质量)与统计属性(观看数、评分、互动趋势)。
- 理解场景(Context)——工作日早晨还是周末深夜?地铁通勤还是居家休闲?细微差别显著影响偏好。
💡 Key Insight: 两种范式的输入相同(都要理解用户、物品、场景),但它们提出的问题截然不同。这一点决定了后续所有的架构与优化目标差异。
第一种思路:判别式推荐(Discriminative)
它将推荐定义为:给定一个具体的「用户—物品—场景」三元组,预测用户会对该物品产生正面行为的概率。核心是 打分函数 :
系统对每个候选物品逐一评估、计算分数、再择优推荐。这就像一位评委,面对所有选手逐一打分,最后选出高分者。
判别式推荐通过整合用户特征 、物品特征 与场景特征 ,对每个候选物品逐一打分,预测「有价值连接」的可能性。
🧠 Mental Model: 评委打分
把推荐想成「选秀评委」。台上站满选手(候选物品),评委(模型)对每一个选手单独打分,最后按分数高低发通行证。评委从不「直接报出名单」,他只负责打分。
第二种思路:生成式推荐(Generative)
它从根本上重新定义了问题:不再逐一评估候选,而是让模型根据用户与场景的理解, 直接「创作」推荐结果。核心是 生成函数 :
模型以用户的历史交互序列和当前场景为输入,通过自回归解码直接生成推荐物品序列。这就像一位了解你品味的朋友,不需要翻遍所有选项,而是直接说「你接下来该看这几个」。
生成式推荐以用户历史交互与场景为输入,通过生成模型直接输出推荐物品序列,无需逐一评估候选。
🤔 Why 两种范式共存? 判别式在「有限候选中择优」上极其成熟稳定;生成式在「开放空间中创造」上潜力巨大。前者问「用户会喜欢这个物品吗?」,后者问「用户接下来想看什么?」——前者是择优,后者是创造。
能力演进的四个阶段
从更纵深的时间线看,推荐算法呈现出一条清晰的能力演进轨迹,它同时贯穿两种范式:
- 纯 ID 的记忆——协同过滤将物品视为不透明符号,记忆「看过 A 的人也看了 B」的共现模式。
- 深度学习的泛化——深度网络通过特征交叉与序列建模,把知识泛化到未见过的用户—物品组合,但物品仍是原子 ID。
- 语义 ID 的理解——当物品被编码为携带语义的结构化 Token,系统开始真正「理解」内容含义,新物品无需积累行为数据即可被推荐。
- 大模型的推理——模型不再隐式算分,而是显式分析意图、评估匹配、给出理由,从「模式匹配器」进化为「能解释决策的推理者」。
💡 Key Insight: 这四个阶段并非线性替代,而是层层叠加、彼此共存。今天的工业系统里,基于 ID 的协同过滤仍是召回要道,深度泛化支撑着召回到排序各环节,语义 ID 与大模型推理则在最前沿崭露头角。
1.1.2 工业视角:规模化的两条技术路线
理解了两种基本范式,我们立刻面临共同的现实挑战: 规模。一个典型视频平台拥有数亿用户、上亿物品,推荐要在毫秒级延迟内完成从海量物品到个性化列表的全过程——页面加载超过几秒,大部分用户就会离开。
⚠️ Warning: 推荐系统工程化的核心矛盾是——如何在极有限时间内,从海量候选中找到最优结果? 两种范式给出了截然不同的解法。
判别式的解法:多阶段流水线
判别式范式的核心困难在于:若为每个用户计算他与所有物品的匹配分数,再强的服务器也会瞬间崩溃。工业界的答案是 分阶段的漏斗式架构 ,用「召回—排序—重排」三层流水线逐步缩小候选,在效率与效果间找平衡。
- ① 召回(Recall)——快速从全量物品库筛出几千个可能相关的候选。奉行「宁可错杀一千,不可放过一个」,不求精准但求全面;模型简单、特征有限(如用协同过滤找相似用户,或基于内容相似性召回)。
- ② 排序(Ranking)——预测函数 真正发威的地方。动用最复杂的深度模型,融合用户/物品/场景全特征,为每个候选算精确分数;追求预测精度最大化。
- ③ 重排(Re-ranking)——对排序结果做最终优化。解决「分数最高的列表 ≠ 体验最佳的列表」问题:引入多样性、新颖性,避免前十全是同类内容造成审美疲劳,同时处理广告、运营等业务规则。
💡 Key Insight: 三阶段流水线的精髓是——在不同阶段用不同策略,逐步从「可能相关」筛到「最优匹配」。召回求全、排序求准、重排求体验,三者缺一不可。
生成式的解法:端到端生成
生成式提出一种截然不同的思路:既然模型能直接「生成」结果,为何还需要多阶段筛选?生成式推荐把用户历史交互序列当作「上下文」,通过 Transformer 等自回归模型直接解码出物品 Token 序列——整个过程在一个统一模型里端到端完成 ,无需召回/排序/重排的级联。
💡 Key Insight: 端到端架构消除了级联架构的三个核心痛点:
- 目标不一致——召回优化相关性、排序优化点击率、重排优化多样性,各自为战;
- 信息损失——召回过滤掉的优质物品,后续阶段永远看不到;
- 计算碎片化——不同阶段用不同模型,难以充分利用现代 GPU 算力。
下面用交互演示直观感受「亿级 → 一份列表」的漏斗过程:
点击「下一步」或「自动播放」,观察候选池如何从亿级逐步收缩到最终 10 条列表,以及每一阶段所承担的不同职责。
📊 Data Point: 目前两种架构在工业界并行发展:判别式流水线以「分而治之」在成熟场景中稳定服务;生成式架构以「端到端优化」在前沿探索中展现巨大潜力。
1.1.3 宏观视角:构建多方共赢的生态系统
把推荐系统放在更大视野中,会浮现一个更深层的问题: 一个技术上完美的推荐系统,是否就是一个真正优秀的推荐系统? 答案往往是否定的。
经典的 「准确率陷阱」 :用户刚把一部手机加入购物车,此时系统向他推荐这部手机,点击率与转化率可能接近 100%。从指标看极其「准确」,但它创造了什么价值?几乎没有——用户本来就要买,推荐只是重复了他已知的信息,没有增量价值。
💡 Key Insight: 推荐系统的最终目标不是单纯最大化技术指标,而是构建一个让所有参与方长期受益的健康生态。生态中有三个基本支点:用户与创作者、内容、平台,三者相互依存。
- 用户与创作者——分处内容消费与供给两端。用户是最终服务对象,系统应帮其发现「尚未接触但真正感兴趣」的内容,而非困在「越看越窄」的过滤气泡;创作者是内容供给核心,分发能力直接决定其生存空间与动力。供给端正从专业团队(PGC)为主,走向普通用户自发创作(UGC)为主体,并涌现出 AI 辅助生成(AIGC),模糊消费者与生产者边界。
- 内容——连接用户与创作者的媒介,是真正分发的「原子单位」。健康系统不仅要分发受欢迎内容,还要持续发掘潜力内容,避免「头部集中、长尾沉没」。
- 平台——生态协调者。既要优化效果、提升满意度与时长,又要关注长期健康(多样性、抑制低质、保护创作者积极性),有时需牺牲短期指标换取长期信任。
⚡ Pro Tip: 真正优秀的推荐系统是一个精巧的平衡器——在用户、创作者、内容质量与平台发展间找动态平衡点。这要求设计者不仅是技术专家,更需具备生态思维。
⚠️ Common Mistakes in 1.1
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把推荐等同于「排序」 | 「推荐系统就是个点击率预估模型」 | 排序只是三阶段之一,前面还有召回、后面还有重排 | 始终用「召回→排序→重排」全景理解推荐 |
| 2 | 混淆两种范式问的问题 | 以为生成式也是「对每个候选打分」 | 生成式直接产出序列,不做逐候选评估 | 记住:判别式 择优 ,生成式 创造 |
| 3 | 唯指标论 | 用 100% 转化率的「加购后推荐」证明系统优秀 | 没有增量价值,落入准确率陷阱 | 追问:推荐是否创造了用户本不会获得的价值? |
| 4 | 忽视生态长期性 | 为短期时长无脑推标题党 | 损害信任与创作者生态,长期崩塌 | 用生态三角评估取舍,敢牺牲短期指标 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 判别式推荐 | ,对候选逐一打分择优 | 工业级推荐的主干,成熟稳定 |
| 生成式推荐 | ,直接生成序列 | 端到端、潜力大,是前沿方向 |
| 三阶段流水线 | 召回(全)→排序(准)→重排(体验) | 在毫秒延迟内平衡效率与效果 |
| 端到端生成 | 单模型替代多阶段级联 | 解决目标不一致、信息损失、算力碎片化 |
| 生态三角 | 用户/创作者·内容·平台 | 跳出指标,理解系统的长期价值 |
❓ FAQ
Q1: 判别式和生成式,哪个更好?
A: 没有绝对优劣。判别式在成熟场景稳定高效,生成式在前沿探索潜力大。当前工业界两者并行发展,应按业务阶段选择。
Q2: 为什么不能直接给用户展示全量物品让他挑?
A: 上亿物品中,用户只会看极少数。推荐的价值正是替用户在亿级空间里做减法,且要在毫秒级完成——这是工程现实,不是设计偏好。
Q3: 召回阶段为什么可以用「简单模型」?
A: 召回奉行「宁可错杀不可放过」,目标是覆盖而非精准。候选集随后会被排序精筛,所以召回侧可用轻量模型换速度。
前后关联
- 1.2 (本书概览)把本节三种视角落到全书技术地图,定位每章在能力演进曲线上的位置。
- 2.1–2.5 (召回)展开三阶段中「召回」的具体算法家族。
- 3.1–3.5 (排序)深入判别式打分函数 的工程实现。
- 5.3 (生成式范式演进)回头呼应本节,系统梳理从判别式到生成式的跃迁。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 1.1.1 — 区分范式 🟢 Easy
给定以下两个系统描述,判断它们更接近 判别式 还是 生成式 范式,并说明理由。
- (a) 系统为每个候选广告计算「用户点击概率」,按概率排序展示前 5 个。
- (b) 系统读取用户近 20 次播放记录,直接输出「接下来你可能想看的 3 个视频 ID」。
💡 Solution (click to reveal)
Approach: 抓住两种范式「问的问题」差异——是逐候选打分,还是直接产出序列。
- (a) 判别式 :对每个候选广告单独算点击概率再排序,正是 的「逐一打分择优」。
- (b) 生成式 :直接由历史序列解码出推荐 ID 序列,不做逐候选评估,对应 。
Key points:
- 判别式 = 候选已知、逐一打分;生成式 = 直接「创作」序列。
- 判断关键是看系统是否枚举并评估了每一个候选。
Problem 1.1.2 — 补全流水线 🟢 Easy
一个推荐系统面对 1 亿物品,最终展示 10 条。请在括号中填入正确的阶段名,使其符合工业级漏斗:
全量物品 (1亿) → [ ① ] → 候选 (约2000) → [ ② ] → 候选 (约200) → [ ③ ] → 最终列表 (10条)
💡 Solution (click to reveal)
Approach: 回忆三阶段漏斗的「职责递进」。
全量物品 (1亿) → [ 召回 Recall ] → 候选 (约2000)
→ [ 排序 Ranking ] → 候选 (约200)
→ [ 重排 Re-ranking ] → 最终列表 (10条)
Key points:
- 召回求全 (覆盖),排序求 准 (精度),重排求 体验(多样性/业务)。
- 量级从亿 → 千 → 百 → 十,逐级收缩。
Problem 1.1.3 — 准确率陷阱分析 🟡 Medium
某新闻 App 发现:向刚读完一篇「世界杯决赛」报道的用户,立即推荐另一篇「世界杯决赛」报道,点击率高达 95%。产品经理据此认为推荐「非常精准」。请指出这个结论的问题,并给出更合理的评估角度。
💡 Solution (click to reveal)
Approach: 用「准确率陷阱」框架审视指标与价值的错位。
答: 95% 点击率只是「重复用户已知信息」,没有创造增量价值——用户本来就会点开同主题后续报道。这落入准确率陷阱:指标高 ≠ 系统好。
更合理的评估角度:
- 增量价值 :推荐是否让用户发现了「本不会主动找」的内容(多样性、探索性)?
- 生态健康 :是否陷入「越看越窄」的过滤气泡,损害长期留存?
- 多目标平衡 :除点击率外,是否兼顾时长、分享、关注等长期指标?
Key points:
- 技术指标高不等于用户价值高。
- 评估应跳出单点准确率,看长期与生态。
🏆 Challenge: 设计权衡论证
假设你要为一款日活千万的新App从零搭建推荐系统。请写一段 150 字内的论证,说明:在初期数据稀疏、算力有限时,为何应 优先采用判别式三阶段流水线 而非端到端生成式架构?并指明当业务进入成熟期后,可在哪类场景尝试引入生成式。
💡 Hint
从「数据需求、算力成本、可解释性、迭代可控性」四个维度对比两种架构;成熟期可优先在 候选生成/召回 或 重排多样性 等环节做生成式试点。
本书概览与技术地图
📝 Before You Continue: 请先读完 1.1 的三种视角。本章把那张「立体认知」展开成一张可导航的技术地图,帮你定位后续每一章。
理解了推荐系统的核心逻辑后,真正的挑战是把认知变成可操作的技术方案。研究者与工程师提出过数百种算法,初学者常陷入迷茫:这些模型有什么关系?什么场景选哪种?如何拼出完整系统?
本章给你一张地图。本书沿 判别式 与 生成式 两条主线组织,同时串起从「记忆·泛化」到「理解·推理」的能力演进。
读完本章,你将能够:
- 说出本书 上下两篇 的划分逻辑与各自的落脚点
- 把 基础篇(Part 1–5) 每一章对应到三阶段流水线或前沿趋势
- 解释为何「召回→排序→重排」是判别式的组织线索
- 预判 生成式主线 在后续版本(Part 6–11)将如何展开
- 完成 4 道分层练习题,检验对技术地图的掌握
1.2.0 一张地图,两条主线
本书的编排可用一张图概括:横轴是 时间/能力演进 (从纯 ID 记忆到 LLM 推理),纵轴是 两条范式主线 (判别式 vs 生成式)。
- 上篇:判别式推荐的工业实践——沿「召回 → 排序 → 重排」流水线逐步深入,是记忆与泛化能力的主战场。
- 下篇:生成式推荐的技术图景——从基础范式出发,经 Scaling Law、端到端建模、推理能力到扩散模型,是理解与推理能力的探索场。
💡 Key Insight: 两条主线不是割裂的。生成式架构往往在判别式成熟模块的基础上「端到端化」;而判别式的语义 ID、特征交叉等技术,又为生成式提供了表示基石。
1.2.1 上篇:判别式推荐的工业实践(本版覆盖)
本版(基础篇)完整收录上篇及承上启下的趋势章,共 5 个 Part:
| Part | 主题 | 在流水线中的位置 | 核心内容 |
|---|---|---|---|
| Part 1 | 引言与概览 | — | 两种范式、三阶段漏斗、生态三角、特征与 Embedding 基础 |
| Part 2 | 快速候选召回 | ① 召回 | 协同过滤 / 向量召回 / 双塔 / 序列召回 / 流式索引 |
| Part 3 | 精准偏好预测 | ② 排序 | Wide&Deep / 特征交叉 / 序列建模 / 多目标 / 多场景 |
| Part 4 | 重排多样性建模 | ③ 重排 | 贪心重排(MMR/DPP)/ 个性化重排(PRM) |
| Part 5 | 前沿趋势 | 跨阶段 | 模型去偏 / 冷启动 / 生成式范式演进 |
召回:从亿到千(Part 2)
召回是流水线起点,要在毫秒级从亿级物品筛出千级候选。其技术演进沿五节展开:
- 协同过滤——经典起点:从 ItemCF 的物品相似度,经 Swing 工业优化、UserCF 用户视角,到矩阵分解把用户/物品映射为隐向量,开启向量化先河。
- I2I 向量召回——把 Word2Vec 序列建模思想迁移到推荐:从 Item2Vec 直接迁移,到 EGES 融合属性,再到 Airbnb 把业务目标融入序列构建。
- 双塔模型(U2I)——用户与物品分别编码为向量,以 FM、DSSM、YoutubeDNN 为代表,实现高效向量检索。
- 序列召回——关注被前面方法忽略的时序信息:MIND 用多向量表示多元兴趣,SDM 分离长短期偏好并以门控动态融合。
- 流式索引召回——跳出模型内部压缩:Trinity 用聚类统计保留全量历史兴趣,Streaming VQ 让索引结构实时适应数据分布。
排序:从千到百(Part 3)
排序对千级候选精准打分,是深度泛化的主战场:
- Wide & Deep——联合训练线性模型与深度网络,确立「记忆 + 泛化」基础框架。
- 特征交叉——从 FM 二阶交叉,经 DeepFM、xDeepFM,走向自动高阶交叉。
- 序列建模——DIN 用注意力按候选动态激活历史;DIEN 显式建模兴趣时序演化。
- 多目标 / 多场景——MMoE、ESMM 平衡多目标;多塔与动态权重适配多场景差异。
重排:从百到一屏(Part 4)
排序输出常高度同质化,重排在保相关性的前提下优化整张列表体验:
- 贪心重排——MMR 线性组合相关性与多样性;DPP 用行列式框架更精确控制多样性。
- 个性化重排——PRM 用 Transformer 建模物品间相互影响,实现端到端个性化列表生成。
1.2.2 下篇预览:生成式推荐(后续版本覆盖 Part 6–11)
为帮你建立完整认知,这里简要预告下篇,让你知道本版之后的路通向何方:
| Part | 主题 | 一句话 |
|---|---|---|
| Part 6 | 生成式基础 | Transformer / 扩散模型 / LLM 流程 / 物品 Token 化(语义 ID) |
| Part 7 | Scaling Law 架构 | HSTU 把逐候选打分转为用户级序列建模;RankMixer 做硬件感知统一架构 |
| Part 8 | 端到端生成 | OneRec(推荐)/ OneSug·OneSearch(搜索)/ EGA(广告)用一个模型替代流水线 |
| Part 9 | 会思考的推荐 | 语义对齐(LC-Rec)→ 推理激活(OneRec-Think)→ 自主推理(RecZero) |
| Part 10 | 扩散模型推荐 | DiffuASR 数据增强 / AsymDiffRec·DMSG 特征与多样性优化 |
| Part 11 | 生产级项目 | 电影推荐全链路:离线训练 + 在线服务 + 前端 + Docker 部署 |
📝 Note: 本版聚焦基础篇(Part 1–5)。下篇内容将在后续版本以相同 book-writer 规范续写。
⚠️ Common Mistakes in 1.2
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把章节当孤立算法 | 「这一章讲 DIN,下一章讲 DIEN,没关系」 | 章节是流水线上的连续环节,前一章是后一章的输入 | 始终用「流水线位置」理解每章 |
| 2 | 只记模型名不记动机 | 背下 FM/DeepFM 却说不清为何要高阶交叉 | 模型是为解决具体局限而生,脱离动机学不牢 | 每学一模型,先问「它解决了前一方法的什么不足」 |
| 3 | 误以为生成式取代判别式 | 「学了生成式就不用看上篇了」 | 二者并行发展,生成式常建立在判别式表示之上 | 把两条主线当作互补而非替代 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 两条主线 | 判别式(上篇)/ 生成式(下篇) | 全书组织骨架,决定你如何归类每个模型 |
| 三阶段线索 | 召回→排序→重排 贯穿上篇 | 理解每章在流水线上的位置 |
| 能力演进 | 记忆→泛化→理解→推理 | 解释为何技术不断迭代而非简单替代 |
| 本版边界 | 覆盖 Part 1–5(基础篇) | 明确本版范围,避免期待错位 |
❓ FAQ
Q1: 基础篇为什么停在 Part 5,不连同生成式主线一起?
A: 生成式主线的基石(Part 6),概念密度陡增(语义 ID、Transformer、扩散模型)。先夯实判别式工业实践,再进生成式,认知更稳。
Q2: 召回、排序、重排必须都用深度学习吗?
A: 不一定。召回常用轻量方法(协同过滤、双塔);排序才动用最复杂深度模型;重排可用规则或轻量模型。复杂度随候选收缩而递增。
Q3: 我该按什么顺序读?
A: 严格按 Part 1→5 顺序。后一章常以前一章为前置(如序列建模建立在特征交叉之后)。
前后关联
- Part 2 召回(2.1–2.5) 把本章「召回:从亿到千」展开为五个算法家族。
- Part 3 排序(3.1–3.5) 深入判别式打分函数 的工业实现。
- Part 4 重排(4.1–4.2) 收尾三阶段流水线,并衔接趋势章。
- Part 5 趋势(5.1–5.3) 用「去偏 / 冷启动 / 生成式」承上启下,指向后续版本的下篇。
Practice Problems
Problem 1.2.1 — 定位章节 🟢 Easy
把下列算法拖入(写出对应 Part/章节)它在流水线中的正确位置: (a) DPP 重排 (b) YoutubeDNN 双塔 (c) DeepFM 特征交叉 (d) Swing 协同过滤
💡 Solution (click to reveal)
Approach: 回忆三阶段与各环节代表模型。
| 算法 | 位置 |
|---|---|
| (a) DPP 重排 | Part 4 重排(4.1 贪心重排) |
| (b) YoutubeDNN 双塔 | Part 2 召回(2.3 双塔 U2I) |
| (c) DeepFM 特征交叉 | Part 3 排序(3.2 特征交叉) |
| (d) Swing 协同过滤 | Part 2 召回(2.1 协同过滤) |
Key points:
- 召回侧方法偏轻量、覆盖导向;排序侧动用复杂深度模型。
- 重排发生在排序之后,优化列表级体验。
Problem 1.2.2 — 能力阶段归类 🟢 Easy
将下列技术归入「记忆 / 泛化 / 理解 / 推理」四个能力阶段之一: (a) 协同过滤共现 (b) 深度特征交叉 (c) 语义 ID(RQ-VAE) (d) OneRec-Think 显式推理
💡 Solution (click to reveal)
Approach: 对照能力演进曲线。
- (a) 记忆(纯 ID 共现)
- (b) 泛化(深度网络推广到未见组合)
- (c) 理解(物品编码为携带语义的 Token)
- (d) 推理(模型显式分析意图、给出理由)
Key points:
- 四阶段层层叠加而非替代;同一条演进曲线串起全书。
Problem 1.2.3 — 动机追问 🟡 Medium
为什么「特征交叉」要从 FM 的二阶,演进到 xDeepFM 的自动高阶?请用一个具体例子说明:仅用二阶交叉会遗漏什么类型的模式。
💡 Solution (click to reveal)
Approach: 从「模型要解决什么局限」切入。FM 的二阶交叉只建模 两两特征 的组合(如 性别×品类)。但真实业务中,价值常来自 更高阶的交互——例如「一线城市 × 年轻女性 × 美妆品类」的三阶组合才触发强兴趣。
若只有二阶交叉,模型无法显式捕捉这种三阶(及以上)协同信号,只能靠隐式近似,表达力受限。xDeepFM 等用向量/神经网络 自动 学习任意阶交叉,摆脱人工特征工程,覆盖高阶模式。
Key points:
- 二阶交叉 = 两两组合;高阶交叉 = 多特征联合。
- 演进动机:表达力不足 → 自动化高阶交互。
🏆 Challenge: 设计你的阅读路线
假设一位同事「只会写 SQL 和简单 LR,没碰过深度学习」,但又急需两周内上手贵司的推荐排序模块。请基于本章技术地图,为他设计一份 两周学习路线 (列出每日/每阶段该读哪几章、跳过哪些、为什么),并说明理由(150 字内)。
💡 Hint
优先保「流水线主线」:Part1→Part2 召回→Part3 排序(Wide&Deep、特征交叉、序列建模),重排与趋势可后置;生成式主线(Part 6+)暂跳过。理由是排序模块最依赖 Part3,且深度基础可从 Wide&Deep 平滑切入。
特征与 Embedding 入门
📝 Before You Continue: 请先读完 1.1 的用户—物品—场景三元组与 1.2 的技术地图。你需要会读基础 C++,并知道哈希函数能把字符串稳定映射为整数;不要求机器学习背景。
推荐系统最终处理的不是抽象的“用户兴趣”,而是一组具体字段:性别=男、城市=北京、广告ID=10001、预估点击率=0.073。业务代码认识这些字段,但神经网络只接受数字张量。两者之间缺少一座桥。
这座桥就是 特征处理。它把原始业务字段变成 slotId + featureSign + value,再由模型服务把无语义的编号查成可学习的 Embedding 向量。这条链路看似只是数据格式转换,却决定了模型能看见什么、怎样泛化,以及训练与线上是否一致。
1.3.0 从业务字段到模型输入
一个排序请求通常同时包含四类信息:
| 类别 | 典型字段 | 回答的问题 |
|---|---|---|
| 用户信息 | 用户 ID、性别、年龄、城市 | 这个人是谁?长期偏好是什么? |
| 物品信息 | 广告 ID、视频 ID、类目、作者 | 当前候选是什么? |
| 上下文信息 | 时间、网络、设备、候选位置 | 这次请求发生在什么场景? |
| 连续数值 | 预估 CTR、eCPM、质量分、时长 | 某个信号具体有多强? |
这些可被模型利用的信息统称为 特征(Feature)。但原始值不能原样送进模型:字符串无法参加矩阵乘法;业务 ID 的数字大小没有语义;不同连续值的量纲又可能相差数十亿倍。
上图给出了完整职责边界:业务服务负责特征生成,模型服务负责查 Embedding、组合特征并完成网络计算。二者通过稳定的特征协议连接。
💡 Key Insight: 特征处理不是“把东西变成数字”这么简单。它要同时保留类别身份、数值大小和工程稳定性,并确保离线训练与在线预测看到的是同一种表达。
1.3.1 三元组:slotId / featureSign / value
工业系统常把一条特征整理为如下记录:
struct FeatureInfo {
int slotId; // 特征属于哪个字段或特征组
int64_t featureSign; // 具体取值的查表 key
float value; // 数值或权重
};
三个字段各管一件事:
| 字段 | 含义 | 图书馆类比 |
|---|---|---|
slotId | 这是什么类型的特征 | 哪个书架 |
featureSign | 这个具体取值的编号 | 书架上哪本书的索引号 |
value | 这次使用它的数值或权重 | 这本书本次被使用的强度 |
例如,用户性别为“男”时,可以表达为:
FeatureInfo sex_feature{
.slotId = SEX,
.featureSign = gen_feasign_string(SEX, "男"),
.value = 1.0F
};
它可以读成:“去 SEX 书架,找到‘男’这个取值对应的条目,本次权重为 1.0。”
连续特征的分工不同。若预估点击率为 0.073:
FeatureInfo ctr_feature{
.slotId = AD_ETR_DENSE,
.featureSign = 1,
.value = 0.073F
};
这里 featureSign=1 只是固定占位,真实信息放在 value 中。先记住这个对照:
| 特征表达 | featureSign 放什么 | value 放什么 | 信息主要在哪里 |
|---|---|---|---|
| 离散 / 分桶 | 类别或桶的编号 | 通常为 1.0 | featureSign |
| Dense 连续 | 固定 key,常用 1 | 归一化后的真实数值 | value |
⚠️ Warning:
featureSign应被视为不透明的 64 位 key。若用uint64_t生成、再存入int64_t,最高位为 1 时在常见二进制补码实现中会显示为负数。只要下游按相同位模式查表通常没有问题,但不要对它做大小比较、abs()或带符号取模。
1.3.2 featureSign 如何生成
一种常见设计,是把 slotId 放进高 32 位,把具体取值的编号放进低 32 位:
这样,即使两个字段的低位编号碰巧相同,只要 slotId 不同,最终 key 仍然不同。
字符串取值:先哈希,再拼接
static uint64_t gen_feasign_string(
uint64_t slot_id,
const std::string& value) {
const uint32_t value_hash = gen_hash_new(value.data(), value.size());
const uint64_t slot_bits = (slot_id << 32) & 0xffffffff00000000ULL;
return slot_bits | value_hash;
}
这段代码分三步:
gen_hash_new把字符串稳定映射为 32 位整数。slot_id << 32把特征类型移到高 32 位。- 按位或
|把高位类型与低位取值合成一个 key。
例如 SEX=男 与 AGE_BUCKET=20 的低位哈希即使都等于 111,最终 key 仍分别是 [SEX][111] 与 [AGE_BUCKET][111]。Slot 分段把不同字段隔离开了。
💡 Key Insight:
featureSign像“班级号 + 学号”。学号只在班级内部区分学生;高位的班级号让不同班级的相同学号不冲突。
整数取值:能直接编码就不要哈希
如果取值本来就是小整数,例如网络类型 4、星期 2 或桶编号 7,可以直接放进低 32 位:
static uint64_t gen_feasign_int32(
uint64_t slot_id,
uint32_t value) {
const uint64_t slot_bits = (slot_id << 32) & 0xffffffff00000000ULL;
return slot_bits | value;
}
只要取值能被 32 位无符号整数完整表示,这种编码没有额外的哈希冲突。因此,小枚举和桶编号应优先使用整数版本。
哈希冲突是取舍,不是异常
字符串被压进 32 位空间后,冲突无法避免。低 32 位只有 个位置;根据生日悖论,一个 slot 内约有 7.7 万个不同取值 时,出现至少一次冲突的概率就超过 50%。
| Slot 示例 | 基数数量级 | 冲突影响 |
|---|---|---|
SEX | 几乎可忽略 | |
CITY | 通常可忽略 | |
AD_ID | 会出现少量冲突 | |
GUID | 大量冲突不可避免 |
两个不同取值发生冲突后,会共享同一条 Embedding,模型无法再区分它们。为什么工业系统仍常用这种 Feature Hashing ?因为它换来了无状态、可扩展的特征生成:不需要维护巨大的字符串词表,新取值也能立即得到 key。
Analysis:
- 收益: 无需中心词表,新增取值天然可处理,线上服务可水平扩展。
- 代价: 少量语义混淆,无法从 key 反查原值,高基数特征更难调试。
- 缓解: 增大哈希空间、使用双哈希、过滤低频值,或为关键高基数 slot 维护独立词表。
1.3.3 为什么需要 Embedding
这是本章最容易混淆、也最关键的一点:
💡 Key Insight:
featureSign是查 Embedding 的 key,不是 Embedding 本身。 它负责稳定地指出“是哪一个类别”,但不负责表达这个类别与其他类别的关系。
二者的区别如下:
| 对象 | 示例 | 是否训练 | 本质 |
|---|---|---|---|
featureSign | 500111 | 否 | 稳定、离散的索引 key |
| Embedding | [0.12, -0.03, 0.88, 0.21] | 是 | 模型从数据中学习的向量参数 |
| Embedding Table | key → vector | 是 | 按 key 保存和更新向量的参数表 |
从 One-Hot 到 Embedding
假设 CITY 只有“北京、上海、深圳”三个取值。最直接的编码是 One-Hot:
北京 -> [1, 0, 0]
上海 -> [0, 1, 0]
深圳 -> [0, 0, 1]
One-Hot 有两个性质:第一,它不会错误地制造大小关系;第二,不同类别彼此等距。但当广告 ID 有 1000 万种取值时,一个样本需要逻辑上占据 1000 万维空间,而且向量中只有一个位置为 1。直接把这种超高维稀疏向量送进网络,参数量和计算量都难以接受。
Embedding 层可以看成一个大矩阵 。One-Hot 向量乘以矩阵,本质上就是从 中选择一行:
因此工程上不必真的构造 One-Hot。只需传入类别对应的 featureSign,直接查出 。这既节省计算,又让模型能通过训练把行为相似的类别拉到相近的向量区域。
为什么不能直接把 featureSign 当 Embedding
假设有三个广告:
运动鞋广告 -> featureSign = 105
篮球广告 -> featureSign = 980001
婴儿奶粉 -> featureSign = 106
若直接把 sign 当成一个标量输入,模型会得到荒谬的几何关系:运动鞋 105 与奶粉 106 的距离只有 1,而与语义更接近的篮球 980001 相距近百万。这个距离完全由编号或哈希偶然决定,不代表用户行为相似度。
直接使用 sign 还有四个问题:
- 虚假的顺序关系。
500222 > 500111不代表某个类别“更大”或“更好”。 - 虚假的距离关系。 两个哈希值接近,不代表两个类别相似;相差很远也不代表不相似。
- 无法学习类别语义。 sign 是固定整数,不会在反向传播中朝“更像篮球”或“更像运动鞋”的方向移动。
- 数值精度风险。 64 位 sign 若转成
float32,超过 后很多相邻整数无法被精确区分,不同 key 可能被舍入成同一个浮点数。
Embedding 则为每个 key 提供一组 可训练参数。若观看篮球内容的用户经常点击运动鞋广告,训练会让这两个类别的向量逐渐靠近;奶粉广告的向量则可能位于另一片区域。类别之间的距离由数据学习,而不是由哈希值决定。
⚠️ Warning: “把 sign 转成 8 维二进制、十进制拆位或做归一化”仍然不是 Embedding。这些操作只是以另一种方式暴露任意编号,不能产生可学习的类别语义。正确做法是把 sign 当索引,查询独立的可训练向量。
一次完整的查表过程
假设 SEX=男 生成 featureSign=500111,Embedding 表当前保存:
E[500111] = [ 0.12, -0.03, 0.45]
E[500222] = [-0.21, 0.34, 0.08]
前向传播时,模型用 500111 查出第一行 [0.12, -0.03, 0.45]。若本次预测误差反向传播到这个特征,只更新 E[500111] 及相关网络参数,而不会把整数 500111 改掉。
这说明两者职责严格分离:
featureSign:稳定定位参数,训练前后保持不变
Embedding:承载可学习语义,会随训练持续更新
同一取值为什么共用一条 Embedding
两个用户都具有 SEX=男,就会生成相同的 featureSign,进而查询同一条 Embedding。这不会让两个用户变得无法区分,因为模型看到的是多个 slot 的组合:
| 用户 | 性别 | 年龄桶 | 城市 | GUID |
|---|---|---|---|---|
| A | 男 | 20–24 | 北京 | abc |
| B | 男 | 35–39 | 深圳 | xyz |
共享反而带来泛化能力:所有男性用户的样本共同更新“男性”这条参数,而年龄、城市、身份等其他特征继续保留个体差异。
Embedding 维度由谁决定
维度不由 C++ 特征生成代码决定,而由模型配置决定,通常按 slot 或特征组设置:
| Slot | 可能的基数 | 常见维度思路 |
|---|---|---|
SEX | 3 | 2–4 维通常足够 |
CITY | 可从 8 维起试 | |
AD_ID | 常在 8–32 维间权衡 | |
GUID | 维度乘基数会形成内存黑洞,需谨慎 |
维度越大,表示能力越强,但内存、通信和计算成本也越高;数据不足时还更容易过拟合。它是模型容量与系统成本之间的超参数,而不是“基数越大就无限加维度”。
1.3.4 离散特征与 Dense 特征如何编码
离散与 Dense 都可以装进 slotId + featureSign + value,但两条路径中“真正承载信息的字段”完全不同:
离散特征用 featureSign 选择“哪一行参数”;Dense 特征通常固定 sign,用 value 决定“同一组参数放大多少”。
| 对比项 | 离散特征(Sparse / Categorical) | Dense 特征(Continuous / Numerical) |
|---|---|---|
| 回答的问题 | 是哪一类? | 具体是多少? |
| 典型值 | 北京、男、广告 10001、网络类型 4 | CTR 0.073、时长 3600 秒、金额 57 元 |
| 算术关系 | 通常没有大小和距离意义 | 加减、大小和差值通常有意义 |
| 信息位置 | featureSign | value |
| 常见模型处理 | 按 sign 查 Embedding | 直接输入或投影为向量 |
离散特征:编码“是哪一个类别”
离散特征 的取值来自有限或可枚举集合。它们的数字形式只是身份,不应被解释为连续大小。例如网络类型 4 并不意味着它是网络类型 2 的两倍;广告 ID 10002 也不比 10001 更优。
一条离散特征通常经过五步:
- 规范化原始值。 统一编码、大小写、空格和缺失值,例如把空城市映射为
__UNKNOWN__。 - 选择 slot。
CITY、SEX、AD_ID各有独立的slotId。 - 生成 sign。 字符串先哈希,小整数可直接编码到低 32 位。
- 设置权重。 单值类别通常令
value=1.0。 - 查 Embedding。 模型用 sign 选择参数表中的一行。
例 1:字符串类别 SEX=男
假设 SEX 的 slotId=12,并假设 hash("男")=0x3A91F20B,那么:
高 32 位:slotId = 12 -> 0x0000000C00000000
低 32 位:hash("男") -> 0x000000003A91F20B
最终 sign -> 0x0000000C3A91F20B
业务服务生成:
const std::string normalized_sex = user.sex.empty()
? "__UNKNOWN__"
: user.sex;
features.emplace_back(
SEX,
gen_feasign_string(SEX, normalized_sex),
1.0F);
模型侧的处理可写成:
embedding = E_SEX[0x0000000C3A91F20B]
= [0.12, -0.03, 0.45]
output = 1.0 × embedding
= [0.12, -0.03, 0.45]
这里 value=1.0 只表示“该类别本次出现”。真正区分男、女、未知的是不同的 sign,以及它们各自对应的 Embedding。
例 2:整数枚举 APN_TYPE=4
网络类型本来就是小整数,无需先转字符串再哈希:
features.emplace_back(
APN_TYPE,
gen_feasign_int32(APN_TYPE, 4),
1.0F);
它会生成 [APN_TYPE][4]。与字符串版本相比,这种方式更直观,也不会引入额外的 32 位哈希冲突。
多值离散特征如何处理
“用户兴趣标签”可能同时包含 篮球、跑步、摄影。这时一个 slot 会产生多条 sign:
[INTEREST][hash(篮球)] value=1.0
[INTEREST][hash(跑步)] value=1.0
[INTEREST][hash(摄影)] value=1.0
模型查出三条 Embedding 后,通常做 sum、mean、加权池化或注意力聚合。若标签数量变化很大,mean 可以避免“标签越多,向量范数越大”的偏差;若不同标签重要性不同,可以把业务权重放进 value。
Analysis:
- 优点: 不制造虚假顺序,参数可按类别独立学习,也能通过向量空间共享行为模式。
- 成本: 高基数 slot 会产生大表;低频类别的向量训练不足。
- 关键检查: 同一业务值在离线与在线必须得到完全相同的 sign。
Dense 特征:编码“具体数值是多少”
Dense 特征 是有连续大小意义的数值。CTR=0.08 确实比 CTR=0.02 大,播放 100 秒也通常比播放 10 秒更长。编码时应保留这种数值关系,而不是为每个小数创建一条独立 Embedding。
Dense 特征在不同框架里有两种常见实现:
- 直接标量输入。 把归一化后的 与其他向量拼接,再送入 MLP。
- 统一 slot 协议。 使用固定
featureSign=1查一条参数向量 ,输出 。
本章工程采用第二种。它在数学上等价于把一维标量通过无偏置线性层投影到 维:
一条 Dense 特征通常经过四步:
- 校验与兜底。 处理缺失、
NaN、inf和非法负值。 - 变换与归一化。 根据分布选择直接使用、
log1p、Min-Max、Z-Score 或分位变换。 - 固定 sign。 该 slot 统一使用
featureSign=1,表示只需一组投影参数。 - 把数值放入 value。
value=x,模型计算x × E[1]。
例 1:已经归一化的 CTR=0.073
CTR 本身位于 ,可以先直接使用:
double ctr = ad.estimated_ctr;
if (!std::isfinite(ctr)) ctr = 0.0;
ctr = std::clamp(ctr, 0.0, 1.0);
features.emplace_back(
AD_ETR_DENSE,
1,
static_cast<float>(ctr));
假设这个 slot 的固定参数向量为:
W = E_AD_ETR_DENSE[1] = [0.40, -0.20, 0.10]
那么该样本送给上层网络的向量为:
0.073 × W = [0.0292, -0.0146, 0.0073]
另一个样本若 CTR=0.20,仍查同一条 ,但输出变为 [0.08, -0.04, 0.02]。因此 Dense 路径保留了“0.20 比 0.073 大”的连续关系。
例 2:长尾播放时长 watch_seconds=3600
时长常呈长尾分布。直接把 3600 放进 value 会让它的量级远大于 CTR 等特征。可以先做 log1p:
double seconds = watch_seconds;
if (!std::isfinite(seconds) || seconds < 0.0) seconds = 0.0;
seconds = std::min(seconds, 86400.0); // 顶部截断为 24 小时
const float encoded = static_cast<float>(std::log1p(seconds));
features.emplace_back(WATCH_TIME_DENSE, 1, encoded);
3600 秒被压缩为约 8.19,既保留“更长”的单调关系,也降低极端值对梯度和其他特征的支配。
📝 Note: Dense slot 中的
E[1]有时也被口头称为“Embedding”,但它与离散类别 Embedding 的角色不同。离散 Embedding 是“每个类别一行”;Dense slot 只有固定的一行,本质上是一组可学习的投影权重。
⚠️ Warning: Dense 特征不能不加检查地塞进
value。时间戳、金额、次数等大量级值会淹没其他特征并放大梯度。必须先做量纲压缩与异常值处理。
常见处理方式:
| 方法 | 形式 | 适用场景 |
|---|---|---|
log1p | 长尾正值:次数、时长、金额、eCPM | |
| Min-Max | 取值范围稳定且已知 | |
| Z-Score | 近似正态分布 | |
| 分位归一化 | 映射到经验 CDF | 分布不规则、离群值多 |
| 直接使用 | 不变 | 本身已在 ,如概率值 |
无论采用哪种方式,都要明确 NaN、inf、缺失值和异常负值的兜底规则。min/max/\mu/\sigma、分位点和截断阈值也必须在离线训练与在线服务之间共享。
Bucket:落在哪个区间
分桶特征 先把连续值切成区间,再把桶编号当类别:
static uint32_t cut_bucket(double value, uint32_t width) {
return static_cast<uint32_t>(value / width);
}
若 eCPM=57、桶宽为 20,则桶编号为 2。最终表达为 [AD_ECPM][2],value=1.0。
这不是 dense 特征。它表达的是“落在哪个区间”,每个桶都有独立 Embedding,因此可以学习非单调的区间效应。
原始 cut_bucket 仍有三个工程陷阱:
- 负值: 内的值截断后可能悄悄落到 0 桶;更小的负值转无符号整数时可能超出可表示范围,不能依赖其结果。
NaN/inf: 转整数没有可用语义,可能触发未定义行为。- 桶宽为 0: 除零后结果无效。
更安全的实现应先校验参数、钳制异常值,并设置顶桶:
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <stdexcept>
uint32_t safe_cut_bucket(
double value,
double width,
uint32_t max_bucket) {
if (!std::isfinite(width) || width <= 0.0) {
throw std::invalid_argument("bucket width must be positive");
}
if (!std::isfinite(value) || value < 0.0) {
value = 0.0; // ← KEY LINE: 异常输入统一兜底
}
const double raw_bucket = std::floor(value / width);
const double capped = std::min(raw_bucket,
static_cast<double>(max_bucket));
return static_cast<uint32_t>(capped);
}
Analysis:
- 等宽分桶: 实现简单,但长尾分布常让大多数样本挤在前几个桶。
- 等频分桶: 每桶样本更均衡,但依赖稳定的分位点统计。
- 对数分桶: 适合跨多个数量级的正值,能兼顾头部与长尾。
- 顶桶截断: 防止极端值制造大量只出现一两次的稀疏桶。
分桶与 Dense 为什么常同时使用
| 维度 | 分桶离散 | Dense 连续 |
|---|---|---|
featureSign | 桶编号 | 固定 key |
value | 1.0 | 真实归一化值 |
| 参数条数 | 每桶一条 | 整个 slot 一条 |
| 擅长 | 非线性、区间效应 | 精确大小、连续变化 |
| 局限 | 桶内无分辨力,边界不连续 | 单个线性缩放难表示复杂非单调关系 |
两者并用不是无意义重复。分桶告诉模型“处在哪个区间”,dense 告诉模型“准确是多少”。它们从不同角度表达同一个业务量。
1.3.5 Embedding 表与工程边界
表大小由唯一取值数决定
Embedding 表的主体内存可以粗略估算为:
其中 是该 slot 的唯一 featureSign 数, 是 Embedding 维度。实际系统还要计算哈希表元数据、key、指针和优化器状态;Adam 等优化器还可能额外保存一到两组同尺寸状态。
表大小不直接取决于请求量。十亿用户都只有三种性别时,SEX slot 仍只需要少量条目;但 GUID 本身接近“一用户一取值”,它的规模就会随用户增长。
准入、淘汰与 OOV
高基数 slot 会持续产生新 key,生产系统必须限制表增长:
| 机制 | 典型策略 | 解决的问题 |
|---|---|---|
| 准入 | 出现次数达到阈值后才建表项 | 过滤一次性噪声与超长尾取值 |
| 淘汰 | 连续若干天未出现则删除 | 清理失活用户、下线广告 |
| OOV | 零向量、默认桶或延迟建表 | 处理表中尚不存在的新 key |
“查询不到 key 时会发生什么”必须在加新特征前确认。若下游默认“随机初始化并立即写入”,一个高基数特征可能在短时间内撑大参数表;若返回零向量,则冷启动阶段该特征没有贡献,需要依赖其他可泛化特征。
Embedding 如何训练
Embedding 是推荐模型的一部分,与上层网络联合训练:
- 前向传播根据
featureSign查询向量。 - 多个向量与 dense 特征拼接或池化。
- DNN 输出点击率、转化率或排序分。
- 预测误差反向传播,同时更新 Embedding 与网络参数。
只有被训练样本覆盖到的 key 才能得到有效更新。只出现一两次的长尾特征,其向量接近随机初始值,既占内存又可能引入噪声——这正是频次准入存在的原因。
离线与在线一致性
这是特征工程中最隐蔽、也最常见的事故来源。训练样本与线上请求必须严格对齐:
- 哈希算法、种子和字符串编码;
slotId枚举值及候选位置偏移;- 分桶边界、桶宽与顶桶;
- 归一化统计量;
- 缺失值、异常值和大小写规则;
- 字符串
trim、拼接顺序和分隔符。
这类错误往往不会崩溃。服务仍能返回分数,监控也可能全绿,只是模型查到了“错误但合法”的参数,导致线上效果悄悄下降。
⚡ Pro Tip: 把改哈希、改 slot、改桶边界视为“换模型”,而不是普通代码热更新。优先让离线与在线共用同一份特征库;上线前抽取真实请求,逐字段对比两侧生成的三元组。
1.3.6 完整案例:给广告增加一个 eCPM 特征
假设业务已有 ad.ecpm,我们希望同时保留它的精确大小与非线性区间效应。合理做法是创建两个不同的 slot:
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <vector>
struct FeatureInfo {
uint32_t slot_id;
uint64_t feature_sign;
float value;
};
enum Slot : uint32_t {
AD_ECPM_BUCKET = 101,
AD_ECPM_DENSE = 102
};
uint64_t make_int_sign(uint32_t slot_id, uint32_t value_id) {
return (static_cast<uint64_t>(slot_id) << 32) | value_id;
}
uint32_t safe_bucket(double value,
double width,
uint32_t max_bucket) {
if (!std::isfinite(value) || value < 0.0) value = 0.0;
if (!std::isfinite(width) || width <= 0.0) return 0;
const double bucket = std::floor(value / width);
return static_cast<uint32_t>(
std::min(bucket, static_cast<double>(max_bucket)));
}
void append_ecpm_features(double raw_ecpm,
std::vector<FeatureInfo>& output) {
const double clean_ecpm =
(!std::isfinite(raw_ecpm) || raw_ecpm < 0.0) ? 0.0 : raw_ecpm;
const uint32_t bucket = safe_bucket(clean_ecpm, 20.0, 100);
output.push_back({
AD_ECPM_BUCKET,
make_int_sign(AD_ECPM_BUCKET, bucket),
1.0F
});
const float dense_value =
static_cast<float>(std::log1p(clean_ecpm));
output.push_back({
AD_ECPM_DENSE,
1,
dense_value
});
}
输入 raw_ecpm=57 时,两条特征分别表达:
| Slot | featureSign | value | 模型获得的信息 |
|---|---|---|---|
AD_ECPM_BUCKET | [slot][2] | 1.0 | eCPM 落在第 2 桶 |
AD_ECPM_DENSE | 1 | log1p(57) | 经压缩后的精确大小 |
Analysis:
- 表达力: 分桶捕捉非线性,dense 保留连续变化,两者互补。
- 参数成本: 分桶 slot 最多 101 条参数;dense slot 只有一条向量。
- 一致性要求: 离线侧必须使用同样的桶宽、顶桶、
log1p与异常兜底。- 上线检查: 对正常值、负值、
NaN、极大值分别做三元组快照测试。
新增真实特征时,可以按下面清单逐项确认:
- 它是类别、连续值,还是需要“分桶 + dense”双表达?
-
字符串的编码、大小写、
trim与拼接规则是否固定? - 小整数是否可以直接编码,避免不必要的哈希?
- Dense 值的量级、归一化和异常兜底是否明确?
- 分桶应使用等宽、等频还是对数边界?是否设置顶桶?
- 唯一取值规模与 Embedding 内存能否接受?
- 高基数 slot 是否受准入和淘汰规则约束?
- OOV 时模型服务返回什么?
- 离线训练与在线服务是否复用相同逻辑和配置?
- 上线前是否完成逐字段一致性对比?
⚠️ Common Mistakes in 1.3
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把 featureSign 当 Embedding | “把哈希值转成浮点数直接喂给 DNN” | 编号制造虚假顺序与距离,64 位整数转 float32 还会丢失 key 精度 | 用 sign 查独立、可训练的向量 |
| 2 | 认为哈希不会冲突 | 高基数 GUID 使用 32 位哈希却不监控 | 不同取值会共享参数 | 估算基数与冲突,必要时扩位或过滤 |
| 3 | Dense 原值直接入模 | 时间戳写入 value | 量级过大,淹没其他特征并放大梯度 | 归一化、钳制并统一统计量 |
| 4 | 分桶前不校验 | 对负值、NaN、inf 直接转 uint32_t | 产生错误桶或不可依赖的行为 | 检查有限性、非负性与桶宽 |
| 5 | 不设置顶桶 | 极端值持续制造新桶 | 参数稀疏且表规模失控 | min(bucket, MAX_BUCKET) |
| 6 | 在线离线各写一套逻辑 | Python 与 C++ 桶边界不同 | 查到错误但合法的 Embedding,难以报警 | 共用库/配置并做特征 diff |
| 7 | 忽略 OOV 行为 | 新 key 自动写表却没有准入 | 高基数特征迅速撑大内存 | 上线前确认 OOV、准入与淘汰 |
| 8 | 对有符号 sign 做算术 | 对负数 featureSign 调 abs() 分片 | 改变位模式或触发边界问题 | 按无符号 key/字节串处理 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 特征三元组 | slotId 管类型,featureSign 管取值,value 管数值/权重 | 是业务服务与模型服务的协议 |
| Feature Hashing | 字符串稳定映射到有限 key 空间,冲突不可避免 | 换来无词表、可扩展的在线处理 |
| Embedding | sign 只负责索引;Embedding 是按监督信号训练的向量 | 让类别关系由数据学习,而不是由哈希编号决定 |
| Sparse | 规范化类别 → 生成 sign → value=1.0 → 查独立向量 | 表达“是哪一类”,不制造虚假大小关系 |
| Dense | 校验/变换数值 → 固定 sign → 数值写入 value → 投影 | 保留“具体是多少”及连续变化 |
| 分桶 | 连续值先切区间,再作为类别查表 | 捕捉非线性区间效应 |
| 表规模 | 由唯一 key 数 × 维度决定 | 高基数特征必须考虑内存治理 |
| 工程一致性 | 哈希、slot、桶、归一化、缺失值规则必须对齐 | 防止“服务正常但效果下降”的静默事故 |
❓ FAQ
Q1:为什么不能直接把 featureSign 当作 Embedding?
A:因为 sign 只是任意编号,数值大小和距离都没有业务语义,而且 64 位 sign 转成
float32还可能丢失精度。Embedding 是按 sign 查询的一组独立可训练参数,类别之间的相似性由点击、转化等数据学习,而不是由哈希值决定。
Q2:为什么 Dense 特征也需要一个 featureSign?
A:在统一的 slot 协议中,它仍需定位该 slot 的一组权重。固定 key 意味着所有样本共享这组参数,再由不同
value缩放。
Q3:一个连续值应该选分桶还是 Dense?
A:需要精确大小与连续变化时用 dense;关系明显非线性或需要区间效应时用分桶。重要特征常同时使用两种表达。
Q4:Embedding 表为什么不会随请求量线性增长?
A:重复出现的相同 sign 会复用同一条参数。它随“唯一取值数”增长;只有 GUID、广告 ID 等高基数 slot 才可能接近用户或物品规模。
Q5:改桶宽为什么通常需要重训模型?
A:桶宽改变后,同一个业务值会查到不同 key,对应的旧 Embedding 语义已经错位。规则变化必须与新模型一起发布。
🔗 Connections to Later Chapters
- Chapter 2.3 (双塔模型)会把用户与物品的多组 Embedding 聚合成两侧向量,再用于大规模检索。
- Chapter 3.1 (Wide & Deep)会把离散 Embedding 与连续特征送入 Deep 部分,建立排序模型的泛化能力。
- Chapter 3.2 (特征交叉)会进一步研究不同特征 Embedding 之间如何发生二阶与高阶交互。
- Chapter 6.4 (Codebook 量化与语义 ID)会展示另一种离散表示:让物品 ID 本身带上层次化语义。
- Part 11 (生成式推荐系统实战)会把离线特征生成、在线特征服务与模型部署串成完整工程链路。
Practice Problems
请按顺序完成。后面的题目会逐渐加入规模、异常值与一致性约束。
Problem 1.3.1 — 三元组分工 🟢 Easy
给定 CITY=北京 与 estimated_ctr=0.08,分别说明它们的关键信息应该放在 featureSign 还是 value 中。
💡 Suggested Answer (click to reveal)
Reasoning: 城市是类别,CTR 是连续数值,两者表达目标不同。
Answer: CITY=北京 的类别身份放在 featureSign,value 通常为 1.0;CTR 使用固定 sign,把 0.08 放在 value。
Key points:
- Sparse 回答“是哪一类”。
- Dense 回答“具体是多少”。
Problem 1.3.2 — 判断 key 与向量 🟢 Easy
假设 hash("男") = hash("20") = 111。SEX=男 与 AGE_BUCKET=20 是否会得到相同的 featureSign?又能否把最终 sign 直接当作模型向量?
💡 Suggested Answer (click to reveal)
Reasoning: 完整 key 由高 32 位 slot 与低 32 位取值编号共同构成;key 只负责定位参数,不表达类别语义。
Answer: 两个 sign 不相同,分别是 [SEX][111] 与 [AGE_BUCKET][111],因为高位 slot 不同。二者都不能直接作为模型向量,必须在各自 slot 的参数表中查询可训练 Embedding。
Key points:
- Slot 隔离了不同字段。
- 哈希冲突只需在同一 slot 内讨论。
- sign 的数值距离没有业务意义,不能代替 Embedding。
Problem 1.3.3 — 选择表达方式 🟡 Medium
你要加入“近 30 天购买金额”,分布极度长尾,既希望保留金额大小,又怀疑不同消费区间存在非单调效应。请设计特征表达。
💡 Suggested Answer (click to reveal)
Reasoning: 单一表达无法同时兼顾连续精度与自由的区间效应。
Answer: 创建两个 slot:一个对金额做 log1p 后作为 dense;另一个使用对数分桶或离线等频边界作为 sparse 桶特征。两侧统一异常值、边界与顶桶配置。
Key points:
- Dense 保留连续大小。
- 分桶捕捉非线性。
- Check:离线和在线对同一金额应输出完全一致的三元组。
Problem 1.3.4 — 定位静默故障 🔴 Hard
新模型离线 AUC 正常,上线后服务无报错,但效果显著下降。排查发现离线 Python 使用 value.strip().lower() 后哈希,在线 C++ 直接对原字符串哈希。解释原因并设计修复与防复发方案。
💡 Suggested Answer (click to reveal)
Reasoning: 两侧对同一业务值生成了不同 key,因此线上查到的不是训练时更新过的参数。
Answer: 统一字符串规范化和哈希实现,重建训练样本并重训模型;上线前用同一批真实请求分别执行离线与在线特征逻辑,逐字段 diff slotId/featureSign/value。把规范化规则与哈希种子放在共享库或同一份版本化配置中。
Key points:
- 这是特征错位,不是模型结构问题。
- 旧模型不能直接适配新 key。
- Check:一致性测试应覆盖空格、大小写、空值和非 ASCII 字符。
🏆 Challenge: 估算高基数特征的成本
某 AD_ID slot 有 5000 万个活跃 key,Embedding 维度为 16,使用 FP32。只计算向量本体需要多少内存?若训练时还保存两份同尺寸优化器状态,总量至少是多少?再说明实际部署为什么还会更大。
💡 Hint
先计算 字节,再乘以参数本体与优化器状态的份数。不要忘记哈希表 key、指针、对齐与装载因子。
召回是「召回—排序—重排」三阶段漏斗的起点。它要在毫秒级延迟内,从亿级全量物品中快速筛出千级候选——奉行「宁可错杀,不可放过」,目标是 覆盖 而非精准。一个召回器即使效果平庸,只要漏掉了真正相关的物品,后序的排序与重排也无能为力。
本部分沿技术演进展开五个章节:从最经典的 协同过滤 到 向量召回(I2I) 、 双塔模型(U2I) ,再到 序列召回 与 流式索引 ,共同构成工业界召回层的方法图谱。各章要点见下表。
本章涵盖
| 章节 | Topic | The Big Idea |
|---|---|---|
| 2.1 | 协同过滤 | 基于「用户—物品」共现统计:从 ItemCF 物品相似度,经 Swing 工业优化、UserCF 用户视角,到矩阵分解开启向量化 |
| 2.2 | 向量召回 (I2I) | 把 Word2Vec 序列建模迁移到推荐:从 Item2Vec 直接迁移,到 EGES 融合属性,再到 Airbnb 融入业务目标 |
| 2.3 | 双塔模型 (U2I) | 用户与物品分别编码为向量,以 FM、DSSM、YouTubeDNN 为代表,实现高效向量检索 |
| 2.4 | 序列召回 | 关注时序信息:MIND 用多向量表示多元兴趣,SDM 分离长短期偏好并以门控动态融合 |
| 2.5 | 流式索引召回 | 跳出模型内部压缩:Trinity 用聚类统计保留全量兴趣,Streaming VQ 让索引实时适应分布 |
What You'll Be Able to Do After This Part
- 🟢 区分 基于邻域的协同过滤(ItemCF / UserCF)与基于模型的矩阵分解,说清各自面对稀疏性的优劣
- 🟢 解释 Swing 如何利用二部图结构过滤噪声,以及 EGES 如何用注意力解决冷启动
- 🟡 推导 FM 二阶交互项的 化简,并说明它如何被重新组织为双塔内积形式
- 🟡 对比 双塔模型与序列召回(MIND / SDM)在「用户表示」上的根本差异:单一向量 vs 多向量 / 长短期融合
- 🔴 分析 Trinity 与 Streaming VQ 如何用聚类统计与流式索引解决「兴趣遗忘」与「索引时效」问题
- 🔴 完成 5 章共 25+ 道分层练习题,巩固从共现到向量检索的全链路
核心概念
| Concept | 章节 | Relevance |
|---|---|---|
| 物品/用户相似度、共现矩阵 | 2.1 | 协同过滤的基石,工业召回要道 |
| Swing score、Surprise | 2.1 | 面向工业鲁棒性与互补商品的相似度优化 |
| 隐向量、低秩假设 | 2.1 | 从统计走向表示学习的转折点 |
| Skip-Gram、序列建模 | 2.2 | 把「句子=行为序列」的思想用于 I2I 召回 |
| 商品特定注意力 (EGES) | 2.2 | 用属性解决冷启动的关键机制 |
| 双塔、内积检索、ANN | 2.3 | 高效 U2I 召回的工程骨架 |
| 多兴趣胶囊 (MIND)、门控融合 (SDM) | 2.4 | 捕捉多元兴趣与时效性的序列召回 |
| 聚类直方图、VQ 索引、EMA | 2.5 | 流式索引召回的统计与实时更新基础 |
前置知识
- 已读完 Part 1 (尤其是 1.1 的三阶段漏斗与 1.2 的技术地图)
- 具备基础的线性代数(向量内积、矩阵)、概率(softmax、余弦相似度)与神经网络常识
- 了解 Python 与 Embedding 的基本概念
召回层方法偏「轻量、覆盖导向」,复杂度大多可控;但向量化方法(矩阵分解、双塔、序列)需要你熟悉 Embedding 与梯度下降。
Tips for This Part
- 先理解「动机」再抠公式。 每个方法都为了解决前一个方法的某个局限——例如 ItemCF 被热门物品主导,于是有了 Swing;共现稀疏,于是有了矩阵分解。
- 抓住「用户/物品如何被表示」这条主线。 从 CF 的 ID 共现,到 MF 的隐向量,到双塔的独立编码,再到序列召回的多向量,表示越来越精细。
- 注意召回的检索效率。 凡是能在线上离线预计算物品向量(双塔、I2I)的方法,往往最容易规模化。
- 配合可视化练习。 每章的交互式 HTML 与 SVG 都值得亲手点一遍,把抽象公式落到「候选池如何收缩」的直觉上。
Let's dive in! 🚀
协同过滤
📝 Before You Continue: 请先读完 Part 1 的 1.1 关于「召回是三阶段漏斗起点」的论述,以及 1.2 中「召回:从亿到千」的脉络。本章是召回层最经典的方法家族。
当你打开电商 App,系统如何判断「你还可能喜欢什么」?最朴素也最强大的直觉来自 协同过滤(Collaborative Filtering, CF) :利用「人」与「物」群体的集体行为来推断个人偏好——喜欢同一个东西的人,口味往往相似;被同一群人喜欢的东西,性质往往相近。
协同过滤的思想几乎与推荐系统同龄,但它远不止「找相似」这么简单。从基于邻域的 ItemCF / UserCF,到为工业鲁棒性而生的 Swing,再到把用户与物品映射为隐向量的矩阵分解,本章带你走完这条从 统计共现 到 向量表示 的演进之路。
读完本章,你将能够:
- 用 余弦相似度 / 皮尔逊相关系数 计算物品与用户之间的相似度,并说清二者差异
- 解释 Swing 如何通过二部图结构过滤随机噪声,以及 Surprise 如何挖掘互补商品
- 说明 UserCF 与 ItemCF 在用户冷启动、可解释性上的取舍
- 描述 矩阵分解(FunkSVD / BiasSVD) 如何用低秩隐向量缓解数据稀疏性
- 完成 5 道分层练习题,巩固从共现到向量化的全链路
2.1.0 协同过滤的两大视角
协同过滤可以沿两个方向切分: 基于物品(ItemCF) 关注「和你喜欢的物品相似的还有什么」; 基于用户(UserCF) 关注「和你相似的人还喜欢什么」。前者更贴合工业场景(物品集合稳定、可离线预计算),后者在社交属性强的场景下更自然。
无论哪种视角,核心都绕不开一个概念——共现(co-occurrence) :两个物品被同一批用户交互过,或两个用户交互过同一批物品。共现越频繁,相似度越高。后面三节我们会看到,所有 CF 方法不过是对「如何定义与利用共现」的不同回答。
2.1.1 ItemCF:基于物品相似度的协同过滤
ItemCF 的核心想法是:用户的兴趣具有连贯性,喜欢某物品的人往往也对相似物品感兴趣。当我们要给用户推荐时,系统先找出他 最近交互过的物品 (种子物品),再为每个种子找最相似的候选,最后汇总打分。
物品相似度计算
大多数真实场景只有隐式反馈(点击、购买),没有评分。ItemCF 用 余弦相似度 量化物品间相似程度:
其中 是与物品 交互过的用户总数, 是两个物品的共现次数(同时交互过两者的用户数)。分母对共现次数做了标准化, 防止热门商品凭借庞大交互量占据绝对优势——这正是朴素共现的最大陷阱。
候选物品推荐
有了相似度矩阵,线上流程分三步:① 取用户最近交互的几百个物品作种子;② 为每个种子找 Top-10 相似物品,快速生成大量候选;③ 计算用户对候选物品 的兴趣分数:
是用户交互过的物品集合, 是用户对物品 的兴趣强度(简单取 1,或按交互时间/类型加权)。最后对所有候选按分数排序取 Top-N。
🧠 Mental Model: 借书人的书单
把物品想成「书」,用户想成「借书人」。ItemCF 的逻辑是:如果 Alice 借过《三体》和《球状闪电》,而 Bob 也借过《三体》,那么系统推测 Bob 大概率也会喜欢《球状闪电》——因为这两本书总是被同一批人借阅。重点不在书的内容,而在「谁在读它们」。
计算效率优化
暴力计算所有物品对相似度是 ,但绝大多数物品对没有共同用户,相似度必为 0。基于 用户-物品倒排表 可大幅提速:为每个用户维护物品交互列表,遍历时把列表内物品两两配对,累加共现矩阵 ,再除以标准化项。优化后复杂度约 ( 为总交互数, 为用户平均交互物品数),在稀疏场景下远低于暴力计算。
处理评分数据的相似度(皮尔逊相关系数)
当系统有显式评分(如 5 星)时, 皮尔逊相关系数 比余弦更稳健,因为它通过中心化消除了物品间评分分布的差异:
基于它可预测用户对未接触物品的评分:
在大规模系统中,出于计算与稀疏性考虑,多数仍用余弦相似度辅以加权归一化。
Analysis: ItemCF 离线可预计算全量物品相似度矩阵,线上只需取种子物品的 Top-N 相似项,延迟极低、可解释性强;但对物品冷启动无能为力(新物品没有共现),且相似度固定、难以融入上下文特征。适合物品集合稳定、交互密集的场景。
2.1.2 Swing:面向工业场景的相似度优化
ItemCF 朴素有效,但工业中暴露明显问题:热门物品因共现多而主导结果;随机误点击等噪声被一视同仁。Swing 给出优雅回答——分析用户-物品二部图的子结构来过滤噪声。
其核心洞察是: 如果多个用户在其他共同购买行为很少的情况下,同时购买了同一对物品,那么这对物品的关联更可信。 也就是说,共同购买行为的「特异性」越高,相似度贡献越大。
物品相似度计算
设 、 为与物品 、 交互的用户集合。对每一对共同用户 ,若他们其他共同购买越少( 越小),说明共同选择这对物品越具特异性,应贡献更高分数:
是平滑系数,防止分母过小导致数值不稳定。为降低活跃用户过度影响,引入用户权重 :
如图,用户 A、B 之间有 4 个 swing 子图 、、、。若 ,且 A、B 其他共同行为数为 4,则用户对 贡献 ;h 与 p 之间因还共享 t、r 而额外贡献两个 ,最终 高于 。共现少但「独家」的组合得分更高 ,这正是 Swing 过滤热门噪声的机制。
Surprise:互补商品推荐
Swing 分数已能捕捉关联,但处理互补商品(先买手机后买手机壳)仍吃力——互补关系有时序性与方向性。Surprise 算法从 类别、商品、聚类 三个层面衡量互补相关性:
- 类别层面 :用 user-category 矩阵算类别间条件概率 ,并用最大相对落点自适应截断长尾。
- 商品层面 :考虑购买顺序与时间间隔,越近互补性越强:
- 聚类层面 :用标签传播算法在数十亿商品图(边权为 Swing 分数)上聚类,缓解稀疏性,最终线性组合:
Analysis: Swing 在保持 ItemCF 高效性的同时显著提升鲁棒性,是工业级 I2I 召回的常青树;代价是需构建与遍历二部图、计算量较朴素 ItemCF 更高。Surprise 进一步针对互补场景,但引入了多层面超参与聚类步骤,工程复杂度上升。
2.1.3 UserCF:基于用户相似度的协同过滤
与 ItemCF 镜像相对,UserCF 假设: 有相似历史行为的用户,未来偏好也相似。它先找与目标用户最像的「邻居」,再基于邻居行为预测目标用户兴趣。
用户相似度计算
给定用户 、 的物品集合 、,三种常用度量:
- 杰卡德系数 (仅隐式反馈):
- 余弦相似度 (考虑活跃度差异):
- 皮尔逊相关系数 (有评分时,中心化消除评分习惯差异):
候选物品推荐
选相似度最高的 个用户作邻居集合 。简单加权平均预测评分:
考虑评分偏置的版本进一步消除个人习惯:
线上推荐时,为目标用户找最相似的 个用户,收集其交互物品作候选,计算兴趣分数 ,排序取 Top-N。优化后复杂度约 ,远低于 。
Analysis: UserCF 在「新闻热点」「突发事件」等用户兴趣趋同的场景表现出色,且天然利于「发现相似人群」的社交推荐;但用户数远大于物品数时计算与存储压力大,且用户冷启动困难(新用户没有行为)。工业中 ItemCF 更常用,因其物品集合稳定、可离线全量预计算。
2.1.4 矩阵分解:从相似度到向量表示
UserCF 与 ItemCF 都面临根本性挑战: 数据稀疏性。真实交互矩阵极度稀疏,难有足够共同评分算可靠相似度。矩阵分解换了个思路——不再显式算相似度,而是学习用户与物品的 隐向量表示 ,让向量空间的距离自然反映偏好。这标志着 CF 从统计方法转向机器学习方法。
隐向量时代的开端
矩阵分解建立在两个假设上: 低秩假设——看似复杂的评分矩阵其实只受少数隐含因子(如「面向男性 vs 面向女性」「严肃 vs 轻松」)支配; 隐向量假设——每个用户/物品都能用一个包含这些因子的向量表示。
FunkSVD:基础模型
FunkSVD 把评分矩阵分解成用户特征矩阵与物品特征矩阵。用户 用 维向量 表示,物品 用 表示,预测评分为二者内积:
优化目标让预测尽量逼近真实评分(仅对已知评分):
用梯度下降更新,误差 :
实践中加 L2 正则防过拟合:。
🧠 Mental Model: 口味坐标轴
把每个用户和每部电影画到一张二维图里:横轴是「男性向 ↔ 女性向」,纵轴是「严肃 ↔ 轻松」。喜欢《公主日记》的用户与这部电影的向量都落在「女性向、轻松」角落,内积自然大。即使两个用户没看过同一部电影,只要他们在隐因子上相近,就能互推——这就是向量表示破解稀疏性的关键。
BiasSVD:改进模型
基础模型忽略了一个事实:有人天生给高分(「老好人」),有人很严格;有的电影因明星云集普遍高分。BiasSVD 引入偏置项:
是全局平均分, 是用户偏置, 是物品偏置。优化目标同步更新偏置:
Analysis: 矩阵分解能自然处理稀疏数据(两个用户无需共同评分也能通过隐因子关联),且内积检索高效;但它仍是线性模型,难以融入side information与复杂特征交叉。这恰好引出了后续章节的双塔与深度模型。
⚠️ Common Mistakes in 2.1
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 直接用原始共现数当相似度 | 热门物品与所有物品都「高相似」 | 分母未标准化,热门品靠交互量霸榜 | 用余弦相似度除以 标准化 |
| 2 | ItemCF / UserCF 混用不加区分 | 用户冷启动场景硬上 UserCF | 新用户无历史行为,UserCF 无法找邻居 | 用户冷启用 ItemCF;物品冷启用属性/向量法 |
| 3 | 把皮尔逊当余弦用 | 隐式反馈场景硬套皮尔逊 | 无评分则无均值可中心化 | 隐式反馈用余弦;有评分再用皮尔逊 |
| 4 | 忽略矩阵分解的稀疏前提 | 认为 MF 总能算准相似 | 交互极少时隐向量学不准 | 稀疏时结合 side info(见 2.2 EGES)或双塔 |
| 5 | 以为 CF 能融入上下文 | 「加时间/地点特征进 ItemCF」 | 邻域法无特征交叉通道 | 需表示学习(MF/双塔)才能融特征 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| ItemCF | ,种子物品扩散候选 | 工业 I2I 召回要道,可离线预计算 |
| Swing | 二部图特异性共现 + 用户权重 | 过滤热门噪声,提升相似度鲁棒性 |
| UserCF | 按用户相似度聚合邻居行为 | 热点/社交场景好,但用户冷启动难 |
| 矩阵分解 | ,低秩隐向量 | 破解稀疏性,开启向量化先河 |
| BiasSVD | 加 偏置 | 分离系统性偏差,精度显著提升 |
❓ FAQ
Q1: 什么时候用 ItemCF,什么时候用 UserCF?
A: 物品集合稳定、需可解释「为什么推荐这个相似物」时用品 ItemCF(工业主流);用户兴趣高度趋同(如突发新闻)或需做社交「相似人群」推荐时用 UserCF。用户冷启动场景 ItemCF 更稳。
Q2: 余弦相似度和皮尔逊相关系数到底差在哪?
A: 余弦只看交互向量夹角,受物品绝对热度影响;皮尔逊先中心化(减去各自均值),消除「老好人 vs 严师」的评分习惯差异,关注相对趋势。有评分数据首选皮尔逊,隐式反馈用余弦。
Q3: 矩阵分解为什么比 ItemCF 更能应对稀疏数据?
A: ItemCF 需要两物品有共同交互用户才能算相似;矩阵分解通过共享的隐因子空间,让两个无共同评分的用户也能因隐向量相近而互推,泛化到未见组合。
前后关联
- 2.2(向量召回 I2I) 把序列建模(Word2Vec)迁移进相似度学习,并用品注意力解决 MF 难融 side info 的问题。
- 2.3(双塔模型) 将 MF 的内积思想升级为深度网络编码,实现高效 U2I 检索。
- 2.4(序列召回) 进一步捕捉 ItemCF/MF 忽略的时序兴趣动态。
- 3.x(排序) 后续用复杂深度模型对本章召回的千级候选精排。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 2.1.1 — 相似度标准化 🟢 Easy
用户 A 交互过 100 个物品,用户 B 交互过 10 个物品,他们共同交互了 5 个物品。请计算杰卡德系数,并说明若改用「原始共现数 = 5」作相似度会有什么问题。
💡 Solution (click to reveal)
Approach: 杰卡德用交集除以并集。
Key points:
- 若用原始共现数 5 作相似度,A 与任何共同交互 5 个物品的人都被判为「同样相似」,忽略了 A 极活跃(100 物品)的事实。
- 标准化(杰卡德/余弦)让「相对重叠比例」而非「绝对共现数」决定相似度,避免活跃用户/热门物品霸榜。
Problem 2.1.2 — ItemCF 打分 🟢 Easy
用户 交互过物品 ,对它们的兴趣强度 、。物品 与 相似度 、与 相似度 。求用户对候选物品 的兴趣分数 。
💡 Solution (click to reveal)
Approach: 套用 ItemCF 兴趣公式 。
Key points:
- 分数随相似度与兴趣强度线性叠加;种子物品越多、相似度越高,候选得分越高。
- 这正是 ItemCF「取种子 → 扩相似 → 汇总打分」的核心。
Problem 2.1.3 — Swing 的特异性直觉 🟡 Medium
考虑两对物品 与 。用户 A、B 都交互过它们,且 A、B 的其他共同行为数分别为 4(对 h,p)和 2(对 h,t)。设 ,且 只有这一对共同用户、 除此之外还被另一对共同用户 C、D 以相同结构贡献。请比较 与 ,并解释 Swing 想过滤什么。
💡 Solution (click to reveal)
Approach: 按 Swing 公式,每对共同用户贡献 。
- :仅 A、B 一对,。
- :A、B 贡献 ,另 C、D(同样 )再贡献 ,共 。
咦,这里 反而更高?注意:Swing 的「特异性」指 这对用户相对其他共同行为少。若 A、B 仅在 h、t 上重叠(其他共同少),而他们在 h、p 上还共享更多物品(共同行为多=4),则 h、p 的关联「不够独家」。题中 h,t 的共同行为数(2)小于 h,p(4),所以 per-pair 贡献 h,t 更大——说明 h、t 的共现更特异、更可信。
Key points:
- Swing 通过 惩罚「什么都一起买」的泛用户,抬高「独家共现」权重。
- 它过滤的是随机误点击/泛热门带来的虚假强关联。
Problem 2.1.4 — FunkSVD 梯度更新 🔴 Hard
给定已知评分 ,当前 、,,无正则。请手算一步梯度下降后的 、(保留 3 位小数)。
💡 Solution (click to reveal)
Approach: 先算预测与误差。
更新规则:,。
Key points:
- 误差为正(预测偏低),参数整体上调,使内积增大逼近 4。
- 每维更新量正比于「对方向量分量」,体现了内积的对称性。
🏆 Challenge: 设计一个召回组合
某短视频平台日增千万物品,长尾内容极多。请写一段约 150 字,说明你会如何 组合 本章的 ItemCF、Swing 与矩阵分解作为多路召回(各路负责什么、如何互补),并指出长尾新物品应由哪路兜底、为什么。
💡 Hint
ItemCF/Swing 负责「行为相似扩散」,Swing 抑制热门噪声更适合挖掘长尾关联;矩阵分解负责「隐向量泛化」覆盖稀疏用户。新物品无共现,CF 路必然漏召,应由能融入 side info 的向量路(思考 2.2 EGES)或双塔兜底——本章 MF 本身也难处理纯新物品,需外部属性。
向量召回 (I2I)
📝 Before You Continue: 建议先读完 2.1 的 ItemCF 与矩阵分解。本章是「把物品当作向量」思路的自然延伸——区别在于,相似度不再由共现统计得出,而由序列建模学到的稠密向量决定。
2.1 的协同过滤靠「谁和谁一起被交互」来定义相似。但如果一个物品几乎没被交互过(新品冷启动),共现统计就失效了。更根本地:共现只告诉你「相关」,却没把物品编码成语义向量,难以进一步融合属性、做近邻检索。
本章的主角是 Word2Vec 的序列建模思想。它有一个简单而深刻的假设: 在相似语境中出现的词,含义也相似。当我们把「句子」替换为「用户的行为序列」,把「词」替换为「物品」,同一套方法就能学到「语义相近、向量相近」的物品表示,用于 I2I 召回。从最直接的 Item2Vec 迁移,到融合属性的 EGES,再到把业务目标写进序列的 Airbnb——你会看到这条线如何一步步贴近工业真实。
读完本章,你将能够:
- 解释 Word2Vec Skip-Gram 的核心公式,以及 负采样 为何不可或缺
- 描述 Item2Vec 如何把「用户行为序列 = 句子」的映射用于 I2I 向量召回
- 说明 EGES 的商品特定注意力如何解决冷启动与稀疏性
- 分析 Airbnb 的全局上下文与同市场负采样如何把「预订转化」融入训练
- 完成 5 道分层练习题,巩固序列建模召回
2.2.0 从词语到物品:一个结构性的类比
Word2Vec 的成功建立在「共现反映语义」之上。在自然语言里,一个句子由词组成,词间共现反映语义;在推荐里,一个用户的交互历史可看作「句子」,其中的物品就是「词」。这就是 Item2Vec 的全部出发点——结构同构,迁移即用。
| 文本世界 | 推荐世界 |
|---|---|
| 词语 | 物品 |
| 句子 | 用户交互序列 |
| 词语共现 | 物品被同一用户交互 |
下面四节我们会看到,这个看似简单的映射,如何支撑起一整个 I2I 向量召回家族。
2.2.1 Word2Vec:序列建模的理论基础
📎 本节只讲 Skip-Gram 的直觉与它在推荐里的迁移。要补 CBOW 架构、中心词/上下文双向量表 / 的结构细节、负采样精确形式与词向量类比性质,见 附录 · Word2Vec 专题。
Word2Vec 包含两种架构: Skip-Gram (用中心词预测上下文)与 CBOW (用上下文预测中心词)。推荐中 Skip-Gram 表现更好,采用更广。
Skip-Gram 模型
给定序列中位置 的中心词 ,模型最大化其窗口内(大小 )所有上下文词的出现概率:
是词 的向量, 是词表。Softmax 保证概率和为 1,分子内积衡量中心词与上下文词的相似度。
🧠 Mental Model: 猜邻居的游戏
想象你在玩「我说一个词,你猜它旁边可能是什么词」。听到「国王」,你大概率猜「王后」「城堡」。Skip-Gram 就是让模型玩这个游戏:它不问「这两个词是否共现」,而是问「给定中心词,周围最可能是哪些词」——通过反复猜,模型被迫把语义相近的词放到向量空间里相近的位置。
负采样优化
直接算 Softmax 分母需遍历整个词表,代价过高。负采样把多分类转为多个二分类:
其中 , 是负样本数。直觉是:对真实词对 抬高 相似度,对随机采样的负样本词对 压低 相似度。这一范式正是后续推荐模型训练的技术基石。
Analysis: Skip-Gram + 负采样高效、可扩展,是直接迁移到推荐的理论原型;但它本身处理的是「词」,需要把「用户行为序列」正确映射为训练语料才能用于推荐。
2.2.2 Item2Vec:最直接的迁移
Item2Vec 的核心洞察,就是上一节的「结构同构」:把用户交互历史视作「句子」,物品视作「词」。
模型实现
Item2Vec 直接采用 Word2Vec 的 Skip-Gram,但序列构建更简化——将每个用户的交互历史视为一个 集合 而非序列, 忽略时序权重 (窗口仍依赖按时间排序后的位置 ,只是不再给不同位置不同的权重)。目标函数保持一致:
其中 是物品, 是窗口大小, 用与 Word2Vec 相同的 Softmax 形式。训练后每个物品得到稠密向量,可做近邻检索实现 I2I 召回。
Analysis: Item2Vec 实现极简(几行 gensim 调用即可),验证了序列建模在推荐的可行性;但它把历史当无序集合、丢失时序,且对新物品冷启动无能为力——没有交互就没有向量。这两点正是 EGES 的改进动机。
2.2.3 EGES:用属性信息增强序列
Item2Vec 把交互史当无序集合、且对冷启动无力。EGES(Enhanced Graph Embedding with Side information)用两个创新解决: 会话级图 更好地反映行为模式, 融合辅助信息 解决稀疏与冷启动。
构建商品关系图
EGES 用「一小时时间窗」切分会话,只在窗口内的连续行为间建 有向边 ,边权为转移频率。相比把整段历史当一条序列,这更准地捕捉特定时段的连续兴趣转移。在图上用 带权随机游走 生成训练序列,转移概率由边权决定:
融合辅助信息
纯行为序列对稀疏物品学不好。GES 先用简单平均聚合物品 ID 向量与各属性向量:
是第 种属性的向量, 是物品 ID 向量。但平均假设所有属性同等重要,显然不成立(手机看品牌、日用品看价格)。
EGES 的核心创新 是商品特定注意力——为每个物品学一组权重,强调更重要的属性:
是可学习权重。对 冷启动新物品 ,没有行为序列与训练好的 ,EGES 退化为对属性向量做 mean pooling,直接获得有意义表示,从而能被纳入 I2I 召回。
训练用类似 Word2Vec 的负采样,损失:
Analysis: EGES 用 side info 显著缓解稀疏与冷启动,在十亿级数据上效果优于传统方法;代价是需维护 的注意力参数矩阵,工程与存储成本上升。它是工业 I2I 召回中「兼顾行为与内容」的代表。
2.2.4 Airbnb:将业务目标融入序列
Airbnb 作为短租平台,房源非标品、预订比点击稀疏、地理位置关键,且更需促进 最终预订转化 而非单纯相似。它重新定义了「序列」。
面向业务的序列构建
- 会话切分 :用户点击间隔超 30 分钟即开新会话,更准捕捉特定搜索场景的连贯意图。
- 行为权重差异化 :最终预订比简单点击含更强的偏好信号,训练中应给更高权重。
全局上下文机制
传统 Skip-Gram 只看滑动窗口内的局部上下文。Airbnb 让 用户最终预订的房源 与序列中每个浏览房源形成正样本对,无论距离多远:
前两项是标准 Skip-Gram(正/负样本),第三项 是创新——预订房源为序列中每个房源提供额外学习信号,让模型捕捉「怎样的房源组合最终会导致预订」。
市场感知的负采样
用户通常只在同市场(城市/地区)预订。若负样本来自异地,模型易学「地理位置」这种简单特征而忽略房源本身差异。Airbnb 让部分负样本来自 相同市场 :
这迫使模型学同地区内房源的细微差别,提升精细度。
Analysis: Airbnb 把「业务转化」与「地理约束」直接写进训练目标,是「业务目标驱动序列构建」的典范;但它高度领域定制(会话阈值、市场划分需按业务调参),通用性弱于 EGES。
⚠️ Common Mistakes in 2.2
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把 Item2Vec 当有序序列 | 用时间戳严格排序训练 | Item2Vec 原文把历史当无序集合,丢时序 | 需时序用 EGES/Airbnb/序列召回(2.4) |
| 2 | 冷启动物品直接进 Item2Vec | 新品无向量无法召回 | 无行为则无共现、学不出向量 | 用 EGES 的 side info mean pooling |
| 3 | 忽略负采样 | 直接算全词表 Softmax | 词表/物品库过大,计算不可行 | 必用负采样近似 |
| 4 | Airbnb 套到非地理场景 | 通用电商硬加市场负采样 | 无地理约束反而引入噪声 | 业务定制需对应领域信号 |
| 5 | 平均聚合属性 | EGES 用简单平均 | 假设所有属性同等重要,不符事实 | 用商品特定注意力加权 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| Word2Vec Skip-Gram | + 负采样 | 序列建模理论基石,直接迁移推荐 |
| Item2Vec | 用户序列=句子,物品=词 | 验证 I2I 向量召回可行性 |
| EGES | 商品特定注意力 | 融 side info 解冷启动/稀疏 |
| Airbnb | 全局上下文 + 市场负采样 | 把预订转化/地理写进目标 |
❓ FAQ
Q1: Item2Vec 和 Word2Vec 本质区别是什么?
A: 架构与目标函数完全一样,区别仅在外语料——Item2Vec 把用户交互历史当「句子」、物品 ID 当「词」,且默认把历史当无序集合(丢时序)。Word2Vec 处理的是真实文本序列。
Q2: EGES 的注意力权重和 Transformer 注意力是一回事吗?
A: 不完全是。EGES 的注意力是「同一物品多种属性源之间的加权聚合」(静态、 per-item),用于得到单个物品向量;Transformer 注意力是序列内 token 间的动态交互。二者都叫 attention,但作用层面不同。
Q3: 为什么 Airbnb 要加全局上下文,而不只靠滑动窗口?
A: 滑动窗口只看局部邻居,会漏掉「最终预订」这一最强正信号(它可能离浏览房源很远)。全局上下文让预订房源与每个浏览房源都成对,强化「什么组合导致转化」的学习。
🔗 前后关联
- 2.3(双塔模型) 用深度网络编码用户/物品向量,把 I2I 的「物品向量」升级为「用户-物品联合向量」做 U2I 检索。
- 2.4(序列召回) 显式建模时序(LSTM/胶囊),弥补 Item2Vec 丢时序的缺陷。
- 2.5(流式索引) 用聚类与流式 VQ 组织海量向量索引,承接本章学到的物品向量。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 2.2.1 — 负采样直觉 🟢 Easy
Skip-Gram 的 Softmax 分母需遍历整个词表 。在推荐里物品库可能有上亿。请用一句话说明负采样解决了什么,并写出它把原目标改成了什么形式的任务。
💡 Solution (click to reveal)
Approach: 回忆负采样把「多分类」转为「多个二分类」。
答: 负采样把「对全物品库做归一化 Softmax」转化为「对真实词对做二分类正样本 + 对少量随机采样负样本做二分类」,避免遍历全库。即把多分类变成 个二分类(抬高正对、压低负对)。
Key points:
- 原目标含 ,不可算。
- 负采样只采样 个负样本近似,复杂度从 降到 。
Problem 2.2.2 — Item2Vec 映射 🟢 Easy
请把下列文本世界概念映射到推荐世界:(a) 词语 (b) 句子 (c) 词语共现。并说明 Item2Vec 训练后如何用于 I2I 召回。
💡 Solution (click to reveal)
Approach: 用本章映射表直接对应。
- (a) 词语 → 物品
- (b) 句子 → 用户交互序列
- (c) 词语共现 → 物品被同一用户交互
召回用法: 训练后每个物品有稠密向量,对目标物品取向量最近邻(如 ANN)即得相似物品集合,作为 I2I 候选。
Key points:
- 结构同构是 Item2Vec 的全部前提。
- 召回 = 近邻检索,无需显式共现矩阵。
Problem 2.2.3 — EGES 注意力 🟡 Medium
EGES 对物品 有 种属性加 ID 共 个向量,注意力权重为 。给出最终向量 的公式,并解释:若某手机的「品牌」权重远高于「价格」,mean pooling(GES)会损失什么?
💡 Solution (click to reveal)
Approach: 写出加权聚合公式并对比平均。
答: mean pooling(GES)对所有属性等权平均:。若手机「品牌」其实远比「价格」重要,等权平均会把关键品牌信号稀释进一堆弱相关属性里,得到的向量更「平庸」、区分度下降。EGES 通过 加权让重要属性主导,表示更精准。
Key points:
- 注意力是 per-item 的,不同物品权重分布不同。
- 等权平均假设「属性同等重要」,通常不成立。
Problem 2.2.4 — Airbnb 全局上下文 🔴 Hard
Airbnb 目标函数第三项 中, 是预订房源、 是序列中某浏览房源。请说明:当 很大(语义相近)时该项对损失的贡献如何变化?这如何帮助模型学到「导致预订的组合」?
💡 Solution (click to reveal)
Approach: 分析 sigmoid 与对数项行为。
,当 很大时 ,(损失趋于 0,已学对);当 很小/负时 ,(强惩罚)。所以第三项 最大化 ,即拉近「预订房源」与「浏览房源」的向量。
答: 该项把所有浏览房源的向量朝其预订房源拉近。训练后,凡是与某预订房源常共现的浏览房源,向量都会被推近——模型于是学到「这类浏览房源组合最终导向该类预订」的模式,召回时更可能推出真正促转化的房源。
Key points:
- 全局上下文打破滑动窗口的局部限制。
- 本质是给「预订」这个最强正信号全局加权。
🏆 Challenge: 设计冷启动 I2I 方案
某平台每天上新 10 万件商品,其中 80% 上架首周交互不足 5 次。请写约 150 字,说明你会如何用本章方法(Item2Vec / EGES / Airbnb 任选组合)搭建一套 I2I 召回,使新品也能在被交互极少时就被召回,并指出必须与哪类数据配合。
💡 Hint
新品无行为 → Item2Vec 不可用;应走 EGES 路线,用商品属性(类目/品牌/价格/标题向量)做 mean pooling 得到冷启动向量,配合「少量早期交互」经随机游走逐步修正;需平台维护商品 side info 库与实时行为流。可参考 2.5 流式索引让向量实时更新。
双塔模型 (U2I)
📝 Before You Continue: 请先读完 2.1 的矩阵分解与 2.2 的 Item2Vec。本章把「内积」思想从物品-物品升级为用户-物品,并用深度网络编码两侧表示,是工业 U2I 召回的主干。
前两节你学到的物品向量(Item2Vec / EGES)做的是 I2I 召回——先有种子物品,再找相似物。但线上召回的起点往往不是「物品」而是「用户」:给定一位用户,直接从亿级物品库里捞出他可能感兴趣的。这就需要 用户表示 与 物品表示 在同一空间里各自编码,再用内积检索——这就是 双塔模型(Two-Tower)。
它的工程魅力在于「分而治之」:物品侧塔可以 离线预计算 并存入近邻索引(ANN),用户侧塔 实时计算 ,线上只需一次向量检索。从 FM 的数学雏形,到 DSSM 的深度编码,再到 YouTubeDNN 的「预测下一个观看」,本章带你走完双塔的演进,并用交互演示直观感受检索过程。
读完本章,你将能够:
- 推导 FM 二阶交互项 从 到 的化简,并说明它如何重组为双塔内积
- 解释 DSSM 的极端多分类训练、向量归一化与温度系数的作用
- 描述 YouTubeDNN 的「非对称双塔」与「时序分割」等工程技巧
- 用交互演示理解双塔召回的「离线建库 / 实时查用户」流程
- 完成 5 道分层练习题,巩固双塔的表示与检索
2.3.0 为什么需要双塔:从 I2I 到 U2I
I2I 召回依赖「用户已交互过某物品」作种子。但很多场景下,用户刚注册、或我们要在他 还没动作时 就推内容。U2I 直接以用户自身(画像 + 行为)为查询,从全库检索候选:
双塔的核心约定是: 两侧塔在训练时几乎不交互,只在最后一步算内积。这换来了宝贵的工程性质——物品向量可离线一次性算好入库,用户向量在线现算,检索成本极低。
2.3.1 FM(因子分解机):双塔模型的雏形
FM 诞生于深度学习之前,却在思想上预示了双塔。它把用户-物品复杂交互优雅分解为两个低维向量的内积。完整表达式:
每个特征 对应 维隐向量 ,交互通过内积 建模。
计算复杂度化简
原本 的二阶项可重写为:
复杂度从 降到 ,使 FM 能处理大规模稀疏数据。
🧠 Mental Model: 拼积木的隐向量
把每个特征想成一块积木,每块积木藏着一根小指针(隐向量)。两个特征是否「合得来」,不看积木本身,只看两根指针指的方向是否一致(内积大=合得来)。FM 的妙处是:不用真的两两试遍,靠「指针平方和减平方平方和」一次算完所有配对。
分解为双塔结构
召回场景下,特征分两类:用户侧 与物品侧 。为同一用户推荐不同物品时, 用户特征内部的交互得分对所有候选相同,排序时可忽略。只保留:物品内部交互 + 用户-物品交互。重排后:
观察最后一项——它恰是两个向量的内积 与 。于是:
- 用户向量:
- 物品向量:
Analysis: FM 用线性代数把特征交叉转为双塔内积,物品向量可离线预计算,是双塔思想的理论雏形;但它是线性模型,对复杂非线性用户-物品关系表达力有限——这正是 DSSM 用深度网络接棒的原因。
2.3.2 DSSM:深度结构化语义模型
DSSM 用 深度神经网络 替代 FM 的线性变换,把用户与物品映射到共同语义空间,相似度由向量间距离衡量。
推荐中的双塔架构
DSSM 含独立的两个 DNN 塔:用户塔处理用户特征(行为、人口统计),输出用户 Embedding;物品塔处理物品特征(ID、类目、属性),输出物品 Embedding。两塔 Embedding 维度必须一致。相比 FM 的线性组合,DSSM 让两侧特征各自在塔内做复杂非线性变换, 两塔交互仅发生在最终内积。物品向量离线预计算、用户向量实时计算,经 ANN 完成召回。
多分类训练范式
DSSM 把召回视为极端多分类:物料库所有物品都是类别,目标是最大化用户对正样本的预测概率:
是整个物料库。因库过大,实际用负采样近似。
双塔的关键细节
向量归一化 :对两侧 Embedding 做 L2 归一化 。原始点积不满足三角不等式,会致「距离」不一致。归一化后点积等价于欧式距离:
关键是 训练与检索的一致性——训练用的(归一化点积)与线上 ANN 用的(欧式距离)本质等价,避免训练-服务不一致。
温度系数调节 :归一化内积再除以 :
放大相似度差异(更「确定」), 使分布更平滑(更保守)。它本质是缩放 logits、改变 Softmax 输出形状。
Analysis: DSSM 的表达力来自深度非线性,工程优势来自「离线物品塔 + 在线用户塔」。归一化与温度是上线必调的两个旋钮——前者保证检索一致性,后者控制召回的「集中度」。代价是双塔「晚期交互」损失了部分细粒度特征交叉信号。
2.3.3 YouTubeDNN:从匹配到预测用户下一行为
YouTubeDNN 是双塔演进的里程碑。它延续双塔,但引入关键转变:把召回定义为「预测用户下一个会观看的视频」,类似 NLP 的 next-token 预测。
非对称双塔架构
用户塔集成观看历史、搜索历史、人口统计等多模态信息,视频 ID 经嵌入后平均池化聚合,并引入 Example Age 特征建模内容新鲜度;物品塔则相对简化——本质是一个巨大嵌入矩阵,每视频一个可学向量,避免复杂物品特征工程。目标为极端多分类:
因视频库庞大,用 Sampled Softmax 高效训练。
关键的工程技巧
- 非对称的时序分割 :不用随机验证,而用「回滚」——预测目标只看其 之前 的历史,避免未来信息泄露(符合真实推荐场景,剧集按顺序看)。
- 负采样策略 :重要性采样,每次只对数千负样本计算,提速 100 多倍。
- 用户样本均衡 :每用户生成固定数量训练样本,避免高活跃用户主导学习,对长尾用户效果关键。
Analysis: YouTubeDNN 建立了「可扩展、可工程化」的双塔范式:训练用复杂多分类目标 + 丰富用户特征,服务时预计算物品向量、实时算用户向量、配 ANN 检索。非对称设计让物品塔保持简洁(易离线建库),用户塔可灵活扩展——这一平衡至今被广泛借鉴。
2.3.4 交互演示:双塔召回的检索过程
下面用交互演示感受双塔召回的核心流程:物品塔 离线 把所有物品编码进向量索引;线上来了一位用户,用户塔 实时 编码其向量,再用近邻检索从索引里捞出最相似的 Top-K 候选。点击「下一步」观察每一步。
注意第三步「检索」:它不遍历全库逐一算分,而是用 ANN 在近邻空间直接定位——这正是双塔能在毫秒级服务亿级物品的根本原因。归一化让内积等价于欧式距离,温度系数则控制检索的集中程度。
📊 Data Point: 在 funrec 评测集上,FM 召回 hit_rate@10≈0.047、DSSM≈0.016、YouTubeDNN≈0.013。数值差异主要来自数据集与特征配置,不代表模型优劣——DSSM/YouTubeDNN 在更丰富特征与更大规模上通常更优。
⚠️ Common Mistakes in 2.3
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 双塔塔间过早交互 | 用户/物品特征早期 concat | 破坏「物品可离线预计算」性质 | 交互只发生在最终内积 |
| 2 | 忘做向量归一化 | 直接点积做 ANN 检索 | 点积非度量,训练-检索不一致 | 两侧 L2 归一化 |
| 3 | 温度系数乱设 | 默认 τ=1 不调 | 召回集中度失控,头部过聚 | 按业务调 τ 控制分布 |
| 4 | 把 FM 当深度模型 | 「FM 能拟合任意非线性」 | FM 是线性模型,交叉阶数固定 | 需非线性用 DSSM |
| 5 | YouTubeDNN 随机分割 | 验证集混入未来行为 | 未来信息泄露,离线指标虚高 | 用时序回滚分割 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| FM 双塔雏形 | 二阶交互重排为 | 理论起点,物品可离线预计算 |
| DSSM | 深度双塔 + 极端多分类 + 归一化/温度 | 工业 U2I 主干,强表达+高效检索 |
| YouTubeDNN | 预测下一观看 + 非对称塔 + 时序分割 | 可扩展可工程化的范式 |
| 训练-检索一致 | 归一化点积 ≡ 欧式距离 | 避免线上线下不一致 |
❓ FAQ
Q1: 为什么双塔「晚期交互」反而是优点?
A: 因为物品向量可完全离线算好、建索引,线上只算用户向量 + 一次 ANN 检索。若塔间早期交互(如特征交叉),物品向量就依赖具体用户,无法预计算,失去规模化能力。
Q2: 温度系数 τ 调大调小分别有什么效果?
A: τ<1 放大相似度差异,模型更「自信」、召回更集中(易扎堆头部);τ>1 平滑分布、更保守、候选更分散。是平衡精准与多样的旋钮。
Q3: FM 和 DSSM 都用内积,区别在哪?
A: FM 的向量由线性组合 + 固定隐向量得到(线性模型);DSSM 的向量由深度网络非线性变换得到(表达力更强),且显式处理归一化与采样训练。
前后关联
- 2.4(序列召回) 把用户表示从「单一向量」升级为「多向量 / 长短期融合」,弥补双塔单向量丢时序的不足。
- 2.5(流式索引) 承接双塔产出的物品向量,组织成可实时更新的流式索引。
- 3.x(排序) 排序侧可用更复杂的「早期交互」模型(如特征交叉),与双塔晚期交互互补。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 2.3.1 — FM 复杂度化简 🟢 Easy
FM 二阶交互项原始形式需对 个特征两两组合,复杂度为 。请写出化简后形式,并说明为何它只需 。
💡 Solution (click to reveal)
Approach: 回忆平方项展开。
答: 右边对每个隐维度 只需遍历一次特征 求和与平方和,再相减,共 个维度、 个特征 → ,而非 。
Key points:
- 关键技巧是把「两两乘积和」转为「和的平方减平方的和」。
- 这正是 FM 能上大规模稀疏数据的原因。
Problem 2.3.2 — 双塔内积重组 🟢 Easy
FM 召回中,用户特征内部交互对所有候选相同故可忽略。最终分数写成 。若用户向量 ,物品向量 ,求内积分(即匹配分)。
💡 Solution (click to reveal)
Approach: 对应分量相乘再求和。
Key points:
- 第一项常数 1 乘物品向量的偏置/线性部分,后两项是隐向量交互。
- 物品向量离线算好,线上只对用户现算并做一次内积。
Problem 2.3.3 — 归一化与距离 🟡 Medium
设未归一化向量 、、。用原始点积作为「相似度」判断谁离 A 更近(dist=点积越大越近)。再对三者 L2 归一化后用欧式距离 判断。说明为何归一化更合理。
💡 Solution (click to reveal)
Approach: 分别算。
原始点积:,。按点积「越大越近」会判 C 更近。这个例子恰好与几何一致(,),但点积的排序并不可靠:它受模长干扰,若把 C 换成 这类与 A 夹角不小的长向量,点积依然很大,排序就会失真。非归一化点积不是真正的距离度量。
归一化:。欧式距离 ,。此时 C 更近(二者同向),B 最远——符合直觉( 同向, 正交)。
Key points:
- 点积受向量模长干扰,非真正度量。
- 归一化后点积 ⇔ 欧式距离,训练(点积)与 ANN 检索(欧式)一致。
Problem 2.3.4 — 温度系数效应 🔴 Hard
DSSM 用 Sampled Softmax 近似 。设某用户与三个物品的内积为 。分别计算 与 时三者的 Softmax 概率(公式 ),并说明 τ 如何影响召回集中度。
💡 Solution (click to reveal)
Approach: 分别代入。
τ=0.5:,,和=63.0 → 。
τ=2.0:,,和=5.367 → 。
答: τ=0.5 时概率高度集中在物品1(0.866),召回很集中;τ=2.0 时分布平缓(0.506/0.307/0.186),候选更分散。τ 越小越「自信/集中」,越大越「保守/分散」。
Key points:
- τ 缩放 logits,改变 Softmax 形状。
- 工业上用 τ 平衡「精准命中」与「多样性覆盖」。
🏆 Challenge: 设计双塔召回链路
某电商要做 U2I 召回,物品库 5 亿、QPS 峰值 10 万。请写约 150 字说明:为何选双塔而非 ItemCF;物品塔离线建库的频率与用户塔实时计算的分工;并指出哪一环必须用 ANN、为什么。
💡 Hint
双塔因「用户无种子物品也能召回」且可离线建物品索引、在线仅算用户向量 + ANN 检索,天然适配高 QPS 大库;离线建库可按天/小时批量重算物品向量入 ANN 索引,用户塔请求时现算。ANN 必不可少——5 亿物品逐一内积不可行,需近邻检索在毫秒级返回 Top-K。温度系数与归一化需配套以保证检索一致。
序列召回
📝 Before You Continue: 请先读完 2.3 的双塔模型。本章的 MIND / SDM 仍做 U2I 召回,但用户表示从「单一向量」升级为「多向量 / 长短期融合」——弥补双塔丢掉的兴趣广度与时序动态。
2.3 的双塔把用户压成一个向量。但这有两个隐患:用户兴趣是 多元 的(你既看编程书也买运动鞋),且是 动态演化 的(此刻的会话比一个月前更能预示下一刻需求)。用一个向量概括「一个人的全部」,就像用一句话标签概括一个人——不够。
序列召回正是冲着这两点来的。MIND 用 多个兴趣向量 (多兴趣胶囊)分别代言不同兴趣;SDM 则显式分离 长短期兴趣 并用门控动态融合。配合交互演示,你会看清「多向量检索」相比单向量的优势。
读完本章,你将能够:
- 描述 MIND 的动态路由(B2I)如何把行为软聚类成多个兴趣胶囊
- 解释 squash 函数 与 标签感知注意力 在 MIND 中的作用
- 说明 SDM 如何用 LSTM + 多头注意力建模短期、用特征维度注意力建模长期,并以门控融合
- 用交互演示理解「多兴趣向量分别检索再合并」的流程
- 完成 5 道分层练习题,巩固序列召回
2.4.0 为什么单向量不够:兴趣的广度与时序
想象你的淘宝历史:今天买编程书、昨天买运动鞋、上周买咖啡豆。若只用单向量,这些异质兴趣会互相抵消、平均成一个「四不像」。更糟的是,短期会话里的即时意图(刚搜了「跑步鞋」)被长期偏好淹没。
序列召回的两大命题: 广度 (MIND:多向量)与 时序 (SDM:长短期分离)。下面逐一拆解。
2.4.1 MIND:用多个向量捕捉用户的多元兴趣
MIND(Multi-Interest Network with Dynamic Routing)借鉴 胶囊网络 的动态路由:把历史行为按兴趣类型软聚类,每类生成一个专门的兴趣向量。核心组件是 多兴趣提取层 与 标签感知注意力层。
多兴趣提取(B2I 动态路由)
把历史行为视为「行为胶囊」,多重兴趣视为「兴趣胶囊」,通过动态路由把相关行为聚到对应兴趣维度。MIND 对原始动态路由做三处改进:
- 共享变换矩阵 :所有兴趣向量在同一表示空间,便于后续相似度计算。路由连接强度 ( 行为向量, 兴趣胶囊)。
- 随机初始化 路由系数 :避免所有兴趣胶囊收敛到相同状态(类似 K-Means 随机中心初始化)。
- 自适应兴趣数量 :行为少的用户用更少兴趣向量,省算力;活跃用户更丰富。
路由迭代四步
- 计算路由权重 :对 做 Softmax 得行为 属兴趣 的软分配:
- 聚合行为 :按权重对所有行为向量经共享矩阵 变换后加权求和,得初步兴趣向量:
- 非线性压缩(squash) :把模长压到 ,方向不变;模长解释为兴趣存在概率,方向编码属性:
- 更新路由系数 :按新胶囊与行为的一致性(点积)更新:
四步重复约 3 次,输出兴趣胶囊集合 。
🧠 Mental Model: 给兴趣配「代言人」
把 MIND 想成给一个人的每个兴趣派一个「代言人」。编程相关行为聚到一个代言人、运动相关聚到另一个、美食再一个。检索时,每个代言人各自去物品库找「自己负责的那类」候选,再把所有代言人找来的合并——覆盖面远胜单个「平均人格」。
标签感知注意力
训练时有「正确答案」(用户实际点的下一物品),用目标物品向量作查询,从多兴趣中挑最相关的:
是兴趣胶囊矩阵, 目标物品向量, 控制集中度: 各兴趣均等; 增大趋于聚焦; 退化为硬注意力(只选最相似)。训练用 Sampled Softmax 最大化正样本相似度。
Analysis: MIND 用多向量自然表达多元兴趣,检索覆盖面优于单向量;但兴趣间无明确时序区分(各胶囊平行),且头数增多会带来冗余检索。这恰好引出 SDM 对「时序」的显式建模。
2.4.2 SDM:融合长短期兴趣,捕捉动态变化
SDM(Sequential Deep Matching)的核心是分别建模 短期即时兴趣 与 长期稳定偏好 ,再智能融合。
捕捉短期兴趣(三层结构)
- LSTM 处理当前会话序列,学时序依赖,门控机制能抑制随机误点击:
- 多头自注意力 捕捉序列内多重兴趣:
- 个性化注意力 用用户画像 作查询对多头输出加权:
捕捉长期兴趣(特征维度聚合)
长期行为按特征分成多个子集:商品 ID、叶子类目、一级类目、商店、品牌 。对每个子集用用户画像做注意力:
拼接各维度表示经全连接得长期兴趣:
长短期兴趣融合(门控)
门控网络接收用户画像、短期 、长期 ,输出 0~1 的门控向量,逐维决定长短期贡献:
🧠 Mental Model: 长期口味 vs 此刻心情
把长期兴趣想成「你一贯的口味」(爱科幻、偏平价),短期兴趣想成「此刻的心情」(正急着买双跑步鞋)。门控就像个调酒师:面对不同维度,有的多放长期、有的多放短期——既不是简单平均,也不是谁压谁,而是逐维动态调配。
Analysis: SDM 显式区分并融合长短期,对时序动态建模能力强于 MIND;代价是结构复杂(LSTM + 多头 + 多特征维度注意力 + 门控),训练与 serving 成本更高。它与 MIND 构成序列召回的两条互补路线:广度 vs 时序。
2.4.3 交互演示:多兴趣向量检索
下面用交互演示感受 MIND 式「多兴趣向量分别检索再合并」的流程:用户的历史行为经动态路由聚成数个兴趣胶囊,每个胶囊各自去物品库检索 Top-K,最后合并去重得到召回候选。点击「下一步」观察路由如何把行为分到不同兴趣。
注意:单向量双塔只做一次检索、易平均掉异质兴趣;多兴趣胶囊各自检索再合并,能同时覆盖「编程」「运动」「美食」多条线索——这正是 MIND 召回长尾多样内容的关键。
📊 Data Point: 在 funrec 评测集上,MIND hit_rate@10≈0.0058、SDM≈0.0555。SDM 显著更高,部分因其显式长短期融合更贴合该数据集的会话模式;二者都展示了序列召回相比单向量的多样性收益。
⚠️ Common Mistakes in 2.4
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把 MIND 胶囊当独立模型 | 「每个胶囊单独训练」 | 路由是共享迭代,端到端联合 | 理解动态路由的软聚类本质 |
| 2 | 忽略 squash 的模长含义 | 以为方向随便定 | 模长=兴趣存在概率 | 用 squash 约束到 [0,1) |
| 3 | SDM 简单拼接长短 | 「拼起来过个层就行」 | 丢信息,难提取相关部分 | 用门控逐维动态融合 |
| 4 | 混淆 MIND 与多向量 DSSM | 「MIND 就是多个双塔」 | 路由软聚类、训练时标签感知 | 区分「静态多塔」与「动态路由」 |
| 5 | 兴趣数 K 设死 | 所有用户都用 K=4 | 行为少的用户浪费算力 | 用自适应 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| MIND 多兴趣 | B2I 动态路由 + squash + 标签感知 | 多向量表达多元兴趣,覆盖长尾 |
| SDM 长短融合 | LSTM+多头(短) / 特征注意力(长) / 门控 | 显式建模兴趣时序动态 |
| 自适应 K | 按需分配算力 | |
| 多向量检索 | 各胶囊分别检索再合并 | 互补于双塔单向量 |
❓ FAQ
Q1: MIND 和双塔最根本的区别是什么?
A: 双塔给每个用户一个向量(单向量检索);MIND 给每个用户多个兴趣向量(多向量分别检索再合并)。前者易把异质兴趣平均掉,后者能同时覆盖多条兴趣线索。
Q2: squash 函数为什么要压模长到 [0,1)?
A: 胶囊网络约定「模长=该兴趣存在的概率」,方向=兴趣属性。压到 [0,1) 让模型用长度表达「这个兴趣有多强」,避免向量无限增长导致数值不稳定。
Q3: SDM 的门控和 LSTM 的门控是一回事吗?
A: 思路同源(都用 sigmoid 门控),但作用不同:LSTM 门控管「序列内部信息流」,SDM 的门控管「长短期兴趣之间逐维的融合比例」。
前后关联
- 2.5(流式索引) 从另一角度解决「多元/长尾兴趣」——用聚类统计保留全量历史,可与多向量检索互补。
- 3.x(排序) 序列建模(DIN/DIEN)在排序侧进一步用注意力激活历史,与本章召回呼应。
- 2.3(双塔) 是序列召回的「单向量基线」,理解它才能体会多向量的增益。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 2.4.1 — 自适应兴趣数 🟢 Easy
某用户历史行为数 ,最大兴趣数 。按 MIND 自适应公式 计算该用户实际兴趣向量数。另一用户仅有 3 条行为,其 又是多少?
💡 Solution (click to reveal)
Approach: 逐分量代入。
用户1:,, → 。
用户2:,,取整后通常取 floor → 得 1.58,→ 实际取 1(或 2,依实现 floor/round)。按公式下界保护至少 1。
Key points:
- 活跃用户封顶到 K,行为少的用户自动减少兴趣数。
- 自适应避免给稀疏用户浪费多个头。
Problem 2.4.2 — squash 模长 🟢 Easy
给定向量 (模长 5)。用 squash 公式计算 ,给出模长与方向,并说明模长代表的含义。
💡 Solution (click to reveal)
Approach: 套 squash。
模长≈0.962,方向同 (即 )。
Key points:
- 模长被压到 [0,1),此处 0.962 表示「该兴趣存在概率很高」。
- 方向保留原属性编码,仅长度被非线性压缩。
Problem 2.4.3 — 门控融合 🟡 Medium
SDM 门控 。设某维度门控值 ,长期向量该维 ,短期向量该维 。求该维融合结果,并解释其含义。
💡 Solution (click to reveal)
Approach: 代入。
答: 融合后该维为 0.76,接近短期值 0.9。因 偏向短期,说明在这一维度上「此刻心情」比「一贯口味」更重要(如该维度对应即时品类意图)。
Key points:
- 门控是逐维的,不同维度可偏长或偏短。
- 比例由用户画像+长短向量共同决定,非全局固定。
Problem 2.4.4 — 标签感知注意力 🔴 Hard
MIND 标签感知 。设用户三兴趣胶囊与目标物品相似度为 。分别取 与 ,计算 Softmax 权重(公式 ),说明 如何聚焦。
💡 Solution (click to reveal)
Approach: 先算 。
p=1:,,和=4.915 → 。
p=10:, 后和≈ → 。
答: p=1 时三兴趣都参与(权重 0.5/0.275/0.225);p=10 时几乎全压到最相似兴趣(0.99998)。p 越大越聚焦,p→∞ 退化为硬选择。
Key points:
- pow 放大差异,使 Softmax 更「尖」。
- 训练时大 p 加快收敛(明确选最相关兴趣)。
🏆 Challenge: 组合召回设计
某内容平台既要「覆盖用户多元兴趣」又要「紧跟此刻会话意图」。请写约 150 字,说明如何 组合 MIND(多兴趣)与 SDM(长短期)作为双路序列召回:各自负责什么、结果如何合并去重,并指出哪路更适合推「用户从没表现过但此刻想看」的内容。
💡 Hint
MIND 多兴趣胶囊负责「广度覆盖」(编程/运动/美食各自检索),SDM 门控融合后的单向量负责「此刻意图精准」。两路 Top-K 合并后按物品去重、再按相似度/多样性截断。SDM 的短期兴趣更贴合「此刻想看」的即时内容,尤其会话内新兴意图;MIND 更适合唤醒长期多元但被平均掉的兴趣。
流式索引召回
📝 Before You Continue: 建议先读完 2.3 的双塔与 2.4 的多兴趣。本章跳出「模型内部把历史压成向量」的思路,改用索引结构本身保留全量兴趣并实时更新。
前面四节都在回答「如何把用户/物品编码成更好的向量」。但有个被忽视的问题: 模型在线学习时倾向于拟合最近样本,长期、长尾兴趣会被逐渐遗忘 ;而传统向量索引需定期重建,无法跟上热点快速更迭的内容平台。
本章的 Trinity 与 Streaming VQ 从 索引层面 破局:前者用聚类统计把全量历史兴趣「显式保留」在直方图里,永不遗忘;后者让向量量化索引 流式实时更新 ,无需中断重建。它们代表了召回工程从「模型内压缩」到「索引外组织」的进阶。
读完本章,你将能够:
- 解释 Trinity 的兴趣遗忘 问题与层次化聚类(VQ)解决方案
- 描述基于 统计直方图 的三种召回器(多元 / 长尾 / 长期)如何互补
- 说明 Streaming VQ 如何用 替代 实现可修复、自适应的索引
- 分析索引平衡性与归并排序服务策略的工程价值
- 完成 5 道分层练习题,巩固流式索引
2.5.0 从模型压缩到索引组织
前几章的召回器都把用户历史 压缩 进固定容量的向量(单向量、多向量、长短期融合)。一旦容量固定,久远或罕见兴趣就可能在训练中「被挤出」。Trinity 提出相反思路: 不在模型里压缩,而在索引里显式保留——把历史行为按聚类统计成直方图,每个聚类都是一条不会被遗忘的兴趣线索。
2.5.1 Trinity:聚类统计的全量兴趣召回
Trinity 把「搜索式兴趣建模」迁移到召回阶段,用基于聚类的统计框架处理数十亿候选。
兴趣遗忘问题
在线学习框架倾向拟合最近样本。当某兴趣主题的训练样本变稀疏,模型对该主题记忆渐退——Trinity 称此为 兴趣遗忘(Interest Amnesia)。长期行为能揭示多元兴趣全貌(短期被热门主导);真正该关注的多元兴趣是尚未被充分推送的 长尾主题 ;而判断是否真对长尾感兴趣,又需回溯长期行为确认。三者相互依存。
聚类系统的构建
训练阶段用 向量量化(VQ) 学物品聚类归属。维护两级可学习聚类中心:粗粒度主聚类 ()与细粒度次级聚类 ()。每物品经最近邻分配:
训练损失同时优化用户-物品与用户-聚类匹配:
聚类中心用 指数移动平均(EMA) 更新(用所属物品 Embedding 加权平均),平滑适应分布变化。由于同时用长期行为序列,近期与早期物品被同等对待——时间无偏 ,不会过度偏向近期样本。
🧠 Mental Model: 给兴趣做「投票箱」
把每个聚类想成一个投票箱,用户的历史行为就是往对应箱子投的票。只要用户曾经对这类内容有过行为,箱子里的票数就非零——永远不会被「遗忘」。Trinity 只是数每个箱子的票数,按票数高低决定唤醒哪些兴趣。模型压成单向量则像把所有票揉成一团,稀有票被淹没。
基于直方图的兴趣召回
任意长度行为序列(可达 2500)被转成固定维度统计直方图:读每个物品的聚类 ID,统计每聚类行为计数,得主聚类直方图 与次级 。按计数降序排列后兴趣分布一目了然。例如排序后 对应聚类 :聚类 10 是主要兴趣,33/100 是多元兴趣,91/62 是探索性兴趣。
Trinity 据此设计三个互补召回器:
- 多元兴趣召回(Trinity-M) :选计数显著但可能被主流忽略的聚类,每主聚类下至多选一个次级聚类以分散化,唤醒「被遗忘」的主题。
- 长尾兴趣召回(Trinity-LT) :用流式频率估计追踪聚类出现间隔 ,间隔大=长尾主题;用户在这些长尾聚类上有显著计数时增强推送。
- 长期兴趣召回(Trinity-L) :用轻量双塔从长期行为选种子物品,再基于 Trinity Embedding 相似度做 I2I 检索。
与多向量方法的对比
MIND 等多向量法也捕捉多元兴趣,但有缺陷:不同头可能重复检索热门内容(效率随头数降)、语义不明难调控、难扩展长尾/长期。Trinity 把物品 排他性 分配到聚类,增加兴趣主题只带来线性开销;每个聚类语义明确(教育/旅游/科技),且直方图 天然不忘——只要历史有相关行为,对应计数非零。
Analysis: Trinity 用统计直方图显式保留全量兴趣,根治兴趣遗忘、语义可解释、易调控;代价是需维护两级聚类中心与 EMA 更新,索引构建比单向量双塔更复杂。它是「索引外组织」路线的代表。
2.5.2 Streaming VQ:实时更新的流式索引
Trinity 解决了兴趣遗忘,但 索引结构的时效性 仍在:传统向量索引需定期重建,期间映射固定。快节奏平台上新内容涌入、热点更迭,固定索引跟不上。Streaming VQ 提出 流式更新的向量量化索引——物品实时分配聚类,中心持续适应分布。
流式索引的核心机制
训练框架含两步: 索引步 与 排序步。索引步用双塔生成用户/物品 Embedding,先用辅助任务(in-batch 对比学习)优化,使物品向量不依赖聚类也能独立学语义:
物品 Embedding 经最近邻量化到聚类:
量化中心也参与用户-聚类匹配优化:
物品到聚类的映射实时写入参数服务器,中心经 EMA 更新,整个索引随训练实时更新,无需中断重建。
索引的可修复性
流式更新带来退化风险(无定期重建「重置」)。原始 VQ-VAE 用 约束距离,但推荐中数据漂移使聚类归属本应动态变化, 反碍事。Streaming VQ 用 替代 :物品 Embedding 先独立更新,再由 据新分布调中心——「物品优先」原则让聚类持续适应,而非把物品锁在过时聚类中。
索引平衡性
召回希望热门物品均匀分布在不同聚类,便于选少数聚类快速缩小候选。Streaming VQ 多机制促平衡:
- 的 softmax 中热门占多数样本,若全挤在少数头部聚类,中心需代表大量语义各异物品、表示模糊、损失高;分散到更多聚类则每中心更一致、损失更低——优化本身倾向均衡。
- EMA 引入流行度调节:,冷门物品间隔 更大, 时获更大权重,中心不被热门主导。
- 量化引入扰动 ,样本量低于均值 的聚类 更「近」,易吸物品加入。
归并排序的服务策略
服务阶段把物品 Embedding 分解为个性化部分与流行度部分:
是全局受欢迎度偏置, 承担个性化匹配。聚类保持「按语义分组」不被热门拉偏,聚类内用 初排。用 最大堆 K 路归并排序 :先由 做聚类级排序,再由 做聚类内排序,保证每聚类都有机会贡献候选。
Analysis: Streaming VQ 让索引实时适应分布、可修复、均衡,且服务用归并排序保证候选多样性;代价是需参数服务器实时写映射 + EMA 维护,工程链路比静态索引重。它与 Trinity 互补:Trinity 管「兴趣不遗忘」,Streaming VQ 管「索引不过时」。
⚠️ Common Mistakes in 2.5
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为双塔能记住长尾 | 「双塔单向量覆盖所有兴趣」 | 固定容量压缩,长尾被挤出 | 用直方图(Trinity)显式保留 |
| 2 | 用 L_sim 约束 VQ | Streaming VQ 仍加相似损失 | 阻碍聚类归属动态变化 | 用 L_aux 替代 L_sim |
| 3 | 忽略时间无偏 | Trinity 只用近期行为训练 | 重现兴趣遗忘 | 训练同时用长期序列 |
| 4 | 热门物品堆头部聚类 | 不干预索引平衡 | 中心表示模糊、匹配差 | 靠 L_ind + 流行度调节 |
| 5 | 混淆 Trinity 与 MIND | 「都是多兴趣所以一样」 | 前者索引统计、后者模型多向量 | 区分索引路线与模型路线 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 兴趣遗忘 | 在线学习遗忘稀疏长尾兴趣 | 引出索引外组织的动机 |
| Trinity 直方图 | 行为→聚类计数直方图→三召回器 | 显式保留全量兴趣,永不遗忘 |
| Streaming VQ | L_aux 替代 L_sim + EMA 实时更新 | 索引实时适应、可修复 |
| 归并排序 | score=uᵀQ(v)+v_bias,K 路归并 | 保证候选多样性与均衡 |
❓ FAQ
Q1: Trinity 和 MIND 都在解决「多元兴趣」,根本区别?
A: MIND 是模型内用多个兴趣向量(在线学习易遗忘稀疏兴趣);Trinity 是索引外用统计直方图显式保留每聚类计数,天然不忘且语义可解释、易调控。
Q2: 为什么 Streaming VQ 要用 L_aux 而不是 L_sim?
A: L_sim 把物品锁在「离当前中心近」的旧归属里,阻碍聚类随数据漂移而动态变化;L_aux 让物品向量先独立更新,再由 L_ind 调中心,实现「物品优先」的自适应。
Q3: 归并排序在服务阶段有什么用?
A: 它把 score 拆成「聚类级个性化 + 聚类内流行度」,用 K 路归并让每个聚类都有机会贡献候选,避免热门聚类垄断,保证召回多样性。
前后关联
- 2.4(序列召回) 是「模型内多向量」路线,与本章「索引外统计」互补,可组合使用。
- 2.3(双塔) Streaming VQ 的索引步正是双塔 + 量化,承接其向量产出。
- Part 3(排序) 本章召回的候选将进入排序阶段精排。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 2.5.1 — 直方图读图 🟢 Easy
Trinity 把用户行为序列转为主聚类直方图,降序排列为 ,对应聚类索引 。请指出主要兴趣、多元兴趣、探索性兴趣分别对应哪些聚类。
💡 Solution (click to reveal)
Approach: 按计数分层。
- 主要兴趣:计数最高(50)→ 聚类 10。
- 多元兴趣:次高且需被唤醒(20,20)→ 聚类 33、100。
- 探索性兴趣:较低计数(4,2)→ 聚类 91、62。
- 其余(21,5,83)计数为 0,可忽略。
Key points:
- 直方图降序后,高计数=主干,中计数=多元,低计数=探索。
- 计数非零即代表该兴趣未被遗忘。
Problem 2.5.2 — 量化分配 🟢 Easy
Streaming VQ 量化公式 。若物品 的向量 ,三个聚类中心为 、、。求 。
💡 Solution (click to reveal)
Approach: 算各中心距离平方。
最小为 0 → 。
Key points:
- 量化 = 最近邻分配,物品归入最近聚类中心。
- 流式更新中该映射实时写入参数服务器。
Problem 2.5.3 — 兴趣遗忘直觉 🟡 Medium
某用户的长期行为含大量「古典音乐」,但近 3 个月只交互热门「流行综艺」。在线学习模型逐渐遗忘古典音乐兴趣。请说明:(a) 双塔单向量为何会遗忘;(b) Trinity 直方图为何不会。
💡 Solution (click to reveal)
Approach: 对比两种表示的信息保留方式。
(a) 双塔单向量: 模型在线拟合近期样本,古典音乐相关梯度稀疏,其隐向量分量被近期热门样本的持续梯度逐步覆盖/平均,容量固定导致稀有兴趣被挤出——即兴趣遗忘。
(b) Trinity 直方图: 古典音乐对应聚类的历史行为计数早已写入直方图,且训练同时用长期序列(时间无偏)。只要历史有该行为,计数非零,召回时仍会被唤醒,不依赖模型「记住」它。
Key points:
- 单向量=信息被压缩进容量,稀有者被覆盖。
- 直方图=信息外置为计数,永久保留。
Problem 2.5.4 — 归并排序分解 🔴 Hard
Streaming VQ 服务分数 。设用户向量与某物品量化向量内积为 0.6,该物品流行度偏置 。求总分。并说明:若两物品内积分别为 0.6 与 0.4,但 为 0.1 与 0.5,归并排序如何在「聚类级」与「聚类内」分别利用这两项。
💡 Solution (click to reveal)
Approach: 代入并解释两级排序。
总分 。
两物品:A(内积 0.6, bias 0.1) → 0.7;B(内积 0.4, bias 0.5) → 0.9。
答: 归并排序先按个性化项 做 聚类级 排序(选出与用户个性化最匹配的聚类),再在聚类内按 做 聚类内 排序。这样聚类保持「按语义分组」(不被热门 bias 拉偏),而聚类内用全局流行度初排。B 虽个性化弱但流行度高,会在其所属聚类内靠前;A 个性化强,在另一聚类级排序中胜出——每聚类都有机会贡献,保证多样性。
Key points:
- 分解让「语义分组」与「流行度」解耦。
- K 路归并保证候选均衡覆盖多聚类。
🏆 Challenge: 组合流式索引召回
某短视频平台热点每分钟更迭,长尾内容极多且用户兴趣易漂移。请写约 150 字,说明如何 组合 Trinity(直方图多召回器)与 Streaming VQ(实时量化索引)搭建召回:二者各补什么、索引如何实时维护、为何比纯双塔更适合该场景。
💡 Hint
Trinity 用直方图三召回器显式保留多元/长尾/长期兴趣,根治双塔遗忘;Streaming VQ 用 L_aux+EMA 让聚类索引实时适应热点更迭、可修复、均衡。物品映射实时写参数服务器,双塔产向量经量化入索引。比纯双塔更适合:长尾不被淹没、热点不过时、索引无需定期重建即可跟随分布漂移。
召回阶段把亿级物品收缩到千级候选后, 排序(Ranking) 接手了最关键的"精准打分"任务。它的目标是对每一个候选计算最接近真实偏好的预测分数(通常是点击率、转化率等),再按分数排出最优序列。排序是深度网络泛化能力的主战场——本 Part 的五个章节,沿着"如何让模型更强、更灵活、更贴合业务"的脉络,逐层递进。
本 Part 不急于堆砌模型名,而是始终追问一件事: 每个新模型解决了前一个方法的什么不足? 只有带着"动机"去读,才能在面对真实业务时知道该选哪个模型。
本章涵盖
| 章节 | Topic | The Big Idea |
|---|---|---|
| 3.1 | Wide & Deep | 用"线性记忆 + 深度泛化"联合训练,奠定排序基础框架 |
| 3.2 | 特征交叉 | 从 FM 二阶交叉,经 DeepFM、xDeepFM,走向自动高阶交叉 |
| 3.3 | 序列建模 | DIN 按候选动态激活历史;DIEN 显式建模兴趣时序演化 |
| 3.4 | 多目标优化 | MMoE、PLE 平衡多目标;ESMM 用全空间建模化解依赖偏差 |
| 3.5 | 多场景建模 | 多塔与动态权重适配多场景分布差异,兼顾共性与特性 |
What You'll Be Able to Do After This Part
- 🟢 解释 Wide & Deep 中"记忆"与"泛化"的分工,及其联合训练的意义
- 🟢 区分 FM 二阶交叉、xDeepFM 向量级高阶交叉、AutoInt 自适应交叉的动机差异
- 🟡 说明 DIN 的局部激活如何突破"固定长度用户向量"瓶颈,DIEN 如何进一步建模兴趣演化
- 🟡 辨析 多任务(同场景多目标)与多场景(不同场景同目标)的本质区别与建模策略
- 🔴 设计 在"点击率 × 转化率"等存在依赖关系或跷跷板冲突的业务中,选用合适的多目标/多场景结构
- 🟡 定位 本章每个模型在"解决前一方法不足"链条上的位置
核心概念
| Concept | 章节 | Relevance |
|---|---|---|
| 记忆 vs 泛化 / 联合训练 | 3.1 | 排序深度模型的基础设计哲学 |
| 因子分解交叉(FM)参数共享 | 3.2 | 缓解稀疏与参数爆炸的核心技巧 |
| 向量级 / 自适应高阶交叉 | 3.2 | 让模型自动捕获任意阶特征交互 |
| 局部激活(注意力) | 3.3 | 用户兴趣随候选动态变化的建模关键 |
| 兴趣演化 / 会话建模 | 3.3 | 把静态"物品袋"升级为动态序列 |
| 负迁移 / 跷跷板 / 门控 | 3.4 | 多目标冲突与缓解机制 |
| 全空间建模(样本选择偏差) | 3.4 | 化解 CVR 依赖关系带来的训练偏差 |
| 场景私有/共享参数 / 动态调制 | 3.5 | 跨场景迁移时兼顾共性与差异 |
前置知识
- 读过 Part 1 (推荐系统范式与三阶段流水线)与 Part 2 (召回算法家族)
- 已读 1.3 特征与 Embedding 入门,理解 Sparse / Dense、分桶与 Embedding 查表;并了解 MLP、激活函数、反向传播
- 知道 CTR(点击率)、CVR(转化率)等业务指标的大致含义
本 Part 是 Part 2 召回的自然下游——候选已就绪,接下来我们学习如何"精准打分"。
Tips for This Part
- 带着"动机"读每个模型。 遇到新模型先问:它解决了前一层方法的什么不足?结构差异在哪?
- 公式服务于直觉。 先理解"为什么这样设计",再看数学表达;公式只是设计思想的精确写法。
- 对比着读 Advanced 章节。 3.2 与 3.3 模型密集、结构相似,用表格横向对比能事半功倍。
- 动手跑交互演示。 3.2 与 3.3 各有一个交互式 HTML,用"下一步"直观感受高阶交叉与注意力激活的过程。
Let's dive in! 🚀
Wide & Deep
📝 Before You Continue: 请先读完 1.3 特征与 Embedding 入门,理解 Sparse / Dense 特征与查表向量;同时建议读完 Part 2 的召回章节,明确“候选已就绪、排序要精准打分”的工程位置。
当你在 App 里搜索一件商品,系统给你推荐了它——这背后是排序模型在毫秒之间对成百上千个候选算出的分数。但在 2016 年之前,工业排序模型面临一个尴尬的取舍: 要么记住历史规律,要么学会归纳推广,很难两者兼得。
Wide & Deep 模型(Google, 2016)给出了一个朴素却影响深远的答案:既然两种能力都需要,那就设计两个部分,让它们 联合训练 ,各司其职。它至今仍是无数推荐业务的基线模型,也是后续所有精排深度模型的起点。读完本章,你不仅能讲清它的结构,更能理解"为什么要这样分"。
读完本章,你将能够:
- 用 一句话 区分 记忆(Memorization) 与 泛化(Generalization) ,并各举一个推荐场景的例子
- 写出 Wide 部分 的线性公式,并说明 交叉特征(Cross-product Features) 如何体现记忆
- 解释 Deep 部分 如何通过 Embedding + DNN 实现泛化,以及与 Wide 的本质差异
- 复述 Wide & Deep 联合训练 的预测公式,并说明 Wide/Deep 为何常用不同优化器
- 完成 4 道分层练习题,巩固"记忆 + 泛化"的设计思想
3.1.0 一对看似矛盾的目标:记忆与泛化
构建推荐模型时,我们常常同时追求两个目标: 记忆 与 泛化。
- 记忆能力 指模型学习并记住历史数据中频繁共同出现的特征组合。例如"买了 A 的用户通常也会买 B"。它能精准捕捉显性、高频的关联,给用户高度相关的推荐——但一旦遇到没见过的组合就无能为力。
- 泛化能力 指模型学到特征间的深层关系,能处理训练时罕见的组合。例如"物品 A 和物品 C 同类,喜欢 A 的用户也可能喜欢 C",即使从未见过该用户与 C 的交互,也能合理推荐。
💡 Key Insight: 记忆让推荐"准",泛化让推荐"广"。单用记忆会陷入信息茧房、无法应对新物品;单用泛化会丢失那些高价值的历史强规则。Wide & Deep 的精髓,就是用一个模型同时拥有两种能力。
左侧记忆路径捕捉"买 A 的人也买 B"这种高频强规则;右侧泛化路径把物品映射到向量空间,让模型能推荐未见过的相似物品(如《三体》附近的新书)。
🧠 Mental Model: 老员工 vs 新人
把 Wide(记忆) 想成一位在公司干了二十年的老员工:他记得每一条历史"规矩"(交叉特征),谁和谁总一起出现,门儿清。把 Deep(泛化) 想成一位受过系统训练的新人:他没背过所有规矩,但懂得举一反三,遇到没见过的组合也能推理。一个好团队,两者都要。
3.1.1 记忆的捷径:Wide 部分
Wide 部分本质是一个 广义线性模型 (如逻辑回归)。它结构简单、可解释性强,擅长"记忆"那些显而易见的关联规则。其数学形式如下:
其中 是预测值, 是权重, 是特征向量, 是偏置。
Wide 部分的关键在于输入特征 不仅含原始特征,更包含大量 人工设计的交叉特征(Cross-product Features)。交叉特征把多个独立特征组合成新特征,用来捕捉特定共现模式。例如在应用商店推荐中,我们可以构造:
AND(installed_app=photo_editor, impression_app=filter_pack)
它代表"用户已装照片编辑器、且当前看到滤镜包推荐"。通过这种交叉特征,Wide 部分能直接、快速地学到"照片编辑器用户对滤镜包有更高安装意愿"这类强关联——这正是记忆能力的直接体现。
左侧原始特征(已装 App、曝光 App)经交叉函数组合成一个新特征,再查一个独立的权重表,直接"记住"这对组合的共现强度。
| 组件 | 作用 | 类比 |
|---|---|---|
| 原始特征 | 用户/物品基础属性 | 员工档案 |
| 交叉特征 | 人工组合的共现模式 | 老员工脑中的"规矩" |
| 权重 | 每个组合的强/弱记忆 | 规矩的信任程度 |
💡 Key Insight: Wide 部分"记忆"的本质,是为每个特征组合分配一个独立权重,通过查表直接记住历史共现。代价是这些特征需要专家手工设计,且无法泛化到未出现过的组合。
3.1.2 学习复杂关系:Deep 部分
Deep 部分是一个 标准前馈神经网络(DNN) ,负责模型的"泛化能力"。与 Wide 依赖人工特征工程不同,Deep 部分能 自动 学习特征之间的高阶、非线性关系。
它的工作流程分两步。首先,对高维稀疏的类别特征(用户 ID、物品 ID)通过 Embedding 层 映射为低维稠密向量——这些向量能捕捉潜在语义。例如《流浪地球》和《三体》的 ID 在嵌入空间中会比《流浪地球》和《熊出没》更近。随后,嵌入向量与其他数值特征拼接,送入多层网络前向传播:
其中 是第 层激活值,、 是权重与偏置, 是激活函数(如 ReLU)。逐层抽象让 DNN 能发掘隐藏的复杂模式,对未见过特征组合做出合理预测。
稀疏类别特征先经 Embedding 变为稠密向量(相似物品在向量空间靠近),再拼接数值特征送入多层 DNN,自动学到高阶非线性关系。
Analysis: Deep 部分擅长泛化、自动学习特征交互,但可解释性弱——它学到的高阶组合难以直观解读;且对极高频率的强规则,可能不如 Wide 的显式交叉记得"牢"。复杂度主要来自深层 MLP,参数量随层宽层数增长;Embedding 查找开销小。
3.1.3 两者结合:联合训练
Wide & Deep 把两部分 联合训练(Joint Training) ,输出结合进行最终预测:
这里 是 Sigmoid 函数, 是 Wide 的输入(原始 + 交叉特征), 是 Deep 最后一层的输出向量。反向传播时,梯度 同时更新 Wide 和 Deep 的全部参数——这是"联合训练",区别于分别训练再集成。
一个值得注意的工程细节:由于两部分处理的参数性质不同,通常 用不同优化器。
- Wide 部分 输入稀疏,常用带 L1 正则的 FTRL 优化器。L1 产生稀疏权重,相当于自动特征选择,只"记住"重要规则。
- Deep 部分 参数稠密,更适合 AdaGrad / Adam 这类优化器。
Wide(线性 + 交叉特征)与 Deep(Embedding + DNN)共享输入,各自产出 logit,相加后经 Sigmoid 输出最终点击概率。两部分在训练时联合优化。
💡 Key Insight: Wide & Deep 的意义不止于一个新结构,更在于给出了一个范式——如何把"记忆"和"泛化"组合进同一个端到端模型。它成为众多精排模型的基线,也为后续章节(用 FM 替代手工交叉、用注意力替代固定用户向量)埋下伏笔。
⚠️ Common Mistakes in 3.1
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把 Wide 当成"另一个小 DNN" | "Wide 和 Deep 都是神经网络,只是深浅不同" | Wide 是 线性 + 交叉特征 ,靠查表记忆,不是非线性网络 | 记住:Wide=记忆(显式规则),Deep=泛化(隐式学习) |
| 2 | 认为交叉特征能自动发现 | "把原始特征丢进去就行" | 交叉特征需 专家手工设计 ,Wide 不会自动组合 | 理解 Wide 的局限,这正是后续 FM/DeepFM 要解决的 |
| 3 | 混淆联合训练与集成 | "先训 Wide 再训 Deep,最后平均" | 联合训练是 同一损失、同时更新 所有参数 | 区分 Joint Training(端到端)与 Ensemble(分别训练) |
| 4 | 忽略优化器差异 | "两部分用同一个 Adam 就行" | Wide 稀疏适合 FTRL(L1 稀疏化),Deep 稠密适合 AdaGrad | 按参数性质选优化器:稀疏→FTRL,稠密→AdaGrad/Adam |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 记忆 vs 泛化 | Wide 记高频规则,Deep 学归纳推广 | 排序模型需两种能力兼得 |
| Wide 部分 | ,靠交叉特征查表记忆 | 可解释、强关联精准,但需人工设计、不泛化 |
| Deep 部分 | Embedding + DNN 自动学高阶非线性 | 泛化强、免手工,但可解释弱 |
| 联合训练 | 端到端同时优化两部分,奠定精排范式 | |
| 优化器分治 | Wide→FTRL(L1),Deep→AdaGrad/Adam | 匹配稀疏/稠密参数性质 |
❓ FAQ
Q1: 既然 Deep 这么强,能不能只用 Deep 不要 Wide?
A: 纯 Deep 在高频强规则上往往"记不牢"——它把规则隐式编码进权重,不像 Wide 直接查表。对历史高频共现,显式记忆更稳定、更可解释。因此保留 Wide 仍有价值。
Q2: 交叉特征一定要人工设计吗?
A: Wide 部分的交叉特征是人工的,这正是它的短板。后续 3.2 节的 FM / DeepFM 正是为了自动学习特征交叉、摆脱人工特征工程而提出的。
Q3: 联合训练为什么比"先训 Wide、再训 Deep"好?
A: 联合训练用同一个损失同时更新两部分,Wide 和 Deep 在训练中互相校准;分别训练再集成(ensemble)是两个独立模型,无法端到端协同优化。
前后关联
- 3.2(特征交叉) 用 FM 自动替代 Wide 的手工交叉特征,演进到 DeepFM 共享 Embedding。
- 3.3(序列建模) 进一步突破"固定用户向量",引入注意力动态激活历史。
- 3.4(多目标) 在 Wide&Deep 的"双塔/共享底座"思想上扩展为多任务共享结构。
- Part 2 召回 中 FM 的双塔用法,与本章 FM 用于交叉是同一技术的两条脉络。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 3.1.1 — 区分记忆与泛化 🟢 Easy
判断下列推荐行为主要依赖"记忆"还是"泛化",并说明理由:
- (a) 系统向"昨天刚买婴儿奶粉"的用户,再次推荐同品牌奶粉 —— 因为历史数据里"买过奶粉的人 7 天内复购同款"频率极高。
- (b) 系统向喜欢《三体》的用户,推荐了一本他从未见过、但与《三体》同属"硬科幻"标签的新书。
💡 Solution (click to reveal)
Approach: 看该行为是"记住历史高频共现"(记忆)还是"归纳推广到未见组合"(泛化)。
- (a) 记忆 :依赖"买奶粉→短期内复购同款"这种高频历史规则,是显式共现的直接套用,正是 Wide 部分做的事。
- (b) 泛化 :用户从未见过这本新书,模型靠"硬科幻"语义相似(Embedding 空间邻近)做归纳推广,是 Deep 部分的能力。
Key points:
- 记忆 = 高频共现的直接复用;泛化 = 未见组合的归纳推理。
- 两者互补,Wide & Deep 同时拥有。
Problem 3.1.2 — 补全交叉特征 🟢 Easy
某外卖 App 想用 Wide 部分记忆一类强规则:"在工作日中午(12:00–14:00)浏览过快餐的用户,更可能点击下午茶优惠券"。请用 AND(...) 形式写出对应的交叉特征。
💡 Solution (click to reveal)
Approach: 交叉特征把多个独立特征组合成一个新布尔特征,捕捉共现。
AND(time_slot=weekday_lunch, browse_cate=fast_food, impression=afternoon_tea_coupon)
Key points:
- 交叉特征是 人工设计 的,需专家定义哪些组合有意义。
- 这正是 Wide 部分的短板,也是后续 FM 想自动化的对象。
Problem 3.1.3 — 联合训练公式 🟡 Medium
Wide & Deep 的最终预测为 。请回答:
- 公式中 与 分别来自哪一部分?
- 为什么 Wide 和 Deep 通常用不同优化器?各举一个。
💡 Solution (click to reveal)
Approach: 对照 3.1.3 的联合训练公式与优化器分工。
- 是 Wide 部分 的输入(原始特征 + 交叉特征); 是 Deep 部分 最后一层隐藏层的输出向量。
- 两部分参数性质不同:Wide 输入 稀疏 (大量 0/1 交叉特征),用 FTRL (L1 正则产生稀疏权重,自动特征选择)更合适;Deep 参数 稠密 ,用 AdaGrad / Adam 收敛更稳。
Key points:
- 联合训练 = 同一损失、同时更新两部分参数。
- 优化器按"稀疏 vs 稠密"分治,是工程经验而非理论强制。
Problem 3.1.4 — 新组合下的记忆失效 🔴 Hard
Wide&Deep 输出 。假设线上出现一个 全新特征组合 (两个高基数 ID 的交叉),训练集中从未出现。请分析:(1) Wide 部分对此组合贡献什么;(2) Deep 部分能否给出非零泛化;(3) 若要提升该组合的预估质量,改 Wide 还是 Deep 更划算?
💡 Solution (click to reveal)
Approach: 分别看两部分对"未见过组合"的行为。
- Wide 的交叉特征 在训练中无共现,其查表权重 (或随机初始化未更新),故 Wide 对此组合 几乎没有记忆信号 ,只剩一阶线性项。
- Deep 部分中 的 Embedding 各自通过与其他特征共现学好,DNN 可借语义邻近给出 非零泛化 预估。
- 该组合属"未见过",应优先靠 Deep(泛化) 兜底;若它高频重要、值得显式记忆,再补 Wide 交叉特征。改 Wide 对新组合无效(查不到权重),故 Deep 更划算。
Key points:
- 记忆失效 = 查表权重未学;泛化兜底 = Embedding 语义。
- 印证"记忆+泛化互补",也点出 Wide 手工交叉的冷启动短板。
🏆 Challenge: 设计取舍论证
假设你负责一个日活千万电商的精排,业务方要求"既要抓住历史高频爆款组合,又要给新上架长尾商品机会"。请用不超过 150 字,论证 Wide & Deep 是否合适,并指出若只用其中一半会损失什么。
💡 Hint
Wide 抓高频爆款(记忆),Deep 给长尾新物品泛化机会;只留 Wide 会困于信息茧房、冷启动差,只留 Deep 会"记不牢"强规则、可解释弱。论证围绕"两种能力缺一不可"展开。
特征交叉
📝 Before You Continue: 请先读完 3.1 Wide & Deep。本章正是为了解决 3.1 中"Wide 部分需人工设计交叉特征"这一短板而生——理解 Wide 的局限,才能体会 FM 的动机。
3.1 的 Wide 部分用 人工交叉特征 记住强规则,但手工设计特征既麻烦又无法穷尽。一个自然的追问随之而来: 能不能让机器自己学会特征之间的交互关系? 这正是特征交叉(Feature Crossing)要解决的问题。
最直接的想法是自动捕捉所有特征对之间的交互——但推荐系统动辄成千上万特征,若每对都学一个参数,参数量会爆炸;而且数据高度稀疏,大多数组合根本没有样本可学。本章我们从 FM 的精妙因子分解出发,一路走到 xDeepFM、AutoInt 等自动高阶交叉,并配一个交互演示,让你"看见"高阶组合如何逐步生成。
读完本章,你将能够:
- 解释 FM 如何用隐向量内积把 参数降到 ,并缓解稀疏问题
- 区分 AFM / NFM / PNN / FiBiNET 各自在 FM 基础上的增强点
- 说明 DeepFM 如何用"共享 Embedding"替代人工 Wide 部分,做到端到端
- 对比 DCN(元素级)/ xDeepFM(向量级)/ AutoInt(自适应) 三种高阶交叉的动机差异
- 完成 4 道分层练习题,并用交互演示理解高阶组合的生成
3.2.0 动机:从手工交叉到自动交叉
Wide & Deep 的 Wide 部分依赖专家手工设计交叉特征,这有两个痛点:(1) 组合空间太大,人工难以穷尽;(2) 新出现的组合没有现成特征。我们想要的,是一个能 自动学习任意特征对交互、又不让参数爆炸 的机制。
回想 Part 2 召回里的 FM:它把用户和物品分解为向量、用内积做高效召回。到了精排阶段,FM 换了一副面孔——它的核心思想"给每个特征学一个向量,再用向量内积捕捉交互"正好能解决上面的痛点。这是同一个技术在不同阶段的两次亮相。
🧠 Mental Model: 给每个特征发一张"名片"
把 FM 的隐向量 想成给每个特征发的一张"名片",上面写着它的兴趣偏好。想知道特征 A 和特征 B 是否合拍?不用为每对 A×B 单独记一本账,只要把两张名片的内积算一下——合拍度高,内积就大。更重要的是:即使 A 和 B 从未在同一条样本里同时出现,只要它们各自和其他特征的"名片"学得好,照样能推断 A×B 的效果。这就是参数共享的威力。
3.2.1 FM:因子分解机(二阶交叉)
为了捕捉特征交互,一个直白的想法是在线性模型上加所有特征的二阶组合项(多项式模型):
它有两个致命缺陷:(1) 参数量 ,特征多时承受不起;(2) 在稀疏数据里,绝大多数交叉项 从未共现,对应权重 学不到。
FM 的精髓是 参数共享 :把交互权重分解为两个低维隐向量的内积 。于是:
其中 是特征 的 维 Embedding()。原本要学 个独立 ,现在只需每个特征一个 维向量,总参数量降到 。更关键的是:即使 从未共现,只要它们各自与其他特征(如 )的共现学好, 就有效,从而泛化预测 的效果。此外,借助代数变换,FM 二阶项计算可从 降到线性的 :
每个特征学一个 维隐向量;任意两特征交互由内积给出,无需为每对单独记权重,参数从 降到 。
Analysis: FM 用参数共享同时解决"参数爆炸"和"稀疏难学"两大问题,是工业界广泛使用的二阶交叉基线。局限在于它只建模二阶两两交互,更高阶组合仍需依赖上层 DNN 隐式学习,且交互方式是固定的"内积",无法区分不同交叉的重要性。
3.2.2 FM 家族的增强:AFM / NFM / PNN / FiBiNET
FM 对所有交叉"一视同仁",但实际中不同交叉的重要性不同。研究者们在此基础上做了多种增强:
- AFM(Attention FM) 引入注意力机制,为每对交叉分配权重 (Softmax 归一化),让模型聚焦重要交互,且注意力权重可可视化、提升可解释性。其交互层先算元素积 ,再注意力池化:。
- NFM(Neural FM) 把 FM 的二阶交叉结果(向量形式)当作"原料"喂给 DNN,学习更高阶非线性。关键是 Bi-Interaction 池化层 :,同样可优化到 ,再送入 MLP。FM 可看作 NFM 无隐藏层的特例。
- PNN(Product-based NN) 认为内积/元素积各有局限,于是在"乘积层"同时用 内积(IPNN)与外积(OPNN) 捕捉更丰富交互,并用矩阵分解/叠加近似把复杂度从 降到 。
- FiBiNET 先学 特征重要性 (借鉴视觉的 SENET:Squeeze→Excitation→Re-weight),再用 双线性交互 打破对称交互限制,兼顾"重要特征"与"灵活交互"。
从"所有交叉同等重要"(FM)到"注意力加权"(AFM)、"喂给 DNN"(NFM)、"多乘积操作"(PNN)、"先重加权再双线性"(FiBiNET),演进始终围绕"更灵活、更强表达"。
💡 Key Insight: 这些模型都在回答"如何在 FM 的二阶交叉之上做得更好"——有的加注意力(AFM)、有的接深度网络(NFM)、有的换乘积方式(PNN)、有的先挑重要特征(FiBiNET)。但它们的二阶交叉方式仍较固定。
3.2.3 DeepFM:低阶高阶统一建模
3.1 的 Wide 部分需要大量人工特征工程。DeepFM 直接把 Wide 换成 无需人工的 FM ,并让 FM 与 Deep 共享同一份 Embedding。这带来两大好处:(1) 同时学低阶与高阶交互;(2) 共享 Embedding 让训练更高效。
DeepFM 由 FM 与 DNN 两个 并行 组件构成,输入共享:
- FM 组件 捕捉一阶 + 二阶交叉:。
- Deep 组件 把所有 Embedding 拼接后送入 DNN,学高阶非线性:,。
最终把两者 logit 相加再过 Sigmoid:。
FM 与 DNN 共享同一组 Embedding:FM 学低阶(一阶+二阶),DNN 学高阶,相加得最终预测,彻底免去人工 Wide 特征。
Analysis: DeepFM 相比 Wide&Deep 的最大改进是用自动学习的 FM 替代手工 Wide 部分,实现真正端到端。复杂度主要来自并行 FM + DNN,但 Embedding 共享避免了参数翻倍。局限:FM 只能显式建模二阶,更高阶仍靠 DNN 隐式学,且交互方式固定。
3.2.4 高阶交叉:DCN(残差高阶)
FM 家族明确建模二阶,更高阶主要靠 DNN 隐式学,而我们不清楚 DNN 到底学到了什么阶。DCN(Deep & Cross Network)用 Cross Network 替代 Wide 部分,每一层都与原始输入 交叉,从而 明确 学到高阶交互:
这就是一个 残差结构 :第 层在上一层输出上加一个"与原始输入交叉"的项。层数越深,交叉阶数越高——第 1 层含二阶、第 2 层含三阶……且参数量只与输入维度 成正比。Cross Network 与 Deep Network 并行,最后拼接过逻辑回归:
每层 :残差连接保留原信息,与 持续交叉使阶数随层数增长,参数仅线性增长。
Analysis: DCN 明确可控地学到任意高阶交叉,参数高效(线性于维度)。但它是**元素级(bit-wise)**交叉——Embedding 每个元素单独交互,把向量拆散,没有把 Embedding 当完整特征看。这正是 xDeepFM 要修正的。
3.2.5 xDeepFM:向量级 CIN 交互
DCN 在元素级做交叉,xDeepFM 提出 压缩交互网络(CIN) ,改为 向量级(vector-wise) 交互,更符合直觉。xDeepFM 含三部分:线性 + DNN(隐式高阶)+ CIN(显式高阶向量级),最后合并。
CIN 的核心:第 层输出 由上一层 与原始输入 的所有成对 哈达玛积 加权求和得到:
其中 是向量级哈达玛积,保留 维向量结构。第 层输出包含 所有 阶 向量级交互。各层特征图经 Sum Pooling 拼接后,与线性、DNN 输出合并过 Sigmoid:
CIN 每层把"上一层特征图 × 原始输入"做向量哈达玛积,再加权压缩成新特征图;逐层累积,得到二阶到 T+1 阶的向量级交叉。
Analysis: xDeepFM 把"向量级显式交互"与"元素级隐式交互"结合,表达更强且交互可解释(哪层对应哪阶)。代价是 CIN 的 个向量加权求和带来额外计算,需谨慎设特征图数量。
3.2.6 AutoInt:自注意力自适应交互
DCN 每层固定与 交叉,xDeepFM 的 CIN 也按固定方式交互。AutoInt 换思路: 让模型自己决定哪些特征交互、强度多大——用 Transformer 的自注意力机制自适应学任意阶交互。
对于特征 ,第 个注意力头的相关性得分:
用得分对 Value 加权求和得新表示 ,多头拼接后加残差连接。堆叠多层,第一层含二阶、第二层含三阶……交互模式 完全由注意力权重动态决定。最终拼接所有层表示过逻辑回归。
💡 Key Insight: 三种高阶交叉的动机差异一目了然——DCN 用残差固定交叉(元素级)、xDeepFM 用 CIN 固定交叉(向量级)、AutoInt 用注意力自适应交叉。前两者交互模式写死,AutoInt 把"选谁交互、多强"交给数据学,更灵活、也可解释(看注意力矩阵)。
3.2.7 交互演示:高阶交叉如何逐层生成
下面用交互演示直观感受"二阶 → 三阶 → 更高阶"的组合是如何从底层特征逐步构造出来的。点击「下一步」观察每一层新增了哪些交叉组合。
演示用 4 个基础特征(如 性别、城市、品类、价格档),逐层展示:第 1 层产出所有二阶组合,第 2 层把二阶再与基础特征交叉得到三阶,依此类推——这正是 DCN / CIN 显式高阶交叉的直觉来源。
⚠️ Common Mistakes in 3.2
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为 FM 给每对特征学独立权重 | "FM 有 个交叉权重" | FM 用隐向量内积 共享 参数,仅 | 记住:,参数量随 线性 |
| 2 | 忽略 FM 缓解稀疏的意义 | "特征没共现就学不到" | 隐向量通过与其他特征共现间接学得,可泛化 | 参数共享是 FM 解决稀疏的核心 |
| 3 | 把 DeepFM 当 Wide&Deep 同款 | "DeepFM 也要人工交叉特征" | DeepFM 用 FM 替代 手工 Wide,端到端 | 区分:Wide&Deep=人工交叉,DeepFM=自动 FM |
| 4 | 混淆 DCN 与 xDeepFM 的交叉粒度 | "两者都是高阶交叉,没区别" | DCN 是 元素级、xDeepFM 是 向量级 | 看交叉发生在标量还是完整 Embedding 向量 |
| 5 | 认为高阶交叉越多越好 | "堆 10 层 Cross 肯定更强" | 过高阶易过拟合、计算贵,且业务未必需要 | 按数据复杂度与验证集选层数 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| FM 因子分解 | ,参数 | 自动二阶交叉,解决参数爆炸+稀疏 |
| FM 家族 | AFM 注意力 / NFM 接 DNN / PNN 多乘积 / FiBiNET 重加权 | 在二阶交叉上做增强 |
| DeepFM 共享 Embedding | FM(低阶)+DNN(高阶) 共享输入 | 端到端替代人工 Wide |
| DCN 残差高阶 | (元素级) | 明确可控的高阶交叉,参数线性 |
| xDeepFM CIN | 向量级哈达玛积逐层压缩 | 向量级显式高阶,可解释 |
| AutoInt 自适应 | 自注意力决定交互与强度 | 最灵活,交互由数据学 |
❓ FAQ
Q1: 为什么不直接用 DNN 学高阶交叉,还要 FM/DCN 这些?
A: DNN 能隐式学高阶,但我们不知道它学的是几阶、哪些组合,也难保证稀疏组合学好。FM/DCN/xDeepFM 做显式交叉,可控、可解释、对稀疏更友好。
Q2: DCN 和 xDeepFM 该选哪个?
A: 若特征交互更宜当作"整体向量"关系(如语义 Embedding),xDeepFM 的向量级更贴合;若追求简单高效、元素级足够,DCN 更轻量。实践中看验证集与算力。
Q3: AutoInt 的注意力权重能当特征重要性用吗?
A: 可以。注意力矩阵 直接显示哪些特征对交互贡献大,是可解释性的重要来源,这也是它相对 DCN/xDeepFM 的优势之一。
前后关联
- 3.3(序列建模) 跳出"静态特征袋",引入时间维度;DIN 的注意力与 AFM/AutoInt 的注意力思想同源。
- 3.4(多目标) 的底层共享结构(Shared-Bottom/MMoE)常以 DeepFM 类结构作 backbone。
- Part 2 召回 中 FM 用于双塔召回,与本章精排用法是同一技术的两端。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 3.2.1 — FM 参数共享 🟢 Easy
某推荐场景有 个特征,FM 隐向量维度 。请回答:
- 若用原始多项式模型,二阶交叉权重 有多少个(约)?
- FM 用隐向量方案,参数量约多少?相比降低了几个数量级?
💡 Solution (click to reveal)
Approach: 直接套数量级公式。
- 多项式模型二阶项约 个权重。
- FM 只需每个特征一个 维向量,共 个参数。
Key points:
- 从 降到 ,约降低 2 个数量级 (百倍)。
- 随 增大差距更夸张,这正是 FM 在工业界可用的关键。
Problem 3.2.2 — 区分交叉类型 🟢 Easy
把下列描述对应到 FM / DeepFM / DCN / xDeepFM / AutoInt 中的正确模型:
- (a) 和原始输入逐层做残差交叉,但拆散了 Embedding 的每个元素。
- (b) FM 与 DNN 共用一份特征 Embedding,分别学低阶与高阶。
- (c) 用多头自注意力让模型自己决定哪些特征该交互、强度多大。
- (d) 把上一层特征图与原始输入做向量级哈达玛积再压缩。
💡 Solution (click to reveal)
Approach: 抓每类交叉的"粒度"与"是否自适应"。
- (a) DCN (元素级 / bit-wise 残差交叉)
- (b) DeepFM (共享 Embedding 的并行 FM+DNN)
- (c) AutoInt (自注意力自适应交互)
- (d) xDeepFM (CIN 向量级交互)
Key points:
- 元素级 vs 向量级:DCN vs xDeepFM。
- 自适应 vs 固定:AutoInt 独一份。
Problem 3.2.3 — 动机追问 🟡 Medium
为什么 FM 能在"特征 与 从未在训练集中共现"时,仍给出合理的 交叉预测?请结合参数共享说明。
💡 Solution (click to reveal)
Approach: 从隐向量的"间接学习"角度解释。
FM 中交互权重是 。即使 从未同现, 可通过 与其他特征(如 )的共现学好, 也可通过 与 的共现学好。只要这些隐向量学得充分,它们的内积就能推断 的倾向——无需 直接样本。
Key points:
- 参数共享让"没直接见过的组合"也能被泛化估计。
- 这是 FM 相比"每个组合独立权重"在稀疏场景下的根本优势。
Problem 3.2.4 — 推导 FM 线性复杂度 🔴 Hard
从 FM 二阶项 出发,证明它可化为 ,从而计算复杂度为 。并说明:当某特征 时,它与所有其他特征的交互如何被自然忽略。
💡 Solution (click to reveal)
Approach: 展开平方并消项。
。移项得 。两项都只需先对 个特征做 的向量加法/平方,再求和,总 而非 。
当 ,它在 中贡献为 0,且 ,故所有含 的交互项自动消失——无需显式跳过,稀疏特征天然被忽略,零计算浪费。
Key points:
- 代数变换是 FM 能用于高维稀疏的关键。
- 时交互自动归零,与稀疏性完美契合。
🏆 Challenge: 设计交叉方案
某新闻 App 有 500 维稀疏特征,既要捕捉"年龄×品类"这类二阶强规则,又希望模型自动发现三阶以上模式,且要求结构可解释(能看出哪些交叉重要)。请你从 FM / AFM / DCN / xDeepFM / AutoInt 中选 2 个组合 并说明理由(150 字内)。
💡 Hint
二阶+可解释权重 → AFM(注意力可视化);高阶+可解释阶数 → xDeepFM(CIN 每层对应固定阶)或 AutoInt(注意力矩阵)。DCN 元素级且不可直接看交叉重要性,可不选。组合如 "AFM + xDeepFM" 兼顾低阶可解释与高阶向量级可解释。
序列建模
📝 Before You Continue: 建议先读完 3.2 特征交叉。特征交叉把用户历史当作"静态特征袋",本章则引入时间维度——理解这个视角切换,是读本章的关键。
3.2 的各种交叉模型,核心目标是从一个 静态特征集合 里挖掘价值。但它们普遍有个局限:把用户历史行为看作一个无序的"物品袋"(bag of items)。然而用户兴趣不是静止的,它具有明显的 时序性 与 动态演化。
想想这个区别:一个用户先浏览"鼠标"再浏览"显示器",与先浏览"小说"再浏览"显示器",背后购买意图截然不同——前者可能是组装电脑的数码党,后者或许只是随性浏览。传统交叉模型抓不住这种蕴含在顺序里的意图。本章我们把用户历史从"静态袋子"升级为"动态序列",看工业界三个代表模型 DIN / DIEN / DSIN 如何驯服时间。
读完本章,你将能够:
- 解释 DIN 的局部激活 如何突破"固定长度用户向量"瓶颈,及为何注意力权重不做 Softmax
- 说明 DIEN 如何用辅助损失 + AUGRU 显式建模兴趣的时序演化
- 描述 DSIN 如何用"会话"作为基本单元做分层建模(会话内自注意力、会话间 Bi-LSTM)
- 用交互演示观察 DIN 如何根据候选广告动态激活不同历史行为
- 完成 4 道分层练习题,巩固序列建模的"动态 / 序列 / 聚焦"三要素
3.3.0 动机:从静态特征袋到动态序列
在大型电商平台,用户兴趣是 多样 的:同一用户可能既关注数码、又看运动、还买日用。传统 Embedding&MLP 范式把用户所有历史行为 Embedding 池化成 一个固定长度向量 来代表用户——问题来了:无论给他推"跑鞋"还是"手机",代表他的都是同一个向量。它想"一视同仁"地塞下所有兴趣,既困难,又对具体任务不够聚焦。
💡 Key Insight: 用户的一次具体点击,通常只被历史兴趣中的一部分激活。给数码爱好者推"机械键盘"时,真正起作用的是他最近看"游戏鼠标""显卡"的行为,而非上个月买的"跑鞋"。兴趣表示应当随候选不同而动态变化。
🧠 Mental Model: 不是一份简历,而是一束聚光灯
把传统"固定用户向量"想成一份静态简历——所有经历挤在一页,谁来看都一样。把 DIN 的"局部激活"想成一束聚光灯:来了一个候选广告,灯只打在与之相关的几段历史上,其余暗下去。候选人没变,但"被照亮的样子"随面试官(候选)而变。
3.3.1 DIN:局部激活的注意力机制
深度兴趣网络(DIN)的核心是 局部激活(Local Activation) :用户兴趣表示不应固定,而应随候选广告 动态变化。为此 DIN 引入 局部激活单元 (注意力机制),对用户 的历史行为 Embedding 做"加权求和":
其中 是历史行为 Embedding, 是候选广告 Embedding,激活单元 通常是一个小前馈网络,接收 输出权重 。与广告越相关的历史,权重越大,在最终兴趣向量里占主导。
一个关键细节: DIN 的注意力权重 不做 Softmax 归一化 ,即 不一定等于 1。这是为了保留兴趣的 绝对强度——若用户大部分历史都与某广告高度相关,加权和向量模长就大;反之则小。这样模型既能感知兴趣"方向",也能感知"强度"。
左:基准模型对所有历史池化为固定向量(与候选无关)。右:DIN 用激活单元按候选算注意力,相关历史(显卡、鼠标)被高亮加权,无关历史(跑鞋)被压低,得到随候选变化的兴趣向量。
Analysis: DIN 用轻量注意力突破固定向量瓶颈,显著提升多样兴趣下的表达能力,且计算开销小(仅加一个激活单元)。局限:它仍把历史当无序集合,忽略了行为间的时序依赖——兴趣是演化的,而非静止的。复杂度主要在注意力打分的前馈网络,随序列长度线性增长。
3.3.2 DIEN:兴趣的演化建模
DIN 抓住了"多样性 + 局部激活",但把历史当无序集合,忽略 时序依赖。深度兴趣演化网络(DIEN)要回答:光知道用户过去喜欢什么不够,还得搞清兴趣 怎么变化 ,才能更好预测下一步。DIEN 用一个两阶段结构实现。
第一阶段:兴趣提取层(Interest Extractor Layer)。 用 GRU 按时间处理行为 Embedding 序列 。但 GRU 隐状态是否真能表示"兴趣"?DIEN 加了一个 辅助损失(Auxiliary Loss) :让 时刻隐状态 去预测 时刻真实行为 (正样本)与负采样行为(负样本):
它与最终 CTR 损失相加:。这个额外监督逼着 GRU 学到更有意义的兴趣表示。
第二阶段:兴趣演化层(Interest Evolving Layer)。 得到兴趣状态序列后,用带注意力更新门的 GRU( AUGRU )建模演化。注意力得分 由 时刻兴趣状态 与候选广告 决定:,并用它缩放 GRU 更新门 。这样,与候选相关的兴趣顺利传递,不相关的"兴趣漂移"被削弱。
兴趣提取层用 GRU 配合"预测下一行为"的辅助损失学到真实兴趣状态;兴趣演化层用 AUGRU(注意力缩放更新门)让与候选相关的兴趣路径顺畅传递,抑制兴趣漂移。
Analysis: DIEN 显式建模兴趣时序演化,比 DIN 更贴合"兴趣会变"的事实,对序列长、兴趣漂移明显的场景更优。代价是结构更复杂、GRU + 辅助损失 + AUGRU 带来更高训练与推理成本;且 GRU 序列计算难以高度并行。
3.3.3 DSIN:从行为序列到会话序列
从 DIN 到 DIEN,兴趣理解从"静态相关"走向"动态演化",但二者都把行为看成一条连续序列。现实中用户行为常是 间断 的:在一个 会话(Session) 内意图集中,不同会话间兴趣可能剧变。DSIN(深度会话兴趣网络)把"会话"作为基本单元,分层建模。
DSIN 分四层:
- 会话划分层 :按时间间隔(如 >30 分钟)把长序列切成多个会话短序列 。
- 会话兴趣提取层 :对每个会话用 自注意力 (Transformer 思想)捕捉会话内关系,聚合成会话兴趣向量 。
- 会话兴趣交互层 :用 Bi-LSTM 对会话序列 建模,捕捉会话间演进。
- 会话兴趣激活层 :根据候选广告,用注意力对会话兴趣加权求和(与 DIN 一脉相承):
DSIN 把长序列切成会话:会话内用自注意力聚合(同质),会话间用 Bi-LSTM 传递(异质),最后按候选注意力激活相关会话,实现"会话内聚合 + 会话间传递"的精细刻画。
💡 Key Insight: 序列建模三模型体现了三条递进思想——动态性(DIN:兴趣随任务变)、序列性(DIEN:利用时间顺序演化)、聚焦性(DSIN:按会话分层、按候选激活)。它们共同把"静态物品袋"升级为"可被任务聚焦的动态序列"。
3.3.4 交互演示:DIN 注意力激活
下面用交互演示感受 DIN 的核心:给定同一个用户(固定历史行为),换一个候选广告,被高亮激活的历史行为会 完全不同。点击「下一步」切换候选,观察聚光灯打在不同历史上。
演示中用户历史包含"显卡、鼠标、跑鞋、小说"等行为。候选为「机械键盘」时,显卡/鼠标被激活;候选切到「跑步袜」时,聚光灯转而打在跑鞋上——这正是"局部激活"的直观体现。
⚠️ Common Mistakes in 3.3
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 认为 DIN 用固定用户向量 | "DIN 把历史池化成一个向量" | DIN 用注意力 动态 生成随候选变化的向量 | 区分基准池化(固定)vs 局部激活(动态) |
| 2 | 给 DIN 注意力加 Softmax | "权重和为 1 才规范" | DIN 刻意不归一化以保留兴趣强度 | 理解:保留模长=保留强度信息 |
| 3 | 以为 DIEN 只用 GRU | "DIEN = GRU 堆两层" | 还有关键的 辅助损失 与 AUGRU | 两阶段缺一不可:提取+演化 |
| 4 | 把 DSIN 当长序列 RNN | "DSIN 直接用一个 RNN 处理全序列" | DSIN 先按会话切分,再分层(自注意力+BiLSTM) | 会话是基本单元,分层建模 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| DIN 局部激活 | ,权重不做 Softmax | 兴趣随候选动态变化,突破固定向量瓶颈 |
| DIEN 演化 | GRU+辅助损失提取兴趣,AUGRU 演化 | 显式建模兴趣时序变化,抗漂移 |
| DSIN 会话 | 会话划分→自注意力→BiLSTM→激活 | 会话内同质、会话间异质的分层刻画 |
| 三要素 | 动态性 / 序列性 / 聚焦性 | 序列建模的核心思想递进 |
❓ FAQ
Q1: 注意力权重不做 Softmax,模型不就"不稳定"了吗?
A: 恰恰相反。Softmax 会把权重压成概率分布(和为 1),丢失"这个用户整体有多相关"的信息。DIN 保留模长,让向量既能表示方向也能表示强度,更贴合业务直觉。
Q2: DIEN 的辅助损失有什么用?
A: 它给 GRU 每一步隐状态加"预测下一行为"的监督,逼着隐状态真正编码"兴趣"而非噪声,否则 GRU 隐状态不一定代表有意义的兴趣状态。
Q3: 什么时候该用 DSIN 而不是 DIN/DIEN?
A: 当用户行为明显呈"会话式"(如短时间内集中浏览、间隔长)且跨会话兴趣差异大时,DSIN 的分层建模更贴合实际行为模式。
前后关联
- 3.4(多目标) 中 ESMM 等常以序列模型(如 DIN)作底层 backbone。
- Part 4 重排 在排序输出基础上优化列表级体验;序列建模的"用户意图"理解对重排多样性同样重要。
- 生成式推荐(下篇) 的序列生成思想,与本章"把历史当序列"一脉相承,只是走向自回归解码。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 3.3.1 — 区分模型思想 🟢 Easy
把下列描述对应到 DIN / DIEN / DSIN:
- (a) 用自注意力在每个会话内聚合,再用 Bi-LSTM 在会话间传递,最后按候选激活。
- (b) 对历史行为算注意力权重得到随候选变化的兴趣向量,且权重不归一化。
- (c) 用 GRU 配辅助损失提取兴趣,再用注意力更新门(AUGRU)建模演化。
💡 Solution (click to reveal)
Approach: 抓每模型最标志性的结构。
- (a) DSIN (会话划分 + 自注意力 + Bi-LSTM + 激活)
- (b) DIN (局部激活注意力,权重不 Softmax)
- (c) DIEN (兴趣提取层 + 兴趣演化层 AUGRU)
Key points:
- DIN=动态激活;DIEN=时序演化;DSIN=会话分层。
Problem 3.3.2 — DIN 为何不 Softmax 🟢 Easy
DIN 的注意力权重 不做 Softmax 归一化。请简述这一设计保留了对模型有用的什么信息,并举例说明。
💡 Solution (click to reveal)
Approach: 从"强度"而非"分布"的角度想。
不做 Softmax, 不一定为 1,加权和向量的 模长 保留了用户兴趣与候选的 绝对相关强度。例如:若用户 80% 的历史都与"机械键盘"相关,向量模长大,表示"强兴趣";若仅 10% 相关,模长小。Softmax 会把两者都压成"和为 1",丢失这种强度差异。
Key points:
- 保留模长 = 保留兴趣强度信息。
- 模型同时感知"方向"与"强度"。
Problem 3.3.3 — 动机追问 🟡 Medium
为什么 DIEN 要在 GRU 之外额外引入"辅助损失"?如果只用最终 CTR 损失训练 GRU,会有什么问题?
💡 Solution (click to reveal)
Approach: 从"GRU 隐状态是否真代表兴趣"切入。
GRU 的隐状态 理论应包含到 时刻的全部信息,但单靠最终 CTR 损失,模型可能让隐状态编码进与"兴趣"无关的噪声或捷径特征。辅助损失强制 能预测 真实行为(正样本)而非负样本,等于给每一步隐状态加了"兴趣预测"的监督,使其更精准表达潜在兴趣,进而让下游 AUGRU 演化更可靠。
Key points:
- 辅助损失 = 每步的兴趣监督,防隐状态跑偏。
- 是 DIEN"兴趣提取"有效的关键。
Problem 3.3.4 — 辅助损失与负采样 🔴 Hard
DIEN 的辅助损失 同时用了正样本(真实下一步行为 )与负采样样本 。若去掉负采样、只用正样本让 预测 ,会有什么问题?从 GRU 隐状态表征的角度分析。
💡 Solution (click to reveal)
Approach: 从"监督信号是否足够区分兴趣"入手。
只用正样本时, 只需与 内积大即可,但没有任何"不该像什么"的约束——模型可学到一个退化解(如把所有 推向固定方向、或 Embedding 坍缩),仍能让正样本得分高却丧失区分度。负采样提供"对比"信号:逼 既接近真下一步、又远离随机行为,使隐状态真正编码"兴趣"而非平凡解。
Key points:
- 负样本 = 对比监督,防表征坍缩。
- 无负采样时辅助损失约束太弱,兴趣表示质量下降,下游 AUGRU 受影响。
🏆 Challenge: 选模型论证
某短视频 App 用户行为特点:(1) 兴趣极多样(游戏/美食/知识);(2) 行为密集但常因热点突然切换主题(兴趣漂移强);(3) 一天内多次短时刷不同内容。请据此在 DIN / DIEN / DSIN 中选一个并说明理由(150 字内),并指出不选另外两个的主因。
💡 Hint
"(3) 多次短时刷不同内容"强烈暗示会话结构 → 优先 DSIN :会话内自注意力聚合、会话间 Bi-LSTM 处理主题切换(漂移)。DIN 忽略时序与漂移;DIEN 把全序列当连续、对"断层式"切换建模不如分层会话自然。
多目标优化
📝 Before You Continue: 建议先读完 3.1 Wide & Deep。多目标模型的"共享底座 + 任务塔"结构,正是 Wide&Deep 思想的延伸与多任务化。
前面的章节都在优化 单一目标 (通常是点击率)。但真实推荐系统几乎总是"既要又要":电商要同时优化点击率(CTR)和转化率(CVR),内容平台要兼顾消费深度与广告曝光。当多个目标放到一个模型里,麻烦就来了——目标之间可能冲突,硬共享会导致"跷跷板":提升一个就牺牲另一个。
本章我们沿着"如何缓解多任务冲突"的主线,从最朴素的 Shared-Bottom ,到 MMoE (多门控)、PLE (显式专家分离),再扩展到存在 依赖关系 的 ESMM / ESM2 ,最后讨论多损失如何 融合优化。核心始终是那句话:每个结构改进,都是为了解决前一个方法的什么不足。
读完本章,你将能够:
- 解释 Shared-Bottom 的"负迁移 / 跷跷板"问题,及其数学来源(梯度冲突)
- 说明 MMoE 如何用"每任务专属门控"实现梯度隔离,缓解冲突
- 描述 PLE(CGC) 如何显式分离共享专家与任务专家,进一步根除负迁移
- 用 ESMM 的"全空间建模"解释它如何化解 CVR 的样本选择偏差与数据稀疏
- 完成 4 道分层练习题,比较多目标结构与损失融合策略
3.4.0 动机:当目标不止一个
多目标建模与单目标最大的不同,是目标之间会 打架。比如在电商同时优化"点击率"和"客单价":低价商品拉高点击却压低客单价;内容平台平衡"消费深度"与"广告曝光"时,深度阅读往往与广告点击负相关。
💡 Key Insight: 当任务 的梯度方向相反(),共享层参数更新就会陷入方向性矛盾——这叫负迁移,也常被称作跷跷板问题:提升一目标常以牺牲另一目标为代价。多目标模型的设计,本质就是"如何减少这种冲突"。
🧠 Mental Model: 一栋楼里的几家租户
把 Shared-Bottom 想成一栋共享地基的楼,每家租户(任务)在地基上盖自己的塔。地基便宜高效,但一家要改结构,整栋都可能裂——这就是负迁移。MMoE 给每家配了独立的电梯调度(门控),各家按需用不同专家;PLE 更彻底,给每家专属房间(任务专家)+ 公共客厅(共享专家),物理隔离、互不干扰。
3.4.1 基础结构:Shared-Bottom 与 MMoE
Shared-Bottom 是多目标奠基架构:"共享地基 + 独立塔楼"。所有任务共用特征转换层 ,各自有任务塔 :
它参数高效(共享层占大部分参数)、有正则化效应(防单任务过拟合)、能在相关任务间迁移知识。但致命缺陷是 负迁移 :当任务本质冲突,硬共享的共享层梯度由所有任务共同决定,方向矛盾时优化陷入零和博弈。
Shared-Bottom 所有任务硬共享底层 ,各自盖独立任务塔 ;任务冲突时共享层梯度方向矛盾,陷入零和博弈(负迁移)。
MMoE(Multi-gate Mixture-of-Experts) 针对负迁移,把"全局共享的一个门控"升级为"每任务专属门控"。每个专家 被所有任务共享,但任务 有自己的门控 来加权融合专家:
当任务 冲突时,门控让两者学 不同的专家权重分布——某专家 在任务 门控里权重高、在任务 里权重低,于是 的参数更新主要由任务 的梯度决定,任务 影响很小,实现 梯度隔离。
左:Shared-Bottom 所有任务硬共享底层,冲突时负迁移。右:MMoE 每任务有专属门控,按需选专家,缓解冲突。
Analysis: MMoE 以"多门控"低成本缓解低相关任务冲突,参数效率仍高。局限:所有专家对所有任务门控可见——即便某专家被任务 门控忽略,其梯度在反传时仍可能流经它(潜在通路),强冲突下共享表征仍可能被污染;且门控需在所有专家上分配权重,专家变多时决策负担重。
3.4.2 PLE:显式专家分离
MMoE 的"软隔离"没根除负迁移: 干扰路径未切断 (专家仍对所有门控可见)、专家角色模糊 (一个专家可能既承载共享又承载多任务特定信息)。PLE(Progressive Layered Extraction)用 CGC(Customized Gate Control) 结构,通过 硬性结构约束 显式分离共享知识与任务特定知识。
CGC 把专家分成两类:
- 共享专家(C-Experts) :只学所有任务共性,输出 。
- 任务专家(T-Experts) :任务 专属,只学该任务特定模式,输出 。
关键约束:任务 的门控 输入被限制为"共享专家 + 本任务专属专家", 完全无法访问 其他任务的专属专家。于是任务 的梯度绝不会更新任务 的专属专家参数——物理切断干扰路径。融合为:
PLE 把多个 CGC 单元 纵向堆叠 ,形成深层架构,逐层做"显式知识分离 + 融合",实现渐进式提取。
CGC 中每任务只有"共享专家 + 自己专属专家"可见,其他任务的专属专家被物理隔离;PLE 纵向堆叠多个 CGC 单元,逐层深化。
💡 Key Insight: Shared-Bottom(硬共享)→ MMoE(软隔离,多门控)→ PLE(硬隔离,专家分离),是一条"冲突缓解逐步加强"的清晰主线。代价是 PLE 参数更多、结构更复杂,但换来更稳的多任务学习。
3.4.3 任务依赖建模:ESMM 与 ESM2
前面方法解决任务间"相关性冲突",但现实任务常有明确 依赖关系。用户行为有天然时序链:曝光 → 点击 → 转化。传统 CVR 模型只在点击样本上训练,线上却要在全量曝光上预测,带来两大问题:
- 样本选择偏差(Sample Selection Bias) :训练/预估样本分布不同,泛化差。
- 数据稀疏性(Data Sparsity) :转化样本 = 曝光 × CTR × CVR(如 CTR≈2%、CVR≈0.5%,转化仅曝光万分之一),极稀疏。
ESMM(Entire Space Multi-task Model) 用概率图约束重建任务关系。它同时训 CTR 塔和 CVR 塔,但 不直接拿 CVR 算 Loss ,而是用 在全曝光空间算 Loss:
其中 用全量曝光样本(标准二分类交叉熵), 用 在全空间算。这样 CVR 塔的梯度也在曝光空间进行 ,彻底化解样本选择偏差与稀疏性——CVR 塔借 CTR 塔的全量样本"间接"学好。
ESM2 把思想扩展到更长链路(曝光→点击→加购DAction→购买)。它设四个塔预测 (点击|曝光)、(决定行为|点击)、(购买|决定行为)、(购买|其他行为),但只算三个全空间 Loss(、、),同样都在曝光空间优化。最终 合并两条购买路径。
ESMM 同时训 CTR 与 CVR 塔,用 在全曝光空间算 Loss,使 CVR 梯度也来自全量样本,化解偏差与稀疏。
Analysis: ESMM/ESM2 的"全空间建模"思路巧妙地用乘积关系把依赖目标拉回同一训练空间,是处理任务依赖的标准解法。局限:它假设 CTR、CVR 建模共享底层(可用 MMoE/PLE 替换底座增强),且依赖"链路可分解为概率乘积"的业务假设。
3.4.4 多目标损失融合
当结构确定,多个损失的联合优化本身就是学问。朴素加权 有三个本质缺陷:量级失衡(CTR 损失 0.1–0.5,CVR 可达 2.0+,大损失主导)、收敛异步(稀疏任务慢)、梯度冲突(任务梯度夹角 >90° 时抵消)。主流自适应方法有三类:
- Uncertainty Weight(UWL) :按任务不确定性 (可学习)动态调权,。损失大且不确定小则权重被压低,防被单任务带偏。
- GradNorm :引入梯度损失,按"梯度量级 "与"相对训练速率 "动态调权,让各任务梯度量级与速率趋向均衡,避免快任务主导、慢任务欠拟合。
- Pareto Optimization :当梯度方向根本冲突(优化 A 必损 B),用 KKT 条件把权重写成可学习变量,交替更新参数 与权重 (满足 ),把优化引向 帕累托前沿 (不存在不损一任务而改进另一任务的解)。
💡 Key Insight: 损失融合策略与网络结构正交——无论用 Shared-Bottom、MMoE 还是 PLE,都可在最外层套一层 UWL / GradNorm / Pareto 来平衡多损失。结构解决"表征冲突",损失融合解决"优化冲突"。
⚠️ Common Mistakes in 3.4
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为共享底座总有益 | "多任务一律用 Shared-Bottom 最省" | 任务冲突时硬共享导致负迁移(跷跷板) | 冲突任务改用 MMoE / PLE |
| 2 | 混淆 MMoE 与 PLE 隔离程度 | "MMoE 已经彻底分开了专家" | MMoE 是软隔离,专家仍对所有门控可见 | PLE 用 CGC 物理隔离任务专家 |
| 3 | 直接拿 CVR 塔算 Loss | "ESMM 和 MMoE 一样训 CVR" | 这会带来样本选择偏差与稀疏 | ESMM 用 全空间算 |
| 4 | 手工固定损失权重 | "w_ctr=1, w_cvr=1 就行" | 量级/收敛速度不同,大损失主导 | 用 UWL / GradNorm / Pareto 自适应 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 负迁移/跷跷板 | 梯度冲突 | 多任务硬共享的根本风险 |
| Shared-Bottom | 共享层 + 任务塔,参数高效 | 任务相关时好;冲突时负迁移 |
| MMoE 多门控 | 每任务专属门控选专家,梯度隔离 | 软隔离缓解冲突 |
| PLE/CGC | 共享专家 + 任务专家物理隔离 | 硬隔离,根除干扰路径 |
| ESMM 全空间 | 化解 CVR 偏差+稀疏 | |
| 损失融合 | UWL / GradNorm / Pareto | 解决优化层冲突 |
❓ FAQ
Q1: 我该用 Shared-Bottom、MMoE 还是 PLE?
A: 任务高度相关 → Shared-Bottom 够用且省;任务弱相关、有冲突 → MMoE;任务强冲突或需稳定 → PLE。本质是"冲突越强,隔离越硬"。
Q2: ESMM 一定要和 MMoE 一起用吗?
A: 不必。ESMM 是"全空间概率建模"思想,原论文底座可用简单 Shared-Bottom,也可替换为 MMoE/PLE 增强底层表征,二者正交。
Q3: 损失融合和选结构哪个更重要?
A: 都重要且互补。结构决定"表征能否分离冲突",损失融合决定"多损失能否平衡优化"。工程中常先定结构,再调损失融合策略。
前后关联
- 3.5(多场景) 把"多任务差异"换成"多场景分布差异",多塔/动态权重与 MMoE 思想同宗。
- 3.3(序列建模) 的 DIN 等常作为多目标模型的底层 backbone。
- Part 4 重排 在排序(多目标打分)之上优化列表级体验,多目标分数是重排输入。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 3.4.1 — 识别负迁移 🟢 Easy
某内容 App 同时优化"消费深度(阅读时长)"与"广告曝光量"。工程师发现:提升广告曝光后,阅读时长明显下降。请判断这是否为负迁移,并说明数学上的成因。
💡 Solution (click to reveal)
Approach: 判断是否符合"提升一目标损害另一目标"的跷跷板特征,并用梯度冲突解释。
是负迁移。两目标呈负相关,共享层梯度方向相反:。Shared-Bottom 硬共享使参数更新方向矛盾,优化一个必损另一个,陷入零和。
Key points:
- 跷跷板 = 负相关目标的硬共享冲突。
- 解法:改用 MMoE/PLE 隔离冲突路径。
Problem 3.4.2 — MMoE vs PLE 🟢 Easy
判断下列说法正误并改正:
- (a) MMoE 中每个任务有专属门控,因此任务间已无梯度干扰。
- (b) PLE 的 CGC 让任务 的门控也能看到任务 的专属专家。
💡 Solution (click to reveal)
Approach: 抓"软隔离 vs 硬隔离"的区别。
- (a) 错误 :MMoE 是软隔离——专家仍对所有门控可见,即便被忽略,反传时梯度仍可能流经它(潜在通路)。PLE 才物理隔离。
- (b) 错误 :CGC 硬性约束任务 门控 输入仅为"共享专家 + 本任务专属专家", 完全看不到 其他任务专属专家;任务 梯度不会更新任务 专属专家。
Key points:
- MMoE=软隔离;PLE/CGC=硬隔离。
- 隔离程度递进:Shared-Bottom < MMoE < PLE。
Problem 3.4.3 — ESMM 动机 🟡 Medium
为什么传统 CVR 模型在"点击样本上训练、全量曝光上预测"会出问题?ESMM 如何用 解决?
💡 Solution (click to reveal)
Approach: 从样本空间不一致 + 稀疏两个角度切入。
传统 CVR 只在点击样本(CTR 正样本)训练,但线上要对全量曝光预估,训练/预估分布不同 → 样本选择偏差 ,泛化差;且转化样本极稀疏(曝光×CTR×CVR),难学。
ESMM 同时训 CTR 与 CVR 塔,但 CVR 不直接算 Loss,而是用 在全曝光空间算 。于是 CVR 塔梯度经 来自 全量曝光样本 ,偏差与稀疏都被化解——CVR 间接借 CTR 的全量数据学好。
Key points:
- 偏差根因:训练空间(点击)≠ 预估空间(曝光)。
- 解法:乘积关系把 CVR 拉回全空间。
Problem 3.4.4 — 证明负迁移的梯度冲突 🔴 Hard
设共享参数 同时服务任务 1、2,损失变化近似 。若采用统一梯度下降 ,且已知 (夹角 >90°),请证明:至少其中一个任务的损失会上升。
💡 Solution (click to reveal)
Approach: 代入 看各任务损失变化。
。因 ,第二项为正,会 抵消 第一项的下降;若 ,则 ,任务1损失上升。同理对任务2对称成立。既然两梯度反向,统一更新方向不可能同时让两者下降——必有一方受损,这正是跷跷板/负迁移的数学本质。
Key points:
- 梯度反向 → 共享参数更新方向"两难"。
- 这解释了为何需 MMoE/PLE 隔离、或 Pareto 优化找不损解。
🏆 Challenge: 设计多目标方案
某电商要同时优化 CTR、CVR、客单价三目标,其中 CTR 与 CVR 有依赖(ESMM 式),CVR 与客单价常冲突(跷跷板)。请组合合适结构并说明理由(150 字内),并指出损失融合策略。
💡 Hint
底层用 PLE/CGC 隔离 CVR 与客单价冲突(硬隔离);CTR-CVR 依赖用 ESMM 式乘积 在全空间联合(可把 CTR/CVR 塔放进共享底座)。损失层用 GradNorm 或 UWL 自适应平衡三损失量级与收敛速度。
多场景建模
📝 Before You Continue: 建议先读完 3.4 多目标优化。多场景与多任务"形似神异"——多任务处理同场景多目标,多场景处理不同场景同目标,二者都建立在"共享 + 差异化"的设计哲学上。
3.4 解决了"同一条样本预估多个目标"的多任务问题。但工业推荐常面对 多个场景 :同一 App 可能有首页推荐、搜索结果页、购物车下方的"猜你喜欢"——这些场景数据分布不同,却要预估 同一个目标 (如 CTR)。这就是 多场景建模。
若为每个场景训独立模型,会忽视场景共性、小场景数据少效果差、资源剧增;若混合样本训单一模型,又忽视场景差异、精度下降。本章我们从"多塔结构"(HMoE、STAR)讲到"动态权重建模"(PEPNet、APG、M2M),看如何兼顾 场景共性 与 场景特性。
读完本章,你将能够:
- 区分 多任务(同场景多目标)与多场景(不同场景同目标)的本质差异
- 解释 HMoE 如何用多专家 + 多场景塔 + 跨场景融合(含 stop-gradient)建模共性
- 说明 STAR 如何用"星型 FCN + 分区归一化 + 辅助网络"同时建模共享与私有参数
- 描述 PEPNet 的 EPNet/PPNet 如何用动态门控(Gate NU)调制共享参数
- 完成 4 道分层练习题,比较多场景结构的"物理隔离"与"动态调制"两条路线
3.5.0 动机:多任务 ≠ 多场景
先厘清一个常见混淆:
- 多任务学习 :同一样本、同一场景,预估 多个不同目标 (如一条样本同时给 CTR、CVR)。
- 多场景建模 :不同场景、不同分布,预估 同一个目标 (如不同场景各预估 CTR)。
前者是"一条样本多目标",后者是"不同样本同目标"。多场景若用独立模型忽视共性(小场景差、资源炸),若混训单一模型忽视差异(精度降)。
💡 Key Insight: 多场景建模的核心张力是——如何在共享底层参数(抓共性)的同时,让模型感知场景差异(抓特性)。本章两条路线:①多塔结构(物理隔离部分参数);②动态权重(共享参数 + 场景/样本调制)。
🧠 Mental Model: 连锁店 vs 中央厨房
把多场景想成一家公司的多个门店(场景)。① 多塔结构像"每个门店有自己的后厨(场景塔),但共享中央厨房的半成品(共享专家)"。② 动态权重像"所有门店用同一套中央厨房,但每个门店有一台'口味调节器'(Gate NU),按本地顾客偏好微调同一份菜"。前者分厨房,后者调味道。
3.5.1 多塔结构:HMoE 与 STAR
HMoE(Hierarchical Mixture-of-Experts) 借鉴 MMoE:底层多专家提多场景共享特征,顶层是 多个场景塔 (而非多任务塔)。对场景 ,底层经门控融合专家得 ,最终打分融合多场景输出:
关键是:融合其他场景打分时,用 stop-gradient 阻断其梯度回传——避免场景 的样本直接改场景 的参数,保住场景感知。这使某场景 既用自己的塔,也借其他场景打分作参考,又不互相污染。
HMoE 底层多专家提取跨场景共享特征,顶层每个场景一个专属场景塔;融合他场景打分时用 stop-gradient 阻断梯度,既借共性又互不污染。
STAR(Star Topology Adaptive Recommender) 用星型拓扑同时建模共享与私有参数。其 STAR FCN 对每个场景的层参数做"共享 + 私有"的元素积融合:
其中 分别是场景私有与全局共享参数。STAR 还有两项创新: 分区归一化(PN)——按场景分别统计 Batch Norm 的均值/方差(避免跨场景统计混淆); 辅助网络——把场景特征经浅层网络得辅助 Logits,与主干相加:。
STAR 用星型 FCN 把"共享中心 × 场景私有"做元素积融合,再配分区归一化(按场景分别统计)与辅助网络,在参数与归一化两层都区分场景。
左:多任务——同一样本、多目标塔。右:多场景——不同场景样本、同目标塔;挑战是共享共性与保留差异。
Analysis: 多塔结构(HMoE/STAR)用"物理隔离的部分参数"保场景特性,直观、可解释。HMoE 的 stop-gradient 防场景污染;STAR 的星型 FCN + PN 在参数与归一化两层都分场景。代价是参数量随场景数增长(每场景一份塔/私有参数)。
3.5.2 动态权重建模:PEPNet
多塔靠"分厨房"保特性,但参数不够共享。PEPNet(Parameter and Embedding Personalized Network)换思路:核心网络参数 跨场景共享 ,但通过动态生成的、与场景/样本高度相关的 权重 来"调制"(Modulate)共享参数的行为——相当于给共享网络注入上下文。
PEPNet 的核心是轻量门控单元 Gate NU (受语音识别 LHUC 启发),用两层网络生成动态缩放权重:
输出 与目标参数维度对齐,通过逐元素相乘 实现调制。PEPNet 用两大模块做分层个性化:
- EPNet(场景感知 Embedding 个性化) :把场景先验信息经 Gate NU 生成门控 ,与共享 Embedding 元素乘得场景个性化 Embedding 。注意对共享 Embedding 用 stop-gradient,不影响底层学习。
- PPNet(用户感知参数个性化) :把用户/内容/作者 ID 先验 + EPNet 的场景 Embedding 作输入,生成逐层、逐任务塔的门控 ,对任务塔 DNN 每层输出做调制 。这是样本粒度(而非任务粒度)的个性化,缓解多任务跷跷板。
Gate NU 由场景/用户先验生成动态缩放权重;EPNet 调制共享 Embedding(场景个性化),PPNet 调制各任务塔 DNN(样本个性化),底层仍共享。
3.5.3 动态参数生成:APG 与 M2M
APG(Adaptive Parameter Generation) 走得更远:根据样本 直接动态生成 该样本对应的参数。把样本感知输入 经 MLP reshape 成参数矩阵 ,预测 。为控开销,APG 做 低秩分解 :,其中私有因子 从样本生成、共享因子 固定;前向用分解计算 降低复杂度。共享 刻画共性、私有 刻画特性,兼顾容量与效率。
M2M(元学习多场景多任务) 用元学习器(MLP)根据场景/输入特征 动态生成 任务模型的参数 。主干网络含专家表征 、任务表征 、场景表征 ;元学习单元把场景表征 转成每层动态参数,作用于特征(类似注入了场景信息的 MLP)。它还在专家融合(Attention 元网络,融合时引入场景)与多任务塔(Tower 元网络,残差方式)都用了元学习单元,实现细粒度场景自适应。
💡 Key Insight: 多场景建模的两条路线殊途同归——多塔结构用"物理隔离的参数空间"保特性(分而治之);动态权重/参数生成用"共享底座 + 动态调制"保特性(注入上下文)。后者参数更高效、更灵活,但对调制/生成机制设计要求更高。
⚠️ Common Mistakes in 3.5
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把多场景当多任务 | "多场景就是多任务,换名字而已" | 多场景=不同分布同目标;多任务=同分布多目标 | 先判"样本分布是否不同" |
| 2 | HMoE 融合不打 stop-gradient | "跨场景打分直接相加梯度也回传" | 场景 a 样本会改场景 b 参数,污染感知 | 其他场景打分加 stop-gradient |
| 3 | STAR 忽略 PN 的动机 | "BN 全局统计就行" | 多场景混合样本不独立同分布 | 用分区归一化按场景分别统计 |
| 4 | 混淆 EPNet 与 PPNet | "两者都调任务塔" | EPNet 调 Embedding(场景),PPNet 调塔(样本) | EPNet=场景级,PPNet=样本级 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 多场景 vs 多任务 | 异分布同目标 vs 同分布多目标 | 建模前先分清问题类型 |
| HMoE 多塔 | 多专家+场景塔+跨场景 stop-gradient 融合 | 共享共性、保场景感知 |
| STAR 星型 | 共享⊗私有参数 + 分区归一化 + 辅助网络 | 参数与归一化都分场景 |
| PEPNet | Gate NU 动态调制:EPNet(Embedding)+PPNet(塔) | 共享底座+动态个性化 |
| APG/M2M | 样本/场景动态生成参数(元学习) | 最灵活,参数高效 |
❓ FAQ
Q1: 什么时候用多塔、什么时候用动态权重?
A: 场景数不多、差异大、要强可解释 → 多塔(HMoE/STAR);场景多、参数效率敏感、要细粒度样本个性化 → 动态权重(PEPNet/APG/M2M)。二者也可组合。
Q2: STAR 的星型 FCN 为什么要元素积?
A: 让每个场景的最终参数是"共享中心 × 场景增量"——既继承共性,又带场景特性;乘法(而非仅相加)让私有参数对共享做"增强/抑制"式调制。
Q3: PEPNet 的 EPNet 为什么要对共享 Embedding stop-gradient?
A: 防止场景个性化门控支路的反向梯度破坏底层共享 Embedding 的通用学习,让"共性"与"场景差异"解耦。
前后关联
- 3.4(多目标) MMoE/PLE 思想在多场景中演化为 HMoE 的多专家+多塔;PEPNet 的 PPNet 同时缓解多任务跷跷板。
- Part 4 重排 在精排(多场景多目标打分)之上优化列表体验。
- 生成式推荐(下篇) 的端到端架构,可视为对"多场景/多任务分塔"的进一步统一。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after yourself.
Problem 3.5.1 — 区分多任务与多场景 🟢 Easy
判断下列情形属于"多任务"还是"多场景",并说明理由:
- (a) 同一首页推荐流,一条样本同时预估点击率与转化率。
- (b) 同一 App 的"首页推荐"与"搜索结果页"两个分布不同的流量,各自预估点击率。
💡 Solution (click to reveal)
Approach: 看"样本分布是否相同、目标是否相同"。
- (a) 多任务 :同场景(首页)、同分布,预估 多个不同目标 (CTR、CVR)。
- (b) 多场景 :不同分布(首页 vs 搜索)、不同样本,预估 同一目标 (CTR)。
Key points:
- 多任务=同分布多目标;多场景=异分布同目标。
- 二者都靠"共享+差异化",但差异化针对的是"目标"还是"分布"。
Problem 3.5.2 — HMoE 的 stop-gradient 🟢 Easy
HMoE 在融合其他场景打分时用了 stop-gradient。请简述:若 不用 stop-gradient,会发生什么问题?
💡 Solution (click to reveal)
Approach: 从"场景参数污染"角度想。
HMoE 融合公式里其他场景的 加 stop-gradient,是为阻断其梯度回传。若不用:场景 的样本在前向参与了场景 打分的融合,反向时梯度会顺着融合路径改到场景 的塔参数,使场景 的表示被场景 的样本干扰,模型对场景的感知下降,多场景效果变差。
Key points:
- stop-gradient 隔离跨场景梯度,保住"每场景只影响自身参数"。
- 这是 HMoE 既能借他场景信息、又不互相污染的关键。
Problem 3.5.3 — STAR 的创新点 🟡 Medium
STAR 相比"给每个场景独立训一个模型",做了哪些共享设计来兼顾共性与特性?请列出至少两点并说明作用。
💡 Solution (click to reveal)
Approach: 回忆 STAR 的三大创新。
- 星型 FCN :——每个场景参数 = 共享中心 × 场景私有,既继承共性又带特性,避免完全独立模型。
- 分区归一化(PN) :按场景分别统计 BN 的均值/方差,避免多场景混合样本不独立同分布导致的统计混淆。
- 辅助网络 :场景特征经浅层网络得辅助 Logits,与主干相加,增强场景特征对输出的直接影响。
Key points:
- 共性靠共享 / PN 共享参数;特性靠 / PN 场景私有统计。
- 比独立模型省参数、小场景也能借共性。
Problem 3.5.4 — 小场景与星型共享 🔴 Hard
STAR 用 :每场景私有参数 与全局共享 元素积融合。若某场景数据极少,其私有参数 易过拟合。请结合星型结构说明:为何共享中心 能缓解该问题?并指出现 PN(分区归一化)在此场景的额外作用。
💡 Solution (click to reveal)
Approach: 从"私有参数量小、受共享约束"与"归一化稳定性"两个角度看。
- 最终参数是 :私有 虽小样本易过拟合,但它只做"对共享中心 的增强/抑制"式调制,主体能力仍来自数据充足的共享 。私有参数维度相对小、且乘性受共享约束,过拟合影响被稀释——相当于用共享做正则。
- PN 按场景分别统计 BN 的均值/方差。小场景若混入全局混合批,统计量被大场景主导、归一化不稳;PN 让小场景用 自己的 统计,训练更稳,进一步缓解小样本下的表示偏移。
Key points:
- 星型 = 共享兜底 + 私有微调,天然抗小场景过拟合。
- PN 补充分布层面的场景隔离。
🏆 Challenge: 选路线论证
某平台有 6 个不同场景(首页/搜索/购物车/频道页/推送/信息流),都预估 CTR,其中 3 个场景数据极少。团队资源有限,希望参数高效且小场景不崩。请选择"多塔结构"或"动态权重"路线并说明理由(150 字内),并指出若选动态权重可用哪个具体模型打底。
💡 Hint
6 场景、参数敏感、小场景弱 → 选 动态权重 路线:共享底座+动态调制,参数高效、小场景借共享共性不崩。可用 PEPNet (Gate NU 调 Embedding 与塔)或 APG (样本动态生成参数)打底;多塔在 6 场景下参数随场景线性增长、小场景独立塔易欠拟合。
当排序模型吐出一张按 CTR 降序排列的列表时,你常会看到一个尴尬的现象:头部清一色是同品类、同风格的内容。排序追求的是 单点精度 ,而用户要的是 一整屏的好体验。本部分站在三阶段漏斗的最末端——重排(Re-ranking) ,研究如何在「分数最高的列表 ≠ 体验最佳的列表」之间架起桥梁。
我们从两条路线展开:一条是 基于贪心 的轻量规则法(MMR、DPP),直观、可解释、易落地;另一条是 基于个性化 的数据驱动法(PRM、PRS),用模型自动学习物品间的高阶相互影响。
本章涵盖
| 章节 | Topic | The Big Idea |
|---|---|---|
| 4.1 | 基于贪心的重排 | MMR 用线性组合权衡相关性与多样性;DPP 用行列式框架更精确控制多样性 |
| 4.2 | 个性化重排 | PRM 用 Transformer 建模物品相互影响;PRS 直接优化排列组合的体验收益 |
What You'll Be Able to Do After This Part
- 🟢 解释 排序输出「同质化」为何是重排的根本动机,以及它带来的两类代价
- 🟢 写出 MMR 的边际收益公式,并用贪心过程在给定相似度矩阵上手算 top-k 列表
- 🟡 推导 DPP 核矩阵 ,说清行列式如何度量多样性
- 🟡 辨析 MMR(启发式线性组合)与 DPP(行列式精确控制)在多样性建模上的本质区别
- 🔴 描述 PRM 如何用 Transformer + 个性化向量(PV)实现端到端列表重排
- 🔴 理解 PRS 为何引入排列变异影响,并用 PMatch / PRank 两阶段解决 组合爆炸
- 完成 8 道分层练习题,巩固两章核心方法
核心概念
| Concept | 章节 | Relevance |
|---|---|---|
| 列表同质化 / 多样性 | 4.1 | 重排的存在理由:打破头部重复、保护长尾 |
| MMR 最大边际相关 | 4.1 | 最经典、最易落地的贪心多样性重排 |
| DPP 行列式点过程 | 4.1 | 用行列式几何意义精确建模集合级多样性 |
| PRM 个性化重排模型 | 4.2 | 用 Transformer 端到端学习物品相互影响 |
| PRS 排列组合重排 | 4.2 | 直接优化排列顺序带来的体验收益 |
前置知识
- 已读 Part 3 排序 的打分函数 ,理解精排如何输出带相关性分数的候选列表
- 了解矩阵基础(行列式、半正定、Cholesky 分解)有助于吃透 DPP 推导
- 了解 Transformer 自注意力机制有助于理解 PRM 编码层
- 基础 Python 与向量表示常识
本部分是三阶段流水线的最后一环——建议先建立 Part 1–3 的「召回→排序→重排」全景。
Tips for This Part
- 先动机、后公式。 每个方法都是为解决「列表级体验」而生,脱离动机学公式很容易迷路。
- 动手算一遍案例。 4.1 的 MMR 手算表、DPP 核矩阵构建,务必自己推一遍,比读十遍更牢。
- 对比两条路线。 学完 4.2 后回头对比:贪心法靠「人设目标函数」,个性化法靠「模型从数据学」。
- 记住可视化。 本章配套 SVG 与交互式 HTML 把抽象公式变成可观察的过程,多看多拖。
Let's dive in! 🚀
基于贪心的重排
📝 Before You Continue: 请先读完 Part 3 排序 的打分函数 ,理解精排如何为每个候选输出一个相关性分数(如 CTR 预估分)。本章正是站在精排之后,对那份「按分数排序」的列表做最后一里路的优化。
想象一下:精排模型自信地交出一份列表,头部十位是十部高度雷同的「科幻动作片」。单看每个位置,分数都很高、都很相关;但连成一张列表,用户立刻感到审美疲劳。这就是重排要解决的真实痛点——排序输出同质化。
重排(Re-ranking)处在「召回→排序→重排」漏斗的最末端,它的职责不是再算一遍精度,而是回答一个更刁钻的问题: 在保持相关性的前提下,如何让整张列表的体验最好? 贪心算法因其思路直观、计算高效、易于实现,成为重排阶段解决多样性、新颖性等问题的首选策略之一。它们通常 不依赖复杂模型训练 ,而是基于预先定义的规则或目标函数,通过逐步选择当前最优解(贪心选择)来构建最终列表。
本章深入剖析两种经典的贪心重排算法: 最大边际相关(Maximal Marginal Relevance, MMR) 与 行列式点过程(Determinantal Point Process, DPP)。
读完本章,你将能够:
- 解释 排序输出的「同质化」现象,以及它造成的用户体验与生态效率两类代价
- 写出 MMR 的边际收益公式,并用贪心过程在给定相似度矩阵上手算出 top-k 列表
- 描述 DPP 如何用「行列式 = 体积」的几何直觉度量集合级多样性
- 推导 DPP 核矩阵 ,并说清相关性项与多样性项如何融合
- 辨析 MMR(启发式线性组合)与 DPP(行列式框架精确控制)的本质区别与适用场景
- 完成 4 道分层练习题,巩固两种算法的手算与代码实现
4.1.0 重排动机:排序输出的同质化
精排模型的目标通常是最大化单点精度(如预测 CTR)。当它的输出按分数降序排列时,头部物品往往具有高度相似性——连续推荐同品类商品、同风格视频、同作者内容。这种 同质化 并非偶然,而是「逐点最优化」的必然副产物。它直接带来两大类问题:
- 用户体验恶化 :用户浏览时产生审美疲劳,兴趣衰减速度加快,原本可能点击的内容因为「看得太多同类」而被跳过。
- 系统效率损失 :长尾优质内容曝光不足,平台生态多样性下降,创作者积极性受挫,长期损害供给端健康。
上图左侧是精排直接吐出的列表——十格内容高度相似(同色块扎堆);右侧是重排期望达成的列表——在保住高相关性的同时,让品类、风格、作者更错落有致。重排的核心使命,就是打破这种「相关但雷同」的僵局。
💡 Key Insight: 重排要实现的不是「相关性的帕累托最优」,而是**「相关性与多样性的帕累托最优」**——在可接受的精度损失内,换取整张列表体验的跃升。
🧠 Mental Model: 自助餐的摆盘
把推荐列表想成一场自助餐的摆盘。精排像一位「每道菜都挑最抢手」的厨师:结果全是红烧肉,虽然每盘都受欢迎,但没人吃得下十盘肉。重排像一位懂得搭配的厨师:在保留几道硬菜(高相关)的同时,插入凉菜、汤品、甜点(多样性),让整桌菜既好吃又不腻。
4.1.1 最大边际相关性重排(MMR)
MMR(Maximal Marginal Relevance) 的核心目标,是在保留高相关性物品的前提下,通过主动引入多样性来打破同质化。它的思想非常直白:每次挑选一个物品时,不仅看它 自己有多相关 ,还要惩罚它 与已选物品有多相似。
边际收益公式
MMR 通过定义一个 边际收益函数 来量化物品 对当前列表 的增量价值:
其中各符号含义如下:
- :已选物品集合
- :物品 的相关性分数,直接继承精排模型输出(如 CTR 预估分)
- :物品 与 的相似度(0~1)
- :权衡参数()
是 MMR 的「灵魂旋钮」:
- :退化为纯精排序(只管相关性,不要多样性)
- :强制多样性优先(可能牺牲相关性)
💡 Key Insight: MMR 的巧妙之处在于——它把「多样性」定义成了对已经选过的东西的相似度惩罚。物品越像已选项,边际收益越低。于是贪心过程天然地「避开了和它选过的东西撞车」的内容。
滑动窗口优化
当精排候选数量太多时,计算与 所有 已选物品的相似度会很昂贵。可以通过 滑动窗口 来对齐优化:相似度惩罚不再遍历整个 ,而只计算与最近选出的 个物品(窗口 )的相似度。
其中 是最近选择的 个物品()。窗口法在长列表场景下大幅降低计算量,是工业落地的常用技巧。
手算案例:从 5 个物品中挑 top-3
假设候选集包含 5 个商品及其精排分(Rel),相似度矩阵如下(对角线为 1,表示自身相似度满分):
| 商品 | Rel | A | B | C | D | E |
|---|---|---|---|---|---|---|
| A | 0.95 | 1.0 | 0.2 | 0.8 | 0.1 | 0.3 |
| B | 0.90 | 0.2 | 1.0 | 0.1 | 0.7 | 0.4 |
| C | 0.85 | 0.8 | 0.1 | 1.0 | 0.3 | 0.6 |
| D | 0.80 | 0.1 | 0.7 | 0.3 | 1.0 | 0.5 |
| E | 0.75 | 0.3 | 0.4 | 0.6 | 0.5 | 1.0 |
取 ,走一遍贪心过程:
- 初始选择 :精排最高分 A(Rel=0.95),令 。
- 第二轮 ():
- B:
- C:
- D:
- E:
- 选 B(score=0.57),令 。
- 第三轮 ():
- C:
- D:
- E:
- 选 E(score=0.405),令 。
最终序列为 [A, B, E] ,对比纯精排序 [A, B, C],三件物品分属更错落的相似关系,多样性显著提升(源文献称提升约 37%)。
Analysis: MMR 的优势是直观、可解释、零训练成本,旋钮 让业务方直接调控「相关 vs 多样」的天平。但代价也明显:(1) 它是贪心局部最优,不保证全局最优;(2) 多样性惩罚只用「与最相似已选物品的相似度」(max,是两两近似,无法捕捉三个相似物品叠加产生的冗余效应——这正是下一节 DPP 要解决的根本局限。
代码实现
def MMR_Reranking(
item_pool, k, lambda_param, sim_func, window_size=None
):
"""基于 MMR 的贪心重排,支持滑动窗口优化。"""
candidates = list(item_pool)
S = []
if not candidates:
return S
# 第一步:选取精排最高分物品
first = max(candidates, key=lambda x: x.rel) # ← KEY LINE: 首物品必选最相关
S.append(first)
candidates.remove(first)
# 第二步:贪心迭代选择
while len(S) < k and candidates:
best_score, best_item = -float("inf"), None
window = S[-window_size:] if window_size and len(S) > window_size else S
for item in candidates:
max_sim = max((sim_func(item, s) for s in window), default=0)
# MMR 公式: lambda*Rel - (1-lambda)*max_sim
score = lambda_param * item.rel - (1 - lambda_param) * max_sim # ← KEY LINE
if score > best_score:
best_score, best_item = score, item
if best_item:
S.append(best_item)
candidates.remove(best_item)
else:
break
return S
4.1.2 行列式点过程重排(DPP)
上一节我们看到,MMR 只计算候选与已选物品的 两两 相似度,贪心地避开与已选最相似的内容。这种方式 无法捕捉多个物品间的复杂排斥关系 (例如三个相似物品叠加的冗余效应),而 行列式 恰恰能优雅地刻画这一点。
行列式如何度量多样性
假设我们通过余弦相似度计算物品间的相似度,每个物品有一个向量表示 。对于待排序的所有物品 ,容易得到两两相似度矩阵 。
矩阵行列式的几何意义是:矩阵列向量张成的超立体的「有向体积」。在矩阵 中,如果列向量 线性相关 (在 2D 中两向量共线、在 3D 中三向量共面),向量「塌缩」到更低维空间,此时 。反之,若线性 不相关 ,向量张成的高维空间没有冗余。
💡 Key Insight: 行列式越大 ↔ 列向量越「正交」↔ 物品间越不相似 ↔ 多样性越高;行列式越小 ↔ 向量越共线 ↔ 多样性越低。这正是用行列式度量多样性的几何直觉。
看一个具体例子。假设有 4 个物品:科幻动作片、科幻喜剧片、古装爱情片、古装悬疑片,其相似度矩阵为:
比较子集 (都是科幻)与 (科幻 vs 古装悬疑):
它们的行列式分别为:
结果印证直觉: 跨类型、几乎正交,行列式大(0.81),多样性高; 同类型、高度共线,行列式小(0.19),多样性低。
相关性与多样性的融合:核矩阵
推荐中相关性与多样性是两个都要的指标。DPP 引入一个 半正定核矩阵 来同时优化二者。该矩阵可分解为 ,其中 的每一列是候选物品的表示向量。具体地, 的列由相关性得分 (精排分)与归一化物品向量的乘积构成,因此核矩阵元素为:
其中 即相似度得分 。于是核矩阵可写为:
即对相似度矩阵的每一行、每一列分别乘上对应的相关性 。
🧠 Mental Model: 核矩阵是一张「双保险」打分表 普通相似度矩阵 只管「长相像不像」;核矩阵 额外给每个物品乘上自己的相关性 。于是:一个既**不相关(与已选差异大)又高相关(本身分高)**的物品,在 里对应的「影响力」才最大。相关性像门票,多样性像座位布局——两者共同决定集合质量。
核矩阵构建示例
假设有 3 个物品,相似度矩阵 与相关性向量 :
计算 :
从行列式到「相关性 + 多样性」目标
对用户 ,被选中的候选集合为 ,核矩阵行列式表示集合质量:
两边取对数,得到:
- 第一项只与「相关性」有关: 越大越相关;
- 第二项 只与「多样性」有关: 越接近正交(余弦越接近 0),行列式越大。
因此 DPP 最终优化的目标,也化成了 相关性项 + 多样性项 的形式,并通过超参 平衡二者权重:
Analysis: 表面上看,DPP 的优化目标与 MMR 一样是「相关性 + 多样性的线性组合」。但关键差异在于:MMR 的多样性惩罚只看「与最相似已选项的两两相似度」(max 项),是逐对的近似;而 DPP 的 通过行列式的体积语义,一次性、联合地刻画了整个子集内所有物品间的相互排斥关系,能精确表达三个甚至更多相似物品的叠加冗余。
贪心求解:Cholesky 加速
DPP 本质是一个概率模型,能把复杂的概率计算转换为简单的行列式计算。推断「使 最大」的子集,是 最大后验(MAP)推断。Hulu 论文提出了一种改进的 贪心算法 快速求解:每次从候选集中贪心选一个使 边际收益(Marginal Gain) 最大的物品加入结果集 ,直到满足停止条件:
由于 半正定,可对其已选部分做 Cholesky 分解 。新物品 加入后的核矩阵分块为:
其中 ,。利用分块下三角矩阵的行列式性质,可推导出:
于是每次选择简化为:
这意味着:每轮只需维护并更新每个候选的 与 ,即可 选出最优,避免重复计算整块行列式——这是 DPP 能在工业级候选上实时运行的关键。
算法流程:
- 初始化 :,,,。
- 迭代 :当未达停止条件时,对每个 :
- ,
- ,更新
- 返回 。
代码实现:
def DPP_Reranking(item_pool, k, kernel_matrix, epsilon=1e-10):
"""基于 DPP 的贪心重排(Cholesky 加速)。"""
n = len(item_pool)
if n == 0 or k <= 0:
return []
cis = np.zeros((k, n)) # 存储 c_i 向量
di2s = np.copy(np.diag(kernel_matrix)) # 存储 d_i^2
selected = []
# 第一步:选 d_i^2 最大的物品(相关性最高者优先)
j = int(np.argmax(di2s)) # ← KEY LINE: 初始选核矩阵对角最大者
selected.append(j)
while len(selected) < k and len(selected) < n:
k_cur = len(selected) - 1
ci_opt = cis[:k_cur, j]
di_opt = math.sqrt(di2s[j])
elements = kernel_matrix[j, :]
# e_i = (L_{ji} - <c_j, c_i>) / d_j
eis = (elements - np.dot(ci_opt, cis[:k_cur, :])) / di_opt # ← KEY LINE
cis[k_cur, :] = eis
di2s -= np.square(eis) # 更新 d_i^2 = d_i^2 - e_i^2
j = int(np.argmax(di2s)) # 下一步选 log(d_i^2) 最大者
if di2s[j] < epsilon:
break
selected.append(j)
return [item_pool[idx] for idx in selected]
def create_kernel_matrix(item_pool, sim_func):
"""构建 DPP 核矩阵 L = diag(r) * S * diag(r)。"""
n = len(item_pool)
r = np.array([it.rel for it in item_pool])
S = np.eye(n)
for i in range(n):
for j in range(n):
if i != j:
S[i, j] = sim_func(item_pool[i], item_pool[j])
return r.reshape((n, 1)) * S * r.reshape((1, n)) # ← KEY LINE: 融合相关性与多样性
Analysis: DPP 的复杂度优于「暴力枚举子集」,Cholesky 加速把每轮选择降到近似 更新。它精确控制集合级多样性,适合对多样性质量要求高、候选规模中等的场景(如前 50~200 个精排候选做最终重排)。代价是:需要构造并维护核矩阵,对相似度质量敏感;且仍属贪心局部最优,不保证全局行列式最大。
下面这个交互演示让你亲手观察:给定候选与相似度,MMR 与 DPP 如何一步步挑出列表,以及 如何影响结果。
拖动「权衡参数」滑块,点击「下一步」逐步观察贪心挑选过程,对比 MMR 的线性惩罚与 DPP 的行列式体积视角在最终列表上的差异。
4.1.3 MMR 与 DPP:启发式线性组合 vs 行列式框架
学完两种方法,我们用一张表把它们的本质区别钉死,避免「会背公式却说不清差异」。
| 维度 | MMR(最大边际相关) | DPP(行列式点过程) |
|---|---|---|
| 多样性建模 | 与 最相似已选项 的两两相似度(max 惩罚) | 整个子集行列式的 体积语义 (联合排斥) |
| 数学本质 | 启发式 线性组合 : | 行列式框架: 度量集合质量 |
| 高阶冗余 | 无法 捕捉「三物品共线」式叠加冗余 | 能精确刻画多物品间相互排斥 |
| 可调性 | 单旋钮 直观易懂 | 核矩阵 构造灵活,超参 |
| 计算成本 | 极低(两两相似度) | 中(需核矩阵 + Cholesky 加速) |
| 适用场景 | 候选大、要求轻量可解释、快速上线 | 候选中等、对多样性质量要求高 |
💡 Key Insight: 两者的目标形态相同(相关性 + 多样性的权衡),但实现哲学不同:MMR 是「人写规则、贪心执行」的启发式;DPP 是「用行列式几何严格定义多样性」的概率框架。当你的多样性需求只是「别太重复」时,MMR 足够;当你要精确控制集合级多样性(如展览选品、信息流去重)时,DPP 更靠谱。
🧠 Mental Model: 拼图 vs 装箱
MMR 像「每次挑一块和已拼部分差异最大的拼图」——只看新块和现有边界的咬合,是个局部 heuristics。DPP 像「先量好整盒拼图能拼出的总体积再决定留哪几块」——它同时考量所有块之间的相互遮挡,是从集合整体出发的全局衡量。
⚠️ Common Mistakes in 4.1
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把重排当排序的重复 | 「重排再算一遍 CTR 不就行了」 | 排序求单点精度,重排求列表级体验,目标不同 | 重排目标是相关性×多样性的帕累托最优 |
| 2 | 设错方向 | 想要多样性却设 | 退化为纯相关性,无多样性 | 要多样性就调低 (如 0.3~0.7) |
| 3 | 以为 MMR 能捕获高阶冗余 | 认为 MMR 已处理「三相似物品」 | MMR 只用 ,只看最相似的一个 | 高阶冗余交给 DPP 的行列式 |
| 4 | 忽略相似度质量 | 直接用未归一化特征算 Sim | 相似度不在 [0,1] 会破坏 DPP 半正定与 MMR 惩罚尺度 | 先归一化/用余弦相似度 |
| 5 | DPP 核矩阵忘记乘相关性 | 只用相似度矩阵 当 | 丢失相关性项,选出「很不同但不相关」的垃圾 | 必须 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 列表同质化 | 排序逐点最优→头部雷同,损害体验与生态 | 重排存在的根本动机 |
| MMR | ,贪心挑选 | 最轻量、可解释的多样性重排 |
| 滑动窗口 | 只惩罚最近 个已选项 | 长列表降成本,工业常用 |
| DPP 行列式 | 体积;越大越正交越多样 | 用几何严格度量集合多样性 |
| 核矩阵 | 融合相关性+多样性 | 把两目标统一进一个矩阵 |
| Cholesky 加速 | 选 | 让 DPP 实时可行 |
| MMR vs DPP | 逐对近似 vs 集合级精确 | 决定方法选型 |
❓ FAQ
Q1: 重排必须放在排序之后吗?能不能只做重排?
A: 重排的输入是「已带相关性分数的候选列表」,所以它天然依赖排序(或召回)先产出候选。只做重排而跳过排序,等于在没有质量排序的池子里硬挑,效果有限。
Q2: 是不是「相关与多样各一半」的最优解?
A: 不一定。最优 取决于业务:内容社区可能偏多样性(更低 ),电商搜推可能偏相关(更高 )。需用线上指标(多样性指标 + 留存/时长)反搜。
Q3: DPP 的行列式一定比 MMR 结果好?
A: 在「需要精确集合级多样性」时 DPP 更优;但 MMR 更轻量、可解释、易调参。小候选、快速上线场景 MMR 往往性价比更高。没有绝对胜负,看约束。
前后关联
- 4.2 (个性化重排)跳出「人设目标函数」,用 PRM/PRS 让模型从数据端到端学列表最优。
- 3.x (排序)提供 MMR/DPP 所需的精排相关性分数 与候选。
- Part 5 趋势 (去偏/冷启动)多样性重排是缓解「头部集中、长尾沉没」的直接手段。
- 生成式推荐(下篇) 把重排融进端到端序列生成,MMR/DPP 的启发式目标被可学习目标替代。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 4.1.1 — 识别重排动机 🟢 Easy
某短视频 App 的精排输出前 5 条全部是「同一搞笑博主的同类段子」,用户刷完 2 条就划走。请指出这反映了重排环节要解决的哪类问题,并各举一条对应的代价。
💡 Solution (click to reveal)
Approach: 用 4.1.0 的「同质化」框架归因。
- 反映的问题: 排序输出同质化——精排逐点最优化导致头部内容高度相似。
- 两条代价:
- 用户体验恶化 :审美疲劳、兴趣衰减,用户早早划走(对应题干「刷完 2 条就划走」)。
- 系统效率损失 :长尾/其他博主内容曝光不足,生态多样性下降。
Key points:
- 重排存在的根本动机就是打破这种「相关但雷同」。
- 诊断时先分清是「精度不够」还是「体验单一」,后者才归重排管。
Problem 4.1.2 — 手算 MMR 🟡 Medium
给定 4 个候选物品及其 Rel 与相似度矩阵(仅上三角需关注,对称):
| 商品 | Rel | A | B | C | D |
|---|---|---|---|---|---|
| A | 0.9 | 1.0 | 0.1 | 0.8 | 0.2 |
| B | 0.8 | 0.1 | 1.0 | 0.3 | 0.6 |
| C | 0.7 | 0.8 | 0.3 | 1.0 | 0.4 |
| D | 0.6 | 0.2 | 0.6 | 0.4 | 1.0 |
取 ,用 MMR 贪心选出 top-3 列表(列出每轮各候选的 值与所选物品)。
💡 Solution (click to reveal)
Approach: 套公式 ,。
- 轮 1(S=∅,惩罚项=0): A: ;B: ;C: ;D: 。选 A(0.54),S={A}。
- 轮 2(S={A}): B: ;C: ;D: 。选 B(0.44),S={A,B}。
- 轮 3(S={A,B}): C: ;D: 。选 D(0.12)。
最终 top-3: [A, B, D]。注意 C 因与 A 高度相似(0.8)被大幅惩罚,体现了 MMR 的多样性避撞。
Key points:
- 每轮只需与「已选集合」算 max 相似度。
- 高相关但撞车的物品(C)会被压低,这正是多样性生效的标志。
Problem 4.1.3 — 核矩阵构建 🟡 Medium
3 个物品相关性 ,相似度矩阵 。请写出 DPP 核矩阵 的结果,并指出 的值与含义。
💡 Solution (click to reveal)
Approach: 逐元素 。
- 。
- 含义:物品 2 与物品 3 之间的「联合影响力」= 二者相关性之积 × 相似度,融合了相关性与多样性信息。
Key points:
- 对角 纯由相关性决定(初始选种依据)。
- 非对角同时编码「像不像」和「各自有多相关」。
🏆 Challenge: 设计一个选型论证 🔴 Hard
某信息流产品有 200 个精排候选,要求重排延迟 < 20ms,业务方强调「绝不能出现连续 3 条同作者」。请写一段论证:应优先采用 MMR(可加「同作者惩罚」规则)还是 DPP?说明你的取舍与必要的工程改造。
💡 Hint
从延迟、可控性、多样性语义三方面权衡:200 候选 + <20ms 下 DPP 核矩阵与 Cholesky 仍可行但偏重;「禁连续 3 条同作者」是 硬业务约束 ,MMR 易加规则(在相似度或惩罚项里注入作者维度的强惩罚),DPP 需把约束编码进核矩阵较麻烦。结论通常倾向 MMR + 业务规则,或 DPP 配合后处理约束。论证要点:可解释性、延迟、约束可表达性。
个性化重排
📝 Before You Continue: 请先读完 4.1 的贪心重排。本章建立在「重排要兼顾相关性与多样性」的共识上,但把手段从「人设目标函数」升级为「模型从数据端到端学习」。
上一节我们探讨了基于贪心策略的重排序方法。它们通过显式定义多样性、相关性或覆盖度的优化目标,在初始排序列表上做局部调整——计算效率高、可解释性强。但它们在处理 复杂的物品间相互影响 和 深度个性化 时存在局限:
- 目标函数往往需要 手工设计 ,难以捕捉高阶、非线性的交互模式;
- 把 用户个性化信息 深度融入列表级优化也颇具挑战。
本章介绍两个经典的个性化重排模型: PRM(Personalized Re-Ranking Model) 与 PRS(Permutation Retrieve System) ,看模型如何替我们「学会」最优列表。
读完本章,你将能够:
- 解释 PRM 为何标志着重排从规则/启发式走向数据驱动、端到端学习
- 描述 PRM 的输入层、编码层(Transformer)、输出层与 个性化向量 PV 的生成方式
- 写出 自注意力公式,并说明 Softmax 在 PRM 输出层如何隐式建模物品间相对关系
- 理解 排列变异影响(Permutation-Variant Influence),以及 PRS 为何要直接优化排列
- 描述 PRS 的两阶段解法:PMatch(FPSA 候选生成)与 PRank(DPWN 排列评估)
- 完成 4 道分层练习题,巩固 PRM/PRS 的核心机制
4.2.0 从规则到学习:为何需要个性化重排
贪心重排(MMR/DPP)的多样性目标是「通用」的——它对所有用户用同一套相似度与权重。但真实推荐里, 同一个列表对不同用户的最优排列是不同的 :有人爱先看深度长文、有人偏爱短视频;有人对价格敏感、有人不在乎。
这就是「个性化重排」的立身之本: 把用户独有的偏好信号,深度融入整张列表的优化过程。它不再依赖预设的多样性公式,而是让模型直接从海量行为数据中学习「哪些物品组合、以何种顺序,对这个用户最好」。
💡 Key Insight: 规则法问「怎样的一份列表总体更优」;个性化重排问「对这个用户,怎样的一份列表更优」。前者是人群平均,后者是千人千面。
🧠 Mental Model: playlist DJ
把贪心重排想成「通用歌单生成器」——它只保证曲风不重复。把 PRM 想成「懂你的 DJ」——他知道你今晚想先听慢歌再听嗨歌,于是把顺序也排好了。模型学的不是「歌单该长什么样」,而是「你的歌单该长什么样」。
4.2.1 Transformer 个性化重排模型(PRM)
PRM(Personalized Re-Ranking Model) 的提出,标志着重排序技术从基于规则/启发式,向数据驱动、端到端学习的重要转变。其核心思想是: 利用 Transformer 强大的序列建模能力,自动学习列表中物品间复杂的相互影响,并把细粒度的用户个性化信息深度融入整个重排序过程 ,通过最大化列表级效用目标(如点击率)进行全局优化。
PRM 的整体架构可分为三层:输入层、编码层、输出层。
输入层:融合个性化与位置
输入层的核心任务,是为初始列表 中每个物品 准备一个信息丰富的初始表示,需包含两个关键方面:
- 物品自身特征() :物品 ID 嵌入、类别、标签、统计特征等基础信息。
- 用户对该物品的个性化偏好() :编码用户 与物品 的互动关系与偏好程度,是 PRM 实现个性化的关键,后面详述。
PRM 将物品原始特征向量 与个性化向量 拼接(Concatenate) ,形成更全面的基础表示 。此外,初始列表本身包含潜在序列信息(排名靠前的物品可能更相关),因此引入可学习的 位置嵌入(PE) ,为每个位置赋予向量。最终输入表示为:
这一组合通常再经一个简单前馈网络做维度调整,以适配 Transformer 编码器输入。
编码层:Transformer 建模物品相互影响
输入层提供了带个性化与位置信息的物品序列。编码层的核心目标,是利用 Transformer 的序列建模能力 ,使列表中的所有物品相互关联,捕捉它们之间复杂的、高阶的相互影响。这一点对重排至关重要,因为:
- 用户是否点击第 个物品,很可能受第 个(甚至更远)物品的显著影响(替代品、互补品、或提供多样性);
- 这种影响往往是 长距离 的,不受物品初始物理位置限制。
Transformer 的核心机制是 自注意力(Self-Attention) :序列中每个物品可关注所有其他物品(含自己),通过计算查询向量 与其他物品键向量 的相似度得到注意力权重,决定聚合多少来自其他物品的 信息:
PRM 采用 多头注意力 ,组织在标准 Transformer 编码器块(含多头自注意力 + 前馈网络)中,并堆叠多层,逐层提炼更高阶的物品间依赖。最终输出每个物品的高级表示 ,融合了物品特征、用户个性化偏好与整列表上下文交互信息。
Analysis: 相对 MMR/DPP 的「两两相似度」,PRM 的自注意力能建模任意高阶、非线性的物品间依赖,且天然融入用户信号。代价是需要训练数据、推理成本高于规则法,且注意力权重不如 MMR 公式直观——可解释性下降。适合数据充足、对个性化收益敏感的核心场景。
输出层:Softmax 列表级打分
PRM 对每个物品的高级表示 施加线性变换(),映射为标量分数(logit),再输入 Softmax :
Softmax 在此扮演两个关键角色:
- 归一化 :将所有分数转为概率分布,所有物品概率之和为 1;
- 隐含相对关系建模 :每个物品的最终概率不仅取决于自身分数,也取决于它与列表中所有其他物品分数的相对比较——这天然契合重排序需评估物品间相对重要性的需求。
个性化向量(PV)的生成
回顾整个流程, PV 是 PRM 区别于普通重排、实现真正「个性化」的关键。PV 从何而来?PRM 采用了一个巧妙且实用的策略: 利用预训练的点击率预估模型来生成 PV。
- 预训练模型的作用 :在海量用户历史行为数据上训练,学习预测给定用户 及其行为历史 ,用户点击候选物品 的概率 。
- 提取个性化向量 :PRM 不直接使用 预训练模型预测的点击概率本身,而是提取该模型在输出最终点击概率(通常经 Sigmoid) 之前的那个隐藏层激活值。该向量蕴含了「用户 对物品 偏好程度」的丰富抽象信息,作为物品 相对用户 的个性化向量 。
- 输入 PRM :对初始列表每个物品 都通过上述预训练模型算出 ,作为关键输入送入 PRM 输入层。
核心代码(节选):
# 用户侧 Embedding -> [B, max_len, D],使每个位置都携带同一用户上下文
user_part_embedding = tf.tile(tf.expand_dims(user_part_embedding, axis=1),
[1, max_seq_len, 1])
# 页面级序列表示:用户 + 物品特征 + PV + Item Embedding 拼接
page_embedding = concat_func(
[user_part_embedding, item_part_embedding, pv_embeddings, item_embeddings],
axis=-1) # ← KEY LINE: 融合四类信号
# 位置编码相加,形成 Transformer 最终输入
enc_inputs = add_func([page_embedding, position_embedding]) # ← KEY LINE: 注入位置信息
# Transformer 编码层堆叠
for _ in range(transformer_blocks):
enc_inputs = TransformerEncoder(
intermediate_dim, nums_head, dropout_rate,
activation="relu", normalize_first=True, is_residual=True)(enc_inputs)
# 打分头:每个位置映射成一个概率
enc_output = tf.keras.layers.Dense(intermediate_dim, activation='tanh')(enc_inputs)
enc_output = tf.keras.layers.Dense(1)(enc_output)
score_output = tf.keras.layers.Activation(activation='softmax')(
tf.keras.layers.Flatten()(enc_output)) # ← KEY LINE: 列表级相对打分
源码实验显示,PRM 相比基线在 map@5 等指标上带来稳定提升,验证了端到端个性化重排的有效性。
下面用交互演示直观感受 PRM 如何以 Transformer 逐步「读」完整列表、再为每个位置输出重排后的相对概率:
点击「下一步」观察:初始列表如何带上 PV 与位置嵌入进入编码器,自注意力如何在各层逐步聚合跨物品信息,最后 Softmax 如何把分数转为重排后的相对概率。
4.2.2 基于排列组合的重排模型(PRS)
虽然 PRM 通过 Transformer 实现了端到端个性化重排,但它仍有一个根本性局限: 缺乏对排列组合影响的深度理解。
想象一个场景:用户面对列表 [A, B, C] 时毫无购买欲望,但看到 [B, A, C] 这个排列时却买了 A。这种现象被称为 排列变异影响(Permutation-Variant Influence)——一种可能的解释是:把价格较高的 B 放在前面,会让用户觉得 A 相对便宜,从而激发购买欲。
传统重排(含 PRM)主要关注 单个物品的分数优化 ,却忽略了 物品排列顺序本身 对用户行为的影响 。PRS 的设计思路是:评估所有可能的物品排列组合,选择用户体验最佳的那一个。但 个物品的排列有 种,计算上不可行,因此 PRS 提出 两阶段**解法:
- PMatch 阶段 :通过搜索算法快速筛选少数候选排列;
- PRank 阶段 :用神经网络模型评估这些候选排列的质量,选出最优解。
PRS 整体框架
PMatch 阶段:候选排列生成(FPSA)
PMatch(Permutation-Matching)的目标,是从指数级排列空间中高效识别候选排列。它采用 FPSA(Fast Permutation Searching Algorithm) ,结合 beam search 与两个用户行为预测模型。
离线训练:双模型预测体系
- CTR 模型 :预测用户点击某物品的概率
- Next 模型 :预测用户浏览完当前物品后继续浏览下一个的概率
两者均用标准 point-wise 建模(Sigmoid 激活 + 交叉熵损失):
Next 模型反映了用户浏览的 连续性 :物品不仅要能吸引点击,还要能引导用户继续浏览后续内容。
在线服务:FPSA 算法
FPSA 把用户浏览行为建模为 序列决策过程——物品在序列中的价值不仅取决于自身特征,更取决于它在整个浏览路径中的作用。其核心是一个 beam search 逐步构建候选排列,每步基于奖励函数剪枝。奖励融合两个指标:
- rPV(Page View Reward) :衡量排列能带来的总浏览深度,鼓励能引导深度浏览的组合;
- rIPV(Item Page View Reward) :衡量排列中物品被点击的总概率,确保商业价值。
FPSA 核心代码(节选):
def fpsa_algorithm(items, ctr_scores, next_scores, beam_size=5, max_length=10,
alpha=0.5, beta=0.5):
"""Fast Permutation Searching Algorithm(Beam Search 生成候选排列)。"""
S = [()] # 候选排列集合,初始为「空序列」
for i in range(1, max_length + 1):
St = S.copy()
S, R = [], {}
for O in St:
for ci in items:
if ci not in O:
Ot = O + (ci,) # 把未出现物品 ci 追加到尾部
r = calculate_estimated_reward(Ot, ctr_scores, next_scores, alpha, beta)
R[Ot], S.append(Ot) = r, Ot
# Beam Search 截断:按奖励保留前 beam_size 个
S = sorted(S, key=lambda x: R[x], reverse=True)[:beam_size] # ← KEY LINE
return S
def calculate_estimated_reward(O, ctr_scores, next_scores, alpha, beta):
r_pv, r_ipv, p_expose = 1.0, 0.0, 1.0
for ci in O:
p_ctr, p_next = ctr_scores[ci], next_scores[ci]
r_ipv += p_expose * p_ctr # 累加期望点击
p_expose *= p_next # 曝光链概率随位置递减
r_pv = p_expose # 浏览到末尾的概率
return alpha * r_pv + beta * r_ipv # 线性融合 PV 与 IPV
Analysis: FPSA 用 beam search 把 降到可控的候选集,是工程上「组合爆炸」的务实解法。但它依赖 CTR/Next 两个 point-wise 模型的精度,且奖励为线性融合,可能漏掉非线性的排列收益。
PRank 阶段:排列评估(DPWN)
PRank(Permutation-Ranking)接收 PMatch 生成的候选排列,用神经网络 DPWN(Deep Permutation-Wise Network) 评估每个排列质量。
DPWN 的设计理念:排列中每个物品的价值不仅取决于自身特征,更取决于它在 整个序列上下文中的位置和作用。为此采用 Bi-LSTM 架构:
- 序列编码层 :双向 LSTM 计算第 个物品的上下文表示:
- 特征融合层 :,融合序列表示与用户/物品特征。
- 预测层 :通过 MLP 预测每个位置点击概率 。
List Reward(LR) 是 PRank 的核心评估指标,定义为排列中所有物品预测点击概率之和:
在线服务时,PRank 计算每个候选排列的 LR,选择 LR 最高的排列作为最终输出。
💡 Key Insight: PRS 与 PRM 的根本分野在于——PRM 优化「每个物品的相对分数」,默认位置由分数决定;PRS 直接优化「排列顺序本身带来的体验收益**(LR)」,把顺序当作一等公民。前者重「选哪些」,后者重「怎么排」。
🧠 Mental Model: 货架陈列 vs 单品定价
PRM 像一位给每件商品定价的经理——他尽量让每件都标得准,但货架顺序只是按价格排。PRS 像一位讲究陈列的店长——他清楚「把贵的最终季款放前面,能让中间的平价款显得划算」,于是为整组商品的摆放顺序单独做优化。
⚠️ Common Mistakes in 4.2
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为 PRM 自带个性化 | 「PRM 输入只有物品特征也能个性化」 | 个性化来自 PV,PV 缺失则退化为普通重排 | 必须接入预训练 CTR 模型的隐藏层作 PV |
| 2 | 混淆 PRM 与排序模型 | 「PRM 就是个 CTR 预估」 | PRM 优化列表级相对关系,排序是逐点 | 记住 PRM 输出是 Softmax 相对概率 |
| 3 | 忽视排列变异影响 | 「[A,B,C] 和 [B,A,C] 效果一样」 | 顺序会改变用户相对价格/偏好感知 | PRS 类方法才把顺序当优化目标 |
| 4 | 低估 组合爆炸 | 「直接枚举所有排列选最优」 | 10! ≈ 360万,20! 不可算 | 用 PMatch 的 beam search 截候选 |
| 5 | 把 PRS 当单阶段 | 「PRank 直接搜排列」 | 无 PMatch 候选生成,PRank 无从评估 | 两阶段缺一不可 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 个性化重排动机 | 规则法对所有人同目标,缺乏千人千面 | 把用户偏好深度融入列表优化 |
| PRM 输入层 | ,融合四类信号 | PV 是个性化核心 |
| PRM 编码层 | Transformer 多头自注意力建模高阶相互影响 | 捕捉跨物品、长距离依赖 |
| PRM 输出层 | Softmax → 列表级相对概率 | 隐式建模物品间相对重要性 |
| PV 生成 | 取预训练 CTR 模型隐藏层激活 | 复用已有排序知识做个性化 |
| 排列变异影响 | 同物品不同序→不同行为 | PRS 存在的动机 |
| PRS 两阶段 | PMatch(FPSA+beam)→PRank(DPWN+LR) | 化解 组合爆炸 |
❓ FAQ
Q1: PRM 和 4.1 的 DPP 能一起用吗?
A: 可以且常见。DPP/MMR 常作为 PRM 的基线或后处理:先用 PRM 学列表级偏好,再用 DPP 做多样性约束兜底。二者互补——一个管个性化、一个管集合多样性。
Q2: PV 为什么取隐藏层而不是最终点击概率?
A: 最终点击概率是被 Sigmoid 压扁的标量,信息高度压缩;隐藏层激活是高维抽象向量,保留了「用户为何偏好该物品」的丰富语义,更适合作为 PRM 的个性化输入。
Q3: PRS 的 beam search 会不会漏掉真正最优排列?
A: 会。beam 只保留奖励前 的局部候选,是近似。但相比 全枚举,这是工程上必要的trade-off;实践中配合好的奖励函数,top 候选已足够优质。
前后关联
- 4.1 (贪心重排)是 PRM/PRS 的对照基线——规则法轻量,个性化法表达力强。
- Part 3 排序 提供 PRM 所需的预训练 CTR 模型与精排分数,是 PV 的来源。
- Part 5 趋势 (生成式范式)将「列表生成」进一步端到端化,PRS 的排列优化思想在生成式架构中以自回归方式自然涌现。
- 下篇生成式推荐 用单一序列模型替代「召回→排序→重排」级联,重排的目标被直接编进生成目标。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 4.2.1 — 区分两类重排 🟢 Easy
判断下列描述更接近 (a) 贪心重排(MMR/DPP) 还是 (b) 个性化重排(PRM/PRS) ,并说明理由:
- (i) 系统对每个用户都用同一套相似度矩阵与固定 做重排。
- (ii) 系统为每位用户提取预训练 CTR 模型的隐藏层向量,作为重排输入。
💡 Solution (click to reveal)
Approach: 抓住「是否融入用户个性化、是否数据驱动」。
- (i) 贪心重排 :固定相似度与 对所有用户一致,不带个性化,属规则/启发式。
- (ii) 个性化重排(PRM) :从预训练 CTR 模型取隐藏层作 PV,是 PRM 的标志性做法,深度融入用户偏好。
Key points:
- 有无「按用户定制的个性化信号」是两类方法的本质分水岭。
- PV 的存在 ≈ PRM;固定目标函数 ≈ 贪心法。
Problem 4.2.2 — PRM 输入表示 🟢 Easy
PRM 中某物品 的最终输入表示 由哪些部分相加/拼接而成?写出公式并说明每一项解决什么问题。
💡 Solution (click to reveal)
Approach: 回忆 4.2.1 输入层。
公式:
- 拼接 :融合「物品是什么」与「用户多偏好它」(个性化),解决「千人千面」问题;
- 位置嵌入 :注入列表中的位置信息,解决「Transformer 本身不含顺序」的问题。
Key points:
- 拼接(concat)用于融合不同来源特征,相加用于注入位置。
- 三者缺一不可:无 PV 则无个性化,无 PE 则无序感。
Problem 4.2.3 — 排列变异影响分析 🟡 Medium
某电商列表有物品 [A(贵), B(平价), C(平价)]。产品经理发现把 [A, B, C] 改成 [B, A, C] 后,A 的点击率明显上升。请用「排列变异影响」解释这一现象,并指出该现象对重排方法选型的启示。
💡 Solution (click to reveal)
Approach: 用 4.2.2 的排列变异影响框架。
- 解释 :A 是贵价品。当 A 排在第一([A,B,C])时,用户先看到高价,阈值被抬高;改成 [B,A,C] 后,用户先看平价 B,再看到 A 时产生「相对便宜」的错觉,购买欲被激发——即 顺序改变了用户对价值的相对感知 ,这就是排列变异影响。
- 启示 :传统逐点打分(含 PRM 的分数优化)默认「顺序不影响单品价值」,会漏掉这种收益。需要像 PRS 那样把「排列顺序」本身作为优化目标(用 LR 评估整列收益),才能捕捉顺序带来的体验增益。
Key points:
- 排列变异影响 = 同物品、不同序 → 不同行为。
- 它指向「顺序是一等优化目标」的方法(PRS),而非仅优化单品分数的方法。
🏆 Challenge: 设计一个混合重排方案 🔴 Hard
某信息流产品希望同时获得「个性化」(PRM 所长)与「强集合多样性」(DPP 所长),并控制推理延迟。请写一段方案论证:如何将 PRM 与 DPP 结合(顺序/并联/级联),并指出每种子方案的一个风险点与缓解手段(150 字内)。
💡 Hint
常见三种结合:(1) 级联——PRM 出分后 DPP 做多样性后处理,风险是 DPP 可能破坏 PRM 学到的个性化顺序,缓解用软约束;(2) 并联——两路打分加权融合,风险是权重难调,缓解用离线网格搜索;(3) DPP 核矩阵注入 PV——把 PRM 的 PV 编码进 ,风险是核矩阵需重算,缓解用增量更新。论证聚焦一种即可。
前三篇带你走完了判别式推荐的完整工业链路——召回、排序、重排。但真实的推荐系统远不止「把候选排好序」这么简单。它还要面对 有偏的数据、没有历史的物品与用户 ,以及一场正在发生的 范式跃迁 :从「给每个候选打分」走向「直接生成推荐序列」。
本部分不再新增某个独立算法模块,而是把镜头拉高,看清楚工业界与学术界在 修正、补全、重塑 推荐系统时的三种思路。
本章涵盖
| 章节 | Topic | The Big Idea |
|---|---|---|
| 5.1 | 模型去偏 | 数据天然有偏且存在反馈闭环,用 IPS 加权与 PAL 解耦位置来矫正 |
| 5.2 | 冷启动 | 用内容/元学习/分群架构,为没有历史的物品与用户生成有效表示 |
| 5.3 | 生成式范式演进 | 从判别式打分到生成式序列生成,串起记忆·泛化 → 理解·推理的跃迁 |
What You'll Be Able to Do After This Part
- 🟢 解释 推荐系统数据偏差的来源(选择/曝光/从众/位置)与结果偏差(流行度/不公平)如何经反馈闭环被放大
- 🟢 应用 逆倾向得分(IPS)重新加权,并用 PAL 在结构上解耦位置效应与用户偏好
- 🟡 辨析 内容冷启动(CB2CF / MetaEmbedding)与用户冷启动(MeLU / POSO)的不同解法
- 🟡 描述 生成式推荐的三大演进路径:生成式召回(HSTU / TIGER)、生成式排序(GenRank / MTGR)、端到端统一生成(OneRec)
- 🔴 对照 Part 1 的两种范式,论证判别式级联架构如何被生成式端到端架构替代
核心概念
| Concept | 章节 | Relevance |
|---|---|---|
| 选择偏差 / 曝光偏差 / 位置偏差 | 5.1 | 训练数据不可信的根源,需主动纠偏 |
| 逆倾向得分 IPS | 5.1 | 用 加权,得到无偏风险估计 |
| 位置感知学习 PAL | 5.1 | 把「看到」与「喜欢」在结构上分离 |
| 内容冷启动 CB2CF / MetaEmbedding | 5.2 | 让新物品借内容获得协同表示 |
| 用户冷启动 MeLU / POSO | 5.2 | 用元学习或分群子模块服务新用户 |
| 语义 ID / 端到端生成 | 5.3 | 生成式推荐的核心:理解内容、直接生成 |
前置知识
- 已读完 Part 1 的两种范式与三阶段漏斗
- 了解 Part 2 召回与 Part 3 排序的基本模型(协同过滤、双塔、矩阵分解)
- 具备基础的深度学习与序列模型概念(Transformer 自注意力、元学习 MAML 会有助于 5.2/5.3 理解)
本部分是基础篇的「承上启下」收尾——它既修补前文流水线的缺陷,又指向后续版本的生成式下篇。
Tips for This Part
- 把偏差当成「看不见的对手」。 读到 5.1 时,时刻问:这个训练样本,真的代表用户的真实偏好吗?
- 冷启动的核心是「借力」。 新物品没有行为,就借内容;新用户没有历史,就借元知识或人群结构。
- 5.3 要回头呼应 Part 1。 它把「判别式 vs 生成式」从概念落到了具体模型(HSTU、TIGER、OneRec)。
Let's dive in! 🚀
模型去偏
📝 Before You Continue: 请先读完 1.1 的两种范式与三阶段漏斗,以及 Part 3 排序 的打分函数 。本章要在这些「理想假设」上加一层现实校正:你用来训练模型的数据,本身并不干净。
当你准备用海量交互数据训练一个推荐模型时,有一个温柔却致命的错觉: 「数据越多,模型越准」。真实推荐系统的数据来自用户在产品里的自由行为,而不是实验室的受控实验。用户的点击、评分、停留,都受到系统自己怎么展示、用户自己什么习惯、物品本身多热门等无数因素的影响。
更微妙的是,推荐系统存在一个 反馈闭环 :今天的推荐决定用户明天看到什么,用户明天的点击又变成后天训练模型的样本。这个环一旦转起来,初始的一点点偏差会被像滚雪球一样不断放大。本章就带你认识这些偏差,并给出两套经得起因果推断检验的纠偏工具——IPS 与 PAL。
读完本章,你将能够:
- 区分 数据偏差(选择/曝光/从众/位置)与结果偏差(流行度/不公平)两类来源
- 解释 反馈闭环如何把微小偏差放大成「推荐单一化」的马太效应
- 写出IPS 估计量,说清它为什么是真实风险的无偏估计,以及权重爆炸时如何截断
- 用 PAL 的双模块架构,在结构上把「看到」与「喜欢」解耦
- 完成 4 道分层练习题,巩固纠偏的数学与工程直觉
5.1.0 数据天生有偏:反馈闭环的陷阱
要理解偏差,先要接受一个事实: 我们观测到的交互,不等于用户的真实偏好。实验室里你可以随机给用户展示任意物品并记录反应,但工业系统里,用户只能看到系统「选择」展示给他的那部分内容。
推荐系统的偏差按产生阶段可分成两大类:
- 数据偏差 :发生在 数据收集阶段 ,是后续一切问题的根。模型看到的就是「被系统筛选过的世界」。
- 结果偏差 :体现在 推荐结果 里,是数据偏差经过模型训练后「加工并放大」的产物。
两者之间并非孤立,而是通过反馈闭环互相喂养。热门物品被推荐得多 → 获得更多交互 → 在下一轮训练数据中占比更大 → 模型更偏向它。这就是「富者愈富」的马太效应。
上图把「数据偏差 → 结果偏差 → 反馈闭环」串成一条链:有偏模型既是偏差的产物,又反过来生产更偏的数据。
💡 Key Insight: 偏看到的不等于偏好的。纠偏的本质,不是「多喂数据」,而是重新理解数据背后的生成机制——这正是 IPS 与 PAL 共同的出发点。
5.1.1 数据偏差:收集阶段埋下的种子
数据偏差有四种典型面孔,它们分别来自用户习惯、系统曝光策略与社会心理。
选择偏差(Selection Bias) 出现在显式反馈(评分)场景。用户倾向于只给 自己感兴趣 的内容打分,于是我们观测到的评分并不能代表他对所有物品的真实态度。大量中性或负面的潜在评分根本没被记录——研究称之为 非随机缺失(MNAR, Missing Not At Random)。它会让模型 高估用户的整体满意度。
曝光偏差(Exposure Bias) 是隐式反馈(点击/观看)的核心挑战。用户只能看到系统推荐给他的物品;那些没交互的物品有两种可能:要么真不感兴趣(真负样本),要么 压根没见过 (潜在正样本)。若朴素地把所有「没交互」都当负样本,模型就会学到错误的偏好——长尾物品受害最深,因为它们本就缺乏曝光机会。
从众偏差(Conformity Bias) 来自社会心理学的群体效应。当用户看到某商品海量好评,常常为了寻求群体认同而附和给出正面评价;反之亦然。于是收集到的反馈未必是用户独立、真实的偏好,而是被舆论热度污染过的表达。
位置偏差(Position Bias) 在列表推荐中格外明显。用户天然更关注排在 前面 的物品,无论相关性如何。数据显示点击率随位置下降而急剧衰减——「点击」这件事,既反映偏好,也强烈受位置摆布。
🧠 Mental Model: 带滤镜的望远镜
把训练数据想成一台自带滤镜的望远镜。你透过它观察宇宙(用户真实偏好),但滤镜只让「系统展示过的、用户凑巧点了的、位置靠前的、大家都说好的」那部分光线通过。你看到的星图越密,不代表那片天区星星真的越多——可能只是滤镜偏差。纠偏,就是给望远镜校准滤镜。
Analysis: 这四类偏差并非都需要同样处理。选择/曝光偏差本质是「观测概率不均」,适合用 IPS 加权在损失层面补偿;位置偏差则有清晰的结构——它只影响「看没看到」,所以用 PAL 在架构层面解耦更干净。先判断偏差类型,再选工具。
5.1.2 结果偏差:模型把偏差「学」了进去
当上述有偏数据流经模型,偏差不会消失,反而常常被强化并体现在结果里。
流行度偏差(Popularity Bias) 是最常见的结果偏差。热门物品贡献了训练数据里绝大多数交互,模型学到「推热门就能拿点击」的惯性,结果推荐频率甚至 超过物品本身的流行度。这既稀释了个性化,也让长尾物品彻底失去被发现的机会。
不公平性(Unfairness) 指系统对某些用户群体或物品类别产生 系统性歧视。若历史数据里某群体长期拿到劣质推荐,模型会学习并延续这种偏见,在未来的推荐中持续不公。
⚠️ Warning: 流行度偏差与反馈闭环是「共生」的。热门物品因曝光多而交互多,在下一轮数据里占比更大,进一步推高流行度偏差——除非在模型或训练环节主动切断这条链,否则它会持续恶化到推荐极度单一化。
5.1.3 用逆倾向得分(IPS)纠正选择偏差
逆倾向得分(Inverse Propensity Score, IPS) 源自因果推断。它把推荐系统里的「物品展示」看作一种 干预(Intervention) ,通过重新加权来消除选择偏差。
核心思想非常直觉:一个样本如果 本来就很容易被观测到 (比如热门商品、排首位的物品),它在训练中的贡献应当被适当压低;反之,一个样本 很难被观测到、却被用户发现并产生交互(比如长尾商品、低位置物品),那它很可能携带更强的真实偏好信号,应当获得更高权重。
倾向得分(Propensity Score) 是关键概念,定义为用户 与物品 的交互被观测到的概率 。IPS 的核心操作就是用它的 倒数 作权重,实现「逆向加权」:高倾向得分 → 低权重,低倾向得分 → 高权重。
一个具体例子
考虑一个电影推荐系统,有两类用户:恐怖片爱好者与爱情片爱好者。恐怖片爱好者 很少 主动给爱情片评分(观测概率 ),但偶尔评了往往给真实低分(1–2 分);他们 频繁 给恐怖片评分()并给高分(4–5 分)。
若用朴素方法直接统计观测数据,会发现恐怖片平均评分远高于爱情片,误导模型高估两类电影的偏好差距。但用 IPS 加权后:罕见的「恐怖迷给爱情片低分」获得 倍权重,常见的「恐怖迷给恐怖片高分」只获 倍权重——模型便能更准确地还原真实偏好分布。
右侧 IPS 加权把「来之不易」的少数低分样本放大,把「唾手可得」的高分样本压低,最终逼近真实差距。
🧠 Mental Model: 给稀有样本发「加权券」
想象你在做民意调查,但只有爱说话的人愿意接受采访,沉默者极少发声。若直接按采访人数统计,沉默群体的意见就被淹没了。IPS 相当于给每一位沉默受访者的发言发一张 10 倍权重的「加权券」——让他们的声音按真实人口比例被听见。
IPS 的数学原理
传统评估方法直接在观测数据上计算平均损失:
其中 是观测数据集, 是真实评分, 是预测评分, 是损失或评价指标。当选择偏差存在时,——朴素估计量 有偏。
IPS 估计量引入倾向得分加权:
可以证明它是真实风险的无偏估计:。
IPS 不仅能用于评估,也能直接用于训练。矩阵分解的传统目标:
加入 IPS 权重后只是把每个样本的损失乘上 :
改动极小,却可无缝集成进现有优化器。
⚠️ Warning: 当某些样本倾向得分极小(如 ),其倒数会大到 倍,导致估计方差爆炸、训练不稳定。工程上通常对权重做截断(clipping)或归一化来缓解——在「无偏」与「低方差」之间取折中。
倾向得分怎么来:估计而非已知
IPS 的关键挑战是倾向得分通常未知,需额外模型估计。朴素贝叶斯方法 假设观测概率只与评分值相关(如 5 分被观测到的概率远高于 1 分); 逻辑回归方法 则利用用户/物品特征建立「是否被观测」的分类模型,捕捉更复杂的观测模式,估计更准。
如何验证纠偏真的有效:半合成实验
一个经典做法是 半合成实验 ,既保留真实数据的复杂性,又允许我们控制偏差严重程度:
- 构建真实评分矩阵 :用 MovieLens 100K(94.4 万条评分,但矩阵仅 6% 有值),以矩阵分解补全为完整 作为 ground truth。
- 设计偏差模型 :对评分为 的用户-物品对,若 观测概率为 (基础概率);若 则为 (递减)。 无偏差, 越小偏差越重; 调至总体观测率约 5% 模拟稀疏。
- 生成有偏观测数据 :按概率随机决定是否观测,得到含偏训练集。
- 比较估计量 :真实 MAE 在 上计算;朴素估计量直接在观测数据上算平均误差;IPS 用 作权重算加权平均误差。
实验显示,当 时,IPS 估计量的误差比朴素估计量 小 2–3 个数量级。这种「已知答案」的测试环境,让不同纠偏方法的效果可被精确量化,成为验证纠偏的标准做法。
下面用交互演示直观感受「朴素 → IPS」的差距还原过程:
点击「下一步」或「自动播放」,观察恐怖片与爱情片的观测均分如何从「朴素掩盖差距」逐步变成「IPS 还原真实差距」。
Analysis: IPS 的优势在简洁与通用——一行权重改动就能嵌入任意推荐模型,且有无偏性的理论保证。但它的代价是方差:权重越极端,训练越抖动,所以生产环境几乎总要配合截断。此外,IPS 只补偿「观测概率不均」类偏差(选择/曝光),对位置偏差这类结构化问题并非最优解——那需要 PAL。
5.1.4 用 PAL 解耦位置偏差与用户偏好
当用户刷手机时,是否会更容易点排在前面的内容?答案是肯定的。位置偏差看似简单,却给系统设计出了道难题:位置在 训练时可知,推理时不可知——线上你没法预先知道一个新候选会被摆在哪个坑位。
位置感知学习(Position-bias Aware Learning, PAL) 的妙处,不是像 IPS 那样重新加权数据,而是 重新设计模型架构 ,把位置影响与真实偏好在结构层面强行分开。
PAL 的关键洞察是:用户点击一个物品,其实包含两个 连续事件——用户先得「看到」它,然后才「决定是否点击」。而位置主要影响的是「看到」的概率,不是「喜欢」的程度。据此把点击概率在数学上分解:
这个分解基于两个合理假设:① 用户看到物品的概率主要由位置决定,与内容关系不大;② 看到之后是否点击,主要由用户偏好决定,与位置关系不大。
双模块架构
基于上述分解,PAL 设计两个模块,在架构层面强制实现这种分离:
- ProbSeen 模块 :只输入 位置 信息,输出该位置被用户看到的概率(如位置 1 可见性 0.9、位置 2 为 0.7、位置 3 为 0.5)。可以用简单查找表,也可以用浅层网络。
- pCTR 模块 :输入用户特征、物品特征、上下文,但 完全不含位置信息 ,用 DeepFM 等复杂深度模型学习真实偏好。
离线训练时,两模块输出相乘得到最终点击率预测:
预测值再与真实标签算损失, 反向传播同时优化两个模块。
训练与推理的分离机制
PAL 的核心技巧在于 训练与推理用不同模块组合 :
- 训练时 :两模块联合优化。模型自动学会分配责任——位置靠前的物品被点击,一部分功劳归位置效应(ProbSeen),一部分归内容质量(pCTR)。这避免了我们需事先知道每个样本「看到概率」的困难。
- 推理时 :只使用 pCTR 模块。由于它在训练时就被设计为不依赖位置,能直接给出 消除位置偏差 的点击率预测。推理时根本不需要为位置特征假设一个值。
💡 Key Insight: PAL 的本质是信息分离——位置相关信息被 ProbSeen 处理,内容相关信息被 pCTR 保留;推理时只取后者,自然得到去偏偏好。它巧妙绕开了「位置推理时不可用」的根本矛盾。
🧠 Mental Model: 把「灯亮」和「菜香」分开
想象餐馆把招牌菜摆在最亮的灯下(位置好),你点了它,可能因为菜真的香,也可能只是因为灯太亮先看见了。PAL 的做法是:用一个专人记录「每个灯位被看见的概率」(ProbSeen),再用另一个专人纯粹评价「菜本身好不好吃」(pCTR)。最后打分时两者相乘;但当你问「这菜到底香不香」时,只问后者——灯的位置不再干扰判断。
Analysis: IPS 与 PAL 代表了两条纠偏路线:通用数据加权(IPS,改损失)vs 专门结构设计(PAL,改架构)。IPS 灵活但受方差困扰、对位置偏差不直接;PAL 精准处理位置、训练推理分离优雅,但只解耦单一偏差源。实践中二者可叠加——先 IPS 补偿观测偏差,再 PAL 处理位置。无论哪种,前提都是先理解偏差的产生机制,而非盲目拟合。
⚠️ Common Mistakes in 5.1
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把「没交互」当「负样本」 | 长尾物品无点击,直接标 0 参与训练 | 没交互可能是没曝光(潜在正样本),朴素标负引入曝光偏差 | 用 IPS/曝光模型校正观测概率 |
| 2 | 以为 IPS 越极端越好 | 不截断权重,小倾向得分样本权重上千倍 | 方差爆炸,训练发散不稳定 | 对权重截断/归一化,平衡无偏与低方差 |
| 3 | 把 PAL 的 pCTR 当普通 CTR | 推理时仍把位置特征塞进 pCTR | pCTR 设计上不含位置,塞位置会重新引入位置偏差 | 推理只用 pCTR,位置留给 ProbSeen |
| 4 | 忽略反馈闭环 | 纠偏一次就以为万事大吉 | 闭环会持续放大残留偏差,单一措施不够 | 多环节(数据+模型)持续纠偏,监控马太效应 |
| 5 | 混淆两类偏差解法 | 用 IPS 处理位置偏差 | IPS 补偿观测不均,对结构化位置偏差不对症 | 位置偏差优先用 PAL 解耦 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 数据偏差 | 选择/曝光/从众/位置,收集阶段产生 | 一切结果偏差的根,需用对工具 |
| 结果偏差 | 流行度/不公平,经模型放大 | 直接伤害个性化与公平性 |
| 反馈闭环 | 推荐→交互→训练 互相喂养 | 不切断会让偏差雪球式恶化 |
| IPS | ,无偏但高方差 | 通用纠偏,需截断稳定 |
| PAL | 分解 | 结构上解耦位置与偏好,推理只用 pCTR |
❓ FAQ
Q1: 既然数据有偏,为什么不干脆多采集无偏数据?
A: 工业环境无法像实验那样随机曝光(会严重伤害用户体验与指标)。只能在「观测到的有偏数据」上做纠偏,IPS/PAL 正是为这种受限场景设计。
Q2: IPS 和 PAL 该用哪个?
A: 偏差来自「观测概率不均」(选择/曝光)优先 IPS;偏差是结构化的位置效应优先 PAL。二者也可叠加,分别处理不同偏差源。
Q3: 为什么 PAL 训练要联合优化两个模块?
A: 因为没人预先知道每个样本的「真实看到概率」和「看到后点击概率」。联合训练让模型自己学会如何在这两件事间分配责任,免去人工标注位置标签。
前后关联
- 5.2 (冷启动)偏差与冷启动常叠加:新物品曝光少,更易被流行度偏差淹没,去偏与冷启动需协同。
- 5.3 (生成式范式)端到端生成用单一模型统一优化,天然弱化级联架构带来的目标不一致偏差。
- Part 3 排序 (Ch3.x)打分函数 是 IPS/PAL 最直接的作用对象——纠偏多在损失或 CTR 模块落地。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 5.1.1 — 偏差分类 🟢 Easy
下面四个场景分别属于「数据偏差」中的哪一类(选择/曝光/从众/位置)?
- (a) 用户只对喜欢的视频打星标,差评从不标记。
- (b) 新上架的小众纪录片几乎没被推荐过,自然没什么播放。
- (c) 某商品有上万条好评,用户跟风给了 5 星。
- (d) 排在第 1 位的普通内容比第 8 位优质内容点击率高 3 倍。
💡 Solution (click to reveal)
Approach: 对照四类数据偏差的定义,看偏差来自「用户习惯 / 系统曝光 / 群体心理 / 列表位置」哪一种。
- (a) 选择偏差 (MNAR):用户只评分感兴趣内容,中性/负面评分未被记录。
- (b) 曝光偏差 :无播放可能源于没被展示(潜在正样本),而非真不感兴趣。
- (c) 从众偏差 :评分被群体热度舆论影响,非独立真实偏好。
- (d) 位置偏差 :点击受排名位置强烈影响,与内容相关性无关。
Key points:
- 先判断偏差「发生在哪个环节」,再归类。
- (b) 与流行度偏差不同:流行度是 结果 ,曝光是 数据收集 阶段的因。
Problem 5.1.2 — 计算 IPS 权重 🟢 Easy
某用户-物品对观测概率 。请写出它在 IPS 下的权重 ,并说明若朴素方法把它当普通样本(权重 1)会怎样。
💡 Solution (click to reveal)
Approach: 直接套用 IPS 权重公式 。
该样本获得 5 倍权重。若朴素方法给权重 1,则这一个「难得被观测到的交互」只按 1 份贡献计算,其携带的强偏好信号被低估——尤其当大多数样本 接近 1 时,这个稀有样本的真实信息几乎被淹没。
Key points:
- 低倾向得分 → 高权重(逆向加权)。
- IPS 的目标不是「平等对待每个样本」,而是「按观测难易还原真实分布」。
Problem 5.1.3 — 解释无偏性为什么成立 🟡 Medium
证明 的核心思路是什么?为什么朴素估计量 做不到?并说明生产环境为何通常还要截断 IPS 权重。
💡 Solution (click to reveal)
Approach: 从「期望值校正观测分布」的角度理解。
无偏性思路: 观测数据 的分布由观测概率 扭曲。IPS 用 作权重,恰好把「被过度采样的样本」调低、「被欠采样的样本」调高,使加权的经验分布 重新对齐到真实分布。于是期望上 等于在全部 上的真实风险 。
朴素估计量为何失败: 直接在扭曲的观测分布上平均,等价于用 本身作权重(隐式),期望天然偏离 。
为何截断: 当某些 极小(如 0.01),倒数达 100,单个样本就能把梯度剧烈拉偏,估计 方差爆炸、训练不稳定。截断(如 )或归一化在「无偏」与「低方差」间取折中,是有偏-方差权衡的工程必需。
Key points:
- IPS 用倒数权重「反扭曲」观测分布 → 期望对齐真实分布。
- 理论无偏 ≠ 实践稳定,故需截断控方差。
Problem 5.1.4 — 设计一个 PAL 改造 🔴 Hard
你负责的排序模型用一个 DeepFM 预测点击率,训练时把「展示位置」作为特征之一。上线后发现:排在前面的低质内容点击率被高估。请说明如何用 PAL 思路改造,并指出改造后 训练和推理 分别该用哪些模块、位置特征放哪。
💡 Solution (click to reveal)
Approach: 按 PAL 的「分解 + 双模块 + 训练推理分离」三步改造。
- 分解 :把现有 CTR 拆成 。
- 双模块 :新增轻量的 ProbSeen 模块,仅输入位置,输出「被看到的概率」;原 DeepFM 改造为 pCTR 模块, 移除其中的位置特征 ,只保留用户/物品/上下文。训练时两者输出相乘得 再算损失。
- 分离 :
- 训练时 :联合优化 ProbSeen 与 pCTR,让模型自学习责任分配。
- 推理时 : 只用 pCTR (不含位置),位置特征完全不进入 pCTR,也不需为位置假设值——pCTR 直接给出去偏点击率。位置信息只在训练期的 ProbSeen 里使用。
这样,排在前面的低质内容不再因「灯太亮」被高估——它的 pCTR 只反映内容本身的真实吸引力。
Key points:
- 位置特征从 pCTR 中 剥离 ,交给 ProbSeen。
- 推理只用 pCTR,是 PAL 解决「位置推理时不可用」的关键。
🏆 Challenge: 偏差叠加的攻防推演
假设一个短视频 App:新创作者内容(长尾)曝光极少,且系统默认把高热内容排前面。请写一段 200 字内的分析,说明 反馈闭环 如何在此同时放大「流行度偏差」与「位置偏差」,并给出至少两种可叠加的纠偏手段及其分别针对哪种偏差。
💡 Hint
闭环逻辑:高热内容排前 → 点击多 → 训练样本更多 → 模型更推高热 → 长尾更无曝光。流行度偏差由「交互分布倾斜」放大,可用 IPS (按曝光/观测概率加权)补偿;位置偏差由「排名摆位」引入,可用 PAL 把位置效应从 pCTR 解耦。两者叠加分别打在不同偏差源上;同时监控马太效应,避免单一措施被闭环抵消。
冷启动
📝 Before You Continue: 请先读完 Part 2 召回 的协同过滤与双塔,以及 5.1 的偏差视角。冷启动本质上是一个「没有历史却被要求精准」的偏差困境。
推荐系统最尴尬的时刻,莫过于一个新物品上架、或一个新用户注册的那一刻。协同过滤依赖用户-物品交互来学偏好,可此时交互是零;基于内容的方法虽能处理新物品,却往往只捕捉到表面相似。
这就是 冷启动问题——系统的核心引擎(行为数据)还没点火,却要立刻输出靠谱的推荐。本章把冷启动拆成两面: 内容冷启动 (新物品缺交互)与 用户冷启动 (新用户缺历史),并各给出两种代表解法。它们的共同智慧是 「借力」 :新物品借内容,新用户借元知识或人群结构。
读完本章,你将能够:
- 区分 内容冷启动与用户冷启动的根本差异
- 说明CB2CF 如何把内容特征映射到协同过滤表示,让新物品直接获得 CF 质量
- 写出MetaEmbedding 的双阶段元损失,理解它优化的是「可学习性」而非固定向量
- 解释MeLU 的参数分离与 POSO 的「个性化淹没」洞察,并对比二者思路
- 完成 4 道分层练习题,巩固冷启动的工程与数学直觉
5.2.0 冷启动的两张面孔
冷启动不是单一问题,而是两个对象各自「没有历史」:
| 类型 | 缺什么 | 典型失败 | 解法直觉 |
|---|---|---|---|
| 🎬 内容冷启动 | 新物品缺用户交互 | 协同过滤无法为其计算相似度 | 借内容 :用属性映射到已有表示 |
| 👤 用户冷启动 | 新用户缺行为历史 | 只能推热门,无个性化 | 借元知识/人群 :快速适应或分群 |
接下来分别展开。
5.2.1 内容冷启动:让新物品「借」到协同质量
协同过滤能发现复杂的隐式关联,但面对新物品束手无策;基于内容的方法能处理新物品,却常只捕捉表面相似。理想状态是: 新物品也能拿到协同过滤级别的表示——这正是 CB2CF 与 MetaEmbedding 的目标。
CB2CF:从内容特征到协同过滤表示
CB2CF(Content-Based to Collaborative Filtering) 的核心思想是学一个 映射函数 ,把物品的内容特征 直接映射到协同过滤嵌入空间,得到 。
对于既有内容描述、又有丰富交互的物品,我们同时拥有它的内容向量与 CF 嵌入。CB2CF 用深度网络学这两种表示间的非线性映射,新物品便 仅基于内容 就获得语义一致的 CF 表示。其多视图架构含三模块:
- 内容编码器(Content Encoder) :把多模态内容(文本、图像、类别)编码为统一内容向量。图像用 CNN、文本用 RNN/Transformer。
- 映射网络(Mapping Network) :核心,多层全连接,学从内容空间到 CF 嵌入空间的非线性映射,捕捉内容与用户偏好的复杂关联。
- 约束优化模块(Constraint Optimization) :用 余弦相似度约束 确保映射后的表示与真实 CF 嵌入语义一致,保证映射有效。
协同过滤向量从哪来? 对有交互的物品,可用多种方式生成 CF 向量:矩阵分解 ,物品 的向量即 的第 行 ;或双塔召回的物品塔输出;或 NCF、自编码器等深度方法。CB2CF 学完 后,新物品的内容 经 即得到 。
🧠 Mental Model: 翻译官
把 CB2CF 想成一位翻译官。CF 嵌入是系统内部通用「语言」,老物品都讲这门语言;新物品只会说「内容语」(文本/图像)。翻译官 学会了把内容语翻成 CF 语,于是新物品虽没交过朋友(无交互),一开口就被系统听懂、纳入协同网络。
Analysis: CB2CF 的优势是简单直接——一次映射,新物品立即获得 CF 级表示,可无缝接入现有召回/排序。局限在于:映射质量上限受「内容→CF」可迁移性约束,若内容与协同信号弱相关,翻译会失真;且它假设已有物品的 CF 向量可信(需先有良好 CF 模型)。
MetaEmbedding:用元学习生成「聪明」的初始 Embedding
CB2CF 解决「新物品拿不到 CF 表示」,但还有另一难题:即使有初始向量,传统 随机初始化 让新物品初期表现差,需大量交互才收敛。
MetaEmbedding 用 元学习 思想,为新物品生成「既初始质量好、又易快速适应」的 embedding。它模拟物品「从冷启动到预热」的完整过程来优化生成器。
算法输入:预训练基础模型 、物品集合 、元损失权重 、步长 。对每个采样物品 :
初始 Embedding 生成阶段 :生成器产出初始向量
其中 是物品 的特征, 是参数 的生成器。再采样两批各 个样本: 与 。
梯度适应与评估阶段 :在第一批上算损失后做一步梯度适应,模拟「少量交互后」:
再在第二批上评估适应后的损失 。
其关键在 元损失 平衡两目标:
最后用所有采样物品的元损失更新生成器:
💡 Key Insight: MetaEmbedding 优化的是 embedding 的**「可学习性」而非 embedding 本身**。它反复在老物品上演练「初始化→适应→评估」,学会给新物品一个「聪明起点」——少量真实交互后就能快速收敛到高质量表示。
🧠 Mental Model: 教人「如何学」而非「背答案」
MetaEmbedding 像一位教练,不直接给新球员比赛答案,而是训练他**「上场前怎么热身、前几球怎么调」**。于是真上场时,他只需少量实战就进入状态。 就是在权衡「开局姿势好不好」与「微调后强不强」。
5.2.2 用户冷启动:为新用户快速个性化
新用户刚注册时缺历史交互,协同过滤只能给基于流行度的通用推荐。用户冷启动聚焦:如何基于 少量 行为快速捕捉个性化偏好。MeLU 与 POSO 给出两种思路——元学习 与 分群架构。
MeLU:把每个用户当独立任务来学
MeLU(Meta-Learned User preference estimator) 把每个用户的偏好学习视为独立任务,用 MAML(Model-Agnostic Meta-Learning) 训练一个能快速适应新用户的模型。MAML 的精髓是「学会如何学习」——不追求在某任务最优,而是学一个 好初始化 ,使少量样本即可适应新任务。
MeLU 采用双层参数:
- 控制用户与物品的 embedding 参数 (所有用户共享)
- 负责模型核心 决策网络 参数(快速适应个体)
训练严格遵循 MAML 双循环:
- 内循环适应 :对每个用户 ,以其交互历史算梯度并本地更新 。
- 外循环元更新 :用所有用户的适应后参数,同时更新两组全局参数:
MeLU 的创新在 参数分离 : 学共享通用表示, 专司快速适应个体。既保表示能力,又能在新用户上快速个性化。此外 MeLU 还提出 证据候选选择 策略,挑选最能区分用户偏好的物品集合用于冷启动评估。
Analysis: MeLU 的优势是理论上优雅——新用户只需几步梯度即个性化,无需从头训练。代价是 MAML 的二阶梯度计算较重,且依赖「用户间任务同分布」假设;当新老用户行为分布差异巨大时,仅靠快速适应可能不够。
POSO:用分群子模块对抗「个性化淹没」
POSO(Personalized cOld Start Modules) 从架构角度切入,提出更直接的洞察:用户冷启动的根因 不只是数据稀缺 ,更是新用户与老用户 行为分布的巨大差异 ,以及模型处理不平衡分布时的 「个性化淹没」(Submergence)——当新用户远少于老用户时,即便有「是否新用户」特征,训练也被多数老用户主导,模型学会 忽略 这个严重不平衡的特征,新用户的个性化信号被淹没。
POSO 可嵌入多种模块,以 MLP 为例:原 MLP 所有用户共享权重 ;POSO 引入 个并行子模块 ,再用 个性化门控 网络(接收 is_new_user、活跃度等 )输出权重 ,最终输出为加权组合:
这让新用户主要依赖「为TA优化的子模块」,老用户用另一组,有效避开特征淹没。该思路可推广到:
- POSO-MHA :扩展为 组注意力头,每组专用 变换,组内拼接聚合,门控按用户特征选组权重。
- POSO-MMoE :底层 个共享专家 + 顶层 个专家组(每组 个专家),叠加 任务门控 与 个性化门控 双重门控,实现任务级与用户群体级的双重个性化。
🧠 Mental Model: 双语柜台 vs 单人柜台
普通模型像一个柜员同时招呼所有顾客,被常客(老用户)的惯常需求带偏,新客(新用户)的特殊要求被淹没。POSO 像开了 个专用柜台:新客去「新客专柜」,老客去「老客专柜」,门口有个引导员(门控)按顾客类型分流——新客的需求再也不会被常客的声量盖过。
Analysis: POSO 与 MeLU 思路互补:MeLU 假设「所有用户同分布、靠快速适应」,适合行为模式相近的场景;POSO 直击「分布不平衡导致特征淹没」,用结构强制分流,工程上更易集成到现成深度模块(MLP/MHA/MMoE),且无需元学习的重梯度。实践中可组合——用 POSO 结构保冷启动不淹没,用元学习进一步加速收敛。
⚠️ Common Mistakes in 5.2
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 随机初始化新物品 embedding | 新物品直接随机向量进模型 | 初期表现差,需大量交互才收敛 | 用 MetaEmbedding 生成聪明起点 |
| 2 | 把内容相似当协同相似 | CB2CF 只靠文本相似度 | 表面相似 ≠ 行为协同,映射会失真 | 用约束优化保证语义一致 |
| 3 | 以为 MAML 一定优于结构设计 | 用户冷启动无脑上 MeLU | 行为分布差异大时适应不足,且二阶梯度重 | 分布不平衡时优先 POSO 分流 |
| 4 | 给新用户加特征就以为够 | 仅加 is_new_user 标志位 | 老用户主导训练,该特征被淹没 | 用 POSO 子模块 + 门控强制分流 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 内容冷启动 | 新物品缺交互,CF 失效 | 借内容映射获得 CF 表示 |
| CB2CF | 内容→CF | 新物品立即获协同质量 |
| MetaEmbedding | 双阶段元损失优化「可学习性」 | 生成易快速适应的初始向量 |
| 用户冷启动 | 新用户缺历史,仅能推热门 | 借元知识/人群结构快速个性化 |
| MeLU / POSO | 元学习适应 / 分群子模块防淹没 | 两种互补的用户冷启动思路 |
❓ FAQ
Q1: CB2CF 和 MetaEmbedding 解决的是同一个问题吗?
A: 不完全。CB2CF 解决「新物品拿不到 CF 表示」;MetaEmbedding 解决「即使有初始向量,随机初始化也收敛慢」。二者可串联:先用 MetaEmbedding 生成好起点,再借 CB2CF 式的映射获得 CF 质量。
Q2: 为什么 POSO 比单纯加 is_new_user 特征有效?
A: 因为训练被老用户主导,单一特征会被「淹没」——模型学会忽略它。POSO 用 个专用子模块 + 门控,从结构上强制新用户走专属通路,无法被忽略。
Q3: MeLU 和 POSO 怎么选?
A: 用户行为模式相近、靠少量样本能适应 → MeLU;新老用户分布差异大、特征易淹没 → POSO。也可组合使用。
前后关联
- 5.1 (去偏)长尾新物品曝光少,易被流行度偏差淹没,冷启动与去偏需协同。
- 5.3 (生成式)语义 ID 让新物品无需行为即被推荐,从表示层面缓解内容冷启动。
- Part 2 召回 (Ch2.x)CB2CF 产出的 CF 表示可直接接入双塔/向量召回。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 5.2.1 — 区分冷启动类型 🟢 Easy
下列情形属于内容冷启动还是用户冷启动?
- (a) 新上架的纪录片,无任何播放记录,需被召回。
- (b) 刚注册的用户,只点了 3 个视频,系统却一直推热门。
- (c) 新歌发布,想直接进个性化歌单而非仅进「最新」列表。
💡 Solution (click to reveal)
Approach: 看「缺的是物品历史还是用户历史」。
- (a) 内容冷启动 :物品无交互,协同过滤失效。
- (b) 用户冷启动 :用户缺历史,只能推热门。
- (c) 内容冷启动 :新歌(物品)缺行为,想借内容进入个性化。
Key points:
- 内容冷启动的「主语」是新物品;用户冷启动的「主语」是新用户。
- 二者解法不同:内容借内容映射,用户借元学习/分群。
Problem 5.2.2 — CB2CF 映射填空 🟢 Easy
CB2CF 学习映射函数 ,把新物品的内容特征 映射到协同过滤空间。请补全输出表达式,并说明约束优化模块的作用。
💡 Solution (click to reveal)
Approach: 回忆 CB2CF 三模块与映射定义。
映射输出为:
其中 由映射网络(多层全连接)实现。约束优化模块 用余弦相似度约束,确保 与真实 CF 嵌入 在语义上保持一致——否则映射可能「看起来收敛」却偏离协同空间,导致新物品被错误推荐。
Key points:
- 新物品无交互,但凭内容 经 即得 CF 表示。
- 约束优化是映射有效的保障,不能省。
Problem 5.2.3 — MetaEmbedding 元损失解读 🟡 Medium
MetaEmbedding 的元损失为 。请解释:① 两项分别衡量什么?② 若 会有什么后果?③ 为什么说它优化「可学习性」而非 embedding 本身?
💡 Solution (click to reveal)
Approach: 对照双阶段过程拆解元损失。
① 衡量初始 embedding 在首批数据上的直接质量(冷启动开局表现); 衡量经过一步梯度适应后的质量(少量交互后的适应表现)。
② 若 ,元损失只剩 ,生成器 只优化初始质量 ,不再关心「能否快速适应」——新物品拿到好起点却难微调,违背冷启动需快速收敛的初衷。
③ 它不在某个具体物品上定死一个向量,而是在大量老物品上反复演练「初始化→适应→评估」,学会 生成具备良好初始性能且强适应潜力 的起点。面对真新物品时,该起点经少量真实数据即快速收敛——优化的是「易学程度」。
Key points:
- 平衡「开局」与「适应」。
- 元学习 = 学如何学,不是学一个固定答案。
Problem 5.2.4 — POSO 改造设计 🔴 Hard
你有一个共享权重的 MLP 排序模型,线上发现新用户推荐效果远差于老用户,即便已加 is_new_user 特征。请用 POSO-MLP 思路给出改造方案:写出子模块与门控的数学形式,并说明为何这能解决「特征淹没」。
💡 Solution (click to reveal)
Approach: 按 POSO-MLP 的三段式改造。
子模块: 引入 个并行 MLP 子模块,每个有独立权重:
门控: 个性化门控接收 (含 is_new_user、活跃度等),输出各子模块权重:
最终输出: 所有子模块加权组合:
为何解决淹没: 原模型所有用户共享 ,训练被老用户主导,单一 is_new_user 特征易被学「忽略」。POSO 让新用户主要走「新用户专用子模块」、老用户走另一组,从 结构上 保证新用户的个性化信号有专属通路,无法被老用户声量盖过。
Key points:
- 关键是「结构分流」而非「加特征」。
- 门控按用户特征动态分配子模块权重,可平滑过渡新老用户。
🏆 Challenge: 冷启动组合拳
某短视频 App 同时面临:新创作者内容(内容冷启动)和新注册用户(用户冷启动)。请写一段 200 字内的方案,说明你会如何 组合 CB2CF / MetaEmbedding / POSO 三类技术分别应对,并指出哪一步最依赖「已有物品的 CF 向量质量」。
💡 Hint
- 新创作者内容:用 MetaEmbedding 生成聪明初始 embedding,再借 CB2CF 式内容→CF 映射获得协同表示接入召回。
- 新注册用户:用 POSO 子模块+门控做结构分流,避免
is_new_user被淹没;若有少量行为,可叠加 MeLU 式快速适应。 - 最依赖「已有物品 CF 向量质量」的是 CB2CF——它的约束优化需要可信的真实 CF 嵌入作对齐目标,若基础 CF 模型差,映射也会失真。
生成式范式演进
📝 Before You Continue: 请先读完 1.1 的两种范式与能力演进四阶段,以及 5.2 的语义/冷启动基础。本章是 Part 1 双范式的「落地版」——把抽象概念变成具体模型。
在 1.1 里我们埋下一根线:推荐能从「判别式打分」转向「生成式序列生成」,就像把自然语言当成一种特殊「语言」来理解和产出。本篇前几章沿着判别式三阶段流水线走完了工业实践;现在,是时候回到这根线,看清 生成式范式如何具体演进。
它的核心是对三个要素的重新设计: 输入如何组织 (从物品 ID 序列到异构事件流)、输出生成什么 (从原子 ID 到语义化表示)、目标与架构如何取舍 (表达能力 vs 计算效率)。沿这三问,生成式推荐走出三条清晰路径——生成式召回、生成式排序、端到端统一生成。
读完本章,你将能够:
- 串起「记忆·泛化 → 理解·推理」的能力跃迁,并对照 Part 1 的两种范式
- 解释HSTU 如何把异构信息统一为事件流、TIGER 如何用语义 ID 重塑输出
- 区分 生成式排序(GenRank / MTGR)与判别式排序的本质不同
- 描述OneRec 端到端生成的四项关键创新,尤其迭代偏好对齐(IPA)
- 完成 4 道分层练习题,巩固从范式到模型的映射
5.3.0 从「择优」到「创作」:一次范式跃迁
回头看 Part 1 的两条主线:判别式问「用户会喜欢这个候选吗?」——择优 ;生成式问「用户接下来想看什么?」——创作。生成式召回(如 SASRec)已验证:把用户行为序列当「语言」,自回归预测下一个物品是可行的。
但真正的变化不止于「换成生成目标」,而是系统性地重塑输入、输出与架构。下表对照三条路径各自的着力点:
| 路径 | 重塑的要素 | 代表模型 |
|---|---|---|
| 生成式召回 | 输入统一化 + 输出语义化 | HSTU、TIGER |
| 生成式排序 | 把自回归引入排序阶段 | GenRank、MTGR |
| 端到端统一生成 | 单模型替代召回到排序全流程 | OneRec |
💡 Key Insight: 这三条路径不是互相替代,而是层层递进——先在召回上证明生成可行,再把生成思想推进排序,最后用一个模型吞掉整条流水线。每一步都在回答「输入/输出/架构」中的某一问。
5.3.1 生成式召回的深化:重做输入与输出
生成式召回在 SASRec 基础上沿两个方向深化: HSTU 代表对「输入」理解的深化, TIGER 代表对「输出」定义的根本重塑。
HSTU:把一切统一为事件流
HSTU 不再满足于简单的物品 ID 序列,而是把用户所有异构信息——属性、行为类型、时间戳——统一编码为一个复杂「事件流」。它学习条件分布 ,其中 是用户当前时刻的综合表示, 是下一个候选物品。
两项技术创新尤其关键:
- 特征统一化处理 :类别特征按时间戳拉平成统一序列,如
[(特征:年龄,值:30), (行为:登录), (行为:浏览,物品:A)];数值特征则隐式建模让模型自动推断。 - 点向聚合机制 :摒弃传统 Transformer 的 softmax 归一化,改用点向聚合 。动机是:推荐中用户兴趣的 「强度」是关键信号 ,而 softmax 会强制把所有历史注意权重归一化,扭曲真实偏好强度。
HSTU 还通过切换预测目标与训练头,可从召回转换为排序任务——体现了生成式架构的灵活性。
🧠 Mental Model: 从「流水账」到「事件流」
判别式把用户历史当作「候选物品清单」逐个打分;HSTU 则把它当成一部带时间戳、带行为类型、带上下文的「生活流水账」。它不把「浏览 A」「登录」「年龄 30」割裂,而是按时间串成一串事件,模型由此读到「强度」与「顺序」的完整信息——就像你读朋友的日记,比只看他的购物小票更懂他。
TIGER:用「语义 ID」重塑输出
TIGER 认为预测无语义的 原子 ID 效率低下且有泛化问题,转而生成结构化的 「语义 ID」 代表物品。流程分两阶段:
第一阶段——生成语义 ID :用残差量化变分自编码器(RQ-VAE)。对物品内容特征向量 ,编码器映射为潜在表示 ;再经 层量化,每层 在码本中找最接近当前残差 的码字:
最终得到语义 ID 元组 。
第二阶段——序列到序列生成 :用户历史交互转为对应的语义 ID 序列,训练 Encoder-Decoder Transformer 自回归生成 下一个物品的语义 ID。优势在于:
- 语义共享 :内容相似物品拥有相似语义 ID,实现知识共享;
- 冷启动优势 :可直接为新物品生成语义 ID 并推荐(呼应 5.2 内容冷启动);
- 结构化表示 :多层码字高效表示大规模物品库。
代价是可能生成 无效 ID、推理代价较高——在表达力与计算效率间做权衡。
Analysis: HSTU 与 TIGER 分别攻坚「输入」与「输出」,恰好对应 Part 1 能力演进中的**「泛化」(深度理解异构信号)到「理解」(物品被编码为携带语义的 Token)**。TIGER 的语义 ID 更是冷启动的天然解药——新物品无需行为积累即被理解。但二者仍属「召回层」生成,尚未动摇排序与重排。
5.3.2 生成式排序:把自回归推进排序阶段
生成式排序把自回归思想引入传统排序阶段,主要两条技术路径。
GenRank:动作导向的序列组织
GenRank 采用「动作导向」设计,把排序重定义为预测用户对给定候选的 动作概率 。核心洞察:预测 行为动作 (点击、喜欢)比预测下一个物品 ID 计算更高效——动作空间远小于物品空间。
架构上,GenRank 把物品视作已知的位置上下文,专注预测每个位置上的动作;输入是五种嵌入之和(物品、动作——候选用特殊 [MASK] 嵌入、位置、请求索引、时间)。它用 ALiBi(线性偏置注意力) 替代可学习相对注意力偏置——一种无参数静态惩罚,降低约 75% 注意力计算成本、提升 94.8% 训练速度。
MTGR:用户样本聚合
MTGR 试图在保留传统 DLRM 丰富特征的同时,获得生成式架构的可扩展性。核心创新是 用户样本聚合 :把用户全部 个候选聚为单个样本 [用户特征, [候选1特征, ..., 候选K特征]],用户相关特征只算一次并在所有候选间共享。
为处理这种异构序列,MTGR 引入: 组层归一化(GLN)——对不同语义空间的 token(用户画像、物品特征)分别归一化; 动态掩码策略——静态用户特征对所有 token 可见、动态用户特征遵循因果、候选 token 互相不可见以防信息泄露。
⚠️ Warning: 尽管叫「生成式」,MTGR 本质仍是排序模型——其「生成式」主要体现在架构风格(用 Transformer 处理 token 序列),最终目标仍是判别式打分排序。不要被名字误导:它是「披着生成式外衣的判别式」。
🧠 Mental Model: 评委换了一种读题方式
判别式排序这位「评委」原本挨个翻选手简历打分。GenRank/MTGR 给评委换了种读题方式——把一堆候选并排摊开、用注意力一次性扫读(生成式架构的算力优势)。但评委最终仍是在打分择优,没变成「直接报名单」的朋友。这就是生成式排序与端到端生成的根本分野。
5.3.3 端到端统一生成:OneRec 的最高形态
OneRec 代表生成式推荐的最高形态——端到端统一生成 ,用单一模型完成从召回到排序的全流程。其核心创新是 会话级生成 :不再预测单一下一个物品,而是直接生成一组有序推荐列表(通常 5–10 个),定义为一个「会话」。
OneRec 用标准 Encoder-Decoder,但在三方面重要扩展:
- 语义化物品表示 :用多级向量量化把每个物品转为语义 token 序列,让模型理解内容含义而非仅 ID。
- 稀疏专家混合(MoE) :在解码器前馈网络引入 MoE 层,激活少数专家子网络,显著增加容量而不成比例增加算力。
- 迭代偏好对齐(IPA) :最具创新性的组件,解决推荐难以获得显式偏好对比数据的问题。
IPA 机制:先训练奖励模型预测会话质量(观看时长、点赞等);用当前 OneRec 为样本生成多个候选会话(通常 128 个);奖励模型评分,选最高分为「选择」响应 、最低分为「拒绝」响应 ;最后用 DPO(Direct Preference Optimization) 损失更新模型。
OneRec 线上部署取得 1.68% 用户总观看时长提升 ,证明端到端统一生成的实用价值。代价是训练流程复杂:需依次训练量化模型、基础生成模型、奖励模型,再做迭代 IPA-DPO 循环,对工程要求高。
🧠 Mental Model: 从「层层筛简历」到「一次写名单」
判别式级联像 HR 招人:先海量海选(召回),再精面排名(排序),最后定编制(重排)——三拨人各管一段,信息传递有损耗、目标各想各的。OneRec 像一个既懂业务又有权力的主管,直接写出一份完整录用名单(会话级生成),一气呵成、目标统一。这就是 Part 1 说的「端到端消解级联三痛点」。
Analysis: 端到端生成的收益是统一优化、无级联信息损失、算力集中;成本是训练复杂度与推理代价陡增,且需要 DPO/奖励模型等配套。它并非「免费午餐」,而是把复杂度从「多阶段协调」转移到「单模型训练工程」。与 Part 1 呼应:生成式用「创作」替代判别式「择优」,把记忆·泛化一路推到理解·推理。
下面用交互演示直观对比「判别式级联」与「生成式端到端」的架构差异:
点击「下一步」或「自动播放」,观察三阶段级联如何被单一生成模型替代,以及范式跃迁如何对应能力演进的「理解·推理」阶段。
⚠️ Common Mistakes in 5.3
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把 MTGR 当真生成式 | 「MTGR 端到端生成推荐」 | 它最终仍是判别式打分,仅架构风格生成式 | 认清政府目标:生成式排序 ≠ 端到端生成 |
| 2 | 以为语义 ID 一定优于原子 ID | 无脑用 TIGER 替换所有召回 | 语义 ID 可能生成无效 token、推理更贵 | 在表达力/效率间权衡,必要时混合 |
| 3 | 混淆 HSTU 的输入与输出创新 | 「HSTU 用语义 ID 做输出」 | HSTU 攻输入统一化,语义 ID 是 TIGER 的 | 区分:HSTU=输入,TIGER=输出 |
| 4 | 忽视 OneRec 工程成本 | 照搬端到端却无 DPO 配套 | 缺奖励模型/IPA,训练无法对齐偏好 | 端到端需量化+生成+奖励+DPO 全链路 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| HSTU | 异构信息统一为事件流 + 点向聚合保强度 | 生成式召回对「输入」的深化 |
| TIGER | RQ-VAE 生成语义 ID,自回归生成 | 对「输出」的根本重塑,天然解冷启动 |
| GenRank / MTGR | 动作导向 / 样本聚合 | 生成式思想进排序,MTGR 仍判别式 |
| OneRec | 会话级 + MoE + IPA(DPO) | 端到端统一生成,吞掉整条流水线 |
| 范式跃迁 | 判别式择优 → 生成式创作 | 对应能力演进:理解·推理 |
❓ FAQ
Q1: 生成式召回(HSTU/TIGER)和端到端生成(OneRec)差在哪?
A: 前者只在「召回」层把候选生成取代逐一打分;后者用一个模型直接生成整份会话列表,吞掉召回到排序全流程。跨度从「单点预测」到「统一生成」。
Q2: 为什么 TIGER 能缓解冷启动?
A: 语义 ID 由内容特征(RQ-VAE)生成,新物品无需行为积累即可获得结构化 Token 并被生成推荐——正是 5.2 内容冷启动想要的「借内容」。
Q3: OneRec 的 IPA 为什么用 DPO 而不是直接监督?
A: 推荐难获「显式偏好对比数据」。IPA 用奖励模型从 128 个候选里挑最高/最低分作「选择/拒绝」对,再用 DPO 对齐——绕开缺标注的困境。
前后关联
- 1.1 / 1.2 (范式与地图)本章是那两根线在模型层的落地:判别式→生成式、记忆泛化→理解推理。
- 5.2 (冷启动)TIGER 语义 ID 与 CB2CF 殊途同归,都让新物品借内容被理解。
- 后续版本下篇(Ch6–Ch10) 在本章 OneRec 基础上展开 Scaling Law(HSTU 架构)、会思考的推荐(OneRec-Think)、扩散模型等。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 5.3.1 — 归类生成式模型 🟢 Easy
把下列模型归入三条演进路径之一(生成式召回 / 生成式排序 / 端到端生成):
- (a) HSTU (b) OneRec (c) GenRank (d) TIGER (e) MTGR
💡 Solution (click to reveal)
Approach: 对照每条路径的着力要素与代表模型。
- (a) HSTU → 生成式召回 (重塑输入:事件流)
- (d) TIGER → 生成式召回 (重塑输出:语义 ID)
- (c) GenRank → 生成式排序 (动作导向)
- (e) MTGR → 生成式排序 (用户样本聚合,但本质判别式)
- (b) OneRec → 端到端生成 (单模型吞掉全流程)
Key points:
- HSTU/TIGER 在召回层;GenRank/MTGR 在排序层;OneRec 跨全流程。
- MTGR 虽称生成式,目标仍是判别式打分。
Problem 5.3.2 — TIGER 语义 ID 计算 🟢 Easy
给定物品内容特征 ,RQ-VAE 编码得 ,第一层残差 。码本 中,与 最近的码字索引为 、对应 。请写出 的选取公式,以及更新残差 的表达式。
💡 Solution (click to reveal)
Approach: 直接套用 TIGER 的量化公式。
码字选取:
故 。
残差更新:
Key points:
- 每层在码本中找最近码字,再从残差里减掉它。
- 多层迭代得到语义 ID 元组 。
Problem 5.3.3 — 辨析「真/假」生成式 🟡 Medium
有人说:「MTGR 用 Transformer 处理 token 序列,所以是端到端生成式推荐。」请指出该说法的错误,并说明 GenRank 与 OneRec 在「是否真生成式」上的关键区别。
💡 Solution (click to reveal)
Approach: 从「最终目标」而非「架构风格」判断生成式。
错误所在: MTGR 虽用 Transformer/注意力(生成式架构风格),但其 最终目标仍是判别式打分排序——候选已知、逐候选算分。它只是「披着生成式外衣的判别式」,并非端到端生成。
GenRank vs OneRec: GenRank 仍属生成式 排序——把动作概率自回归化,但候选集合已知、输出是动作/分数,未吞掉召回与重排。OneRec 才是 端到端生成——单一模型直接生成有序会话列表(5–10 个物品),替代从召回到排序的全流程,目标从「打分」变为「创作序列」。
Key points:
- 判据是「目标:打分择优 or 创作序列」,不是「是否用 Transformer」。
- 生成式排序 ≠ 端到端生成,跨度差一个量级。
Problem 5.3.4 — 设计 OneRec 对齐流程 🔴 Hard
你要在 OneRec 上做偏好对齐。请写出 IPA 的完整步骤(含候选数量、选择/拒绝响应定义),说明为何用 DPO 而非直接监督,并指出该流程依赖哪三个前置模型。
💡 Solution (click to reveal)
Approach: 按 IPA 机制逐步展开。
步骤:
- 训练 奖励模型 预测会话质量(观看时长、点赞等)。
- 用当前 OneRec 为训练样本生成 128 个 候选会话。
- 奖励模型对所有候选评分,选 最高分 为「选择」响应 , 最低分 为「拒绝」响应 。
- 用 DPO 损失 更新 OneRec 参数。
为何 DPO 而非直接监督: 推荐难以获得「显式偏好对比数据」(用户不会标「这两个列表哪个更好」)。IPA 用奖励模型从模型自生成的候选里 构造「选择/拒绝」对,绕开缺标注困境;DPO 无需训练独立 critic,直接以此对比对优化策略,稳定高效。
依赖的三个前置模型: ① 多级向量量化的 语义表示模型 (物品→token);② OneRec 基础生成模型 ;③ 奖励模型。三者须先就位,IPA-DPO 循环才能跑。
Key points:
- IPA = 自生成候选 → 奖励打分 → 选/拒对 → DPO。
- DPO 解决了「无显式偏好标注」的核心障碍。
- 端到端工程成本高:量化+生成+奖励+DPO 全链路。
🏆 Challenge: 范式迁移论证
假设贵司现有判别式三阶段系统(召回+排序+重排),指标进入瓶颈。请写一段 200 字内的论证:在哪些 信号 出现时,应优先尝试「生成式排序(如 GenRank)」而非一步到位「端到端生成(OneRec)」?并说明这样分步走的风险与收益。
💡 Hint
优先生成式排序的信号:排序阶段算力碎片化严重、注意力计算成本高(GenRank 的 ALiBi 可降 75% 算力)、且已有成熟召回/重排不愿动。分步走的 收益 是风险可控、局部收益快、不推翻全链路; 风险 是仍受级联信息损失与目标不一致制约,未触及根本。待排序验证生成式价值、且工程具备量化+奖励+DPO 能力后,再上 OneRec 做端到端。呼应 Part 1「级联三痛点」与本章三条路径的递进逻辑。
生成式推荐正在把推荐系统从「对候选集打分排序」的判别范式,转向「直接生成推荐结果」的生成范式。本部分作为「生成式推荐主线」的起点,系统搭建四根支柱—— 范式动机 、 架构基石 、 LLM 建模流程 、 Tokenizer 技术 ,层层递进,构成理解后续章节的完整基础。各章要点见下表。
本章涵盖
| 章节 | Topic | The Big Idea |
|---|---|---|
| 6.1 | 生成式推荐范式引言 | 判别式 vs 生成式:局部打分决策 vs 全局概率建模,三道固有局限驱动范式转变 |
| 6.2 | 生成式架构基础 | Transformer 自注意力/位置编码/两类架构范式/因果掩码,与 Diffusion 互补 |
| 6.3 | LLM 基础 | 预训练—指令微调—偏好对齐三阶段范式,及向生成式推荐的映射与挑战 |
| 6.4 | Codebook 量化与语义 ID | 稀疏/文本/语义 ID 三范式,VQ-VAE、RQ-VAE、RQ-Kmeans、RQ-OPQ 工业方案 |
What You'll Be Able to Do After This Part
- 🟢 区分 判别式与生成式的核心公式与「问的问题」,列出判别式三大固有局限
- 🟢 解释 自注意力的 Q/K/V 机制、位置编码(含时间感知)与因果掩码的作用
- 🟡 对比 Encoder-Decoder 与 Decoder-Only 两类架构的优劣与适用场景
- 🟡 复述 LLM 三阶段范式(预训练/SFT/RLHF/DPO)并映射到推荐场景
- 🔴 推导 VQ-VAE 三损失与 RQ-VAE 残差量化,说明语义 ID 的三大价值
- 🔴 完成 4 章共 18+ 道分层练习题,巩固从范式到语义 ID 的全链路
核心概念
| Concept | 章节 | Relevance |
|---|---|---|
| 判别式/生成式范式 | 6.1 | 全书生成式主线的总开关 |
| 自注意力 / 位置编码 / 因果掩码 | 6.2 | Transformer 生成架构的核心机制 |
| Encoder-Decoder vs Decoder-Only | 6.2 | 生成式架构选型的根本权衡 |
| Diffusion 模型 | 6.2 | 与 Transformer 互补的生成机制 |
| 预训练/SFT/RLHF/DPO | 6.3 | LLM 训练范式的方法论框架 |
| 物品 Token 化 / 语义 ID | 6.4 | 连接推荐数据与生成模型的桥梁 |
| VQ-VAE / RQ-VAE / RQ-Kmeans / RQ-OPQ | 6.4 | 语义 ID 的离散化技术谱系 |
前置知识
- 已读完 Part 1 (1.1 的两种范式、1.2 技术地图)
- 已读完 Part 2 (2.3 双塔的内积与向量空间直觉)
- 具备基础的线性代数(矩阵、内积)、概率(softmax、KL 散度)与神经网络常识
本部分为前沿内容,术语较新(生成式检索、语义 ID、RQ-VAE、Scaling Law 等),首次出现均中英对照并配心智模型与图表。
Tips for This Part
- 先看动机再看技术。 6.1 的「为什么需要生成式」是理解后续一切技术的钥匙——每个技术都在回应某个判别式局限。
- 抓住「统一架构」主线。 从 6.2 的 Transformer 到 6.3 的 LLM,再到 6.4 的语义 ID,「统一、可扩展、端到端」是一以贯之的设计哲学。
- 多动手点可视化。 每章的交互式 HTML 与 SVG 都值得亲手走一遍,把抽象公式落到「序列如何生成」「向量如何量化」的直觉上。
- 对照判别式思考。 每遇到一个生成式组件,先问「它解决了判别式的哪个局限?」
Let's dive in! 🚀
生成式推荐范式基础
📝 Before You Continue: 请先读完 1.1 的「两种根本范式」与 2.x 的判别式召回/排序。本章把「判别式」与「生成式」的对照从直觉推进到建模哲学与架构层面,是后续所有生成式章节的理论起点。
过去十余年,推荐系统从传统机器学习演进到深度学习,模型表达能力越来越强、业务指标越来越高。但有一个事实很容易被忽略: 无论模型怎么变,底层的建模范式始终没变——我们一直在做「判别」。
给定一个候选物品集合,判别式模型判断用户会不会喜欢其中某个物品,本质是一个分类或排序问题。这套体系在工业界已经非常成熟,却也逐渐暴露出深层次的局限:多阶段级联带来的目标不一致、对每个物品独立打分难以捕捉序列依赖、海量 Embedding 参数难以喂饱现代硬件。
正是在这样的背景下, 生成式推荐(Generative Recommendation) 作为一种全新范式开始崭露头角。它不再把推荐看成「对候选集打分」,而是重新定义为「序列生成任务」——模型主动学习「用户接下来会与哪些物品交互」。这一看似微妙的转变,带来了根本性的改变:从局部打分决策转向全局概率建模,从多阶段级联转向端到端优化,从固定候选集转向开放生成空间。
读完本章,你将能够:
- 写出 判别式 与 生成式 的核心条件概率公式,并解释二者「问的问题」有何不同
- 列出判别式范式在 参数效率、语义建模、多阶段级联 三方面的固有局限
- 说明生成式的 自回归建模 如何天然捕捉序列依赖、并为端到端优化打开大门
- 从 目标函数、信息流动、模型架构 三个维度对比两种范式的本质差异
- 完成 4 道分层练习题,巩固「判别 vs 生成」的建模哲学
6.1.0 判别式推荐:我们一直以来的做法
判别式推荐的核心是学习一个 条件概率分布 ,预测用户 在上下文 下对物品 产生正向交互(点击、购买等)的概率。这一建模方式直观、高效,是工业界绝对的主流。
现代深度学习推荐模型几乎都遵循「Embedding & MLP」范式:先把用户 ID、物品 ID 及各类特征通过嵌入层映射为稠密向量,再经多层感知机或更复杂的特征交互模块处理,最后输出一个标量分数,表示用户对该物品的兴趣强度。它的灵活性很高——通过设计不同的特征交互模块(FM、DeepFM、DCN 等)捕捉高阶特征交叉,通过序列建模模块(DIN、SIM 等)刻画短期与长期偏好。
判别式推荐通过整合用户特征 、物品特征 与场景特征 ,对每个候选物品逐一打分,预测「是否会产生正向交互」的概率。
💡 Key Insight: 判别式模型的输入与生成式完全相同(都要理解用户、物品、场景),但它提出的问题是「这个物品是否应该被推荐」——一个局部的、逐候选的二分类问题。
判别式范式的三道固有局限
然而,这种「对每个物品独立打分」的建模方式,也带来了三个难以根治的问题。
① 参数效率问题。 Embedding 层通常占据模型 90% 以上的参数量,但这些参数是稀疏的、低效的,难以充分利用现代 GPU/TPU 的并行计算能力。大量参数「沉睡」在稀疏 ID 查表中,硬件利用率(MFU)长期偏低。
② 语义建模缺失。 判别式模型把每个物品视为独立的 原子单元(Atomic Unit) ,物品 ID 之间没有任何语义关联。一部「科幻悬疑片」和另一部「科幻悬疑片」的 ID 在向量空间里毫无先验关联,模型只能靠海量行为数据去「死记硬背」它们的相似度,导致 冷启动 问题难以解决。
③ 多阶段级联困境。 为应对海量物品库与毫秒级延迟,工业系统不得不采用「召回—粗排—精排—重排」的多阶段级联。各阶段由不同模型负责、优化目标各不相同(召回看相关性、排序看点击率), 全局目标难以对齐 ;更糟的是,每一次级联都会丢失信息——召回阶段因简单相似度计算过滤掉的优质物品,后续阶段 根本没有机会看到。这种逐级筛选虽保证了效率,却让系统陷入「局部最优」,难以实现真正的端到端优化。
⚠️ Warning: 这三道局限并非判别式模型的「工程瑕疵」,而是其「逐候选打分」建模范式的内在属性。想根治,就要从范式本身动手——这正是生成式推荐登场的动机。
6.1.1 生成式推荐:重新定义推荐任务
生成式推荐从根本上重新定义了推荐任务。它不再把推荐当作一个对候选集打分的判别问题,而是建模为一个 序列生成过程。给定用户 、上下文 以及历史交互序列 ,生成式推荐学习这个序列的生成概率:
这个公式看似简单,却藏着深刻的建模思想:它不再孤立地看待每个物品,而是把用户的交互行为视为一个 连续演化的过程。模型要学习的不是「某个物品是否该被推荐」,而是「在已知历史行为的条件下,用户接下来最可能与哪个物品交互」。
生成式推荐以用户历史交互序列为条件,通过自回归解码直接生成下一个(或下一段)物品,无需逐一评估候选。
🧠 Mental Model: 评委打分 vs 朋友推荐
把两种范式想象成两种人。判别式模型像一位选秀评委:台上站满选手(候选物品),评委对每一个单独打分,最后按分高低发通行证——他从不「直接报出名单」,只负责打分。生成式模型像一位很懂你品味的朋友:他不需要翻遍所有选项,而是直接说「你接下来该看这几个」,因为他已经理解了你的喜好脉络。前者是择优,后者是创造。
自回归建模为什么是分水岭
自回归建模(Autoregressive Modeling)的优势不仅在于捕捉序列依赖,更在于它为 端到端优化 打开了大门:
- 消除误差累积 :模型一次前向传播直接生成推荐结果,无需依赖多阶段级联,从而消除了级联带来的误差累积与目标不一致。
- 支持全局目标 :生成式模型可以优化全局目标(如用户长期满意度、平台生态平衡)做端到端强化学习,这在判别式框架下几乎无法实现。
- 自带序列依赖 :当前时刻的预测依赖之前所有时刻的输出,天然捕捉长程行为依赖。
此外,生成式推荐在 物品表示 上也更灵活:它可以用文本描述或 语义 ID(Semantic ID) 来表示物品,这些表示天然携带语义信息,使得新物品无需积累行为数据即可被推荐,大幅缓解冷启动。
🤔 Why 这个转变很关键? 判别式假设「候选集已由召回确定」,任务是在有限空间内排序;生成式则不预设候选集,让模型从全体物品空间直接生成。前者是「自上而下」的工程化思路,后者更接近人类决策本质——我们做选择时,往往不是对选项逐一打分,而是基于经验生成一个候选方案。
6.1.2 两种范式的本质区别
判别式与生成式的差异不只是公式不同,更深地反映在 目标函数、信息流动、模型架构 三个维度。
目标函数:局部决策 vs 全局分布
判别式模型优化的是 局部决策边界——给定候选集,学习区分正负样本,让正样本分数尽量高、负样本尽量低。这种方式直接,却局限于候选集范围,难以刻画全局物品分布。
生成式模型优化的是 完整的概率分布 。它不仅关心「哪些物品该被推荐」,更关心「整个交互序列是怎么生成的」。这种全局建模让模型更好捕捉偏好演化规律,也为多目标优化提供了更自然的框架。
信息流动:前馈独立 vs 自回归循环
判别式模型通常采用前馈网络,信息从输入层经多层变换流向输出层, 每个物品的打分独立计算——高效,却忽略了推荐列表中物品之间的依赖关系。
生成式模型采用自回归结构,当前预测依赖之前所有时刻的输出,信息在 时间维度上形成循环流动。这既捕捉长程依赖,也为引入强化学习等高级优化技术打下基础。
左:判别式前馈网络,每个候选独立打分;右:生成式自回归,信息沿时间回流,逐 token 生成。
模型架构:异构专用 vs 统一 Transformer
判别式系统为适配不同阶段,往往需要多种专用模块——召回用双塔或图网络、排序用复杂特征交互网络、重排考虑列表级约束。这些模块异构、高度定制,导致系统复杂、维护成本高。
生成式推荐则倾向采用 统一的 Transformer 架构 ,通过自注意力与前馈网络堆叠处理所有任务。其矩阵运算密集型特点与 GPU/TPU 高度契合,能实现远超判别式模型的硬件利用率(MFU),并通过简单堆叠实现参数规模化(Scaling)。
更深一层:建模哲学的差异
把视角再拉高一层,两种范式的根本区别是 建模哲学 的差异:判别式追求「在给定候选集下做出最优选择」,生成式试图「学习用户行为的生成过程」。前者适合处理明确定义的优化问题,后者更接近人类决策本质,也为推荐系统与语言模型、多模态模型的深度融合打开了新的可能性。
📊 Data Point: 需要客观指出:当前工业界完全采用端到端的生成式推荐仍面临挑战(训练成本、推理延迟、系统稳定性)。因此研究呈现三条并行路径——① 渐进式(在级联架构上借鉴 LLM 的 Scaling 能力);② 知识增强(注入 LLM 世界知识);③ 完全生成式(召回/排序/重排统一到一个生成模型)。本章聚焦基础,后续章节逐一展开。
下面的交互演示把两种范式并排放在一起,你可以逐步观察同一个推荐请求在「判别式打分」与「生成式序列生成」两条路径上的处理差异:
⚠️ Common Mistakes in 6.1
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把生成式也理解为「对每个候选打分」 | 「生成式就是换个方式算点击率」 | 生成式直接产出序列,不做逐候选评估 | 记住:判别式 择优 ,生成式 创造 |
| 2 | 认为判别式的问题只是「工程没做好」 | 「加个更大的模型就能解决级联」 | 误差累积/语义缺失是范式内在属性 | 从范式层面理解局限,而非堆叠参数 |
| 3 | 混淆条件概率的两个方向 | 把 写成 当成生成式 | 前者是序列生成分布,后者是逐候选判别 | 看清公式「条件」在哪一侧 |
| 4 | 以为生成式不需要候选集概念 | 「生成式完全没有候选空间」 | 生成式是把候选空间内化为生成分布,并非不存在 | 理解「不预设候选」≠「无物品空间」 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 判别式推荐 | ,逐候选打分 | 工业主流,成熟稳定但有三道固有局限 |
| 三大局限 | 参数低效、语义缺失、级联困境 | 推动范式转变的根本动机 |
| 生成式推荐 | 自回归、端到端、自带语义表示 | |
| 本质差异 | 目标函数/信息流动/架构三维度 | 决定能否做全局优化与 Scaling |
| 三条路径 | 渐进式/知识增强/完全生成式 | 当前工业落地的现实图景 |
❓ FAQ
Q1: 生成式一定比判别式好吗?
A: 不是。判别式在成熟场景稳定高效,生成式在端到端、冷启动、语义理解上潜力更大。当前工业界两者并行发展,应按业务阶段选择。
Q2: 自回归建模到底解决了什么?
A: 它让模型一次前向传播直接生成结果,消除多阶段级联的误差累积与目标不一致,并天然捕捉序列依赖,为端到端强化学习铺路。
Q3: 为什么说语义缺失是「范式问题」而不是「数据问题」?
A: 判别式把物品当原子 ID,ID 间无任何先验关联,只能靠行为统计「死记」相似度;生成式用语义 ID 让相似关系编码在表示结构里,从根上缓解冷启动。
🔗 前后关联
- 6.2 (生成式架构基础)承接本节「统一 Transformer」论断,展开自注意力、位置编码与两类架构范式。
- 6.3 (LLM 基础)把生成式的三阶段训练方法论(预训练/指令微调/偏好对齐)系统讲清。
- 6.4 (Codebook 量化)回答本节埋下的关键问题——生成式如何用语义 ID 表示物品。
- 1.1 (两种范式)从直觉层对照,本章把它深化为建模哲学与架构层对照。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 6.1.1 — 区分范式 🟢 Easy
给定以下两个系统描述,判断更接近 判别式 还是 生成式 ,并说明理由。
- (a) 系统为每个候选广告计算「用户点击概率」,按概率排序展示前 5 个。
- (b) 系统读取用户近 20 次播放记录,直接输出「接下来你可能想看的 3 个视频 ID」。
💡 Solution (click to reveal)
Approach: 抓住两种范式「问的问题」差异——是逐候选打分,还是直接产出序列。
- (a) 判别式 :对每个候选单独算点击概率再排序,正是 的「逐一打分择优」。
- (b) 生成式 :直接由历史序列解码出推荐 ID 序列,不做逐候选评估,对应 。
Key points:
- 判别式 = 候选已知、逐一打分;生成式 = 直接「创造」序列。
- 判断关键:系统是否枚举并评估了每一个候选。
Problem 6.1.2 — 列出三大局限 🟢 Easy
请写出判别式范式在迈向生成式时被反复诟病的三道固有局限,并各用一句话说明其后果。
💡 Solution (click to reveal)
答:
- 参数效率 :Embedding 层占 90%+ 参数却稀疏低效,硬件利用率(MFU)偏低。
- 语义建模缺失 :物品被当原子 ID,彼此无语义关联,冷启动难以解决。
- 多阶段级联困境 :各阶段目标不一致、且逐级丢失信息(优质物品被召回误杀后永不可见)。
Key points:
- 这三点都源自「逐候选打分 + 级联」的范式本身,不是工程能单独抹平的。
Problem 6.1.3 — 公式改写 🟡 Medium
判别式的逐候选打分可写作 。请将生成式推荐的核心公式 用自然语言复述,并指出它与判别式在「条件」一侧的本质区别。
💡 Solution (click to reveal)
Approach: 逐部分翻译公式。
答: 该公式读作「用户 在上下文 下产生整个交互序列 的概率,等于每个时刻 在已知之前所有交互 、用户 、上下文 的条件下,生成第 个物品的概率之连乘」。
本质区别:判别式的「条件」是 ——物品 是被给定的;生成式的「条件」是 ——物品是 要被生成出来的变量 ,序列内先前物品作为条件回流。前者对候选打分,后者从条件中创造候选。
Key points:
- 连乘结构 = 自回归,每个 token 依赖历史。
- 「条件侧」在物品 上有无——这是判别与生成的分水岭。
🏆 Challenge: 范式选型论证
某团队要在「日均新增 10 万物品、长尾占比高」的电商场景下重构推荐。请写约 150 字论证:为何此处生成式(语义 ID 路线)比纯判别式更具长期价值?重点结合「冷启动、参数效率、级联信息损失」三点,并指出落地时仍应保留的判别式组件。
💡 Hint
长尾/高频新物品 → 判别式原子 ID 难以积累行为、冷启动严重;语义 ID 让新物品靠内容即获表示,前缀泛化缓解长尾。参数效率上,统一 Transformer 比多阶段异构模块更易 Scaling。但仍建议保留判别式 召回/重排 作为生成式生成的候选约束与体验兜底,采用「渐进式 + 知识增强」混合路径平滑过渡。
生成式架构的基石
📝 Before You Continue: 建议先读完 6.1 的「统一 Transformer」论断,以及 2.3 中对内积与向量空间的直觉。本章不再深究数学推导,而是强调架构的直观理解与推荐场景适配。
理解了生成式推荐的核心思想后,我们来搭建支撑它的技术地基——生成式架构(Generative Architecture)。生成式推荐把推荐建模为序列生成任务,而要产出高质量的序列生成,需要强大的模型架构做后盾。
当前生成式推荐主要依赖两大类架构范式: Transformer 与 Diffusion 模型(扩散模型)。二者生成机制本质不同,却都为生成式推荐提供坚实支撑——Transformer 通过自回归逐 token 生成、擅长捕捉因果依赖;Diffusion 通过迭代去噪从噪声恢复数据、提供全新生成视角。更重要的是,它们 并非互斥 ,而是互补协同。
读完本章,你将能够:
- 用「查询—匹配—聚合」解释 自注意力 的 Q/K/V 计算与多头机制
- 说明 位置编码 (绝对/相对、时间感知)为何对推荐序列不可或缺
- 对比 Encoder-Decoder 与 Decoder-Only 两类架构的优劣与适用场景
- 解释 因果掩码 如何实现自回归生成并支持训练并行
- 概述 Diffusion 的前向扩散/反向去噪及其在推荐中的应用
- 完成 5 道分层练习题,巩固生成式架构的关键机制
6.2.0 为什么是 Transformer 与 Diffusion
自 2017 年《Attention is All You Need》问世,Transformer 已成为 NLP 主流,并扩展到视觉、语音等领域。它成功不只因表达力强,更因其 高度规整的计算模式——海量矩阵乘法能充分利用 GPU 并行,训练/推理效率远超 RNN、LSTM。
对生成式推荐而言,Transformer 的优势尤为明显:
- 长程依赖 :自注意力天然适合捕捉用户行为序列中任意位置间的依赖,无论历史多长都能灵活关注任意时刻信号。
- 并行高效 :可高效处理长序列,这对建模用户完整行为历史至关重要。
- 可扩展 :堆叠更多层、增宽隐层即可提升容量,为推荐模型的 规模化(Scaling) 提供坚实基础。
而 Diffusion 提供了另一种角度:它不从序列起点逐 token 构建,而是从 纯噪声 出发、通过 迭代去噪 逐步恢复目标,类似「从模糊石料雕出清晰形象」。这种全局并行去噪,在某些场景能突破自回归的速度瓶颈。
6.2.1 自注意力机制:查询—匹配—聚合
自注意力的核心创新,是让模型 动态、选择性 地聚焦于序列中的任意位置。它的本质用一句话概括: 给定当前查询(Query),序列中哪些部分(Key)最相关,它们的内容(Value)以多大权重被聚合?
QKV 的三步计算
给定输入序列表示矩阵 ( 序列长、 特征维),先经三个线性变换得到 Query、Key、Value:
- Query :当前位置「想查询什么信息」,可理解为「当前时刻的预测需求」。
- Key :序列每个位置「提供什么信息」,是用来与 Query 匹配的索引。
- Value :序列每个位置「实际包含什么内容」,确定重要性后聚合的就是它。
第二步 计算注意力权重——Query 与每个 Key 的内积(相似度),缩放后 softmax:
缩放因子 防止维度过大时内积方差过大、softmax 过于尖锐(接近 one-hot)、梯度趋零。注意力矩阵第 行即「预测第 个物品时,历史各位置应被赋予的关注度」。
第三步 按权重聚合 Value:
举个具体例子:用户历史 [item1, item2, item3],预测 item4 时,Query 与三个物品 Key 匹配,若注意力权重为 [0.1, 0.3, 0.6],则输出为 0.1·V1 + 0.3·V2 + 0.6·V3——模型自适应地从历史提取信息,而非对所有历史一视同仁。
🧠 Mental Model: 多头注意力是「专家组」
单个注意力头只能学一种「关注模式」。但用户行为受多因素驱动——有时看价格、有时看品牌、有时看功能。多头注意力(Multi-Head Attention) 把 组独立 Q/K/V 并行计算,每个头像个「专家」:第 1 个头可能专盯「同品牌」(买了 iPhone 推 AirPods),第 2 个头专盯「同类别」(买了手机壳推贴膜),第 3 个头专盯「最近行为」。并行多专家让模型从多角度理解序列。
Analysis: 为何不用一个大单头? 个维度 64 的头,总参数量与单个维度 512 的单头相同,但多头让每个头学独立子空间、避免信息混杂,表达力更强。代价是算力随 线性增长。
6.2.2 位置编码与时间感知
自注意力有个天然缺陷: 它对序列顺序不敏感。[item1,item2,item3] 与 [item3,item1,item2] 只要内容相同,计算结果完全一样。但推荐里顺序含关键时间信息——「先买手机再买壳」与「先买壳再买手机」语义不同。位置编码(Positional Encoding) 就是为序列每个位置注入位置信息。
绝对位置编码 :为每个位置 分配固定编码 加到输入上:。经典的正弦编码
确定性、可外推;也可改为 可学习位置编码 (更灵活但不可外推)。
相对位置编码 :不在绝对位置上加编码,而是在注意力计算中引入相对位置偏置 :
泛化更强、更自然处理变长序列(BERT/GPT 用绝对,T5/DeBERTa 用相对)。
推荐特有的时间编码
用户行为序列不仅有顺序,还有 真实时间间隔。例如:
用户A: [item1(1/1)] → [item2(1/2)] → [item3(1/3)] # 密集短期兴趣
用户B: [item1(1/1)] → [item2(3/1)] → [item3(6/1)] # 跨月长期兴趣
顺序相同,时间尺度却迥异。常见做法是将时间戳离散为小时/天/周多粒度嵌入再求和;更前沿如 HSTU 用 相对时间位置编码 :
对数变换压缩时间尺度,让模型对长/短期行为都建模良好。短视频场景间隔仅秒级,电商可跨数周——时间粒度选择对性能至关重要。
6.2.3 两类架构范式:Encoder-Decoder vs Decoder-Only
理解了自注意力与位置编码,我们进入 Transformer 的整体架构设计。生成式推荐主要采用两类范式。
结构差异
Encoder-Decoder(编码器—解码器) 采用双塔:Encoder 用 双向自注意力 处理输入(如用户历史 ,每个位置可看全部前后位置),获得全局理解;Decoder 同时用两种注意力——因果自注意力 (预测第 个 token 只能依赖前 个,保证自回归)与 交叉注意力 (以 Decoder 隐状态为 Query,Encoder 输出为 Key/Value,动态查询输入信息)。代表:原始 Transformer、T5、BART,推荐里 TIGER 最早引入 T5 架构。
Decoder-Only(仅解码器) 采用统一单塔:输入与输出视为连续序列,统一因果自注意力从左到右自回归生成,生成位置可关注所有输入位置与已生成位置。代表:GPT 系列,推荐里 HSTU、RecGPT、OneRec-V2 采用。
| 维度 | Encoder-Decoder | Decoder-Only |
|---|---|---|
| 注意力类型 | Encoder 双向 + Decoder 因果 + 交叉注意力 | 统一的因果自注意力 |
| 参数分配 | 分散在 Encoder/Decoder/交叉注意力 | 集中在 Decoder 层 |
| 计算模式 | Encoder 并行编码 + Decoder 自回归解码 | 完全自回归处理 |
| 序列组织 | 输入输出分离 | 输入输出拼接 |
优劣权衡
Encoder-Decoder 优势 在 结构化信息处理 :解耦「理解用户」与「生成推荐」,Encoder 双向建模完整行为序列,交叉注意力提供显式「查询—检索」模式。特别适合 输入输出异构 场景——如输入是多模态特征(行为序列+画像+上下文)、输出是物品 Semantic ID 序列。OneRec 更把 Encoder 细分为短期/长期/正反馈多个 pathway,处理不同行为信号。
缺点 是 效率与扩展性 :三套注意力机制参数与计算都多;交叉注意力开销随输入长度线性增长;参数分散降低单模块容量,限制 Scaling 潜力。
Decoder-Only 优势 在 简洁与统一 :① 参数效率高——所有参数集中在 Decoder,扩展时新增参数直接增强核心建模;② 工程简化——只有一种注意力,更易算子融合/内存优化,工业部署 MFU 更高(OneRec-V2 达 20%+,Encoder-Decoder 仅 5–10%);③ LLM 生态兼容——主流 LLM(GPT/LLaMA/Qwen)皆 Decoder-Only,可复用其架构配置、训练框架(如 HuggingFace Transformers),只需重初始化物品词表的 Embedding。
缺点 是 单向约束 (因果注意力看不到未来,离线训练损失部分建模力)与 上下文长度压力 (无独立 Encoder 压缩,长行为序列全作上下文输入)。近期工作探索 混合架构 (如 OneRec 的 Lazy Decoder 共享 Encoder KV、Decoder-Only 加双向预训练目标)取长补短。
Analysis: 架构选择无绝对优劣。任务维度:显式区分「理解/生成」或模态异构 → Encoder-Decoder;可表述为「序列续写」→ Decoder-Only。规模维度:充足数据支撑大规模预训练 → Decoder-Only 扩展性更优;小数据小模型(<1B)→ Encoder-Decoder 更易稳定训练。部署维度:极致延迟下,Decoder-Only 因 KV Cache/推测解码等端到端优化可能反而更高效。
6.2.4 因果掩码与 Diffusion 模型
因果掩码:自回归的关键
无论选哪类架构, 因果注意力掩码(Causal Masking) 都是实现自回归的关键。它在 softmax 前对未来位置施加 :
保证预测第 个 token 时只能依赖前 个,信息不泄漏。
因果掩码还带来 训练效率提升 :生成虽自回归,训练时却可并行计算所有位置损失。给定序列 ,模型可 一次前向 同时学习「基于 预测 」「基于 预测 」……每个预测只用了「合法」历史。这是 Transformer 相对 RNN 的重要优势。
推荐场景还发展了 定制化掩码 :Session-level Masking(跨会话边界屏蔽,建模多场景行为)、Task-specific Masking(CTR 看完整序列、CVR 只看已点击子序列)、Bidirectional Prefix Masking(静态特征作 prefix 双向可见,行为序列仍因果,HSTU 采用)。
Diffusion 模型:迭代去噪的生成视角
与 Transformer 逐 token 序列化生成不同, Diffusion 模型 提供全新范式:从 纯噪声 出发,通过 迭代去噪 逐步恢复目标数据。核心是两个互逆的马尔可夫过程:
- 前向扩散 :从真实数据逐步加高斯噪声,经 步得近似纯噪声。
- 反向去噪 :从随机噪声出发,经学习到的去噪网络逐步去噪,恢复真实数据。
按操作空间分两类: 数据空间扩散 (DDPM,直接在原始空间,计算大)与 潜在空间扩散 (Stable Diffusion,先压缩到低维潜在空间再扩散,效率高——推荐场景更常用,因能降成本又提供紧凑语义表示)。还可发展 条件扩散 ,通过拼接/交叉注意力/分类器引导注入用户历史等条件。
Diffusion 在推荐中的应用包括: 特征增强与表示学习 (潜在空间去噪生成鲁棒 embedding,缓解稀疏)、序列生成 (并行去噪整条序列,不受严格顺序约束)、多模态融合、协同过滤与图结构建模 (在交互图潜在表示上扩散)。其挑战在于 多步迭代采样带来推理延迟 ,工业部署需采样加速、模型蒸馏来平衡质量与实时性。
💡 Key Insight: Diffusion 与 Transformer 互补非对立——许多先进 Diffusion(如 DiT)直接以 Transformer 作去噪骨干。生成式推荐可据场景灵活组合两种机制:Transformer 抓因果依赖与并行 Scaling,Diffusion 提供多样性内在支持与全局并行生成。
⚠️ Common Mistakes in 6.2
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 认为自注意力天然感知顺序 | 「注意力已含位置信息」 | 自注意力顺序无关,需显式位置编码 | 必须加位置/时间编码 |
| 2 | 忽略缩放因子 | 直接 softmax(QKᵀ) | 大 内积方差大、softmax 过尖、梯度消失 | 务必除以 |
| 3 | 以为 Encoder-Decoder 总优于 Decoder-Only | 「双塔信息更全」 | 参数分散限制 Scaling,MFU 低 | 据任务/规模/部署权衡 |
| 4 | 因果关系泄漏 | 训练时未加因果掩码 | 未来信息泄露,离线指标虚高 | 加下三角因果掩码 |
| 5 | 把 Diffusion 当 Transformer 的替代 | 「二选一即可」 | 二者互补,可结合(如 DiT) | 按场景组合两种机制 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 自注意力 | Q/K/V 查询-匹配-聚合,多头并行 | 捕捉长程依赖、自适应聚焦 |
| 位置编码 | 绝对/相对 + 时间感知(HSTU) | 让顺序/时间间隔进入建模 |
| Encoder-Decoder | 双向编码+因果解码+交叉注意力 | 适合异构输入输出、结构化建模 |
| Decoder-Only | 统一因果自注意力 | 参数高效、MFU 高、LLM 生态兼容 |
| 因果掩码 | 下三角 ,训练可并行 | 保证自回归一致性与效率 |
| Diffusion | 前向加噪/反向去噪、潜在空间主流 | 并行生成、多样性、与 Transformer 互补 |
❓ FAQ
Q1: 为什么推荐里时间编码比 NLP 更重要?
A: NLP 的「位置」主要是语法顺序;推荐行为还带真实时间间隔(秒级到数月),同一顺序可能对应密集或长期兴趣,需将时间戳/间隔显式编码。
Q2: Decoder-Only 的 MFU 为什么更高?
A: 只有一种注意力机制,计算模式高度统一,更容易算子融合与内存优化,硬件利用率显著高于三套注意力并存的 Encoder-Decoder。
Q3: 因果掩码怎么做到「训练并行、生成串行」?
A: 训练时一次前向对所有位置算损失,但掩码让每个位置只看合法历史;生成时则严格按 逐步解码。
🔗 前后关联
- 6.1 (范式基础)提出「统一 Transformer」论断,本章给出其机制细节。
- 6.3 (LLM 基础)深入 Decoder-Only 的预训练/微调/对齐,呼应本节架构选择。
- 6.4 (Codebook 量化)的语义 ID 是 Decoder-Only 自回归生成的「词表」。
- 7.x (Scaling)承接本节「堆叠即规模化」,展开生成式模型的参数扩展。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 6.2.1 — 注意力权重计算 🟢 Easy
用户历史 [item1, item2, item3],预测 item4 时 Query 与各 Key 内积经缩放 softmax 后得到权重 [0.2, 0.3, 0.5],对应 Value 为 V1=[1,0]、V2=[0,1]、V3=[1,1]。求聚合输出 。
💡 Solution (click to reveal)
Approach: 加权求和各 Value。
Key points:
- 权重和为 1(softmax 保证)。
- item3 权重最大,输出最接近 V3。
Problem 6.2.2 — 缩放因子作用 🟢 Easy
设 ,某 Query 与 Key 内积为 16。若不做缩放直接 softmax 与除以 后 softmax,哪个更「尖锐」?说明后果。
💡 Solution (click to reveal)
答: 不缩放时输入为 16,缩放后为 。softmax 输入越大分布越尖锐(趋近 one-hot)。不缩放会让注意力几乎只盯一个位置,梯度趋零、训练困难。缩放后分布更平滑,利于学习。
Key points:
- 控制内积方差,防止大维度下数值爆炸。
- 这是 Transformer 训练稳定的关键小技巧。
Problem 6.2.3 — 架构选型 🟡 Medium
某团队要构建一个「输入=用户多模态特征(行为序列+画像+上下文),输出=物品 Semantic ID 序列」的检索式生成推荐。请说明理由更倾向 Encoder-Decoder 还是 Decoder-Only,并指出一条改用 Decoder-Only 的可能前提。
💡 Solution (click to reveal)
答: 更倾向 Encoder-Decoder :输入(多模态)与输出(ID 序列) 模态异构 ,双塔可自然解耦「理解用户」与「生成推荐」;交叉注意力让 Decoder 动态查询用户历史。改用 Decoder-Only 的前提:若任务可重述为「序列续写」(把多模态特征与历史拼接成统一序列、预测后续物品),且追求更高 MFU 与 LLM 生态复用、数据量足以支撑大规模预训练,则可转 Decoder-Only。
Key points:
- 异构输入输出 → Encoder-Decoder 占优。
- 序列续写 + 大数据 → Decoder-Only 占优。
Problem 6.2.4 — 因果掩码矩阵 🔴 Hard
对长度为 4 的序列,写出因果掩码矩阵 (下三角 0、上三角 )。并说明训练时模型如何「一次前向」同时学习预测 。
💡 Solution (click to reveal)
答:
训练时,输入完整序列 ,因果掩码使第 1 位只看 (学预测 ),第 2 位看 (学预测 ),第 3 位看前三者(学预测 ),第 4 位看全部但不预测。所有位置损失在 一次前向 中并行计算,但各自只用合法历史——既保证自回归一致性,又获并行效率。
Key points:
- 掩码形状 = 下三角。
- 并行训练是自回归模型相对 RNN 的核心效率优势。
🏆 Challenge: 设计混合推理链路
一款短视频 App 要求「毫秒级」生成 10 条推荐,且希望兼顾生成质量与多样性。请写约 150 字说明:是否应采用纯 Diffusion 或纯 Transformer?能否组合?并指出压缩 Diffusion 推理延迟的两种工程手段。
💡 Hint
不宜纯 Diffusion(多步迭代采样延迟高)也不宜纯 Transformer 若需强多样性。可组合:用 Decoder-Only Transformer 主生成、Diffusion 做候选增强/多样性补全;或 DiT 式以 Transformer 为去噪骨干。压缩延迟手段:采样加速(少步采样/蒸馏)、模型蒸馏把多步去噪压成单步、KV Cache 与推测解码加速自回归。
大语言模型(LLM)基础
📝 Before You Continue: 建议先读完 6.2 的 Decoder-Only 架构与自注意力机制。本节聚焦「LLM 怎么训练出来的」,为后续把这套流程迁移到推荐打基础。
从 Transformer 到 LLM 的演进,不只是参数规模的增长,更重要的是 训练范式的系统化。现代 LLM(GPT-3/4、LLaMA 等)发展出一套完整的「预训练—指令微调—偏好对齐」三阶段训练流程,让模型既能生成流畅文本,又能理解指令、遵循人类意图。
但把 LLM 用到推荐, 并非简单「套用」现成语言模型 ,而要理解其建模原理、针对推荐场景做改造优化。本节系统介绍 LLM 建模基本流程,重点放在与生成式推荐紧密相关的技术环节。
读完本章,你将能够:
- 解释 LLM 三阶段范式(预训练/指令微调/偏好对齐)各自的目标与损失
- 区分 RLHF (含奖励模型与 PPO)与 DPO 的流程差异
- 说明 Scaling Law 与涌现能力对生成式推荐的启示
- 把三阶段范式 映射 到推荐场景,并指出物品 Token 化等特有挑战
- 完成 4 道分层练习题,巩固 LLM→推荐的知识链条
6.3.0 LLM 三阶段范式总览
当前主流 LLM 遵循「预训练—指令微调—偏好对齐」三阶段范式,最早在 InstructGPT 系统化,被 GPT-4、Claude、LLaMA 广泛采用。三者目标递进,共同构成完整的能力构建体系。
- Step 1(SFT) :收集人类示范数据做监督微调,让模型初步学会遵循指令。
- Step 2(RM) :收集对比数据训练奖励模型,自动评估输出质量。
- Step 3(PPO) :以奖励模型为反馈,用强化学习持续优化生成策略,并以 KL 散度约束防止偏离参考模型过远。
🧠 Mental Model: 从「续写器」到「助手」
预训练后的 LLM 只是个「文本续写器」——给它一段开头,它自然往下写,但不懂「你要它做什么」。指令微调像上岗培训(教它理解任务指令);偏好对齐像价值观校准(教它什么是更好的回答)。三步之后,它才从「补全工具」变成「可靠助手」。
6.3.1 预训练与指令微调
预训练:语言能力基础
预训练(Pre-training) 是第一阶段,也是最耗算力的阶段。目标是在 大规模无标注文本 上学习通用语言表示与生成能力,完全依赖 自监督学习 (数据自身构造信号,无需人工标注)。
训练目标:因果语言建模(CLM) ,也称 下一个 token 预测(Next Token Prediction) :
其中 。模型最大化该似然,掌握语言统计规律、语法、语义乃至常识推理。
当模型规模与数据规模达到一定程度,会涌现 Scaling Law(规模化效应) :性能随参数量、数据量、计算量持续提升,甚至出现零样本/少样本等 涌现能力(Emergent Abilities)。
Analysis: 现代 LLM 多为 Decoder-Only 架构(GPT/LLaMA),简洁高效、适合大规模训练。参数从数十亿到数万亿(GPT-3 175B、PaLM 540B、LLaMA-2 7B–70B、GPT-4 估计超 1T)。预训练需数千到数万 GPU/TPU、数周至数月,成本极高——多数团队直接在开源预训练模型(LLaMA、Mistral)上微调。
指令微调:遵循指令
预训练模型只会「文本补全」,不等于「理解并执行指令」。指令微调(Instruction Tuning) 又称 监督微调(SFT) ,解决「让模型理解任务指令并按要求生成」。
核心是构造「指令—输入—输出」三元组,例如:
指令:总结下面这段文字的主要内容。
输入:[一段关于人工智能发展历史的文字]
输出:[人工智能从1950年代……经历了多个发展阶段……]
训练目标:条件语言建模损失 ,仅对输出部分计算:
其中 是条件信息(指令+输入), 是目标输出。关键:损失只在输出 token 上算 ,指令与输入不参与梯度更新。可采用全参数微调或参数高效方法(如 LoRA)。经 SFT 的模型在零样本/少样本任务上显著超越纯预训练模型——它学会了「理解指令」这一元能力。
6.3.2 偏好对齐与从 LLM 到推荐
偏好对齐:RLHF 与 DPO
即便经指令微调,LLM 输出仍可能有用性不足、幻觉、安全风险。根源是 SFT 只学「人类会怎么答」,未优化「什么回答更好」。偏好对齐(Preference Alignment) 让输出更符合人类价值观与偏好。
RLHF(基于人类反馈的强化学习) 三步走:
- 收集偏好数据 :同一 prompt 让模型生成多个输出,人类标注者排序,得偏好对 ( chosen, rejected)。
- 训练奖励模型(RM) :
- 策略优化(PPO) :最大化奖励、同时用 KL 散度约束防偏离参考模型:
DPO(直接偏好优化) 更简洁:核心思想是「奖励模型可用策略模型自身隐式表示」,无需显式训练 RM、无需强化学习:
DPO 训练类似监督学习,简单稳定,效果常媲美甚至超越 RLHF,近期被广泛采用。
三阶段范式向推荐映射
LLM 的三阶段为推荐提供完整能力框架,但每阶段都需重新定位:
| LLM 阶段 | 推荐适配方向 | 核心挑战 |
|---|---|---|
| 预训练 | 用户行为序列预训练、多模态内容预训练 | 如何表示物品?如何平衡语言能力与推荐能力? |
| 指令微调 | 推荐任务指令化、多任务联合训练 | 如何设计推荐指令?如何处理 ID 化物品? |
| 偏好对齐 | 隐式反馈对齐、业务指标优化 | 如何构造偏好数据?如何平衡多目标? |
- 预训练 :核心是「让模型同时掌握语言理解与推荐建模」。过度强调语言会忽视协同信号,过度聚焦行为会削弱语义——需权衡:内容型物品(新闻/视频)语言能力更重要,协同丰富型(电商/音乐)行为建模更重要。
- 指令微调 :难点是 物品以 ID 形式存在 ,对语言模型是完全陌生符号。必须把这些 ID「翻译」成模型能懂的语义表示——这正是 物品 Token 化 的核心,也是连接传统推荐数据与生成式模型的关键桥梁(见 6.4)。
- 偏好对齐 :推荐反馈多为 隐式 (点击、时长、跳过),目标常 多维度 (点击率、留存、生态健康)。如何从隐式反馈构造有效偏好信号、在多重指标间权衡,比 LLM 更微妙。
推荐场景的特殊挑战
除三阶段适配,生成式推荐还要直面 LLM 领域少有的四类挑战:
- 物品 Token 化 :自然语言 token 自带语义,推荐物品 ID 是抽象数字、对模型无意义。如何注入语义、刻画 ID 间相似?—— 第 6.4 节核心议题。
- 协同信号融合 :「买 A 的用户也买 B」无法从文本描述获得,需精心设计把协同信号注入生成式架构。
- 冷启动 :新物品/新用户缺乏交互,生成式可借 LLM 语义理解从内容特征快速建立能力,但需培养模型「有交互靠协同、无交互靠内容」的自适应切换。
- 实时性 :在线服务常要求数十毫秒内完成;自回归逐 token 生成延迟可能数百毫秒。需推理优化(量化、KV Cache、推测解码)与系统级创新(混合架构、离在线结合、缓存)。
💡 Key Insight: 生成式推荐不是「把语言模型套到推荐上」,而是把推荐问题重新概念化为序列生成问题,并针对推荐独特性深度适配。它借鉴 LLM 成功范式,又创造性解决推荐特有挑战——这串知识链正是后续章节(Scaling 架构、端到端生成、会思考的推荐、扩散模型)的基础。
⚠️ Common Mistakes in 6.3
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把 SFT 损失算在全部 token 上 | 指令也参与梯度 | SFT 只对输出算损失,输入/指令是条件 | 损失仅在 上 |
| 2 | 以为 RLHF 不需要参考模型 | 直接最大化奖励 | 易「欺骗」奖励模型、质量退化 | 加 KL 约束到 |
| 3 | 混淆 RLHF 与 DPO 复杂度 | 「两者都要训奖励模型」 | DPO 隐式表示奖励,无需显式 RM/RL | DPO 训练似监督学习 |
| 4 | 直接套用 LLM 词表到物品 | 「用现成 tokenizer 编码商品」 | 物品 ID 对 LLM 是陌生符号 | 需物品 Token 化(见 6.4) |
| 5 | 忽视推荐偏好对齐的多目标 | 「用点击率当奖励就行」 | 隐式反馈+多目标需精细构造 | 显式处理多目标与隐式信号 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 预训练 CLM | 通用生成能力基础,Scaling Law 涌现 | |
| 指令微调 SFT | 条件语言建模,仅输出算损失 | 从「补全」到「遵循指令」 |
| RLHF | RM + PPO + KL 约束 | 价值观对齐,但流程复杂 |
| DPO | 隐式奖励,似监督训练 | 简单稳定,近期主流 |
| 推荐映射 | 三阶段→行为预训练/任务指令化/隐式对齐 | 每阶段需重新定位 |
| 四类挑战 | Token 化/协同/冷启动/实时性 | 决定能否从研究走向落地 |
❓ FAQ
Q1: DPO 为什么比 RLHF 更简单却常更有效?
A: DPO 把「训练奖励模型 + 强化学习」合并为一步——奖励由策略与参考模型的比值隐式表示,训练像普通监督学习,避免了 RL 的不稳定与额外 RM。
Q2: 推荐里为什么偏好对齐更难?
A: LLM 有显式人类偏好排序;推荐的反馈多为隐式行为(点击/跳过),目标多维且常冲突,构造「什么是更好」的信号更微妙。
Q3: Scaling Law 对推荐意味着什么?
A: 与 LLM 类似,生成式推荐模型的性能随参数/数据/算力提升而持续提升,这正支撑了 [6.2] 中「堆叠即规模化」与后续 Scaling 章节。
🔗 前后关联
- 6.2 (架构基础)的 Decoder-Only 正是 LLM 预训练的主架构。
- 6.4 (Codebook 量化)解决本节反复提及的「物品 Token 化」桥梁问题。
- 8.x (端到端生成)落地三阶段范式到推荐的训练管线。
- 9.x (会思考的推荐)深化偏好对齐与推理式生成的结合。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 6.3.1 — SFT 损失范围 🟢 Easy
指令微调样本:指令「翻译为英文」、输入「你好世界」、输出「Hello world」。若输出分词为 2 个 token,训练时损失应覆盖哪些 token?指令与输入 token 是否参与梯度更新?
💡 Solution (click to reveal)
答: 损失仅覆盖输出 token Hello 与 world(2 个),逐位算 。指令「翻译为英文」与输入「你好世界」作为条件 不参与梯度更新——模型只学「给定指令+输入,如何生成正确输出」。
Key points:
- 条件语言建模:条件固定,仅输出算损失。
- 这是 SFT 与预训练 CLM 的关键区别。
Problem 6.3.2 — 奖励模型损失 🟢 Easy
偏好对 ,奖励模型给出 。写出 RM 损失项 的计算,并说明它鼓励什么。
💡 Solution (click to reveal)
Approach: 代入。
;;损失项 。
答: 该损失小(接近 0)说明奖励模型已正确给 更高分。RM 损失整体鼓励「对更优输出给更高奖励分」,使 RM 能自动评估任意输出质量。
Key points:
- 把分差压成概率。
- RM 学的是「相对优劣」而非绝对分数。
Problem 6.3.3 — RLHF vs DPO 🟡 Medium
简述 RLHF 与 DPO 在「是否需要显式奖励模型」「是否使用强化学习」「训练稳定性」三方面的差异。
💡 Solution (click to reveal)
答:
| 维度 | RLHF | DPO |
|---|---|---|
| 显式奖励模型 | 需要(单独训 RM) | 不需要(策略与参考模型比值隐式表示奖励) |
| 是否用 RL | 用 PPO 强化学习 | 不用,训练似监督学习 |
| 训练稳定性 | 较低(RL 易不稳、易骗 RM) | 较高(无 RL、无独立 RM) |
Key points:
- DPO 用参考模型 替代 RM + RL。
- DPO 近期更受青睐,因简单稳定且效果可比。
🏆 Challenge: 推荐偏好对齐设计
某音乐 App 想用偏好对齐优化推荐,但其只有隐式信号(播放完成率、收藏、跳过)。请写约 150 字说明:如何从隐式行为构造偏好对 ?需兼顾哪些业务目标(至少列 2 个)?并点明与 LLM 显式排序的本质差异。
💡 Hint
构造:对同一用户同一上下文生成多个候选序列,用隐式信号定义优劣——如完成率高且收藏的 ,跳过多/完成率低的 。兼顾目标:用户留存、内容生态健康(多样性/长尾)。本质差异:LLM 有人类显式排序,推荐靠行为 proxies 推断偏好,噪声大、且多目标常冲突需加权,非单纯「好坏二分类」。
推荐中的 Tokenizer 技术:Codebook 量化与语义 ID
📝 Before You Continue: 请先读完 6.3 反复提及的「物品 Token 化」问题,以及 6.2 的 Decoder-Only 自回归生成——语义 ID 正是喂给它的「词表」。
在 [6.3] 我们指出, 物品 Token 化(Item Tokenization) 是连接传统推荐数据与生成式模型的关键桥梁。本章直面这个核心问题: 如何把推荐系统中的物品,转化为生成式模型能理解、能生成的 Token 序列?
读完本章,你将能够:
- 对比 稀疏 ID / 文本 ID / 语义 ID 三种范式的优劣
- 说明语义 ID 的「可控词表、层次结构、从记忆到推理」三大价值
- 推导 VQ-VAE 的量化与三损失,理解 直通估计器(STE)
- 解释 RQ-VAE 的残差量化如何生成层次化语义 ID
- 了解 RQ-Kmeans / RQ-OPQ 等工业级解耦与混合方案
- 完成 5 道分层练习题,并用交互演示感受量化过程
6.4.0 三种 Tokenizer 范式演进
理解物品表示的三种主流范式,是技术选型,更是建模哲学的转变。
稀疏 ID 范式(Sparse ID-Based)
传统做法:为每个物品分配唯一原子 ID(如 item_10086)。判别式模型中,ID 经 Embedding 层映射到连续向量,再经深度网络学交互。代表:HSTU(把行为组织为 [item, action, timestamp, ...] 结构化序列)、GenRec(生成式架构中直接用稀疏 ID)。
优势 :无碰撞保证、特征交互自由、工程成熟。
但迁移到生成式时面临 三大根本困境 :
- 词表爆炸 :生成式在词表上做下一 token 预测,Softmax 复杂度 。GPT-3 词表约 5 万、LLaMA 约 3.2 万尚可承受;但抖音数十亿视频、淘宝数亿商品的词表达十亿级,Softmax 难以承受。
- 存储与泛化的双重困境 :十亿 ID 各维护 256 维 Embedding 约需 1TB 参数;更致命的是 原子 ID 正交 ,新物品对模型是陌生符号,须从零积累数据才被「认识」。
- 协同信号隐式依赖 :ID 相似度只能靠海量行为统计「看过 A 也看 B」才学习,数据稀疏时急剧恶化。
文本 ID 范式(Text-Based)
既然 LLM 擅长自然语言,为何不用文本表示物品?把属性/描述序列化为自然语言,用 LLM 预训练词表(3–5 万)编码生成。代表:M6-Rec(模板填充属性为文本)、LLMTreeRec(树状层次文本)、TallRec/P5(键值对复用 T5)。
优势 :语义丰富、零样本泛化、可解释强。
两大致命缺陷 :
- 表示效率低 :一个商品需数十到上百 token(iPhone 例约 30 token),自注意力 计算量随长度平方增长,信息密度稀疏。
- Grounding 困难 :生成文本如何精确映射回候选集?存在歧义(「Apple 手机」匹配数百机型)、不完整、候选集外问题。BIGRec 用两阶段+L2 重排弥补,却违背端到端初衷。
语义 ID 范式(Semantic ID-Based)
语义 ID(Semantic ID, SID) 是对前两者的革命性超越:把物品表示为 固定长度的离散 token 序列 ,每个 token 来自可控大小的语义码本(数千到数万)。以 TIGER 为例,一段「NBA 球星扣篮集锦」视频编码为:
SID = [10, 5, 42] # 体育竞技 → 篮球 → 扣篮集锦
三大核心优势 :
- 可控的固定词表 :无论物品库多大,基础语义单元有限。词表 、序列长 时,理论可表示 个物品,远超任何实际库。OneRec 用约 8000、OneSearch 用 4000–6000 词表,使端到端自回归训练开销可控。
- 天然层次化结构 :SID 是层次化序列,前缀粗粒度(「体育」)、后缀细粒度(「篮球扣篮」)。天然支持 前缀匹配——先定大类再细化,与人类认知一致;相似物品共享前缀,提供结构化归纳偏置。
- 从记忆到推理的跨越 :原子 ID 只能「死记」关联;语义 ID 把相似关系 编码在 token 结构里——所有篮球视频共享
[10,5,...]前缀。一旦模型学会用户喜欢「篮球」这一语义,便能泛化到所有含该 token 的新物品,即使从未出现于训练数据。
💡 Key Insight: 语义 ID 巧妙平衡了表征能力、计算效率、精确 grounding 三者的矛盾,是当前工业级生成式推荐的主流选择——既能被 LLM 高效处理,又保留推荐赖以工作的协同信息。
6.4.1 从原子 ID 到语义 ID 的设计哲学
传统原子 ID(ID:10086)在判别式架构运作良好——Embedding 层把 ID 映射连续向量,海量行为让两部成龙动作片 ID 的向量彼此接近。但重构为生成式问题时,它与生成式架构 根本性不兼容 :生成式需在离散 token 空间概率建模,而原子 ID 的超大规模词表使建模在数学与工程上都不可行。
语义 ID 的核心思想是把物品从「身份标识」转为「语义描述」——不用随机数字标记,而用一串承载语义的 token 序列表征内容属性。类比:你不会说「推荐 ID:89757」,而会说「推荐一部科幻悬疑片,讲 AI 觉醒,视效震撼」——这段描述通过 层次化概念组合 (科幻→悬疑→AI→视效)唯一确定影片,并天然编码相似性(所有科幻片共享「科幻」前缀)。
工程实现中,语义 ID 综合两类信号:
- 内容信号 :多模态特征(画面/标题/图片)经预训练编码器(CLIP、BERT)提取语义向量。
- 协同信号 :用户-物品交互矩阵蕴含的群体行为模式。
两类信号联合编码为连续语义向量,再经 离散化编码 (向量量化)转为 token 序列,如「NBA 扣篮集锦」→ [体育竞技, 篮球, 扣篮, 集锦] → 数字 [10, 5, 42, 89]。
三个层面的根本性改进
- 可控固定词表 :来自序列的组合性质——有限基础单元组合表达海量物品。
- 层次化结构 :纵向(粗→细粒度递进)+ 横向(同层相似物品聚近)。模型学到用户喜欢 token 5(篮球)后,自然迁移到所有
[10,5,...]物品,实现 基于前缀的泛化。 - 从记忆到推理 :一阶推理(同前缀物品 B 似 A)、二阶推理(跨类「篮球→足球」迁移)、组合推理(「教学+篮球」→ 篮球教学视频)。冷启动/长尾下仍强,是语义 ID 成主流的根本原因。
6.4.2 VQ-VAE:离散化的奠基
VQ-VAE(Vector Quantised-VAE) 是语义 ID 离散化的奠基技术,解决「将连续高维语义转为离散符号序列、同时保持表征力」的关键问题。它引入 可学习码本(Codebook) ,建立连续语义空间到离散符号空间的有效映射——既大幅降维(十亿原子 ID → 万级码本),又赋予 ID 间语义关联。
三阶段架构
① 编码器映射 :编码器 把输入 映射为连续潜在向量 ( 实现降维)。
② 向量量化 :维护可学习码本 ( 数千到数万),量化即最近邻搜索:
将连续 离散化为码本索引 。数值推演 :若 ,码本 、,则距 为 、距 为 ,选 即 ——把连续空间「坍缩」到最近离散点。
③ 解码器重建 :。整体:。
损失函数(三部分协同)
- 重建损失 :度量重建质量(图像用 ,文本用余弦)。
- 码本损失 :用 (停止梯度)推动码本向量 靠近编码器输出,梯度只更新码本 、不影响编码器。
- 承诺损失 ( 建议 0.25):约束编码器输出不远离量化码字,防训练不稳定。
梯度传播:直通估计器(STE)
量化 几乎处处不可导,标准反向传播失效。VQ-VAE 用 STE :前向严格执行离散化,反向把量化视为恒等映射 ,把解码器梯度直接传回编码器。梯度流:编码器收重建(经 STE)+承诺梯度;解码器仅收重建梯度;码本仅收码本损失梯度。
Analysis: 注意 VQ-VAE 名含「VAE」却与变分自编码器本质不同——它直接优化重建损失、用离散码本做表示学习,更接近普通自编码器,不引入 KL 约束 ELBO。
6.4.3 RQ-VAE:层次化残差量化
VQ-VAE 把每个物品映射为 单一 离散 token,面临「表征精度—码本规模」权衡:增大 提精度但训练不稳、减小 则单 token 难捕复杂多维语义。
RQ-VAE(Residual Quantised-VAE) 用 残差量化 根本打破限制:把单次量化扩展为 层级联,每层捕获上一层遗漏的残差,生成长度为 的 token 序列。码本规模仍控为 ,理论表征容量升至 。
残差量化迭代机制
给定编码器输出 ,第 层():
其中 ,最终量化表示 ,语义 ID 即令牌序列 。
数值推演(残差逼近) :目标 (1 维),两层码本。Layer1 码本 ,最近 ,残差 ;Layer2 码本 ,最近 ,残差 。重建 ,误差从 0.5 降到 0.1。
层次化语义涌现 :逐层逼近天然形成层次——前期层捕粗粒度(「体育」),后续层捕细粒度(「篮球教学」)。以「NBA 球星扣篮集锦」为例:
- Layer 1(粗) :最接近 的是「体育竞技」,ID=
[10],残差含「什么体育?」 - Layer 2(中) :残差中最接近「篮球项目」,ID=
[10,5],残差聚焦「比赛还是教学?扣篮还是投篮?」 - Layer 3(细) :用「扣篮动作」 捕获细节,最终
SID=[10,5,42]。
这种「不断对焦」机制使模型只看前缀 [10,5] 也知是篮球视频,实现有效模糊匹配。
损失与梯度
RQ-VAE 损失在 VQ-VAE 上扩展为多层累积:
每层独立优化其码本 ,承诺损失级联防残差偏移。梯度仍依赖 STE,每层量化处独立应用。
下面用交互演示直观感受 RQ-VAE 如何逐层量化一个物品向量、生成层次化语义 ID:
点击「下一步」观察:编码器输出 → 第 1 层量化捕获粗粒度语义 → 残差传递给下一层 → 逐层细化直到生成完整 SID 序列。注意每层的残差如何越来越小。
6.4.4 工业级方案:解耦与混合
RQ-VAE 端到端训练在工业大规模部署有维护难题:每次模型更新都需为所有物品重算 SID。因此基于 解耦 的两阶段方案应运而生。
RQ-Kmeans:聚类解耦
RQ-Kmeans 提出:码本本质是对表示空间的聚类划分,为何不直接用 K-means 构建?它将离散化解耦为两步:① 任意表示模型(BERT/CLIP)得物品连续向量;② 在向量上直接 K-means 聚类建码本。表示模型与码本可独立迭代,新物品量化只需向量检索无需重训。
残差量化框架保留,但把梯度学习换成 K-means:第 层在残差集 上聚类得码本 ,为每个物品分配最近中心索引 ,残差 传下层。最终 ,量化表示 。
与 RQ-VAE 的核心区别是 表示学习与码本构建解耦——新物品可经 Faiss 向量检索快速分配 SID,K-means 的均匀聚类还天然缓解「码本坍塌」。
RQ-OPQ:混合编码
RQ-VAE/RQ-Kmeans 有个关键问题: 最后一层残差被直接丢弃 ,而它含独特属性(特定品牌型号、价格区间)——电商搜索中恰是区分相似物品的关键。
RQ-OPQ 提出混合方案: RQ 处理层次化语义,OPQ(Optimized Product Quantization)处理横向独特特征。OPQ 先学旋转矩阵 把残差投影到更易量化子空间,再分 个子向量独立标量量化,各子空间索引拼接为 OPQ 令牌(隐式码本 )。以 OneSearch 配置 得 表征空间。
完整编码 :RQ-Kmeans 得层次令牌 与最终残差 ;OPQ 把 编码为补充令牌 。最终
OneSearch 实际用 (4096,1024,512 | 256,256):3 层 RQ-Kmeans + 2 层 OPQ,每物品 5 令牌。以 iPhone 15(粉色,256G) 为例:RQ 部分 [102,8,1](电子产品→手机通讯→Apple)确立层级身份;OPQ 把残差中的「粉色」「256G」编码为 [56,99]。最终 [102,8,1,56,99] 既含手机层级事实,又保留特定 SKU 独特属性,完美解决长尾商品区分与召回。
核心挑战与应对
| 挑战 | 根因 | 应对策略 |
|---|---|---|
| SID 冲突 | 量化聚类「码本利用不均」,多物品映射同 SID | 训练时优化(均匀分配、限容)+ 推理时补救(混合编码消歧) |
| 目标不一致 | 表示提取/SID 量化/生成训练三阶段独立优化、缺端到端对齐 | 联合优化(梯度端到端)+ 自监督对齐(循环一致性、迭代适应) |
| 多模态融合 | 内容/协同/场景模态分布不一致,简单拼接无效 | 表示层融合(门控/对比学习)+ 量化层融合(模态特定码本、MoE) |
⚠️ Common Mistakes in 6.4
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 直接把物品 ID 当生成式词表 | 「十亿商品直接做 Softmax」 | 词表爆炸,Softmax 不可承受 | 用语义 ID 压缩到 可控词表 |
| 2 | 以为文本 ID 万能 | 「用自然语言描述物品即可」 | 表示效率低+Grounding 困难 | 语义 ID 兼顾效率与精确映射 |
| 3 | 混淆 VQ-VAE 与 VAE | 「VQ-VAE 用 KL 约束 ELBO」 | VQ-VAE 无变分推断,是直接重建 | 记住它是带码本的自编码器 |
| 4 | 忽视直通估计器 | 「量化可直接反向传播」 | 几乎处处不可导 | 用 STE 把量化当恒等传梯度 |
| 5 | 丢弃 RQ 最后一层残差 | 「残差没用可扔」 | 残差含独特属性,长尾区分关键 | RQ-OPQ 用 OPQ 编码残差 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 三范式 | 稀疏ID/文本ID/语义ID | 语义ID平衡效率·泛化·grounding |
| 语义ID价值 | 可控词表/层次结构/从记忆到推理 | 工业主流选择 |
| VQ-VAE | 编码器-量化器-解码器+三损失+STE | 离散化奠基 |
| RQ-VAE | 残差量化→层次化SID,容量 | 突破单token表征瓶颈 |
| RQ-Kmeans | K-means替代梯度学码本,解耦 | 新物品免重训 |
| RQ-OPQ | RQ层次+OPQ独特属性混合 | 长尾商品精确区分 |
❓ FAQ
Q1: 为什么语义 ID 能缓解冷启动?
A: 相似物品共享语义前缀(如
[10,5,...]),模型学到「篮球」偏好即可泛化到所有含该 token 的新物品,无需靠行为数据死记。
Q2: RQ-VAE 相比 VQ-VAE 多了什么?
A: 残差量化把单 token 升级为 层令牌序列,码本规模不变但容量升至 ,并自然涌现层次化语义。
Q3: 工业界为何偏好 RQ-Kmeans 而非端到端 RQ-VAE?
A: 端到端每次更新要重算全库 SID;RQ-Kmeans 解耦表示与码本,新物品经向量检索即分配 SID,且 K-means 均匀聚类缓解码本坍塌。
🔗 前后关联
- 6.2 (架构基础)的 Decoder-Only 自回归,正是消费语义 ID 序列的「生成器」。
- 6.3 (LLM 基础)把「物品 Token 化」列为迁移核心挑战,本章给出解法。
- 8.x (端到端生成)将 SID 作为 TIGER/OneRec 等模型的输入输出接口。
- 10.x (扩散推荐)的潜在空间扩散与本节码本量化在空间压缩思想上相通。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 6.4.1 — 词表容量计算 🟢 Easy
设语义 ID 码本大小 ,序列长度 。理论最多可表示多少个不同物品?对比稀疏 ID 范式下需为同等数量物品维护的 Embedding 规模(每物品 256 维、float32)。
💡 Solution (click to reveal)
Approach: 组合性质。
个物品。
稀疏 ID 需 字节 字节 艾字节(EB)——完全不可行;而语义 ID 只需 个码本向量(每个码字 256 维 float32 约 1KB,全部码本合计约 32MB)。
Key points:
- 语义 ID 用「短序列组合」表达海量物品,词表可控。
- 这正是解决词表爆炸的关键。
Problem 6.4.2 — VQ-VAE 量化 🟢 Easy
编码器输出 ,码本 。求量化索引与 ,并说明 STE 在反向时如何近似。
💡 Solution (click to reveal)
Approach: 最近邻。
距 : ;距 : 。选 ,,。
反向时 STE 把量化视为恒等:,梯度直接穿过离散跳跃传回编码器。
Key points:
- 前向严格离散,反向近似恒等。
- STE 是训练 VQ 类模型的标配。
Problem 6.4.3 — RQ-VAE 残差 🟡 Medium
目标 ,Layer1 码本 选 ,Layer2 码本 选 。写出每层残差 与最终重建 ,并说明层次语义如何涌现。
💡 Solution (click to reveal)
答:
- Layer1: (代表「整数量级」),。
- Layer2: (代表「小数部分」),。
- 重建 ,误差 (从 降到 )。
层次语义:第 1 层捕获粗粒度(整体量级/大类),第 2 层捕获细粒度(残差细节),逐层细化即「不断对焦」,序列 [5, 0.4] 本身携带由粗到细的结构。
Key points:
- 残差 = 上一层未捕到的信息,传下层。
- 多层叠加容量 ,且天然层次化。
Problem 6.4.4 — RQ-OPQ 必要性 🔴 Hard
说明为何 RQ 最后一层残差不应丢弃,并写出 RQ-OPQ 最终 ID 的结构。以 iPhone 15(粉色,256G)为例解释 RQ 与 OPQ 的分工。
💡 Solution (click to reveal)
答: RQ 残差含物品独特属性(品牌型号、价格、颜色)——电商搜索中恰是区分相似物品的关键,丢弃会令长尾商品无法精确区分。
RQ-OPQ 最终 ID:
iPhone15(粉,256G):RQ 部分 [102,8,1]=电子产品→手机通讯→Apple,确立层级身份(与华为/小米同归「手机」类);OPQ 把残差中「粉色」「256G」编码为 [56,99],专用于精确匹配用户具体属性约束。最终 [102,8,1,56,99] 既含层级事实又保留 SKU 独特性。
Key points:
- RQ 管共性语义,OPQ 管个性特征。
- 混合编码兼顾召回(层次)与精确(独特)。
🏆 Challenge: 设计 SID 方案
某电商有 5 亿商品、每日新增 50 万。请写约 150 字说明:应选 RQ-VAE 端到端还是 RQ-Kmeans 解耦?给出词表与层数配置思路,并指出如何应对「SID 冲突」与「新物品上线无需重训全库」。
💡 Hint
选 RQ-Kmeans 解耦 :每日新增 50 万若用端到端 RQ-VAE 需重算全 5 亿 SID,成本爆炸;解耦后新物品经向量检索(Faiss)即分配 SID、无需重训。配置如 3 层 RQ + 2 层 OPQ(参考 OneSearch),码本约 4096–8000。SID 冲突用均匀分配/限容算法缓解、长尾靠 OPQ 独特属性消歧;新物品上线只向量检索不入训练。
传统深度学习推荐模型(DLRM)长期是深度学习 Scaling Law(缩放定律) 的「例外」:砸下更多参数、更多数据,指标却很快触顶。本部分沿着 Meta 的 HSTU 首次验证推荐界 Scaling Law 的脉络,逐一拆解小红书、美团、阿里、字节的后续工作,看清工业界如何把「生成式排序」从论文数字变成服务数十亿用户的现实。
本章涵盖
| 章节 | Topic | The Big Idea |
|---|---|---|
| 7.1 | HSTU:Scaling Law 的首次探索 | 把用户行为历史当作「语言」,用统一序列 + 自回归训练 + 高效架构,首次证明推荐也能 Scale |
| 7.2 | 生成式排序总体范式(GenRank) | 自回归机制才是本质,Action-Oriented 序列组织让序列长度减半、训练提速 ~79% |
| 7.3 | MTGR:混合范式建模 | 用「生成式架构 + 判别式目标」保留交叉特征,破解纯生成式的特征缺失难题 |
| 7.4 | RankMixer:硬件效率优化 | 从 GPU 硬件特性反推架构,用 Token Mixing / Per-Token FFN / Sparse MoE 把 MFU 从 4% 拉到 45% |
| 7.5 | OneTrans:统一 Transformer | 单一 Transformer backbone 同时做序列建模与特征交互,并复用 KV Caching 等 LLM 系统优化 |
What You'll Be Able to Do After This Part
- 🟢 解释 为什么传统 DLRM 难以 Scale,以及 HSTU 如何用 user-level 序列建模打破瓶颈
- 🟢 区分 生成式范式里「自回归机制」与「训练范式细节」各自的贡献(见 7.2)
- 🟡 说明 MTGR 的混合范式如何在保留效率的同时兼容传统交叉特征(见 7.3)
- 🟡 分析 RankMixer 的 hardware-aware 设计如何把 MFU 从 4% 提升到 45%(见 7.4)
- 🔴 复述 OneTrans 如何用统一 Transformer + Pyramid Stack + Cross-Request KV Caching 实现整体可扩展(见 7.5)
- 🔴 对比 五个工作在「统一性 vs 效率 vs 兼容性」三角上的不同取舍
核心概念
| Concept | 章节 | Relevance |
|---|---|---|
| 行为序列建模(user-level) | 7.1 | 把推荐当作「语言」是 Scaling Law 的前提 |
| Pointwise Aggregation / 相对时间偏置 | 7.1 | HSTU 针对推荐场景的三大架构创新 |
| 自回归本质是生成式的核心 | 7.2 | 区分「手段」与「目的」的分水岭 |
| Action-Oriented 组织 | 7.2 | 序列长度减半的关键技巧 |
| 混合范式(生成架构 + 判别目标) | 7.3 | 兼容交叉特征的新思路 |
| Group LayerNorm / Dynamic Masking | 7.3 | 让异构 token 在同一 Transformer 中共存 |
| Token Mixing / Per-Token FFN / Sparse MoE | 7.4 | hardware-aware 重构推荐计算图 |
| 统一 Tokenization / Mixed Parameterization / Pyramid Stack | 7.5 | 序列与特征在单一 backbone 内深度融合 |
前置知识
- 已读完 Part 1 引言 与 第 3 部分 排序 的判别范式基础
- 了解 Transformer 的自注意力、LayerNorm、残差连接基本概念
- 知道 Scaling Law 在 NLP/CV 中的含义(性能随算力/数据/参数量呈幂律提升)
本部分是「生成式推荐主线」下篇的第二站。若尚未读 Part 6 生成式范式基础,建议先建立生成式检索与语义 ID(RQ-VAE)的背景。
Tips for This Part
- 区分「手段」与「目的」。 生成式架构(Transformer + 序列)是强大的表征手段,但不必服务于生成式目标——这正是 7.3 MTGR 的洞见。
- 每个工作都在回答同一个问题 :推荐模型如何真正享受 Scaling Law 红利?从架构、训练、特征、硬件四个角度反复对照。
- 多配图、少死记公式。 本章偏前沿,重点理解「为什么这样设计」,而非精确推导每一条公式。
Let's dive in! 🚀
HSTU:Scaling Law 的首次探索
📝 Before You Continue: 请先建立 3.1 Wide & Deep 的判别式排序认知。本章会反复对比「传统 DLRM 逐候选打分」与「生成式序列建模」的差异——理解前者的瓶颈,才能体会 HSTU 的动机。也建议先读 6.1 生成式推荐范式 了解语义 ID 与生成式检索的背景。
过去十年,深度学习在 CV 与 NLP 领域疯狂 Scaling:ResNet 把网络深度推到上千层,Transformer 参数量突破万亿,并涌现出惊人的智能行为。它们背后有一个共同规律——只要架构合适,模型性能会随计算量、数据量、参数量的增加而持续提升,且遵循可预测的幂律关系 ,这就是著名的 Scaling Law(缩放定律)。
但推荐系统长期是这个规律的反例。工业界投入巨资精心设计数千个特征、搭建复杂的 DLRM 架构、每天处理数十亿用户数据,性能却很快触顶。增加参数、扩大数据,往往只换来微小甚至为零的收益。问题出在哪?本章将带你从传统 DLRM 的三大瓶颈出发,走到 Meta 用 HSTU 首次验证「推荐也能 Scaling」的完整故事。
读完本章,你将能够:
- 说出传统 DLRM(Deep Learning Recommendation Model) 难以 Scaling 的三个根本性限制
- 解释 Generative Recommender(GR) 如何把行为历史当作「语言」来建模,并实现
user-level的序列训练 - 描述 HSTU 针对推荐场景的三大架构创新(Pointwise Aggregation、相对时间偏置、门控前馈)
- 说明 Stochastic Length 与 M-FALCON 如何分别解决超长序列训练与多候选推理的工程难题
- 复述推荐界 Scaling Law 的实验结论 ,并理解其对推荐基础模型的启示
- 完成 4 道分层练习题,巩固从范式到工程的完整链条
7.1.0 传统 DLRM 的三个根本性限制
要理解 HSTU 为什么是突破,先要看清它突破的是什么。传统 DLRM 在推荐效果上已极其成熟,却有三个让 Scale 失效的硬伤:
首先是 特征瓶颈。DLRM 依赖手工设计的数值型特征(点击率、平均观看时长等统计特征)来压缩历史信息。当模型容量增加时,这些预聚合的特征成为信息瓶颈——模型能力上去了,输入信息的丰富度却没上去。
其次是 架构碎片化。DLRM 由 FM、DCN、DIN、MMoE 等异构模块拼成,每个模块只针对特定交互优化。扩大某个模块容量往往只带来局部改善,难以产生系统性提升。
最后是 训练范式限制。传统 DLRM 采用 item-level(物品级)建模 :对每个候选项独立计算评分 ,每个训练样本只对应一个 三元组。这意味着模型每次只能从一个交互中学到一个监督信号,且计算成本随候选规模 线性增长 ,独立评分机制也无法捕捉候选之间的关联。
💡 Key Insight: 这三个限制共同作用,让传统 DLRM 的「算力增长曲线」几乎停滞。要突破,需要的不是工程修补,而是范式的转变。
7.1.1 范式转变:从物品序列到行为序列
Meta 团队获得了一个关键洞察: 如果把用户的行为历史看作一种特殊的「语言」,会发生什么?
在 NLP 中,GPT 等语言模型的成功建立在一个简洁强大的范式上:给定前文 ,自回归地预测下一个词 。统一序列表示让所有信息编码进 token 序列,自回归训练让每个样本提供多个监督信号,Transformer 则提供强大的序列建模能力与参数效率。
但推荐不是直接照搬语言建模。GRU4Rec、SASRec 早已把用户交互历史建模为序列,却只关注 物品 序列 ,预测下一个物品 ,忽略了推荐系统最关键的信息——用户的行为反馈。
Meta 提出的 Generative Recommender(GR,生成式推荐) 范式,把推荐视为两个交织的随机过程:系统展示内容 ,用户产生行为反馈 (点击、点赞、观看时长等)。完整的数据流是交替出现的内容—行为序列:
这个看似简单的改变影响深远。要建模的不再是 ,而是完整联合分布 。按概率链式法则分解后,立刻揭示两个核心任务:
- 排序任务(Ranking) 对应 ——给定用户历史与当前候选 ,预测用户会产生什么行为 。注意这是 target-aware(目标感知) 的:模型先看到候选,再预测行为。
- 召回任务(Retrieval) 对应 ——给定历史交互,预测下一个该推荐的物品,更接近传统序列推荐。
🧠 Mental Model: 把推荐写成「日记」
传统 DLRM 像是给每件事单独打分:「小明对视频 A 打 0.8 分,对视频 B 打 0.6 分」。GR 则把推荐写成一篇日记:「看了科技博主 A(点赞)→ 看了美食博主 B(收藏)→ …」。模型读完整篇日记,就能预测「接下来你会做什么、想看什么」——而且每读一句,它都同时学到了一个监督信号。
7.1.2 统一异构特征空间
传统 DLRM 的特征是高度异构且碎片化的:类别型(Sparse)特征如用户 ID、物品 ID、创作者 ID,基数可达数十亿;数值型(Dense)特征如点击率、平均时长,是精心设计的聚合统计。它们通过 embedding lookup、特征交叉、MLP 等不同模块处理后再拼接。
GR 要把这些异构特征统一进序列,需要巧妙设计。对类别型特征,核心思路是 时间轴对齐与压缩合并 :
- 找出变化最频繁的「主时间线」(通常是用户交互历史)。
- 对变化慢的特征(关注列表、城市等),采用 段压缩 :把连续相同值只保留首次出现。如
[张三,张三,张三,李四,李四,王五,...]压缩为[张三,李四,王五]。 - 将压缩后的序列按时间戳合并到主时间线,得到统一的类别型特征序列。
对数值型特征,洞察更深:它们通常是对类别型特征的 聚合统计 (「科技话题点击率」本质是「历史中科技物品点击行为」的统计),而基础信号已在类别型序列里。这意味着 若序列模型足够强、序列足够长,理论上可从原始序列自动学出这些聚合特征——用模型容量换特征工程。
形式化地说,传统 DLRM 特征空间 ,GR 统一为 。当序列长度 时:。
左:DLRM 把稀疏/稠密特征分流到不同模块,拼接前信息彼此隔离;右:GR 把所有信息编码进一条统一序列,由单一 Transformer 端到端学习交互。
⚠️ Warning: 完全放弃数值型特征并非免费。论文消融显示:给 DLRM baseline 也用「仅类别型」配置时,性能显著下降。说明低算力场景下,精心设计的数值特征仍有价值。GR 的优势在于用更大容量和更长序列自动学出这些信号——这是「用算力换特征工程」的取舍。
7.1.3 训练效率的飞跃
统一序列表示不仅带来建模优势,更 从根本上改变了训练的计算复杂度。
传统 DLRM:每个样本对应一次交互 ,需一次前向传播。若有 个交互,就要 次前向传播,总计算量 。
GR 下,一个用户序列 总长 。在自回归训练中,它提供 个监督信号 (位置 0 后预测 ,位置 2 后预测 ……)。关键是: 这 个预测能在一次前向传播中并行完成。
Transformer 的 causal mask(下三角掩码)确保位置 只能看 到 ;一次前向传播隐式完成所有前缀编码,每个内容 token 后的位置都用于预测对应行为,它们共享同一次前向的中间结果。
总计算量从 降为 ——训练效率提升约 倍。用户平均 500 次历史交互时,就提升 500 倍。这意味着 用同样算力预算,可训练复杂度高一到两个数量级的模型。
💡 Key Insight: 这是 GR 突破 Scaling 瓶颈的第一个关键因素——它提供了足够的计算空间去尝试更深的网络、更大的容量。但还不够,还需要一个为推荐场景量身设计的高效架构。
7.1.4 HSTU 架构:为推荐优化的序列模型
直接用标准 Transformer 行不行?在 NLP 已证明强大,但推荐场景有独特性。Meta 设计的 HSTU(Hierarchical Sequential Transduction Unit,层级序列变换单元) 做了三个关键架构创新。
创新一:Pointwise Aggregation 取代 Softmax Attention
标准 Transformer:。Softmax 归一化让注意力权重和为 1,学习的是历史 token 的 相对重要性。
但推荐里我们不仅要知道「哪些历史重要」,还要知道「它们有多重要」。例如:用户 A 科技点 10 次、娱乐点 1 次;用户 B 科技点 100 次、娱乐点 10 次。Softmax 下二者分布可能都是 90%/10%——抹去了用户 B 对科技 绝对强度 更高的信息。
HSTU 用 pointwise aggregation 替代 softmax:
其中 是 SiLU 激活(Swish), 是相对注意力偏置, 是逐元素乘。完整输出:, 是门控投影。关键在于 SiLU 把相似度映射到连续值域但 不做全局归一化 ,每个位置权重独立,累加和可以大于 1——模型能学到「这用户对某类内容兴趣很强烈」的绝对强度。
创新二:相对位置编码的重新设计
推荐序列的时间特性与语言序列本质不同:语言位置离散均匀(第 3 与第 5 词距离恒为 2);推荐时间连续且不均匀(两次交互可能相隔几秒或几个月)。
HSTU 引入增强的相对位置偏置 ,不仅考虑位置差 ,还考虑实际时间差 ,并区分 token 类型(内容 / 行为 ):
这让模型学到:最近行为更重要、某些行为衰减更快(浏览 vs 点赞)、内容 token 与行为 token 的关系不同于内容 token 之间。
创新三:简化的前馈网络与门控机制
标准 Transformer 在 attention 后接两层 FFN(中间维度是隐藏的 4 倍),占据大部分参数与算力。HSTU 受 GLU 变体启发,用逐元素门控替代显式 FFN:
门控函数 是轻量变换。好处:(1) 避免 4 倍隐层的 FFN,减少参数量与算力;(2) 降低激活值内存。后者在工业界极重要——超大 batch size(数万到数十万)下激活内存常成瓶颈。HSTU 把每层激活内存从标准 Transformer 的 33 倍隐层维度降到 14 倍,可在同内存预算下训练更深的网络。
📝 Note: HSTU 名字里的「Hierarchical」指可用分层 token 表示超高基数类别特征(如物品 ID 拆成多个 sub-token)。但后续研究发现大多数场景 flat 表示已够用,真正价值在前述三个架构创新。
一个 HSTU Block:Query/Key/Value 投影后,用 SiLU 逐元素聚合(非 Softmax 归一化)引入相对时间偏置,再由门控投影做残差融合。
Analysis: HSTU 三项创新都围绕「推荐场景的特殊性」——绝对兴趣强度(pointwise)、非均匀时间(rab)、大 batch 内存(门控 FFN)。相比直接套标准 Transformer,在效率与效果上都有显著提升,是能部署万亿参数模型的工程基础。
下面用交互演示直观感受 HSTU 如何把「行为历史」逐步变换为「行为预测」:交织序列组织 → causal mask → pointwise aggregation → 候选位置 target-aware 预测 → 一次前向产出多个监督信号。
点击「下一步」或「自动播放」,观察每一步序列如何变化,以及为什么这能带来训练效率的跃升。
7.1.5 训练与推理的工程优化
有了高效架构,超长序列训练与多候选推理仍是难题。HSTU 用两项工程创新分别破解。
Stochastic Length:利用行为的多尺度冗余
自注意力复杂度 ,序列数千上万时难以承受。但用户行为在 不同时间尺度有重复模式 :长期稳定偏好、中期兴趣演化、短期场景需求。基于这个观察,HSTU 提出 Stochastic Length(随机长度) :对长度 的序列,不总用完整序列,而以一定概率随机截取较短子序列。
具体地,若 超过阈值 ,以概率 采样长度 的子序列,否则用完整序列。 控制截断激进度: 小(如 1.6–1.7)截断更激进、训练更快; 时退化为不截断。子序列采样基于特征加权,确保覆盖不同时间尺度。
这带来双重好处:(1) 自注意力复杂度从 降到 ,序列稀疏度可达 80%+,训练数倍提速;(2) 随机子序列起类似 dropout 的正则化作用,迫使模型学更鲁棒的表示,泛化反而更好。实验表明在很大 范围内对质量几乎无负面影响。
M-FALCON:全局成本分摊的推理算法
推理延迟同样关键。排序要对成百上千候选逐一评分,朴素做法需 次前向传播,总计算量 ,累积延迟不可接受。HSTU 的 M-FALCON(Microbatched-Fast Attention Leveraging Cacheable OperatioNs) 用三层递进优化解决:
第一层:Batched Inference——把 个候选拼在一起,修改 attention mask 使候选间不能互看(候选 只能 attend 用户历史),于是 个候选评分可在一次前向并行完成。设 (全部 batch),复杂度降为 ,消除对 的线性依赖。
第二层:Microbatching——当 很大时, 会让 过大。把 个候选分成 个 microbatch(如 与 同量级),在「全并行」与「全串行」间找甜点。
第三层:KV Caching——Microbatching 解锁跨 microbatch 的 KV 缓存:用户历史部分的 在所有 microbatch 相同,首个 microbatch 算完整 ,后续只需算新增候选的 。后续 microbatch 复杂度降到 ,获 倍加速。KV cache 还可跨请求复用(同用户短时多次刷新)。
三层组合:Batched inference 带来数十倍加速,Microbatching + KV Caching 再带来 倍加速,综合可达数百倍——让同等延迟预算下能用复杂数百倍的模型。
Analysis: M-FALCON 是 HSTU 能部署万亿参数模型的工程基石。它把「历史表征计算」与候选数量解绑,每次请求用户侧只算一次,这正是后续 7.5 OneTrans Cross-Request KV Caching 思想的源头。
7.1.6 推荐系统的 Scaling Law
所有技术积木就位后,回到最初的问题: 推荐模型能否像语言模型一样持续 Scale?
Meta 做了系统性 scaling 实验:序列长度从 512 扩到 8192,隐藏维度从 256 到 1024,深度从几层到 24 层。因推荐是流式训练,训练计算量归一化到 365 天,便于与 GPT-3、LLaMA-2 公平对比。指标用召回的 Hit Rate@100/@500 与排序的 Normalized Entropy(越低越好)。
把结果画在对数坐标上, 所有指标呈现清晰的幂律关系 :
其中 是性能指标, 是总训练计算量(PetaFLOPs/day), 是拟合参数。拟合结果:
- 召回:
- 排序:
即 计算量每增 10 倍(一个数量级),HR@100 约提升 4.5 个百分点,NE 约下降 1.2 个百分点。更惊人的是,这个关系在 三个数量级的计算量范围内稳定成立。
左:排序 NE 指标随算力持续下降;右:召回 HR@100 随算力持续上升。两条曲线在三个数量级内稳定,与 LLM 的 Scaling Law 同构。
这个发现意义深远:(1) 首次证明 推荐模型的 Scaling Law,推荐不再是深度学习例外;(2) 可用小规模实验预测大规模性能, 为研发指明方向、降低盲目性与碳排放;(3) 打开了 推荐基础模型(Foundation Model) 的可能——预训练大模型再跨场景微调。最大配置(8192 序列、1024 维、24 层)达 1.5 万亿参数 ,并成功部署到 Meta 多个场景服务数十亿用户,线上 A/B 排序指标提升达双位数百分比。
下面用交互曲线亲自验证 Scaling Law:拖动滑块调节训练计算量,观察 Hit Rate@100 与 Normalized Entropy 如何沿幂律曲线移动;也可点「下一步」看从小规模到万亿参数部署的几个关键场景。
每一步计算量增 10 倍,HR@100 约 +4.5pp、NE 约 −1.2pp——这种可预测性,正是推荐模型能像 LLM 一样 Scale 的根本保证。
7.1.7 为什么 HSTU 能够突破?
回顾整个技术体系,四个层面的创新相互支撑:
- 范式转变是根本——从 item-level 到 user-level,从独立评分到序列生成,解除了计算成本与候选数量的线性绑定。
- 架构创新是关键——attention、位置编码、前馈网络针对性设计,比直接套标准 Transformer 显著提升。
- 工程优化是保障——Stochastic Length 让超长序列训练可行,M-FALCON 让复杂模型推理高效,激活内存优化让大 batch 不再是瓶颈。
- 统一特征空间是基础——异构特征进统一序列,简化特征工程,更让模型端到端学复杂交互、提升参数效率。
这四者缺一不可。HSTU 的成功证明了推荐模型可以 Scale,也留下新问题:哪些因素真正 essential?完全生成式训练是否必需?如何推广到多任务多场景?这些将由后续研究回答——首先是 7.2 的 GenRank,去追问「自回归机制到底是不是本质」。
⚠️ Common Mistakes in 7.1
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为推荐天生不能 Scale | 「DLRM 加参数没用,推荐就是例外」 | 不是推荐不能 Scale,是 item-level 范式 + 碎片化架构绑住了算力 | 理解 HSTU 的 user-level 序列解绑 |
| 2 | 把 GR 当成普通序列推荐 | 「GR 就是 SASRec 加长序列」 | GR 建模内容—行为 交织 序列,且 target-aware 预测行为 | 区分物品序列 vs 行为序列 |
| 3 | 以为 Softmax Attention 够用 | 「直接拿标准 Transformer 当 HSTU」 | Softmax 归一化抹去兴趣 绝对强度 信息 | 记住 pointwise aggregation 的关键区别 |
| 4 | 忽略训练效率的来源 | 「序列建模只是效果更好」 | 一次前向产 个监督信号,训练提速 倍 | 理解 user-level 聚合的算力红利 |
| 5 | 以为 Scaling Law 只对大模型成立 | 「只有万亿参数才谈 Scaling」 | 幂律在三个数量级都成立,小规模即可外推 | 用小实验预测大规模性能 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| DLRM 三限制 | 特征瓶颈 / 架构碎片化 / item-level 训练 | 解释推荐为何长期不 Scale |
| GR 范式 | 交织序列,user-level 自回归 | 统一序列 + 多监督信号,训练提速 倍 |
| HSTU 三创新 | Pointwise Agg / 相对时间偏置 / 门控 FFN | 为推荐场景定制的序列架构 |
| Stochastic Length | 随机截断超长序列 | 训练数倍提速 + 正则化 |
| M-FALCON | Batched→Microbatch→KV Cache | 推理数百倍加速,万亿参数可部署 |
| Scaling Law | ,三数量级稳定 | 首次证明推荐可 Scale,开启基础模型 |
❓ FAQ
Q1: 为什么 Pointwise Aggregation 比 Softmax 更适合推荐?
A: Softmax 强制权重和为 1,只学「相对重要性」;推荐还需「绝对强度」(用户 B 比 A 更爱科技)。SiLU 逐元素聚合不做全局归一化,权重可累加超 1,保留绝对兴趣强度——对预测点击后深度行为至关重要。
Q2: 为什么 GR 训练比 DLRM 快这么多?
A: DLRM 每个交互一次前向,M 个样本 M 次前向。GR 把用户序列一次前向同时预测 个行为(causal mask 下共享计算),总前向数降到 ,提速约 倍。
Q3: 推荐基础模型为什么现在可能了?
A: Scaling Law 证明性能随算力可预测提升,意味着可预训练大规模通用推荐模型再跨场景微调——这是 HSTU 1.5 万亿参数部署后最令人兴奋的方向。
🔗 前后关联
- 7.2(生成式排序/GenRank) 追问自回归是否本质,并用 Action-Oriented 进一步提速——直接延续本章「哪些因素 essential」的设问。
- 7.3(MTGR) 在混合范式下保留交叉特征,回应「完全生成式训练是否必需」。
- 6.1–6.4(生成式基础) 给出语义 ID、RQ-VAE 等前置,理解 item 如何变成 token。
- 3.1–3.5(判别排序) 是本章反复对比的「旧范式」,看清瓶颈才能体会突破。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 7.1.1 — 识别 DLRM 瓶颈 🟢 Easy
某团队把 DLRM 的 embedding 维度翻倍、加深 MLP,但线上 CTR 预估 AUC 几乎没变。请结合 7.1.0 的三个限制,指出最可能的原因(选一个并说明)。
💡 Solution (click to reveal)
Approach: 从「增加容量 ≠ 增加信息」角度判断。
最可能的是 特征瓶颈 :DLRM 用预聚合的数值特征(点击率、平均时长)压缩历史,模型容量涨了,但输入信息丰富度没涨。其次是 item-level 训练——每个样本只一个监督信号,加容量不增加每样本信息量。架构碎片化也可能(单模块扩容只局部改善)。
Key points:
- 算力增长曲线停滞,往往不是参数不够,而是信息/范式被绑住。
- 这正引出 HSTU 的 user-level 序列解法。
Problem 7.1.2 — GR 序列组织 🟢 Easy
传统序列推荐建模物品序列 ,HSTU 的 GR 建模 。请回答:
- GR 序列长度(按 token 数)是物品交互次数 的几倍?
- 排序任务 是 target-aware 还是 target-agnostic?
💡 Solution (click to reveal)
Approach: 直接对应正文定义。
- GR 序列总长 (内容、行为交替),是 的 2 倍。
- 中模型先看到候选 再预测行为 ,是 target-aware。
Key points:
- 交织序列牺牲长度换取行为反馈信号。
- target-aware 是后续生成式排序预测深度行为的基础。
Problem 7.1.3 — 训练效率倍数 🟡 Medium
设用户平均历史交互 ,训练集有 条交互记录。对比 DLRM(每条一次前向)与 GR(按用户序列组织,序列长 )所需的「前向传播次数」数量级。GR 提速约多少倍?
💡 Solution (click to reveal)
Approach: DLRM 前向次数 = 。GR 把 条交互组成 个序列,每个序列一次前向。
次前向。提速倍数 倍。
Key points:
- 加速比 ≈ 平均序列长度 ,因为一次前向产 个监督信号。
- 这解释了「同样算力可训复杂数百倍的模型」。
Problem 7.1.4 — Scaling Law 外推 🔴 Hard
已知召回 HR@100 ( 单位 PetaFLOPs/day)。若算力从 增到 (一个数量级),HR@100 提升多少个百分点?并说明为何这比「盲目堆参数」更可控。
💡 Solution (click to reveal)
Approach: 用对数差值。
。即约 4.5 个百分点 ,与正文一致。
Key points:
- Scaling Law 给出可预测的幂律,小实验可外推大模型性能。
- 相比盲目堆参数(可能触顶),它把研发变成「按算力预算规划性能」的可控工程。
🏆 Challenge: 设计取舍论证
假设你是某中型公司推荐团队负责人,算力仅为 Meta 的 1%。请写一段 150 字内论证:你应直接照搬 HSTU 万亿参数方案,还是先借鉴其「范式转变 + 工程优化」思路做轻量落地?并指出哪两项 HSTU 技术对你最实用。
💡 Hint
算力有限时,万亿参数不可行;但「user-level 序列训练提速 倍」与「M-FALCON 的 KV Caching/批处理」是算力无关的架构红利,最值得借鉴。Stochastic Length 的截断也可直接降训练成本。重点是把范式红利而非参数规模搬过来。
生成式排序总体范式
📝 Before You Continue: 请先读完 7.1 HSTU。本章是 HSTU 的「追本溯源」——它会反复回到 HSTU 的设计决策,追问哪些是必需的、哪些可优化。理解 7.1 的架构与工程,才能体会 GenRank 的取舍逻辑。
HSTU 用万亿参数模型证明了推荐也能遵循 Scaling Law,但这建立在 Meta 的巨型算力之上:万亿参数、数千 GPU、每天数十亿用户数据。这个门槛对绝大多数公司过高。
这就引出一个关键问题: HSTU 的设计中,哪些是必需的?哪些可以优化? 小红书团队在实践中面临这个挑战——他们想为服务数亿用户的系统引入生成式推荐,首先要回答:生成式推荐的有效性究竟来自哪里?
7.2.0 追本溯源:什么才是本质
要优化 HSTU,先理解其有效性来源。HSTU 是复杂系统:生成式架构、自回归训练、序列化组织、统一特征空间共同作用。但工程上需明确每个因素的真实贡献——若某设计只贡献 0.1% 性能却带来 10 倍开销,资源受限时就该放弃。
小红书团队在数千亿真实曝光日志上,以 HSTU 为基准、每次改动一个设计决策做对照实验。第一个要验证的是: 自回归机制是否必要?
回顾 HSTU:用 causal mask 训练,但只在候选物品位置算 loss,历史位置不参与——类似 LLM 的 SFT(用户历史+候选构成 prompt,模型预测行为反馈)。LLM 中 SFT 保持自回归是为延续预训练能力;但推荐通常没有预训练阶段,自回归会不会只是个可选 trick?
两组对照实验:
第一组 :在历史位置也算 loss。若自回归只是可选技巧,更多监督信号应提升性能——但 AUC 显著下降。这可用「one-epoch 问题」解释:用户/物品 ID 等稀疏特征占绝大部分参数,长尾分布下大量 ID 只出现一两次。历史位置算 loss 让模型倾向「记住」每个交互细节,却难以泛化(如小明历史「看科技 A→点赞」,测试时看科技 C,模型没见过此组合)。且推荐常只训一个 epoch,没机会纠正这种过拟合。
第二组 :历史位置用全可见 mask(双向 attention)。从特征交互看应增强表达,但性能仍下降,且随模型增大降幅扩大。全可见 mask 破坏了关键归纳偏置——用户兴趣演化的因果性。Causal mask 强制学因果结构而非任意统计相关。例如允许双向 attention,模型在处理「看科技 A」时能看到后面「点赞」和「看美食 B」,可能学到虚假关联(「因为后面看了美食,所以给科技点赞」)——但现实中 时刻行为不可能被未来影响。
两组实验指向同一结论: 自回归机制是生成式推荐的本质特征。它通过架构约束引入有益归纳偏置,帮模型学行为因果结构,同时抑制对稀疏特征的过拟合。
🧠 Mental Model: 自回归是「因果眼镜」
把 causal mask 想成给模型戴上一副因果眼镜:它只能朝前看,被迫学「过去如何导致现在」。摘掉眼镜(双向 attention)模型会偷看答案、学虚假关联。这副眼镜不是性能负担,而是防止作弊的正则化——这正是自回归本质的来源。
相比之下,样本组织方式影响较小。传统 DLRM 用 point-wise 训练(每样本一次交互),HSTU 用 user-level 组织成序列。但实验显示:保持序列化组织、只在最后位置算 loss(模拟 point-wise),性能几乎没降。说明 user-level 组织主要带来工程便利(高吞吐、易实现 KV Caching),而非性能根本来源。
团队还测了工业常用模块兼容性:SIM、PPNet、PLE 在生成式架构下仍有效;大部分历史聚合特征价值大幅降低(序列建模能自动学统计规律),但 实时特征依然重要 (捕捉训练窗口外新信息)。特征工程简化还释放了系统资源,为处理更大候选集创造可能。
7.2.1 Action-Oriented:重新理解任务本质
HSTU 核心是 interleaving(交织) 公式:,建模为马尔可夫链。但分析计算开销会发现问题:用户 次交互 + 候选,序列长 ,attention 复杂度 。 数千时, 负担沉重。
核心问题: 给定用户历史和候选,我们真正要预测什么? 答案是用户对物品会产生什么 行为反馈 (点击率、观看时长、点赞概率)。在排序任务中,物品是给定 context,行为才是预测目标——物品更像上下文或位置标识符。
仍以小红书排序 100 个候选为例:对每个笔记预测「会不会点 / 看多久 / 会不会赞」。笔记本身(标题、图片、作者)是已知输入,行为反馈才是输出。既然如此,把「笔记」和「行为」平等对待(各占一个 token 位置)是否必要?
基于此,GenRank 演进: 将行为作为序列主体,物品作为行为的属性 :
其中 表示「用户对物品 产生的行为 」——这就是 Action-Oriented Organization(行为导向组织)。
上:HSTU 交织序列每个交互占 2 个 token;下:GenRank 把物品作为行为的属性融合进同一 token,序列长度从 降到 。
技术上每个 token 表示为:
物品 embedding 与行为 embedding 在同一空间直接融合;候选物品用特殊 mask action embedding:。
直接好处: 序列长度减半 (从 到 ),带来 attention 计算减 75%、线性投影减 50%、激活内存减约 50%、KV cache 减半。实验显示仅此一项就带来 78.7% 训练加速。
这会损失信息吗?从信息论看,用户行为受物品内容强烈影响,二者互信息很强。加法让 embedding 在表示空间「对齐」:重要维度信号增强,独特维度信息保留。例如某维度编码「娱乐性」,搞笑视频物品 embedding 0.8、「点赞」行为 embedding 0.6,相加 1.4 信号增强;维度编码「视频时长」只与物品相关,行为 embedding 近 0,保留物品信息;「完播率」只与行为相关,保留行为信息。既然 HSTU 中物品/行为 token 在 attention 中最频繁交互,不如在 token 级就融合,反而减轻 attention 层负担。
Action-oriented 还带来更灵活的 mask:排序对一批候选评分有两个冲突需求——候选评分要独立(真实展示时用户一次只看一个),但都要看完整历史。GenRank 用特定 mask 平衡:历史 token 间 causal mask,候选可 attend 所有历史,但候选间相互屏蔽。这既保证独立性,又为未来扩展到 sequential re-ranking 留空间。
7.2.2 位置与时间:该学习什么、该编码什么
Action-oriented 解决了序列长度,但还有另一瓶颈:位置与时间信息的编码。
HSTU 用相对注意力偏置(RAB):
同时考虑位置差、时间差甚至 token 类型,能让模型学时间衰减等模式。但问题是 计算/存储开销是 :对长度 序列, 是 矩阵,前向要读、反向要算梯度。当 数千时 达数百万,现代训练中内存带宽是瓶颈, 内存访问大量耗在数据传输,GPU 利用率下降。
GenRank 的替代方案: 用轻量级 embeddings 编码绝对信息,用无参数 bias 编码相对信息。
核心思想:位置/时间可分解为两部分——绝对信息(「第几个交互」「何时发生」)用 embedding;相对信息(「两交互相隔多远」)用简单无参数规则。GenRank 用三种轻量级 embeddings:
- Position Embeddings :,记录序列索引;同请求内候选共享位置索引,保证训练/推理一致。
- Request Index Embeddings :,捕捉行为 burst 模式(用户常一次打开连续交互后离开,帮模型区分同 session 内与跨 session 兴趣)。
- Pre-Request Time Embeddings :,编码距上次请求的间隔,实现自适应衰减(高频用户短间隔就有意义,低频用户几小时不算什么)。
三种 embedding 加到 token 表示:。参数量仅几百万,I/O 复杂度 。
对相对信息,GenRank 借鉴 ALiBi(Attention with Linear Biases) :给距离远的 query-key 对施加与距离成正比的惩罚:
ALiBi 三优点:符合直觉(越远影响越小)、无参数( 预定义)、可融合进 FlashAttention kernel。GenRank 扩展到同时考虑位置与时间:
🧠 Mental Model: 参数 vs 规则
把编码策略想成一个分工:复杂的、非线性的模式(如「第几个交互」「属于哪次打开」)交给可学习 embeddings;普适的、近似线性的规律(如「越远越不重要」)直接写进规则。这就像公司里——奇葩个案交给专家处理,通用流程写成 SOP 自动跑,不必事事上会。
历史 token 间用 causal mask(左下三角可见),候选可 attend 全部历史,候选之间对角线屏蔽(相互独立)。
实验显示:action-oriented 加速 78.7%,新 position & time biases 额外加速 25.0%,合计 94.8% 总加速,且 AUC 略升。更简单的设计获得更好效果,验证原则: 好的归纳偏置比纯粹的参数容量更重要。
💡 Key Insight: 从 HSTU 到 GenRank,是推荐从「工程驱动」到「原理驱动」的转变。自回归机制是核心,训练范式等细节可灵活优化。但 GenRank 保持生成式 formulation 的纯粹性——这意味着必须放弃传统 DLRM 中那些需要同时观察历史统计与候选属性的交叉特征。这引出 7.3 的灵魂一问:用户粒度建模的效率优势,是否必然绑定完整生成式 formulation?
⚠️ Common Mistakes in 7.2
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为自回归只是训练 trick | 「去掉 causal mask 加双向 attention 应该更强」 | 破坏因果归纳偏置,学到虚假关联,AUC 下降 | 记住自回归是生成式本质特征 |
| 2 | 以为 user-level 组织是性能来源 | 「按用户聚合序列才让 HSTU 变强」 | 实验:只最后位置算 loss(模拟 point-wise)性能几乎不降 | 它主要带来工程便利(吞吐/KV Cache) |
| 3 | 以为 Action-Oriented 会丢信息 | 「物品行为融成一个 token 肯定丢东西」 | 二者互信息强,加法在对齐维度增强、独特维度保留 | 理解 token 级融合反而减负 |
| 4 | 以为 RAB 的 无所谓 | 「相对位置偏置直接学就行」 | 数千长度时 成内存带宽瓶颈,GPU 利用率降 | 用轻量 embedding + ALiBi 无参数 bias |
| 5 | 混用绝对/相对编码 | 「时间信息全用可学习矩阵」 | 普适规律不必学,过度参数化易过拟合 | 复杂用 embedding,线性规律用规则 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 自回归是本质 | 两组对照实验证因果归纳偏置不可弃 | 区分「手段」与「目的」的分水岭 |
| user-level 组织 | 主要工程便利,非性能来源 | 可灵活调整而不伤本质 |
| Action-Oriented | 行为作主体、物品作属性,序列减半 | 训练加速 78.7%,性能几乎无损 |
| 轻量位置/时间编码 | 3 种 embedding + ALiBi 无参数 bias | 再加速 25%,总 94.8% |
| 归纳偏置 > 参数容量 | 更简设计更好 | 指导资源受限下的优化方向 |
❓ FAQ
Q1: 为什么自回归不能去掉换成双向 attention?
A: 双向 attention 让模型偷看「未来」行为,学到虚假统计关联,破坏用户兴趣演化的因果结构;且随模型增大性能降幅扩大。自回归的 causal mask 是防止过拟合稀疏特征的有益正则化。
Q2: Action-Oriented 把物品融进行为 token,排序时还能区分不同候选吗?
A: 能。每个候选有独立 token ,物品信息通过 区分;候选间 mask 相互屏蔽,保证评分独立。序列减半只减少位置,不混淆候选身份。
Q3: 为什么相对距离衰减用 ALiBi 而非学习?
A: 「越远越不重要」是普适近似线性的规律,直接编码更高效稳定、可融进 FlashAttention kernel;过度参数化反而降训练效率、增过拟合。复杂非线性模式才交给可学习 embedding。
🔗 前后关联
- 7.1(HSTU) 本章所有「追本溯源」都建立在其架构/工程之上,直接回应「哪些因素 essential」。
- 7.3(MTGR) 承接末尾的灵魂一问:效率优势是否必绑定完整生成式 formulation?MTGR 用混合范式给出否定答案。
- 3.4(多目标/MMoE) 文中提到 PLE 在生成式架构下仍兼容,是判别多目标模块的延续。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 7.2.1 — 自回归必要性判断 🟢 Easy
以下两个改动哪个预期会 提升 性能、哪个会 下降 ?说明原因。
- (a) 历史位置也计算 loss(更多监督信号)
- (b) 保持 user-level 序列,但只在最后候选位置算 loss
💡 Solution (click to reveal)
Approach: 对应正文两组实验结论。
- (a) 下降 :历史位置算 loss 让模型记细节、难泛化(one-epoch 过拟合),AUC 显著降。
- (b) 几乎不变 :这正是 GenRank 验证的——user-level 组织主要带来工程便利,非性能来源。
Key points:
- 自回归(causal)是本质,加双向监督反而伤。
- 组织方式灵活,架构约束才是核心。
Problem 7.2.2 — Action-Oriented 序列长度 🟢 Easy
HSTU 交织序列对 次历史交互,序列 token 数是多少?GenRank 的 Action-Oriented 下是多少?attention 计算量(正比于长度平方)相对降低多少?
💡 Solution (click to reveal)
Approach: 直接套公式。
- HSTU: 个 token。
- GenRank: 个 token(行为作主体,物品作属性融合)。
- attention 计算量正比于长度平方:,即 降低 75%。
Key points:
- 序列减半 → 平方级计算大降。
- 这与正文「attention 减 75%」一致。
Problem 7.2.3 — 编码分工 🟡 Medium
GenRank 对「用户第几次打开 App(request index)」和「两个交互相隔多久(相对时间)」分别用什么方式编码?为什么这样分工?
💡 Solution (click to reveal)
Approach: 区分绝对信息 vs 相对信息。
- request index(第几次打开)= 绝对、结构化、不同位置语义不同 → 用 可学习 Request Index Embedding 。
- 相对时间衰减(越远越不重要)= 普适近似线性规律 → 用 无参数 ALiBi bias 。
Key points:
- 原则:复杂非线性用参数,普适线性用规则。
- 避免过度参数化导致的过拟合与 内存瓶颈。
Problem 7.2.4 — 加速归因 🔴 Hard
某团队复现 GenRank:仅做 Action-Oriented 得 78.7% 加速,再加新位置/时间编码得 94.8% 总加速。问新编码相对「已 Action-Oriented 的基线」贡献了多少额外加速?(提示:加速 78.7% 意味着耗时降到 21.3%)
💡 Solution (click to reveal)
Approach: 用耗时比例相乘。
Action-Oriented 后耗时 = 。总加速 94.8% 后耗时 = 。新编码相对 Action-Oriented 基线的加速比 ,即额外约 75.6% 加速 (或说新编码使耗时再降到 )。
Key points:
- 加速是乘性叠加,不是简单相加。
- 这也印证「轻量编码」在 Action-Oriented 之上再省 25% 总耗时。
🏆 Challenge: 设计优化论证
你要在算力有限的场景落地生成式排序。请写 150 字内论证:应优先保留 HSTU/GenRank 中的哪两项设计,可放弃哪类特征工程?结合「自回归是本质」与「实时特征仍重要」两点。
💡 Hint
必保留:(1) 自回归 causal mask(本质,提供因果归纳偏置);(2) user-level 序列组织 + Action-Oriented(工程红利,训练近 80% 加速)。可放弃:大部分历史聚合特征(序列建模自动学),但保留实时特征(训练窗口外新信息)。这正呼应 7.2 的实验结论。
MTGR:混合范式建模
📝 Before You Continue: 已读 7.2 生成式排序。本章承接其末尾的灵魂一问——用户粒度建模的效率优势,是否必然绑定完整生成式 formulation?MTGR 用「混合范式」给出否定答案。
HSTU 证明推荐可遵循 Scaling Law,GenRank 揭示生成式本质是自回归而非训练范式。两者都朝「纯粹性」演进:用统一序列建模替代碎片化特征工程,用端到端 Transformer 替代异构模块。
但这种纯粹性有代价。
在 HSTU/GenRank 中,为实现完整行为序列建模,预测用户对候选的行为时 不能使用任何候选相关的交叉特征(cross features)。这些是工业界多年迭代的宝贵经验——「用户对该类目历史点击率」「用户在该时段对此类内容的偏好」「物品与用户画像匹配度」等,精确捕捉用户与候选的细粒度交互。
美团团队发现一个严峻事实: 去除交叉特征会导致性能显著下降,且即使大幅增加模型规模也无法弥补。这引出根本问题:生成式推荐的用户粒度建模范式,能否与传统 DLRM 的特征工程经验结合?
MTGR(Meituan Generative Recommendation,美团生成式推荐) 给出肯定答案。它的核心贡献不是更快训练或更低延迟,而是提出一种 混合范式 :在保持用户粒度聚合效率的同时,支持 target-aware 的判别式建模。
7.3.0 范式的再思考:生成 vs 判别
HSTU/GenRank 的根本假设
两者都采用交织式建模 ,联合分布分解为 。排序任务对应 ——看起来 target-aware,因为模型看到了候选 。
但问题在于: 候选 是序列的一部分,与历史行为 地位平等。自回归训练时,位置 的预测只能依赖 到 。而交叉特征往往需要「跨越」这种顺序依赖——它们需同时看用户某历史统计(如「科技内容平均停留时长」)和当前候选属性(「这是科技类视频」)再算交互。纯生成式下这种跨越被禁止:若允许 的表示依赖「用户对该候选所属类目的历史偏好」,就破坏了因果性——因为这特征实际已「看到未来」(它针对当前候选 计算)。
GenRank 的 action-oriented 虽压缩序列长度,但没改变根本限制,仍保持严格时序依赖。
美团消融实验给出明确答案: 去除交叉特征后,即使最大规模生成式模型,性能也退化到甚至不如中等规模传统 DLRM。这不是 scaling 能补的 gap,而是信息本身的缺失。
判别式排序的本质
为什么交叉特征如此关键?看排序任务本质:输入是用户历史 + 一组候选,任务是对每个候选预测行为倾向(点击、停留、转化)。这是典型 判别式任务 :给定输入 (历史+候选),预测标签 (行为)。
传统 DLRM 表述为 , 是用户表示, 是物品表示。关键在于: 用户表示 可以依赖于候选物品 。例如「用户对科技类内容平均点击率」只在候选是科技类时才有意义——这是 的交互,二阶甚至更高阶交叉。很多重要信号来自「条件统计」(用户在该时段对此类内容的历史行为、该创作者内容对这类用户的吸引力),它们需同时观察用户子集历史与候选属性再算统计量,在生成式方式中难自然表达。
从概率看,判别式关心条件分布 ,不需建模完整联合分布 。生成式通过分解联合分布得条件分布,却带来额外负担:必须建模 ——即使这不是真正关心的。
MTGR 的核心洞察
用户粒度建模带来的效率提升,本质上来自样本聚合和计算复用,而不一定要求完整生成式建模。
7.3.1 MTGR 的混合范式
MTGR 提出看似矛盾实则巧妙的方案: 用生成式模型的架构(Transformer + 用户粒度聚合),但保持判别式建模目标。
具体数据组织:把同一用户的多个候选聚合到一个样本:
关键差异:
- 历史部分 (User, Seq, RealTime)与 HSTU/GenRank 一致,是用户完整行为序列
- 候选部分 (Cross, Item)不再是历史延续,而是待预测目标,每个候选表示直接包含交叉特征
这打破了「内容—行为交替」的严格时序结构,承认:排序阶段候选是给定输入,不是需生成的中间状态。因此可为每个候选构造针对性特征(含依赖历史统计与候选属性的交叉特征)。
用户/序列/实时 token 编码历史,多个候选 token 各自融合物品特征与交叉特征(如 ctr、pv),并行处理。候选部分包含交叉特征是 MTGR 相对纯生成式的关键优势。
各 token 含义:User tokens(年龄、性别、城市等静态属性);Sequence tokens(长期行为序列);RealTime tokens(近期交互);Candidate tokens(每个候选一个,融合物品+交叉特征)。
这种组织仍保留用户粒度聚合优势:对 个候选,历史部分(User+Seq+RealTime)只编码一次, 个候选 token 并行。复杂度 而非 ,当 时显著提速。但 MTGR 不再建模完整行为序列,只在候选位置算 loss、预测行为——判别式目标允许候选表示含任意用户—物品交叉信息。
💡 Key Insight: MTGR 的哲学是区分手段和目的。生成式架构(Transformer+序列建模)是强大的表征手段,但不必服务于生成式目标;用户粒度聚合是高效计算组织,但不必要求完整因果序列。混合范式在保持效率的同时,恢复了判别式建模的灵活性。
7.3.2 架构创新一:特征到 Token 的映射
统一框架引入交叉特征时,问题出现。考虑 3 个候选:
- 候选1:科技视频,用户科技类历史点击率 0.8
- 候选2:美食视频,用户美食类历史点击率 0.3
- 候选3:科技视频,用户科技类历史点击率 0.8
候选1、3 交叉特征相同,但是不同候选,应独立评分。MTGR 对每个候选构造独立 token,融合:
- 物品固有特征(ID、类目、标签、时长)
- 交叉特征(用户对该类目历史点击率、该时段偏好)
- 位置与时序信息(列表位置、曝光时间)
形式化,候选 :
关键决策: 交叉特征视为候选表示的一部分,而非历史序列一部分。即使候选1、3 交叉特征相同,仍生成两个独立 token(因其他维度如物品 ID、标题不同)。
用户历史部分 token 生成简单:User tokens(每属性一 token)、Sequence tokens(每历史物品一 token)、RealTime tokens(每近期交互一 token)——都是「纯粹」的,不依赖任何候选,只编码历史。
这种非对称 token 组织带来问题: 不同类型 token 处于不同语义空间。User token 编码人口统计,Sequence token 编码行为模式,Candidate token 编码物品+交叉。直接用统一 Transformer 处理,不同语义空间 token 会相互干扰。
7.3.3 架构创新二:Group Layer Normalization
标准 LayerNorm 在 token 特征维度归一化:,假设所有 token 共享相同特征分布,用全局参数 。
但 MTGR 下这假设被打破。考虑一个 batch 的 token 序列:
Age token 激活值可能在 (离散人口统计),Sequence token 可能 (经更多层累积)。全局 LayerNorm 会算所有 token 均值方差再归一化,导致 Age 被「过度放大」、Sequence 被「过度压缩」。更严重的是 语义混淆 :维度 100 在 User token 可能编码「用户活跃度」,在 Candidate token 可能编码「候选热度」,全局归一化把它们混在一起,削弱表达。
MTGR 提出 Group Layer Normalization(GLN,分组层归一化) :按 token 类型分组归一化。
- Group 1: User tokens
- Group 2: Sequence tokens
- Group 3: RealTime tokens
- Group 4: Candidate tokens
每组内独立算均值方差与归一化参数:
其中 是 token 所属组。
左:标准全局 LayerNorm 把所有 token 混在一起,分布与语义相互干扰;右:GLN 按 User/Seq/RT/Cand 四组独立归一化,分布对齐、语义独立。
好处:(1) 分布对齐——同组 token 语义相近、分布相似,独立归一化稳定训练;(2) 语义独立——不同组同维度可编码不同信息,参数独立性保证语义独立。GLN 仅在 LayerNorm 上加 group 信息,计算开销可忽略,却承认重要事实: 混合范式中,不同类型信息应在表示空间保持相对独立,而非强行统一。这原则也体现在 MTGR 其他处(不同组可用不同维度 embedding、不同层处理)——这是统一架构与特征灵活性间的平衡点。
7.3.4 架构创新三:Dynamic Masking
Transformer 自注意力允许任意 token 交互,但序列建模通常需限制以满足因果性。HSTU/GenRank 用 causal mask(下三角)。但 MTGR 混合范式下 causal mask 不再适用——token 序列不严格按时间组织。
回顾 MTGR 组织:。User 静态、Seq 已按时间排序、RealTime 近期(可能与候选曝光时间重叠)、Candidate 并行(不应互见,因真实曝光用户一次只看一个)。简单 causal mask 会有问题:Cand 能看到 Cand,但训练时候选在不同时刻曝光、推理时需同时评分,候选间可见性不合理。
更复杂的是 RealTime 处理。RealTime 记录近期窗口(如最近 1 小时)交互。若把一天多次曝光聚合,RealTime 可能含某候选曝光后的交互,导致 信息泄露。例如:12:00 看候选 A(点击)、12:30 看候选 B(未点)、13:00 看候选 C(点击)。聚合训练时 RealTime 含 13:00 点击,但预测 12:30 的候选 B 时模型不该看到它。
MTGR 的 Dynamic Masking(动态掩码) 用细粒度可见性控制解决,定义三条规则:
规则1:静态序列对所有 token 可见——User 和 Seq 来自聚合窗口前历史,任何候选都可 attend(长期历史对所有候选有意义)。mask 矩阵中 User/Seq 列全为 1。
规则2:动态序列遵循因果性——RealTime token 时间戳可能在聚合窗内,与候选曝光有先后。RT 对 RT 可见性取决于时间戳( 则可);RT 对 Cand 可见性也按时间戳( Cand 曝光时间则可)。mask 中 RealTime 间是 causal(下三角),对 Candidate 按实际时间戳动态决定。
规则3:候选之间相互独立——Cand 对 Cand()不可见,保证评分独立。mask 中 Candidate blocks 间是对角 mask(仅对角线为 1)。
白色可见、灰色不可见:用户特征与历史序列列全白(全局可见);实时序列按时间戳呈部分三角(因果);候选间仅对角线可见(独立)。
这 mask 不是预固定,而是按每样本 token 实际时间戳 动态生成——这就是「Dynamic Masking」名字由来。它避免信息泄露:训练时防模型学虚假因果,推理时允许同请求所有候选并行处理(RealTime 仅含请求前交互、候选相互独立),保持计算效率。Dynamic Masking 是混合范式最后一块拼图,让统一 Transformer 同时处理因果序列(历史)与非因果目标(候选评分),在灵活性与正确性间找到平衡。
Analysis: MTGR 不追求最快训练,而追求兼容性——用生成式架构的计算复用(user-level 聚合、)换回判别式的交叉特征灵活性。GLN 与 Dynamic Masking 是让异构 token 在同一 Transformer 共存的两个关键技术:前者解决语义空间冲突,后者解决时序/独立性冲突。
⚠️ Common Mistakes in 7.3
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为交叉特征可 scale 弥补 | 「去了交叉特征加大模型就补回」 | 美团实验:最大生成式模型仍不如中等 DLRM | 交叉特征是信息缺失,非容量问题 |
| 2 | 以为 MTGR 仍是纯生成式 | 「MTGR 只是 HSTU 加特征」 | MTGR 只在候选位置算 loss,是判别式目标 | 它是混合范式:生成架构+判别目标 |
| 3 | 把交叉特征塞进历史序列 | 「把 ctr 当 sequence token」 | 破坏因果性(特征已「看未来」) | 交叉特征属候选 token,非历史 |
| 4 | 对混合 token 用全局 LayerNorm | 「统一 Transformer 就用标准 LN」 | 不同组分布/语义冲突,互相干扰 | 用 Group LayerNorm 分组归一化 |
| 5 | 混合范式沿用 causal mask | 「候选按顺序排,causal 就行」 | 候选间泄露、RealTime 跨曝光泄露 | 用 Dynamic Masking 按时间戳动态生成 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 生成式代价 | 纯生成式禁用候选交叉特征,性能难补 | 引出混合范式必要性 |
| 判别式本质 | , 可依赖 | 交叉特征是条件统计,生成式难表达 |
| 混合范式 | 生成架构 + 判别目标,候选含交叉特征 | 效率与灵活性兼得 |
| Group LayerNorm | 按 User/Seq/RT/Cand 分组归一化 | 解决异构 token 语义冲突 |
| Dynamic Masking | 静态全可见/动态按时间戳因果/候选对角 | 解决信息泄露与独立性 |
❓ FAQ
Q1: MTGR 和 HSTU 最核心的区别是什么?
A: HSTU 是纯生成式(建模完整行为序列联合分布、自回归);MTGR 是混合范式——用生成式架构做判别式排序,只在候选位置算 loss,候选 token 可含交叉特征。一句话:HSTU 生成行为序列,MTGR 判别候选行为。
Q2: 为什么交叉特征不能放进历史序列?
A: 交叉特征(如「用户对该候选类目的历史偏好」)是针对当前候选计算的,放进序列就等于让历史「看到未来」候选,破坏因果性。MTGR 把它作为候选 token 的一部分,与历史解耦。
Q3: GLN 相比标准 LayerNorm 多花多少算力?
A: 几乎可忽略——只是在 LayerNorm 上增加 group 索引,按组独立算均值方差。代价极小,却避免了异构 token 的分布/语义相互干扰,训练稳定性显著提升。
🔗 前后关联
- 7.2(生成式排序) 末尾的灵魂一问由本章直接回答:效率优势不必绑定完整生成式 formulation。
- 7.4(RankMixer) 同样处理异构特征,但走 hardware-aware 路线(Token Mixing + Per-Token FFN),可对照 GLN 的思路。
- 3.2(特征交叉) 中 FM/DCN 的交叉特征正是 MTGR 想保留的「判别式经验」,本章是其在生成式时代的回归。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 7.3.1 — 范式辨析 🟢 Easy
判断以下陈述更贴近 HSTU/GenRank(纯生成式)还是 MTGR(混合范式):
- (a) 在候选位置算 loss,候选 token 包含「用户对该类目历史点击率」
- (b) 建模完整行为序列 的联合分布,自回归预测
💡 Solution (click to reveal)
Approach: 抓住「是否在候选位置用判别式目标 + 是否含交叉特征」。
- (a) MTGR :候选含交叉特征、只在候选算 loss,是判别式目标。
- (b) HSTU/GenRank :纯生成式联合分布建模 + 自回归。
Key points:
- 混合范式 = 生成架构 + 判别目标。
- 交叉特征的存在是 MTGR 的标志。
Problem 7.3.2 — 复杂度对比 🟢 Easy
对 历史 token、 候选,HSTU 式逐候选独立评分复杂度约 ,MTGR 聚合后约 。两者数量级相差约多少倍?
💡 Solution (click to reveal)
Approach: 代入估算。
- HSTU 式:。
- MTGR:。
- 相差 倍。
Key points:
- 用户粒度聚合让历史只编码一次,候选并行。
- 这是 MTGR 保留效率的来源。
Problem 7.3.3 — GLN 动机 🟡 Medium
为什么对 MTGR 的 token 序列用标准全局 LayerNorm 会有问题?举一个「语义混淆」的具体例子。
💡 Solution (click to reveal)
Approach: 从分布差异 + 同维度异语义两个角度。
全局 LayerNorm 算所有 token 的均值方差归一化。User token(如 Age)激活范围小(如 ),Sequence token 经多层累积范围大(如 ),全局方差被 Sequence 拉高 → Age 被过度放大、Sequence 被过度压缩。更糟的是语义混淆:维度 100 在 User token 编码「用户活跃度」,在 Candidate token 编码「候选热度」,全局归一化把两语义混在一起。
Key points:
- 异构 token 需分组归一化(GLN)。
- GLN 让每组分布对齐、语义独立。
Problem 7.3.4 — Dynamic Masking 规则 🔴 Hard
设计一条 Dynamic Masking 规则,处理以下场景:用户 12:00 点候选 A(点击)、12:30 看候选 B(未点)、13:00 点候选 C(点击),三者聚合成一个训练样本,RealTime 含 13:00 点击。预测候选 B(12:30 曝光)时,RT(13:00)应可见吗?为什么?
💡 Solution (click to reveal)
Approach: 套用规则2(动态序列按时间戳因果)。
不应可见。RT(13:00)时间戳晚于候选 B 曝光时间(12:30),按规则2「RT 对 Cand 可见当且仅当 Cand 曝光时间」,13:00 > 12:30,故屏蔽。否则模型偷看 B 之后的行为,造成 信息泄露 ,学到虚假因果。
Key points:
- Dynamic Masking 按实际时间戳动态生成,防泄露。
- 候选间(A/B/C)相互独立(规则3),互不可见。
🏆 Challenge: 混合范式设计
某业务有强交叉特征(如「用户×时段×类目」三维统计),但想借用生成式架构的 user-level 聚合提速。请写 150 字内,说明你如何用 MTGR 思路设计 token 组织与 mask,并指出必须保留哪两个架构创新。
💡 Hint
token 组织:历史(User/Seq/RT)+ 多候选(每候选融合三维交叉特征)聚合。mask:静态序列全可见、RealTime 按时间戳因果、候选间对角屏蔽(Dynamic Masking)。必保留:Group LayerNorm(异构 token 不冲突)+ Dynamic Masking(防泄露/保独立)。这正对应 MTGR 的两个核心架构创新。
RankMixer:硬件效率优化
📝 Before You Continue: 已读 7.3 MTGR(关注特征兼容性)与 3.2 特征交叉(关注交叉表达)。本章换一个角度——不从「能不能建模」而从「GPU 算得值不值」看 Scaling,核心是 hardware-aware 架构设计。
传统 DLRM 在 GPU 上的 MFU(Model FLOPs Utilization,模型浮点利用率) 通常只有 4–5%,而大语言模型可达 40–60%。这十倍效率差距,直接导致推荐模型无法享受 Scaling Law 红利——即使加参数量,大部分新增计算也浪费在低效内存访问上。
根源在于传统 DLRM 继承自 CPU 时代的架构,在 GPU 上暴露三个根本问题:(1) 核心操作以 memory-bound(访存受限) 为主,embedding lookup、特征交叉、序列建模访存量远大于计算量;(2) 计算图 高度碎片化 ,多个独立手工模块串联,kernel launch 开销与 global memory 传输累积成瓶颈;(3) 无法充分利用 Tensor Core ,大部分是小向量运算或不规则访存,发挥不了矩阵乘法加速单元。
RankMixer 通过 hardware-aware 架构设计从根本上解决。核心原则: 从硬件特性反推架构设计 ,把推荐模型重构为统一的、GPU 友好的计算图——用 Token Mixing 替代 Self-Attention 降复杂度,用 Per-Token FFN 捕捉特征异质性,用 Sparse MoE 实现参数高效扩展。
7.4.0 RankMixer 整体架构
模型核心是 层堆叠的 RankMixer Block,每个 block 含 Multi-head Token Mixing(替代 Self-Attention)与 Per-Token FFN(捕捉特征异质性)两个模块。输入特征经 tokenization 转为 个统一维度 token,经 层 block 后通过 mean pooling 产生输出。
输入特征 token 化后,经多层 RankMixer Block(每层 = Token Mixing + Per-Token FFN),最后 mean pooling 输出 logit。所有核心操作均为矩阵乘法。
每个 RankMixer Block 前向:
整体复杂度 。Sparse MoE 版本中 Per-Token FFN 可替换为专家网络,在保持推理成本下扩展参数量。设计遵循三原则:(1) 所有核心操作为矩阵乘法,充分利用 Tensor Core;(2) 计算图尽量简洁,减少 kernel launch 开销;(3) 保持推荐任务所需表达能力。
7.4.1 Token Mixing 机制
Self-Attention 复杂度 (来自计算所有 token pair 相似度矩阵 )。推荐场景特征数可达数百上千,这个 项成显著瓶颈。RankMixer 的核心洞察: 推荐任务需要的是 token 间信息混合(mixing),而非基于相似度的动态加权(attention)。例如学「年轻用户在一线城市更爱科技类物品」这类高阶交互,本质是让多个 token 信息融合成新表示,不一定需显式算 token pair 相似度。
Token Mixing 核心思想: 在特征维度而非 token 维度混合。给定输入 ,含两步:
第一步 Multi-head decomposition——每个 token 分解为 个 head:, 是第 个 token 第 个 head。
第二步 Token-wise mixing——每个 head 内把所有 token 的该 head 部分拼接:。
关键: 改变数据组织,从「按 token」变「按 head」。原 是 个长度 向量,经 SplitHead+Concat 后变 个长度 向量,每 head 内不同 token 特征紧密排列,为混合创造条件。实际设 ,每「head」含所有 token 一部分特征。混合后 token 数不变,便于残差连接。
左:Self-Attention 算全 相似度矩阵();右:Token Mixing 按 head 重排后在特征维度线性变换(),无 softmax。
复杂度看,Token Mixing 计算量 (主要是内存重排)。相比 self-attention 的 ,当 较大(推荐中 几百上千)时避免 项,显著降低。且 Token Mixing 无 softmax normalize(需额外 reduction kernel),进一步减 kernel 开销。
关键问题: 不显式算 token pair 相似度,如何保证捕捉交互? 答案在 多层堆叠。单层 Token Mixing 是「feature-level mixing」——不同 token 同维特征相互影响(因 concat 到同一向量)。堆叠多层时,第 1 层每 token 输出融合所有 token 一阶信息,第 2 层输入已是 mixed 结果,每 token 已含他 token 信息,第 2 层再 mixing 实现二阶交互:
每层 Token Mixing 在特征维度做线性变换(经后续 FFN),堆叠 层可建模 token 间 阶多项式交互。实际 通常 6–12 层,足以捕捉所需高阶交叉。
从硬件看,Token Mixing 核心是数据重排(SplitHead、Concat),可用高效 kernel 实现,设计为连续内存读写(coalesced memory access)充分利用带宽。相比 attention 需算 softmax(全局归一化),Token Mixing 局部、可并行。更重要的是 SplitHead、Concat、FFN 可融合成一个 kernel,减 kernel launch overhead——这是 MFU 提升的关键。
Analysis: Token Mixing 用「特征维混合 + 多层堆叠」替代「token 对相似度 + softmax」,把 降到 (整体),且所有操作可融为矩阵乘法 kernel。牺牲的是 attention 的「动态相似度路由」,换来的是 GPU 利用率——在推荐这种特征多、交互模式相对固定的场景,这笔交易很划算。
7.4.2 Per-Token FFN
标准 Transformer 的 FFN 对所有 token 用相同权重:。这在 LLM 合理(所有 token 同语义空间)。但推荐特征语义空间完全不同:用户 ID 表隐式偏好、物品类目是粗粒度分类、点击率服从长尾、时间戳有周期性。强行同 FFN 处理导致参数效率损失。
RankMixer 核心设计: 每个 token 有独立 FFN 参数。第 个 token:
每 token 的 独立,使:(1) 每 token 学特定语义空间变换;(2) 高信息量 token 自动分配更大参数容量;(3) 避免不同语义空间相互干扰。
Per-Token FFN 与 MMoE 本质不同。MMoE 多 expert 共享同输入,gating 动态加权输出 expert 组合:(所有 expert 看相同 )。Per-Token FFN 每 token 有独立输入与独立 FFN:(每 FFN 看不同 )。参数隔离确保不同特征空间学习相互独立,避免高频特征 dominate 低频特征。
参数效率看,设 个 token,Per-Token FFN 总参数 ,相比 shared FFN()增 倍。但 计算复杂度不变 :,与 shared FFN 相同(shared 也需对 个 token 分别计算)。增加的参数是「专门化」的,每块只服务特定 token,学习效率更高。
跨特征空间交互通过 Token Mixing 层实现。Per-Token FFN 专注各自空间深度建模,Token Mixing 确保不同 token 信息混合。这种「mixing + per-token processing」组合,在保持参数隔离的同时,通过多层堆叠实现充分跨空间交互。
7.4.3 Sparse MoE 扩展
有了 Token Mixing 与 Per-Token FFN,如何扩到十亿甚至百亿参数?直接加深度/宽度会线性增计算量,推理延迟同比增,工业不可接受。Sparse MoE(稀疏专家混合) 提供方案:不是所有参数都参与每样本计算,而是按样本特性动态选部分 expert。模型参数量可很大,但每样本计算量固定(只激活少数 expert)。
MoE 理想模式是每个 expert 专门化到某种样本模式。但推荐场景实现有效 expert specialization 面临三大挑战:(1) 输入是高维稀疏特征,组合空间指数级,representation 散布高维各角落,缺清晰 cluster 结构,gating 难学稳定路由;(2) 数据极度不均衡,头部用户占 50% 样本,若 gating 早期把大量头部样本路由到某 expert,该 expert 获更多梯度,后续 gating 继续发它,导致少数 expert 处理大部分样本(expert overload),其余几乎不用(expert underutilization);(3) 即使训练负载均衡,推理时请求分布可能不同,某些 expert 成瓶颈,增延迟方差。
RankMixer 用两种互补训练策略应对。首先是 ReLU Routing——标准 MoE 用 Top- + Softmax routing,每 token 固定激活 个 expert。RankMixer 用 ReLU Routing 允许每 token 激活不同数量 expert:
ReLU 使输出可为 0(不激活)或正值(激活),高信息量 token 可能激活更多 expert。为控稀疏度加正则:,, 控平均激活 expert 数。
其次是 Dense-Training / Sparse-Inference(DTSI-MoE)——Per-Token FFN 已增参数 倍,加 MoE 再扩 expert 数,易致 expert under-training。DTSI-MoE 用两个 router:训练时 dense router 激活所有或大部分 expert 确保充分训练,推理时 sparse router 只激活少数 expert 降计算成本。两 router 同时训练,仅 受 约束:
训练时前向用 ,同时算 并对其施加稀疏正则;推理时只用 。实现训练充分、推理高效、策略一致。
负载均衡通过 软约束实现。expert 在 batch 总激活量 ,正则可重写 。当某 expert 过大,梯度 抑制其激活概率,实现负载均衡。相比硬约束(capacity 限制),软约束不会因 expert 满载强制分配次优 expert,保持路由灵活。
左:传统 DLRM 计算图碎片化(embedding lookup 访存受限、小 kernel、launch 开销),有效 GEMM 仅 5%;右:RankMixer 核心操作全为 GEMM,Token Mixing + PFFN 占 ~85% 计算,MFU 达 45%。
RankMixer 实现高 MFU 的关键: 所有核心操作都是 compute-bound 的大矩阵乘法。Token Mixing 和 PFFN 占约 85% 计算时间,全是 GEMM,可高效用 Tensor Core(单 GEMM kernel MFU 达 60–80%)。相比之下传统 DLRM 中 embedding lookup(40% 时间,memory-bound)、小 kernel(35% 时间,MFU<10%)、launch 开销(20% 时间)主导,有效 GEMM 仅 5%——这正是 DLRM 的 MFU 只有 4–5%、RankMixer 达 45% 的原因。
💡 Key Insight: RankMixer 把推荐模型从碎片化设计转为统一架构范式。算法上 Token Mixing 把复杂度从 降到 ,Per-Token FFN 捕捉特征异质性,Sparse MoE 通过 ReLU Routing 和 DTSI-MoE 实现参数高效扩展。系统上把所有核心操作统一为矩阵乘法,MFU 从 4–5% 升到 45%,让推荐模型成为 GPU 的「第一类公民」,可直接用 Tensor Core 和 LLM 成熟工具链,打开可持续 Scaling 路径。但 RankMixer 聚焦模型内部计算效率,pipeline 仍有其他碎片化——序列建模与特征交互分离、召回排序分离、多任务碎片化。下一节 OneTrans 进一步突破这些壁垒。
⚠️ Common Mistakes in 7.4
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为 MFU 低只是参数少 | 「加 GPU 就能解决利用率」 | 是架构碎片化+访存受限,非算力不足 | 用 hardware-aware 统一为 GEMM |
| 2 | 以为 Token Mixing 丢交互 | 「不算子对相似度就无交叉」 | 多层堆叠实现 阶多项式交互 | 看 的堆叠 |
| 3 | 把 Per-Token FFN 当 MMoE | 「每个 token 一个 expert 就是 MoE」 | MMoE 共享输入加权组合,PFFN 每 token 独立输入/参数 | 区分参数隔离 vs 路由加权 |
| 4 | 用 Top-k Softmax routing | 「MoE 都该固定激活 k 个」 | 推荐稀疏难稳定路由,且不均容易 overload | 用 ReLU Routing 动态激活 |
| 5 | 忽略 DTSI-MoE 的必要性 | 「直接 sparse 训练就行」 | PFFN 已增参数 T 倍,纯 sparse 易 under-training | 训练 dense、推理 sparse 双 router |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| MFU 瓶颈 | DLRM 仅 4–5%,LLM 40–60% | 推荐难 Scale 的硬件根因 |
| Token Mixing | 特征维混合替代 ,复杂度 | 去 项 + 可融 kernel |
| Per-Token FFN | 每 token 独立 FFN 参数,复杂度不变 | 捕捉特征异质性,参数隔离 |
| Sparse MoE | ReLU Routing + DTSI-MoE | 参数高效扩展到十亿级 |
| 统一为 GEMM | 核心操作全矩阵乘法 | MFU 升到 45%,成 GPU 一类公民 |
❓ FAQ
Q1: Token Mixing 不计算相似度,真能替代 Self-Attention 吗?
A: 能。推荐的高阶交叉本质是「多 token 信息融合成新表示」,单层在特征维 mixing,多层堆叠实现 阶多项式交互。代价是不再有动态相似度路由,但推荐特征多、模式相对固定,换来的 GPU 利用率提升更划算。
Q2: Per-Token FFN 参数量增 T 倍,为什么 FLOPs 不变?
A: Shared FFN 也要对 T 个 token 分别计算(每 token 一次 FFN),FLOPs 本就是 ;Per-Token 只是把共享权重换成 T 份独立权重,每 token 仍算一次,FLOPs 相同。增加的是「专门化」参数,学习效率更高。
Q3: 为什么推荐 MoE 用 ReLU Routing 而非 Top-k?
A: 推荐输入高维稀疏、分布不均,Top-k 固定激活数易使少数 expert overload、其余 underutilization;ReLU 让每 token 按信息量动态激活不同数量 expert,配合正则实现软负载均衡,更适配推荐数据。
🔗 前后关联
- 7.3(MTGR) 同样处理异构特征,但用 GLN + Dynamic Masking;可对照 RankMixer 的 Per-Token FFN(异参数)思路。
- 7.5(OneTrans) 进一步打破「序列建模与特征交互分离」的碎片化,是 RankMixer 硬件思路在统一架构上的延伸。
- 3.2(特征交叉) 中 DCN/xDeepFM 的高阶交叉,在 RankMixer 中以 Token Mixing 多层堆叠重新实现,且更 GPU 友好。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 7.4.1 — MFU 根因 🟢 Easy
传统 DLRM 的 MFU 约 4–5%,LLM 约 40–60%。请指出导致 DLRM 低 MFU 的三个架构层面原因。
💡 Solution (click to reveal)
Approach: 对应正文三个根本问题。
- 核心操作 memory-bound(embedding lookup、特征交叉访存量 >> 计算量);
- 计算图高度碎片化(多独立模块串联,kernel launch + global memory 传输开销);
- 无法充分利用 Tensor Core(小向量/不规则访存,非 GEMM)。
Key points:
- 不是算力不够,是算得「不值」。
- RankMixer 统一为 GEMM 把 MFU 拉到 45%。
Problem 7.4.2 — Token Mixing 复杂度 🟢 Easy
Self-Attention 复杂度 ,Token Mixing 约 (重排)。当 时,两者数量级相差约多少倍?
💡 Solution (click to reveal)
Approach: 代入估算(忽略常数)。
- Self-Attention:。
- Token Mixing:。
- 相差 倍(即 倍)。
Key points:
- Token Mixing 去除了 项,随 token 数线性。
- 推荐中 数百上千,收益显著。
Problem 7.4.3 — Per-Token FFN vs MMoE 🟡 Medium
为什么说 Per-Token FFN 与 MMoE「本质不同」?各用一句话概括它们的参数组织方式。
💡 Solution (click to reveal)
Approach: 区分「参数隔离」与「路由加权」。
- MMoE:多个 expert 共享同一输入 ,gating 动态加权组合输出 ——所有 expert 看相同输入。
- Per-Token FFN:每个 token 有独立输入 与独立 FFN ——参数隔离,避免高频特征 dominate 低频。
Key points:
- 一个是「同输入、加权选 expert」;一个是「异输入、各自独立 FFN」。
- 目的都是处理异构特征,机制不同。
Problem 7.4.4 — DTSI-MoE 设计 🔴 Hard
解释 DTSI-MoE 为何需要两个 router( 与 ),并说明若只用 做训练会发生什么。
💡 Solution (click to reveal)
Approach: 从「充分训练 vs 高效推理」矛盾切入。
Per-Token FFN 已把参数增 T 倍,再加 MoE 扩 expert 数,若训练时也稀疏激活,很多 expert 收不到足够梯度 → expert under-training。DTSI-MoE 用 在训练时激活多数 expert(充分训练),仅 受稀疏正则约束用于推理。若只用 训练,expert 会 under-training,部署后效果差。
Key points:
- 训练 dense 保质量,推理 sparse 保效率。
- 两 router 同时训练、策略一致。
🏆 Challenge: hardware-aware 重构
你要把一个碎片化 DLRM(embedding lookup + 手工交叉 + DIN + MLP)重构成 GPU 友好架构。请写 150 字内,说明你会用 RankMixer 的哪三个组件替代现有模块,并点明重构后 MFU 预期变化与前提。
💡 Hint
用 Token Mixing 替代 Self-Attention/手工交叉(去 、可融 kernel)、Per-Token FFN 替代共享 FFN(捕捉特征异质性)、Sparse MoE 扩展参数。前提是先把所有特征 token 化、统一为矩阵乘法计算图;预期 MFU 从 ~5% 升到 ~45%。这正对应 RankMixer 的 hardware-aware 重构思路。
OneTrans:统一序列与特征交互
📝 Before You Continue: 已读 7.4 RankMixer(模型内计算效率)。本章更进一步——打破「序列建模模块」与「特征交互模块」的架构壁垒,用单一 Transformer backbone 做端到端联合优化,并复用 LLM 系统优化。
RankMixer 通过 hardware-aware 设计解决了 GPU 利用率问题,但推荐系统整体架构仍碎片化。工业界主流推荐模型普遍采用 encode-then-interaction(先编码后交互) 范式:序列建模模块(DIN、LONGER)把行为序列编码为固定长度向量,再与非序列特征拼接,输入特征交互模块(如 RankMixer)学高阶交叉。
这种分离式设计有两个根本问题:(1) 信息流受限——序列必须压缩为固定维向量,静态特征无法在序列编码阶段发挥作用,只能后期「补救式」融合;(2) 执行碎片化——两模块独立执行,无法享受 LLM 系统优化(KV Caching、FlashAttention),且需分别调优,难形成统一 Scaling Law。
OneTrans 提出根本性架构革新: 用单一 Transformer backbone 同时完成序列建模和特征交互。通过统一 tokenizer 把序列特征(S-tokens)和非序列特征(NS-tokens)转为统一 token 序列,在堆叠 Transformer 层联合建模,打破序列与特征的信息壁垒,为应用 LLM 系统优化奠基。
7.5.0 统一 Tokenization
推荐输入含两类截然不同特征: 序列特征 (用户多行为序列,如点击、加购、下单序列)与 非序列特征 (静态属性与上下文,如年龄、类目、查询词、时段)。传统方法把 压成固定向量后与 拼接;OneTrans 核心创新是 把两类特征统一转为 token 序列,在同一 Transformer 处理。
对序列特征 ( 种行为类型),每序列 含 个事件 embedding(事件 = 物品 ID + 物品侧信息)。因不同行为序列原始维度可能不同,先用行为特定 MLP 对齐到统一维度 :
对齐后多序列需合并为单一 token 序列。OneTrans 支持两种融合策略:(1) Timestamp-aware——若行为带时间戳,按时间交错排列所有行为并加行为类型标识符;(2) Timestamp-agnostic——若无时间戳,按行为意图强度排序(下单选 > 加购 > 点击),不同序列间插可学习 [SEP] token 分隔。实验表明有时间戳时 timestamp-aware 更好(时间顺序蕴含兴趣演化)。最终:
对非序列特征 (数值与类别特征,经 bucketization 或 one-hot 后 embedding),OneTrans 把所有特征 concat 后通过单个 MLP 投影,再切分为 个 token(称为 Auto-Split Tokenizer ):
这避免手工特征分组的主观性,让模型自动学如何组织非序列特征。最终初始输入是 S-tokens 与 NS-tokens 拼接:
左:传统分离式(序列编码为定长向量后与静态特征拼接,信息流受限);右:OneTrans 统一 token 序列,S-tokens 与 NS-tokens 在同一 Transformer 联合建模。
与传统方法有本质区别: 传统压缩序列为单个向量,OneTrans 保留完整序列 token。后续 Transformer 层中,每个行为事件作为独立 token 参与 attention,非序列特征也以 token 形式存在,两类特征可在同一 attention 矩阵中交互。
7.5.1 Mixed Parameterization 的核心机制
若直接用标准 Transformer 处理统一 token 序列,会遇到推荐特有难题: token 异质性。LLM 中所有 token 都是词/sub-word,语义空间统一,共享 Q/K/V 和 FFN 合理。但 OneTrans 中 S-tokens 来自行为序列(同质性强,都是用户—物品交互事件),NS-tokens 来自完全不同空间(年龄是人口统计、价格是数值、查询词是文本)。强制所有 token 共享参数会导致冲突——例如捕捉「序列中相邻物品相似性」的参数,对「用户年龄→物品类目」交互可能完全不适用。
OneTrans 核心创新是 Mixed Parameterization(混合参数化) : S-tokens 共享一套参数,每个 NS-token 拥有独立的 token-specific 参数。基于两个观察:(1) 行为序列所有事件在同一语义空间(物品空间),可高效共享参数学序列模式;(2) 非序列特征来自异构空间,需独立参数捕捉各自特性。
Mixed Causal Attention
OneTrans Block 中 Multi-Head Attention 的 Q/K/V 采用混合参数化。第 个 token 的 query/key/value:
权重矩阵 遵循条件参数化:
所有 S-tokens 用同一组 ;第 个 NS-token 有自己的 等。
OneTrans 采用 Causal Attention Mask ,但 NS-tokens 置于 S-tokens 之后,导致三个关键信息流模式:
- S-side 因果依赖——每 S-token 只能 attend 之前的 S-tokens。timestamp-aware 自然建模时间因果;timestamp-agnostic(按意图排序)下 causal mask 让高意图行为(下单选)信息传到低意图(点击),实现「强信号过滤弱信号」。
- NS-side 全局 attention——每 NS-token 可 attend 所有 S-tokens(完整行为历史)及之前的 NS-tokens。使非序列特征充分利用序列证据,如「物品类目」token 可 attend 所有历史点击类目,自动学「用户对该类目历史偏好」。
- 支持 Pyramid——causal mask 方向性使信息自然向序列尾部聚集,为 Pyramid Stack 提供理论基础。
Mixed FFN
FFN 同样混合参数化:
与 attention 同条件参数化:S-tokens 共享 ,每 NS-token 独立。
需与 RankMixer 的 Per-Token FFN 对比:RankMixer 为 每个 token 配独立 FFN(含序列 token),参数 ;OneTrans 的 Mixed FFN 只为 个 NS-tokens 配独立参数,S-tokens 共享,参数 。推荐中 ,OneTrans 在保表达同时显著降低参数开销。参数共享不是妥协,而是设计——行为序列同质性使共享参数更高效学序列模式,避免冗余。
OneTrans 用 Pre-norm + RMSNorm。S-tokens 与 NS-tokens 数值范围/统计差异显著,Post-norm 易致 attention 分数尺度失衡引发训练不稳;Pre-norm 在子层前先归一化,确保输入 attention/FFN 的 token 表示尺度相近,RMSNorm 进一步通过 root mean square 归一化提供更稳梯度传播。
S-tokens 共享 Q/K/V/FFN 参数并因果依赖;NS-tokens 独立参数、可全局 attend 所有 S-tokens。两类特征在同一 attention 矩阵交互。
7.5.2 Pyramid Stack 渐进式蒸馏
OneTrans 的 Causal Attention 有一重要特性: 信息自然向序列后方聚集。第 层位置 融合 信息;第 层位置 又融合更新后的 。随层数加深, 靠后 token 渐成前面所有 token 信息的「汇聚点」。特别地,NS-tokens 位于序列末尾,深层会积累整个序列与前面 NS-tokens 信息。
Pyramid Stack 利用此特性: 逐层减少参与 attention 的 query token 数量,只保留序列尾部 token。设第 层输入长度 ,定义尾部索引集 ()。attention 计算:
- Keys 和 Values :仍从所有 个 token 算,保持完整上下文
- Queries :只从 中 个 token 算
attention 输出只保留 对应位置,序列长度从 缩到 。多层间设递减的 (如 1190 → 595 → 297 → … → 12),形成金字塔式层级。
每层的 query 只取尾部 个 token(含 NS-tokens),Keys/Values 用全部 token;序列长度逐层减半,信息逐步蒸馏到尾部。
两个核心收益:
- Progressive Distillation(渐进式蒸馏)——长行为序列(数百上千事件)逐层收缩,信息逐步「蒸馏」到少量尾部 token。浅层学局部模式(相邻物品相似),深层在压缩 token 上学全局模式(长期兴趣漂移)。最终所有序列信息汇聚到 NS-tokens,为下游提供紧凑而信息丰富的表示。
- Compute Efficiency——标准 Transformer attention 复杂度 ,FFN 。Pyramid 降到 (attention)与 (FFN)。当 (如 1190 逐层减到 12),计算量与激活内存显著下降。
与标准 Transformer 关键差异:标准需在每层保持完整序列长度(LLM 要输出每位置预测);推荐只需最终排序分数,中间序列 token 可逐层丢弃,只要尾部 token 充分融合历史。Causal attention 方向性保证这一点。
7.5.3 Cross-Request KV Caching
统一架构的关键优势是可无缝应用 LLM 系统优化,最重要的是 KV Caching。一次请求通常返回数百候选,每候选对应一个样本,这些样本 用户侧特征完全相同 (同用户、同行为序列),只有物品侧不同。传统 encode-then-interaction 中序列编码模块虽可复用,但特征交互模块须为每个候选重算,无法充分利用共享结构。
OneTrans 统一 Transformer 自然支持两阶段计算:
Stage I(S-side,每请求一次)——处理所有 S-tokens,算每层 K/V 及 attention 输出并缓存。此阶段 每请求只执行一次 ,与候选数无关。
Stage II(NS-side,每候选)——对每个候选算其 NS-tokens,每层执行:用缓存的 S-side K/V、算 NS-tokens 的 queries、执行 Cross-Attention(NS attend 缓存的 S-side K)、执行 NS-tokens 间 Self-Attention、经 token-specific FFN 处理 NS-tokens。
关键:S-tokens 的 KV 在所有候选间共享,只有 NS-tokens 的 QKV 需每候选重算。设一次请求 个候选,传统需 序列计算,KV Caching 降到 。因 ,复杂度近似 (相对候选数 )。
更进一步,OneTrans 实现 Cross-Request KV Caching。用户行为序列是 append-only 的,每次新请求相比上次只在末尾新增少量事件。可在多请求间复用 KV cache:
- 首次请求——算完整序列 KV,缓存
- 后续请求——只算新增 个事件的 KV,与旧 cache 拼接
每次请求序列计算从 降到 ( 通常个位数)。高频场景(信息流刷新)用户序列短时变化很小,Cross-Request KV Caching 收益尤显著。
Stage I 每请求算一次 S-side KV 并缓存;Stage II 每候选只算 NS-side;跨请求仅追加 个新事件 KV,复用旧 cache。
需注意,KV Caching 有效性依赖 统一 Transformer 计算图。若序列建模与特征交互是两独立模块,它们中间表示无法跨候选复用(输入/参数完全不同)。OneTrans 通过统一 tokenization 与 Mixed Parameterization,把两类特征置于同一 attention 矩阵,使 S-tokens 的 KV 可被所有候选 NS-tokens 共享——这是 encode-then-interaction 无法实现的。
除 KV Caching,OneTrans 还继承 LLM 其他优化: FlashAttention-2 (kernel fusion + memory tiling 减 attention I/O、降激活内存)、Mixed-Precision Training (BF16/FP16)与 Activation Recomputation 结合(保数值稳定同时压内存)。这些对训练部署数亿参数 OneTrans 至关重要。
7.5.4 统一建模的本质
OneTrans 核心贡献是推荐架构根本性转变: 从模块组合到统一建模。传统 encode-then-interaction 把序列编码与特征交互分离为独立模块,不同类型交互(序列内、跨序列、多源特征、序列—特征)被人为隔断。OneTrans 通过统一 Transformer 让这些交互在每层同时发生,多层堆叠形成复杂组合模式。
统一架构另一关键优势是 整体可扩展性。分离架构需分别调优序列与交互模块,难形成统一 Scaling Law。OneTrans 把整个模型统一为单一 Transformer backbone,扩展策略简单明确:加层数(depth)、加隐藏维度(width)、加序列长度(length)——推荐模型可像 LLM 一样获可预测性能提升。
从 RankMixer 到 OneTrans,推荐架构演进两方向清晰可见:hardware-aware 计算设计解决 GPU 利用率,统一建模框架打破模块碎片化壁垒。两者结合为推荐系统走向大规模、可扩展智能化奠基。
💡 Key Insight: 本章是 Part 7 的收尾——从 HSTU 验证 Scaling Law,到 GenRank 追问本质、MTGR 兼容特征、RankMixer 优化硬件、OneTrans 统一架构。五个工作从架构、训练、特征、硬件、统一性五个角度,共同证明:推荐系统不再是深度学习 Scaling 的「例外」。
⚠️ Common Mistakes in 7.5
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为 OneTrans 只是 RankMixer 换皮 | 「都是 Transformer,没区别」 | OneTrans 打破序列/特征模块壁垒,统一 token | 区分「模型内效率」vs「架构统一」 |
| 2 | 让所有 token 共享参数 | 「统一序列就用标准 Transformer」 | S/NS token 异质,共享参数冲突 | 用 Mixed Parameterization(S 共享/NS 独立) |
| 3 | 把序列压成定长向量 | 「S-tokens 先 pooling 再拼 NS」 | 丢失逐事件交互,回到 encode-then-interaction | 保留完整序列 token,同 attention 交互 |
| 4 | 忽略 Pyramid 的因果前提 | 「随便截断 query 就行」 | 需 causal mask 保证尾部汇聚历史 | 仅保留尾部 个 query,KV 用全部 |
| 5 | 以为 KV Cache 在分离架构也能用 | 「DIN+RankMixer 也能跨候选复用」 | 两模块输入/参数不同,中间表示不可跨候选复用 | 统一计算图是 Cross-Request KV Cache 前提 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 统一 Tokenization | S-tokens(序列)+ NS-tokens(非序列)同序列 | 打破序列/特征信息壁垒 |
| Mixed Parameterization | S 共享参数 / NS 独立参数 | 解决 token 异质性冲突 |
| Pyramid Stack | 逐层收缩 query 到尾部,KV 用全部 | 渐进蒸馏 + 计算效率 |
| Cross-Request KV Cache | S-side KV 跨候选/跨请求复用 | 复杂度近 (相对候选) |
| 统一建模本质 | 单 Transformer backbone 联合优化 | 整体可扩展,形成统一 Scaling Law |
❓ FAQ
Q1: OneTrans 和 RankMixer 最大的区别是什么?
A: RankMixer 聚焦模型内部计算效率(Token Mixing 替代 attention、MFU 45%),但仍把序列与特征当作可分离的输入;OneTrans 更进一步,把序列事件和非序列特征统一为 token 序列,在同一 Transformer 内联合建模,并复用 KV Caching 等 LLM 系统优化。
Q2: 为什么 S-tokens 共享参数、NS-tokens 独立?
A: 行为序列所有事件在同一「物品空间」,同质性高,共享参数更高效学序列模式、避免冗余;非序列特征来自异构空间(人口统计/数值/文本),需独立参数捕捉各自特性。这是「参数共享是设计而非妥协」。
Q3: Pyramid Stack 为什么能丢中间 token?
A: 推荐只需最终排序分数,不需像 LLM 输出每位置预测。Causal attention 使信息向尾部汇聚,保留尾部 个 query(含 NS-tokens)、KV 用全部 token,即可在大幅降计算的同时不丢历史信息。
🔗 前后关联
- 7.1(HSTU) 的 M-FALCON 首次提出 KV Caching 解绑历史与候选;OneTrans 的 Cross-Request KV Caching 是其思想在统一架构上的延伸。
- 7.4(RankMixer) 的硬件效率是 OneTrans 统一架构可扩展的基础;两者共同指向「推荐模型成为 GPU 一类公民」。
- Part 6 生成式基础 与 Part 8 端到端生成 把统一建模思想推向「召回—排序—重排」全链路,可顺着这条线继续读。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 7.5.1 — 范式辨析 🟢 Easy
判断以下描述属于「encode-then-interaction(分离)」还是「OneTrans(统一)」:
- (a) DIN 把行为序列编码为定长向量,再与静态特征拼接送入交叉模块
- (b) 行为事件与非序列特征都作为 token,在同一 Transformer 每层联合注意力
💡 Solution (click to reveal)
Approach: 抓「是否保留完整序列 token、是否同层交互」。
- (a) 分离式 (encode-then-interaction):序列被压成定长向量,后期拼接。
- (b) OneTrans 统一 :两类特征同为 token,同 attention 矩阵交互。
Key points:
- 统一建模的核心是「不压缩序列、同层交互」。
- 分离式的信息流受限是 OneTrans 要解决的痛点。
Problem 7.5.2 — Mixed Parameterization 🟢 Easy
OneTrans 中 S-tokens 与 NS-tokens 的参数组织有何不同?为什么这样设计而非全部共享?
💡 Solution (click to reveal)
Approach: 直接对应 Mixed Parameterization。
- S-tokens(行为序列) 共享 一套 Q/K/V/FFN 参数(同物品空间、同质)。
- NS-tokens(非序列特征) 每个独立 参数(异构空间)。
- 若全部共享,异质 token 参数冲突(如「相邻物品相似」参数不适于「年龄→类目」)。
Key points:
- 参数共享是设计(序列同质性),非妥协。
- 相比 RankMixer 每 token 独立 FFN,OneTrans 因 更省参数。
Problem 7.5.3 — Pyramid 复杂度 🟡 Medium
标准 Transformer 对长度 序列,attention 复杂度 。Pyramid Stack 每层 query 取尾部 (设 ),KV 用全部 。若叠 4 层( 从 1190 逐层减半到约 12),总 attention 计算量相对标准 Transformer(同等 4 层、保持全长)约降为多少比例?
💡 Solution (click to reveal)
Approach: 每层 Pyramid attention 为 ,标准每层 。
估算(KV 固定全长 的情形): Pyramid 各层 query 长度依次约 ,4 层总量 。对比标准 4 层的 ,约降为 1/4。
实际更低: 每层的 KV 序列 也随层收缩,各层计算 比上式更小,故真实比例略低于 0.94/4 ≈ 0.23。
Key points:
- 核心不是精确倍数,而是「逐层收缩 query」带来的平方→线性量级下降:,当 时大幅降。
- 推理时可给数量级结论:约为标准 Transformer 的 1/4 或更低。
Problem 7.5.4 — KV Cache 收益 🔴 Hard
一次请求有 候选, 序列 token,。传统逐候选序列计算量约 ,OneTrans 用 Cross-Candidate KV Caching 约 。两者数量级相差约多少倍?
💡 Solution (click to reveal)
Approach: 代入估算(忽略常数 )。
- 传统:。
- OneTrans:。
- 相差 倍。
Key points:
- S-side KV 跨候选只算一次,复杂度近 (相对 )。
- 因 ,收益随候选数 增大而更显著。
🏆 Challenge: 统一架构蓝图
请写 150 字内,结合 Part 7 五个工作,描述你心目中「可 Scaling 的推荐排序引擎」应具备的四大特性(分别从范式、特征、硬件、架构统一性各取一点)。
💡 Hint
四大特性:(1) 范式——user-level 自回归序列建模(HSTU/GenRank 本质);(2) 特征——保留交叉特征兼容性(MTGR 混合范式);(3) 硬件——统一为矩阵乘法、MFU 45%(RankMixer hardware-aware);(4) 架构统一——单 Transformer backbone 联合序列与特征交互 + KV Caching(OneTrans)。这正对应 Part 7 五工作的合力方向。
过去十余年,推荐、搜索、广告几乎都建立在 多阶段级联架构(Multi-stage Cascading Architecture, MCA) 之上:召回、预排序、排序、重排……数据像漏斗一样层层筛选。这种设计在历史上平衡了效率与复杂度,但随着数据规模爆炸与用户体验要求提高,其结构性缺陷日益凸显——目标冲突、信息损失、计算碎片化。
本部分沿 生成式范式 主线,看工业界如何用统一神经网络 直接从用户输入生成最终结果 ,颠覆「级联漏斗」:聚焦三个核心场景的真实落地——快手的 OneRec (推荐)、电商搜索的 OneSug + OneSearch (搜索)、在线广告的 EGA + GPR (广告)。各章要点见下表。
💡 Key Insight: 三个场景的端到端实践呈现出一条共同主线——语义 ID 是连接生成模型与业务数据的桥梁;Encoder-Decoder 是融合上下文的主力架构;强化学习是对齐生成过程与线上业务目标的关键工具。
本章涵盖
| 章节 | Topic | The Big Idea |
|---|---|---|
| 8.1 | 端到端生成式推荐 | OneRec-V1/V2 用语义 ID + Encoder-Decoder + 强化学习,把推荐重定义为「用户上下文 → 语义 ID 序列」的生成任务 |
| 8.2 | 端到端生成式搜索 | OneSug 做查询补全、OneSearch 做商品检索,以统一生成式架构覆盖电商搜索全链路 |
| 8.3 | 端到端生成式广告 | EGA 把竞价机制嵌入生成、GPR 用预训练统一多场景超长序列,让机制约束与生成模型深度统一 |
What You'll Be Able to Do After This Part
- 🟢 解释 传统 MCA 的三大结构性缺陷,及其如何催生端到端生成式范式
- 🟢 描述 语义 ID(Semantic ID)如何把亿级物品压缩到有限词表,使生成式推荐在数学上可行
- 🟡 对比 OneRec-V1 的 Encoder-Decoder 与 V2 的 Lazy Decoder-Only 在算力分配上的根本差异
- 🟡 辨析 搜索场景「先相关性、后个性化」与推荐场景优化目标的本质区别
- 🔴 说明 EGA 如何在生成过程中内嵌激励相容(IC)与个体理性(IR)约束
- 🔴 概述 GPR 的异构层次化解码器与价值引导 Beam Search 如何解决跨场景与超长序列难题
- 🏆 完成各节分层练习题,亲手推演语义 ID 编码、奖励建模与约束解码过程
核心概念
| Concept | 章节 | Relevance |
|---|---|---|
| 多阶段级联架构 MCA | 8.1 | 被端到端范式颠覆的传统工业骨架 |
| 语义 ID(Semantic ID) | 8.1 | 连接生成模型与离散物品/商品/广告的核心桥梁 |
| Encoder-Decoder 生成架构 | 8.1 / 8.2 / 8.3 | 融合上下文、自回归生成序列的主力结构 |
| Lazy Decoder-Only | 8.1 | 把算力集中到目标 Token,解码成本降 94% |
| 强化学习对齐(ECPO/GBPO/DPO) | 8.1 / 8.2 / 8.3 | 让生成过程对齐线上多目标业务信号 |
| 激励相容 IC 与个体理性 IR | 8.3 | 广告场景下机制设计的经济学约束 |
| 价值引导 Trie Beam Search | 8.3 | 在解码中内嵌约束、提升推理效率 |
前置知识
- 已读完 1.1 (两种范式、端到端生成的动机)与 2.x (双塔、语义 ID 的初步概念)
- 了解 Transformer 的基本结构(自注意力、交叉注意力、编码器/解码器)
- 对强化学习基础概念(策略、奖励、优势)有初步认识(本部分会结合案例逐步展开)
本部分是生成式主线的工业落地篇,难度偏 Advanced——公式较多,但请记住:宁可多配图,也不要死抠公式。重点在于理解架构选择的「为什么」。
Tips for This Part
- 抓住「语义 ID」这条暗线。 推荐、搜索、广告三节都在反复解决同一个问题——如何把离散业务对象变成生成模型能「说出」的 Token 序列。先理解语义 ID,后面水到渠成。
- 对比着读三节。 每节都是「MCA 的痛点 → 生成式解法 → 对齐线上目标」,但业务约束各不相同:推荐追求兴趣、搜索先保相关性、广告还要满足经济学机制。
- 关注算力与约束的工程权衡。 OneRec-V2 的 Lazy 架构、GPR 的 Trie 约束解码,都是用架构换效率与合规的典型思路。
Let's dive in! 🚀
端到端生成式推荐
📝 Before You Continue: 本章假设你已理解 1.1 的两种范式与端到端生成动机,并熟悉 2.3 中语义 ID 的初步概念。本章把它推向工业级落地。
传统多阶段级联架构(MCA)在推荐场景中暴露出最尖锐的矛盾:海量算力消耗在 通信与存储 而非模型计算,GPU 利用率远低于大语言模型;各阶段目标分散,模型结构差异导致建模不一致;级联结构更阻碍了 Scaling Law、强化学习对齐等先进技术的应用。
快手提出的 OneRec 框架,把推荐重新定义为 端到端的生成式任务 :模型根据用户上下文直接「生成」推荐序列,而不是从候选集里「挑选」。本节先看级联架构的深层瓶颈,再从 OneRec-V1 的体系,走到 V2 如何突破瓶颈。
读完本章,你将能够:
- 说明 语义 ID(Semantic ID) 如何解决「直接生成原子 ID 导致 Softmax 爆炸」的难题
- 描述 OneRec-V1 的四通路编码器与奖励系统设计,及其面对的两个瓶颈
- 解释 Lazy Decoder-Only 为何能把解码计算量降低 94%
- 复述 Scaling Law 在 OneRec-V2 上的验证与 GBPO 相比 ECPO 的改进
- 完成 5 道分层练习题,巩固语义 ID、架构与对齐算法
8.1.0 为什么需要端到端生成式推荐
推荐系统长期运行在「召回—预排序—排序—重排」的漏斗上。但正如 1.1 所述,级联架构有三个挥之不去的痛点,在推荐场景下尤为突出:
- 计算碎片化——各阶段独立部署、独立通信,大量资源花在数据传输而非有效计算,GPU 利用率远低于 LLM 训练。
- 优化目标冲突——召回优化相关性、排序优化点击率、重排优化多样性,各自为战,全局次优且误差逐层累积。
- 与 AI 前沿脱节——阶段割裂使 Scaling Law、RLHF 等在大模型领域验证有效的技术难以直接引入。
💡 Key Insight: 端到端生成式架构的本质,不是「换一个更大的模型」,而是把分散的子目标重新收束为一个统一的序列生成损失,从而让全局最优成为可能。
🧠 Mental Model: 从「海选评委」到「私人裁缝」
把级联推荐想成一场海选:先让成千上万选手过初筛(召回),再让评委逐一打分(排序),最后导演统筹出场顺序(重排)。每一步都在「缩小候选」。端到端生成式则像一位了解你品味的裁缝——他不听你报一堆候选,而是直接根据你的身形(上下文)裁出一件衣服(生成序列)。少了中间环节,也少了走样。
8.1.1 语义 ID:让模型「说出」一个物品
生成式推荐面临的第一个硬骨头是: 模型怎么「说出」一个物品? 传统系统用原子 ID(如视频 ID vid_12345678)标识物品,但快手有数十亿物品,直接生成原子 ID 会让 Softmax 层计算量爆炸。
OneRec-V1 采用 语义 ID(Semantic ID) :把物品映射到一个有限且可控的词表空间。每个视频被编码为 个语义 Token,词表大小为 。总编码空间为 ——远大于实际物品数,既保证覆盖,又用更大词表引入更多参数提升性能。
语义 ID 的生成分两个阶段:
阶段一:协同感知的多模态表示学习。 视频的标题、标签、ASR、OCR、封面、采样帧等经视觉语言模型(如 miniCPM-V-8B)压成 1280 个 Token,再用 QFormer 压缩为 4 个可学习查询向量。但仅依赖内容特征捕捉不到协同信号,于是引入 物品对对比学习 ,拉近高协同相似度的物品对:
同时用标题生成辅助任务防止表示退化,保留内容理解能力。
阶段二:RQ-Kmeans 层次化量化。 获得协同感知表示后,用 残差量化 K-means(RQ-Kmeans) 把连续表示离散化为语义 ID。与端到端训练的 RQ-VAE 不同,RQ-Kmeans 直接在残差上做 K-means 构建码本:
经过 3 层量化,每个视频 获得由粗到细的语义标识符序列 ,这成为生成模型的输出目标。
Analysis: 语义 ID 是连接「生成模型」与「离散物品」的桥梁。它把 的超大词表压缩到可控规模,同时让语义相近的物品共享前缀 Token——这既利于生成,也利于后续「先粗后细」的层次化解码。代价是量化有损,需要精心设计码本。
8.1.2 OneRec-V1:Encoder-Decoder 与偏好对齐
有了语义 ID,OneRec-V1 用经典 Encoder-Decoder 架构 实现端到端生成:编码器处理用户的多尺度特征,解码器基于上下文以自回归方式生成目标物品的语义 ID 序列。
编码器:四通路理解用户
编码器体现了对用户兴趣 多时间尺度 的深刻理解,含四个通路:
- 用户静态特征通路——ID、年龄、性别等基础画像,经两层密集层得 。
- 短期行为通路——最近 次交互,含物品/作者 ID、标签、时间戳、时长、交互标签,得 。
- 正反馈行为通路——最近 次高参与交互,得 。
- 超长期历史通路——OneRec-V1 一大创新。用户可达 10 万条历史,直接处理会算力爆炸。先用分层 K-means 压缩(聚类数 选代表物品),再用 QFormer 以 128 个可学习查询对压缩后的 2000 长度序列做交叉注意力,得 。
四路输出拼接后经 层 Transformer 编码器:
最终输出 提供全面上下文。
解码器:自回归生成语义 ID
解码器输入为 [BOS] 与目标物品的语义 ID 序列,每层含因果自注意力(捕获已生成 Token 依赖)、交叉注意力(关注编码器上下文)、MoE 前馈(top-k 路由增容量保效率)。训练用下一 Token 预测的交叉熵:
奖励系统:突破「模仿天花板」
预训练只拟合历史曝光分布,而曝光数据来自传统系统——模型本质上在「模仿」过去,性能上限被旧系统束缚。OneRec-V1 引入基于奖励系统的 RL 后训练,含三层奖励:
① 用户偏好对齐(P-Score)。 用神经网络学习个性化偏好分数,基于 SIM 架构为每个目标(CTR、LTR、VTR 等)建独立塔,各塔用对应标签算二元交叉熵作为辅助任务,再输入最终 MLP 输出 P-Score:
② 生成格式规范化(格式奖励)。 语义 ID 编码空间远大于物品数,推理可能生成无法映射真实物品的 非法序列。RL 引入后会急剧恶化——源于 挤压效应(Squeezing Effect) :模型把概率质量压到当前最优输出,使部分合法 Token 概率被压到与非法 Token 相近。OneRec-V1 对合法样本设优势为 1、直接丢弃非法样本以避免挤压。
③ 工业场景对齐(SIR)。 端到端特性让「只需把优化目标融入奖励系统」。如病毒内容占比超阈值 时对 P-Score 降权:
实验表明 SIR 降低病毒内容曝光 9.59%,核心指标稳定。
ECPO:偏好对齐算法
OneRec-V1 用 ECPO(Early Clipped GRPO) 对齐偏好。对用户 用旧策略生成 个物品,各经 P-Score 得奖励 :
优势 ,旧策略经早期裁剪:
ECPO 的关键改进是 对负优势样本的策略比率预先裁剪 ,避免 GRPO 中负优势比率任意大导致梯度爆炸。
Analysis: V1 在快手线上验证了端到端生成式推荐的可行性。但扩展模型规模时暴露两个瓶颈:一是 Encoder-Decoder 计算资源分配失衡——绝大部分算力消耗在上下文编码,真正产生梯度的目标 Token 解码占比极低;二是基于奖励模型的 RL 面临采样效率低与 reward hacking 风险。这催生了 V2。
8.1.3 OneRec-V2:Lazy Decoder-Only 与 Scaling Law
OneRec-V2 从架构与算法双维度突破:架构上提出 Lazy Decoder-Only 解决计算效率,算法上引入基于真实用户反馈的 RL 突破奖励模型局限。
Lazy Decoder-Only 架构
设计哲学是: 把计算资源集中到真正对损失贡献梯度的目标物品 Token 上。它含两个核心组件:
Context Processor。 把所有用户特征拼成统一上下文序列,每个 Token 映射到维度:
其中 是键值分离系数( 共享、 分离), 键值层数。Context Processor 沿特征维切成 组,每组经 RMSNorm 生成键值对。巧妙之处在于: 这些键值对对同上下文全程不变,可被多层解码器共享 ,无需每层重算。即使极致共享()性能也不明显受损。
Lazy Decoder Block。 与传统 Decoder-Only 把所有输入拼成长序列做自注意力不同,它 不把上下文作为序列一部分 ,而是视为 静态条件信息 ,仅通过交叉注意力访问。「Lazy」指:只在目标 Token 位置算损失,不对整序列每位置算 NTP 损失。
训练时,目标物品的前两个语义 ID 加 [BOS] 组成仅 3 个 Token 的输入序列:
每层含三步骤:Lazy Cross-Attention(无键值投影、用 GQA 分组查询降内存)、Causal Self-Attention(语义 ID 间自回归)、FFN(深层可换 MoE)。
效率提升量化
通过这种设计,Lazy Decoder-Only 实现 接近 100% 计算集中在目标 Token :
| 架构 | 参数量 | 计算量 (GFLOPs) | 收敛损失 |
|---|---|---|---|
| Encoder-Decoder (1:1) | 1B | 296.36 | 3.28 |
| Lazy Decoder-Only | 1B | 18.89 | 3.27 |
换言之,在相近性能下,计算开销降低 94% ,训练资源节约 90%。
Scaling Law 验证
Lazy Decoder-Only 展现出优秀可扩展性。OneRec-V2 将规模从 0.1B 扩到 8B,损失 随参数量 幂律衰减:
| 模型规模 | 参数量 | 收敛损失 |
|---|---|---|
| Dense | 0.1B | 3.57 |
| Dense | 0.5B | 3.33 |
| Dense | 1B | 3.27 |
| Dense | 2B | 3.23 |
| Dense | 4B | 3.20 |
| Dense | 8B | 3.19 |
| MoE | 4B (0.5B 激活) | 3.22 |
引入 MoE 后,总参 4B、每次仅激活 0.5B 的稀疏模型收敛损失 3.22,优于 2B 密集模型(3.23),计算开销却与 0.5B 密集相当。
用户反馈强化学习:GBPO
OneRec-V2 用大规模部署后的真实反馈(播放时长最密集)做 RL。原始时长有偏差:长视频天然累积更长。于是提出 时长感知奖励塑形(Duration-Aware Reward Shaping) :对数分桶 ;算目标视频在对应时长桶内的百分位 ;选前 25% 为正()、明确负反馈为负()、其余过滤()。
针对传统裁剪(PPO/GRPO/ECPO)对策略比率=1 的样本仍可能梯度爆炸的问题,OneRec-V2 提出 GBPO(Gradient-Bounded Policy Optimization) ,用 BCE 损失的稳定梯度界定 RL 梯度:
GBPO 相比传统裁剪有两个优势:(1) 完整样本利用——保留所有样本梯度,鼓励更多样探索;(2) 有界梯度稳定化——用 BCE 梯度界定 RL 梯度,增强稳定性。
下面用交互演示直观感受 OneRec 的端到端生成式 pipeline:从用户上下文编码,到语义 ID 自回归生成,再到偏好对齐与最终列表输出。点击「下一步」观察每一步。
注意「Lazy 解码」这一步:输入只有 3 个 Token([BOS] + 前两个语义 ID),上下文作为静态条件通过交叉注意力访问——这正是 V2 把算力集中到目标 Token、将成本砍掉 94% 的关键。
⚠️ Common Mistakes in 8.1
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为可直接生成原子 ID | 「让模型直接输出视频 vid」 | 数十亿词表使 Softmax 计算爆炸 | 用语义 ID 压缩到可控词表 |
| 2 | 混淆 RQ-Kmeans 与 RQ-VAE | 「两者一样都是端到端量化」 | RQ-Kmeans 在残差上直接 K-means 建码本,非端到端训练 | 记住 V1 用 RQ-Kmeans、EGA 用 RQ-VAE |
| 3 | 忽视挤压效应 | RL 后非法序列变多 | 概率质量被压到最优输出,合法/非法难分 | 用格式奖励丢弃非法样本 |
| 4 | 以为 V1 架构已高效 | 「Encoder-Decoder 直接上规模」 | 编码占绝大多数算力,目标 Token 解码占比极低 | V2 改 Lazy Decoder-Only 集中算力 |
| 5 | 把 GBPO 当普通裁剪 | 「ECPO 已足够」 | 策略比率=1 的负样本仍可能梯度爆炸 | GBPO 用 BCE 梯度界定 RL 梯度 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 语义 ID | 个 Token, 编码空间,RQ-Kmeans 量化 | 让生成式推荐在数学上可行、且语义相近物品共享前缀 |
| OneRec-V1 | 四通路编码 + Enc-Dec + P-Score/ECPO/SIR | 首个工业级端到端生成式推荐验证 |
| Lazy Decoder-Only | 上下文作静态条件 + 仅目标 Token 算损失 | 计算降 94%,释放 Scaling Law 潜力 |
| Scaling Law | 推荐模型首次呈现可预测的规模收益 | |
| GBPO | BCE 梯度界定 RL 梯度 | 突破奖励模型上界,稳定利用真实反馈 |
❓ FAQ
Q1: 语义 ID 和 2.3 里的语义 ID 有什么不同?
A: 思想一致(把物品离散成层次 Token),但本章用 RQ-Kmeans 在残差上直接聚类建码本,而非端到端训练的 RQ-VAE;并且显式融合了协同对比学习,使语义 ID 同时编码内容语义与行为模式。
Q2: 为什么 V2 不干脆去掉编码器?
A: 不是去掉,而是把编码结果预处理成「静态键值对」(Context Processor),让多层解码器共享。这避免了 V1 里每层重复编码同一上下文的浪费,同时保留上下文的全部信息。
Q3: 真实用户反馈比奖励模型好在哪?
A: 奖励模型在旧 MCA 数据上训练,性能上界被旧系统束缚;真实曝光/时长/负反馈是「地面真值」,GBPO 借此突破天花板,且无需维护独立奖励模型。
🔗 前后关联
- 8.2 (端到端生成式搜索)把同一套语义 ID + Enc-Dec 思路迁移到「文本查询 → 商品」的跨模态匹配。
- 8.3 (端到端生成式广告)在生成式中额外内嵌竞价机制与经济学约束。
- 6.1–6.4 (生成式推荐范式基础)回顾语义 ID、RQ-VAE 等更底层的原理,本节是其工业落地。
- 9.1–9.3 (生成式思考/推理)进一步讨论模型如何显式推理用户意图,与 OneRec 的偏好对齐技术互补。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 8.1.1 — 语义 ID 编码空间 🟢 Easy
某系统词表大小 ,每个物品编码为 个语义 Token。问:(a) 总编码空间有多大?(b) 若实际物品数为 1 亿,编码空间是物品数的多少倍?(c) 为何「编码空间远大于物品数」是好事?
💡 Solution (click to reveal)
Approach: 编码空间是每层词表大小的 次方。
- (a) (约 687 亿)。
- (b) 倍。
- (c) 远大于物品数,保证所有物品都能被唯一覆盖(不会因码本不够而冲突),同时更大的词表引入更多可学参数,提升模型容量。
Key points:
- 语义 ID 用「小词表 + 多层」换「大覆盖、可控计算」。
- 编码空间 > 物品数 是刻意设计,不是浪费。
Problem 8.1.2 — RQ-Kmeans 残差量化 🟢 Easy
一维表示 ,第 1 层码本中心 ,第 2 层码本中心 (在残差上)。求两层语义 ID 与最终重构值。
💡 Solution (click to reveal)
Approach: 每层选最近中心,残差传给下一层。
- 第 1 层: → 最近是 8,故 ,残差 。
- 第 2 层(在残差 上): → 最近 或 (并列)。取 。
- 重构值 (相比原值 7 有 1 的量化误差)。
Key points:
- 每层量化的是「上一层没表达的残差」,逐步细化。
- 层数越多、码本越大,重构越精确。
Problem 8.1.3 — Lazy 架构的算力账 🟡 Medium
Encoder-Decoder (1:1) 计算量 296.36 GFLOPs、收敛损失 3.28;Lazy Decoder-Only 计算量 18.89 GFLOPs、损失 3.27。若训练预算固定为 GFLOPs,且每单位算力带来的「有效梯度」与目标 Token 占比成正比,估算 Lazy 架构相比旧架构在相同预算下能多训练多少倍的样本?
💡 Solution (click to reveal)
Approach: 假设两者单位计算产生的有效梯度相近(损失几乎相同,说明每 FLOP 的学习效率相当),则相同预算下可处理的样本量与单样本计算量成反比。
即在相同算力预算下,Lazy 架构约能多训练 15.7 倍 的样本(与文中「训练资源节约 90%」一致:)。
Key points:
- 关键洞察:旧架构大量算力花在「编码上下文」而非「解码目标」,这些算力不产生针对推荐目标的梯度。
- Lazy 把算力挪到刀刃上,预算利用率近线性提升。
Problem 8.1.4 — 挤压效应与格式奖励 🔴 Hard
假设某物品语义 ID 第 3 层有合法 Token (对应真实物品)与非法 Token (不映射任何物品)。预训练后 。对负优势物品应用 RL 后,模型把概率质量压到当前最优输出 ,使 。此时若不用格式奖励,会发生什么?格式奖励(合法优势=1、非法丢弃)如何缓解?
💡 Solution (click to reveal)
Approach: 分析合法/非法概率的相对关系变化。
- 不用格式奖励时: 从 0.45 跌到 0.15,已接近非法 的量级。模型越来越难区分「合法但当前次优的 B」与「非法 X」——这正是挤压效应:合法 Token 概率被压到与非法相近,解码时可能输出非法序列。
- 格式奖励做法:对合法样本设优势 1、非法样本直接丢弃(不进入梯度)。这相当于给模型一个强先验——「只许在合法 Token 内优化」,把 与 之间的选择留给偏好对齐,同时把 这类非法项彻底排除在优化路径外,避免其概率被「挤」到与合法项难分。
Key points:
- 挤压效应的危害是「合法空间被压缩到与非法难分」,而不仅仅是次优。
- 格式奖励 = 合法性硬约束 + 把合法内部排序交给偏好奖励。
🏆 Challenge: 设计端到端生成式推荐的落地论证
某短视频平台日活 1 亿,当前是典型「召回→排序→重排」级联系统。请写约 180 字论证:在引入 OneRec 类端到端生成式架构时,应先在哪一环节试点?需要优先解决哪些工程问题(参考 V1 的两个瓶颈与 V2 的解法)?
💡 Hint
优先在「候选生成/召回」或「重排多样性」环节做生成式试点,风险可控;工程上需先解决:(1) 语义 ID 的构建与码本维护(RQ-Kmeans 定期重算);(2) 算力分配——直接上 Enc-Dec 会算力失衡,应借鉴 V2 的 Lazy Decoder-Only 把计算集中到目标 Token;(3) 对齐线上多目标须引入偏好奖励(P-Score/SIR)与格式奖励防非法序列;(4) 用真实用户反馈(GBPO)突破奖励模型上界。
端到端生成式搜索
📝 Before You Continue: 建议先读 8.1 的语义 ID 与 Encoder-Decoder 思路——本节把同一套生成式哲学迁移到「文本查询 → 商品结果」的跨模态匹配,但业务约束更尖锐。
8.1 的 OneRec 输入与输出都是 封闭词表 的物品 ID。电商搜索则截然不同:用户用 明确的文本查询 表达意图,系统需在强相关性约束下从海量商品库返回精准匹配。这种「文本查询 → 商品结果」涉及 开放词表 (任意查询)与 封闭词表 (有限商品库)的混合,以及查询理解、语义匹配、个性化排序等多层次任务。
传统电商搜索同样是 MCA:查询理解(纠错/改写/意图)→ 召回(倒排+向量)→ 预排序 → 精排,存在查询与商品检索解耦、冷启动长尾、标题关键词堆砌噪声三大问题。OneSug 与 OneSearch 分别针对搜索链路的前半段(查询补全)与后半段(商品检索)提出端到端生成式方案,共享统一架构哲学,但在输入输出空间、ID 设计上有不同权衡。
读完本章,你将能够:
- 说明 OneSug 如何把查询补全重定义为条件文本生成,并用 PRE 模块增强短前缀
- 描述 RWR 策略 如何用六级交互反馈把业务价值注入排序
- 解释 OneSearch 的 KHQE 如何用「3 层语义 + 2 层 OPQ」平衡语义层次与商品独特性
- 复述 Mu-Seq 的三视角用户建模与 PARS 的偏好感知奖励
- 完成 5 道分层练习题,巩固前缀增强、语义 ID 编码与约束解码
8.2.0 电商搜索的三大独特挑战
与视频推荐相比,电商商品检索约束更复杂:
- 强相关性是第一优先级。 推荐可基于历史推风格相似但类目不同的商品;搜索则不可妥协——用户搜「红色连衣裙」,即便他常买蓝色商品,返回「蓝色连衣裙」也是严重相关性违反。系统必须 先满足相关性,再优化个性化。
- 商品信息充斥噪声与冗余。 商家在标题堆砌大量关键词(「2024新款韩版修身显瘦长袖连衣裙女学生小个子甜美气质裙子百搭」),传统文本编码器被冗余淹没,难识别核心属性。
- 语义层次与商品独特性的平衡。 既要理解类目层次(服装→女装→连衣裙→韩版连衣裙)做粗粒度匹配,又要保留每件商品的独特属性(款式/品牌/价格),否则所有「韩版连衣裙」会被映射到相同表示。
💡 Key Insight: 搜索的端到端难点,本质是在「生成」与「强约束」之间走钢丝——生成的自由度高,但相关性是不可逾越的底线。这正是 OneSearch 在奖励系统中把相关性权重放大 10 倍的原因。
8.2.1 OneSug:查询补全生成
查询补全是搜索第一道关口:用户输入前缀「红色连」,系统需实时生成完整查询候选(「红色连衣裙」「红色连帽衫」)。传统 MCA 用前缀树(Trie)从 候选粗召回到 ,再预排序到 、精排展示 16 个,存在前序性能瓶颈限制后续上界、各阶段目标冲突两大问题。
OneSug 把查询补全重定义为 端到端的条件文本生成任务 :
绕过传统多阶段链路。其核心挑战:短前缀语义歧义(「苹」可能指水果或手机)、个性化与流行度平衡、多级反馈精细化建模、100ms 实时性约束。
编码器:前缀增强与多源特征
前缀-查询语义对齐。 对纯文本前缀 用预训练 Text Encoder(BGE)提取 。但通用 NLP 模型在电商语义空间有偏差,OneSug 对 BGE 做领域对齐微调:从日志挖高质量 prefix-query 与 query-query 共现对,对比学习拉近协同相关查询:
对齐后 BGE 在查询检索任务上的语义相关性从 0.67 升至 0.81。
前缀表示增强(PRE 模块)。 短前缀表示不足,PRE 从历史日志检索与此外共现的高质量查询集合 ,平均嵌入加权融合:
消融显示 时 MRR 比无增强提升 2.3%,但 引入噪声致性能下降。为高效检索,OneSug 用 RQ-VAE 把查询编码为分层离散码(4 层,每层码本 512),推理时从粗到细层级匹配,复杂度从向量检索的 ( 为全部候选物品数)降为逐层码本查找的 ——与候选规模 无关,只随层数 和码本大小 线性增长。
用户特征。 整合短期历史查询 (最近 条,超过会引噪声使 MRR 降 1.2%)与静态画像 。注意 OneSug 不引入商品交互特征——查询补全发生在用户输入阶段,尚无商品曝光。编码器输入构造为:
解码器与 RWR 排序策略
解码器用标准 Causal Transformer 自回归生成子词,训练最小化 NTP 损失。推理用 Beam Search (束宽 ),并引入长度归一化避免偏好短查询:
仅靠 NTP 的生成模型无法区分候选的业务价值。RWR(Reward-Weighted Ranking) 把六级交互反馈转为精细化偏好信号:
| 层级 | 反馈类型 | 业务含义 | 基础权重 |
|---|---|---|---|
| Level 1 | Order | 通过该查询完成购买 | 2.0 |
| Level 2 | Item Click | 点击查询返回的商品 | 1.5 |
| Level 3 | Click | 点击该查询 | 1.0 |
| Level 4 | Show | 展示未点击 | 0.5 |
| Level 5 | Not Show | 召回池未展示 | 0.2 |
| Level 6 | Rand | 随机负样本 | 0.0 |
对每个 <前缀, 查询> 对,奖励 ( 是该查询在对应层级的归一化频率),使高频交互查询获更高奖励。从 6 层构造 9 类偏好对,偏好差异 。最终在 DPO 损失上引入奖励加权与边界 :
Analysis: OneSug 把查询补全从 MCA 变为端到端生成式。PRE 解决短前缀歧义,六级反馈构建的奖励系统精准建模偏好差异。统一框架不仅简化架构,更能全局优化、避免前序瓶颈。代价是 Beam Search 与 RWR 对齐需额外推理开销,须控制在 100ms 内。
8.2.2 OneSearch:商品检索生成
用户敲下「红色连衣裙」后,系统需一秒内从数亿商品中找最相关结果。OneSearch 把「查询 → 召回 → 预排序 → 精排」统一为端到端序列生成:
即直接输入查询文本与用户行为特征,输出有序商品列表。它设计四个核心模块: KHQE (关键词增强分层量化编码)、Mu-Seq (多视角行为序列注入)、统一 Encoder-Decoder 生成架构、PARS (偏好感知奖励系统)。
KHQE:关键词增强的分层量化编码
核心问题:在生成式框架中,如何表示数亿个商品? 原子 ID 有两大致命问题:词表 使 Softmax 不可行;原子 ID 是随机数字,不含语义。
OneSearch 用 分层语义 ID :商品映射为多层离散码序列 。例如某韩版连衣裙编码为 ,词表约 6000 个唯一 Token,远小于数亿。前 3 层保语义层次,后 2 层保商品独特性。
商品表示学习。 文本、结构化属性、统计特征经蒸馏 BGE 得初始嵌入 ,再用多类对齐任务同时捕获语义与协同:query-query / item-item 对比、query-item 对比、分层反馈对齐(曝光/点击/下单赋不同 Margin)、难样本相关性校正(用 LLM 评边界样本)。
核心关键词增强。 标题的营销词(「爆款」「包邮」)稀释核心属性。OneSearch 用 NER 构建 18 类属性词表,以 Aho-Corasick 自动机 ( 多模式匹配)在标题快速匹配核心词,50%-50% 加权增强:
RQ-Kmeans 语义层次编码。 逐层提取语义、残差传下层:L1(码本 4096)捕最粗类目(服装/数码/食品),L2(1024)细分层(女装/男装),L3(512)捕细粒度(连衣裙/ T 恤)。关键优化: 仅在 L3 应用平衡 K-means——早期层强制平衡会导致层次聚类崩溃、丧失语义区分度。
OPQ 商品独特性编码。 3 层 RQ 后残差仍含独特属性(款式/品牌/价格)。若只用前 3 层,两件「韩版连衣裙」(一件 Zara 299 元、一件无牌 99 元)会被视为完全相同。于是引入 OPQ(Optimized Product Quantization) 把残差切分 子向量分别 K-means(码本 256):
为何不对所有层用 OPQ?实验发现会破坏层次语义性、性能大幅下降——失去「粗到细」的渐进生成模式。
Mu-Seq:多视角行为序列注入
行为序列驱动的用户 ID。 不用随机哈希 ID,而用行为序列构造 User ID:短期点击 与长期点击 各自加权求和(权重 ,越近权重越高但不激进),向上取整后拼接(总长 10)。好处:兴趣相似用户得相近 ID;冷启动可用平台「查询→Top 点击」作默认序列。
显式短期序列注入。 最近历史查询与点击商品显式放入输入:查询用原始文本(短,直接 Tokenize),商品用语义 ID(标题冗长,更紧凑);长度限制(查询 、点击 )。
滑动窗口数据增强。 完整序列 传统只生成 1 样本,OneSearch 用最大窗口 生成多个,让模型学习兴趣演化、自然处理冷启动。
Q-Former 长期序列压缩。 活跃用户可能有数千至上万长期行为。按行为类型(点击/下单/RSU)分层聚合为 个向量,再用 个可学习查询向量经交叉注意力提取固定长度表示 ,无论历史多长都不显著增加计算。
统一 Encoder-Decoder 生成架构
OneSearch 选 BART (Encoder-Decoder,编码器双向建模、解码器自回归,且有良好预训练权重与工业加速优化)。编码器输入异构序列(离散 Token + 连续向量),输出 。
解码器逐 Token 生成目标商品 5 层语义 ID,以 为例:
步骤 0:输入 [BOS] → 预测 L1 = 3856
步骤 1:输入 [BOS, 3856] → 预测 L2 = 724
步骤 2:输入 [BOS, 3856, 724] → 预测 L3 = 385
步骤 3:输入 [BOS, ..., 385] → 预测 OPQ1 = 142
步骤 4:输入 [BOS, ..., 142] → 预测 OPQ2 = 201
每步经 Causal Self-Attention 与 Cross-Attention,Softmax 预测下一 Token:
训练目标为最大化真实 SID 对数似然 。推理用 Beam Search ,可选约束搜索(强制每层 Token 来自有效 SID 池,确保对应真实商品)或非约束搜索。
PARS:偏好感知奖励系统
仅靠 NTP 的模型只学到「哪些商品与查询共现」,没学到「用户更偏好哪些」。PARS 含 多阶段监督微调 与 自适应奖励系统。
多阶段 SFT。 阶段一语义内容对齐(文本↔SID、文本→类目),阶段二共现关系同步(query↔item 文本与 SID 层面的协同),阶段三用户个性化建模(引入完整用户上下文)。
自适应奖励信号。 用户交互分 6 层(搜索下单 2.0 / 推荐同类目下单 1.5 / 点击 1.0 / 曝光未点 0.5 / 同类目未展示 0.2 / 随机 0.0)。为避免新商品曝光少致偏差,用对数平滑算 CTR、CVR,奖励为调和平均:
奖励模型(三塔 SIM)。 CTR 塔 / CVR 塔 / CTCVR 塔分别预测,综合分数 ——离线相关性分数 权重放大 10 倍 ,确保先满足相关性再优化个性化。
混合排序框架。 基于奖励模型做 List-wise DPO :采样 512 候选,对排序发生变化的样本训练,损失结合 DPO 与 SFT 目标,既学偏好排序又保持生成能力。上线后持续用真实交互(Level 1-3 正、Level 4-6 负)做近实时在线学习。
Analysis: OneSearch 用 KHQE 的「3+2」语义 ID 优雅平衡了语义层次与商品独特性;Mu-Seq 三视角建模兼顾相关性与个性化;PARS 把相关性作为硬约束(×10)嵌入奖励。整条链路从 MCA 的多阶段变为单一生成模型,但代价是训练数据工程(对齐、滑动窗口、多阶段 SFT)与推理时 Beam Search 的延迟控制。
⚠️ Common Mistakes in 8.2
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把搜索当推荐优化 | 「搜红色连衣裙也推蓝色款」 | 搜索强相关性不可妥协 | 先满足相关性再个性化(奖励×10) |
| 2 | 忽视前缀语义歧义 | OneSug 直接编码 1 字前缀 | 短前缀无明确意图信号 | 用 PRE 模块检索共现查询增强 |
| 3 | KHQE 全用 OPQ | 「5 层都 OPQ 更细」 | 破坏粗→细层次语义 | 前 3 层 RQ 保层次,后 2 层 OPQ 保独特 |
| 4 | L1/L2 强制平衡 K-means | 「每层都平衡更均匀」 | 早期层平衡致层次聚类崩溃 | 仅在 L3 应用平衡约束 |
| 5 | 混淆 SID 与原子 ID | 「直接用 item_123 当词表」 | 数亿词表使 Softmax 爆炸 | 分层语义 ID 压缩到约 6000 词表 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| OneSug | 条件文本生成 + PRE 前缀增强 + RWR 六级反馈 | 查询补全从 MCA 变端到端生成 |
| KHQE | 3 层 RQ-Kmeans(语义)+ 2 层 OPQ(独特) | 数亿商品压缩到可控语义 ID |
| Mu-Seq | 行为序列 UserID + 短期显式 + Q-Former 长期压缩 | 相关性优先下的个性化建模 |
| PARS | 多阶段 SFT + 自适应奖励 + 相关性×10 | 先保相关性,再优化偏好 |
| Beam Search | 约束/非约束两种,SID 池过滤非法 | 生成真实商品、控延迟 |
❓ FAQ
Q1: OneSug 为何不引入商品交互特征?
A: 查询补全发生在用户输入阶段,此时还没有商品曝光行为。引入商品特征既无数据支撑,也会让前缀表示被无关信号污染。它只用前缀、历史查询与静态画像。
Q2: 为什么 KHQE 前 3 层用 RQ-Kmeans、后 2 层用 OPQ,而不是全部 RQ?
A: 前 3 层要表达「服装→女装→连衣裙」的渐进类目层次,RQ 的残差传递天然契合;后 2 层要编码残差中的独特属性,OPQ 的子向量独立量化更适配。全 OPQ 会丢失层次语义性。
Q3: PARS 把相关性权重放大 10 倍,会不会伤害个性化?
A: 恰恰是保护个性化——它先保证「不返回不相关商品」,再在相关集合内用 CTR/CVR 等优化个性化。这避免了推荐系统常见的「相关性漂移」。
🔗 前后关联
- 8.1 (端到端生成式推荐)的语义 ID 与 Enc-Dec 是本节的方法基础,OneSug/OneSearch 是其跨模态延伸。
- 8.3 (端到端生成式广告)在生成式中再叠加竞价机制与经济学约束。
- 2.3 (双塔)的向量检索思路,被 OneSearch 用语义 ID + Beam Search 的「生成式检索」替代。
- 6.x (生成式基础)的 RQ-VAE 量化,在本节以 RQ-Kmeans(OneSearch)/ RQ-VAE(OneSug)两种形态出现。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 8.2.1 — PRE 增强计算 🟢 Easy
前缀嵌入 ,相关查询平均嵌入 。PRE 模块权重 ,求增强后 。若 会有什么趋势?
💡 Solution (click to reveal)
Approach: 加权平均。
若 :,前缀自身信号被大幅稀释,过度依赖共现查询——正是文中 引入噪声、性能下降的原因。
Key points:
- 是经验最优平衡点。
- 过大 让前缀「变成别人」,丢失用户真实输入信号。
Problem 8.2.2 — KHQE 编码空间 🟢 Easy
某商品经 KHQE 得 SID ,各层码本大小分别为 4096 / 1024 / 512 / 256 / 256。问:(a) 总词表唯一 Token 数约多少?(b) 该编码如何同时体现「语义层次」与「商品独特性」?
💡 Solution (click to reveal)
Approach: 词表唯一 Token 数为各层码本之和(不同层码字独立编号)。
- (a) 个唯一 Token。
- (b) 前 3 层 RQ-Kmeans:L1=2341(服装)、L2=567(女装-裙装)、L3=89(连衣裙-韩版)体现由粗到细的类目层次;后 2 层 OPQ 编码残差中的独特属性(款式/品牌/价格),使两件同「韩版连衣裙」也能被区分。
Key points:
- 总词表远小于数亿原子 ID,Softmax 可行。
- 「层次 + 独特」是 KHQE 设计的核心张力平衡。
Problem 8.2.3 — 行为序列 User ID 构造 🟡 Medium
用户短期点击商品的语义 ID 为 (按时间从早到晚),权重 。求归一化权重 (保留 3 位小数),并说明为何用 而非线性 。
💡 Solution (click to reveal)
Approach: 计算 再归一化。
和
越近行为权重越高(0.218 < 0.329 < 0.453)。用 而非线性 :线性衰减(如 )会让最近行为权重爆炸式主导、早期行为几乎归零; 是「温和递增」,既体现时序远近,又保留较早行为的贡献,避免过激遗忘长期兴趣。
Key points:
- 权重反映时间远近但不激进。
- 这是用「软衰减」平衡短期意图与长期偏好。
Problem 8.2.4 — 约束 Beam Search 的非法过滤 🔴 Hard
OneSearch 解码生成 5 层 SID,约束搜索要求每层 Token 必须来自有效 SID 池(真实商品集合)。假设第 1 层候选 Token 共 4096 个,其中有效 SID 池在第 1 层只覆盖 2000 个;Beam 宽度 。对比「约束搜索」与「非约束搜索」在 (a) 生成合法性、(b) 单步候选数上的差异,并说明为何约束搜索能降延迟。
💡 Solution (click to reveal)
Approach: 分析搜索空间与后处理。
- (a) 约束搜索:每层只在有效池(第 1 层 2000 个、逐层收窄)内解码,生成序列必对应真实商品,无「幻觉 SID」;非约束搜索:允许任意 Token 组合,可能生成不映射真实商品的非法 SID,需在后处理过滤。
- (b) 单步候选:约束搜索第 1 步最多 2000 候选(且后续层随树收窄更小);非约束搜索每步固定 4096 候选。约束搜索实际搜索空间 ,远小于 。
- 延迟:约束搜索在解码早期就剔除非法分支,避免非约束生成大量无效候选后再过滤;结合 Trie 前缀树(见 8.3 的 GPR),可将搜索空间从 缩到有效商品数,显著降低每步计算。
Key points:
- 约束搜索 = 把「合法性」做成解码时的硬 mask。
- 这是生成式检索落地的关键工程技巧。
🏆 Challenge: 设计搜索端到端落地论证
某电商搜索当前 MCA 在「红色连衣裙」查询下常返回蓝色款(相关性漂移)。请写约 160 字,说明引入 OneSearch 类端到端生成式架构时:(1) 应优先改哪一环节;(2) KHQE 与 PARS 中哪两个设计能直接缓解该问题;(3) 需警惕什么新风险?
💡 Hint
(1) 优先替换「查询理解 + 召回 + 精排」为统一 Enc-Dec 生成,消除意图在阶段间损失。(2) KHQE 的分层语义 ID 让「红色连衣裙」与「蓝色连衣裙」在 L3 层即区分;PARS 把离线相关性分数 权重放大 10 倍,强制先满足相关性。(3) 新风险:Beam Search 延迟、训练数据工程复杂(多阶段 SFT、滑动窗口)、以及生成式检索的不可解释性带来的bad case 定位困难。
端到端生成式广告
📝 Before You Continue: 建议先读 8.1 的语义 ID / Enc-Dec / 强化学习对齐,以及 8.2 的强约束检索——广告场景同时叠加了二者的技术挑战,再额外背负经济学约束。
8.1 与 8.2 通过端到端生成架构解决了级联系统的性能瓶颈。但 在线广告 面临更复杂的约束:系统不仅要优化用户体验,还要平衡平台收益与广告主利益,满足竞价机制的经济学约束。传统广告系统「召回→排序→创意选择→竞价→位置分配」的多阶段架构,目标碎片化、难适应快速变化的市场。
端到端生成式广告要突破三个核心挑战: 如何把竞价机制深度融入生成过程、如何保证广告主的激励相容性(Incentive Compatibility, IC)、如何在超长异构序列中高效建模用户意图。本节介绍两个工业方案: EGA 把竞价机制与生成模型统一,通过 Token 级竞价与 POI 级支付的双层设计内嵌 IC/IR 约束; GPR 通过异构层次化解码器与预训练,在微信生态超长异构序列中实现多场景统一建模。
读完本章,你将能够:
- 解释广告场景相对推荐/搜索的 三重约束 (IC/IR、POI+创意联合、分配支付解耦)
- 描述 EGA 的双模态语义 ID、概率分解生成与 Token 级竞价机制
- 说明 ex-post regret 与 Lagrangian 优化 如何近似保证激励相容
- 概述 GPR 的四类 Token、RQ-Kmeans+、异构层次化解码器与价值引导 Trie Beam Search
- 完成 5 道分层练习题,巩固竞价聚合、支付网络与层次化策略优化
8.3.0 广告生成的三重约束
通过一个场景理解广告与推荐、搜索的本质差异:用户在本地生活平台刷 feed,系统要在第 3 位插一条广告,候选是附近餐厅、健身房、美容院,每个商户提交不同竞价 ,且各有若干创意图。一次前向传播要完成四个决策——展示哪个商户(POI)、用哪张创意、如何计算支付、如何保证公平。这揭示三重重约束:
约束一:激励相容性(IC)与个体理性(IR)。 广告主是独立博弈方,会依规则调竞价。IC 要求如实出价是最优策略:对真实估值 与申报 , 时效用最大:
效用 (点击收益减支付)。IR 要求支付不超竞价 。注意传统 GSP 拍卖按「下一位价格支付」在多坑位场景下并 不满足 IC(仅 VCG 满足,但工程上难以落地),且它假设广告相互独立、无法处理位置外部性。
约束二:POI 与创意的联合生成。 一个 POI(餐厅)可关联多张创意图,不同用户偏好不同创意。系统须联合决定「展示哪个 POI」与「用哪张创意」——POI 定内容主体,创意优化呈现方式。
约束三:分配与支付的解耦设计。 若直接把竞价当生成概率权重,会导致「赢家诅咒」:高竞价广告按自己竞价支付,广告主倾向压价。EGA 分离 分配 (竞价引导生成概率)与 支付 (独立网络学 IC 支付函数)两模块解决矛盾。
💡 Key Insight: 广告的端到端难点,是生成模型要「顺便」满足一套经济学机制——这不只影响目标函数,更要求架构上把「分配」与「支付」解耦,才可能用数学保证 IC/IR。
8.3.1 EGA:统一竞价与生成
双模态语义 ID 与概率分解
EGA 用 RQ-VAE 把 POI 与创意的连续表示离散为多层语义 ID(两套独立语义空间)。POI 原始表示含类目、地理位置、统计特征、文本描述;创意表示含视觉特征、OCR 文案、创意类型。用 层残差量化、码本 ,每个 POI 编码为 3 个 Token:
创意同理得 。用户历史交互表示为 (POI, 创意) 对序列。
概率分解策略。 直观想法是把 POI 与创意的 6 个 Token 拼接自回归生成,但 EGA 发现这会导致 POI 与创意不匹配(「餐厅 A 的 POI + 健身房 B 的创意」)。于是分解为:
直觉:POI 定「展示什么」,创意定「如何呈现」。先据兴趣生成 POI,再据 POI 特性与用户偏好选创意。
Encoder-Decoder 双解码器
EGA 用经典 Enc-Dec,但用 两个解码器 分别生成 POI 与创意。编码器处理混合了广告与有机内容的历史序列 (每项标 type∈{ad, organic}),输出 。POI 解码器 自回归生成 3 层语义 ID; 创意解码器 以生成的 POI Token 为条件生成创意 ID——输入含 POI Token 序列,使模型据 POI 语义选匹配创意。
MTP 模块。 标准解码器每步只预测下一 Token;EGA 用 MTP(Multi-Token Prediction) 每步同时监督两解码器,让它们共享底层表示、加速收敛并提升一致性:
排列感知奖励模型:处理位置外部性
预训练模型不知「哪个广告更好」。竞价微调需要奖励模型,但广告场景必须处理 位置外部性——广告非独立:位置效应(位置 1 的 CTR 远高于位置 5)、相邻效应(两个相邻餐饮广告相互抑制)、对比效应(高质量后跟低质量 CTR 下降)。数学上:
传统 point-wise 模型(DeepFM、Wide&Deep)无法建模序列级依赖。EGA 用 permutation-aware(排列感知) 设计,通过 Self-Attention 让每个广告「看到」序列中其他广告:
三个独立塔分别预测 POI-CTR / Creative-CTR / CVR ,综合奖励:
Analysis: 排列感知奖励模型是 EGA 相对 OneRec P-Score 的关键差异——它把「序列级位置外部性」建模进奖励,而非 point-wise 预估。代价是 Self-Attention 在序列长度上 ,且需额外训练三塔奖励模型。
Token 级竞价:最大值聚合
生成式框架输出 Token 序列,而 Token 与广告是 多对多 关系(一个广告编成多个 Token;一个 Token 可能对应多个广告),传统 item-level bid 不可用。EGA 用两层设计:
Token 级竞价聚合(最大值)。 对第 层 Token 对应的广告集 ,用 最大值 聚合竞价:
为何 max 而非 avg?若某 Token 对应高竞价广告,生成它有高商业价值,应提升概率;avg 会被低竞价稀释。基于此定义分配概率:
- :竞价影响权重。 退化为纯兴趣推荐, 变纯竞价排序。
- :广告与有机内容比例。 越大,有机内容(竞价 0)生成概率越高。
POI 级支付网络:学习满足 IC 的支付
直接按生成概率 支付有问题:生成概率不可微且难保 IC。EGA 解耦分配与支付 :分配用竞价引导,支付用独立神经网络学 IC 支付函数。支付网络输入含 POI 序列表示、自排除竞价矩阵(仅依赖他人竞价与自己分配,是 IC 关键)、期望价值(分配概率 × pCTR)。Sigmoid 输出支付率:
Sigmoid 保证 ,从而满足 IR 。
Ex-post Regret 约束。 借鉴机制设计量化 IC 违反:对广告主 ,如实出价效用 ,谎报最大收益为 regret:
时如实出价最优。实践中采样候选竞价近似。EGA 用 Lagrangian 对偶 求解约束优化(最大化收益、regret 约束近 0):
交替更新:固定 优化支付网络;固定网络更新 。regret 高的广告主,其 增大,迫使损失更关注降其 regret。
两阶段联合训练
阶段一 Interest-based Pre-training :忽略竞价,用曝光序列训 NTP+MTP 联合损失,得基础生成模型 。
阶段二 Auction-based Post-training :引入竞价、奖励模型、支付网络,三子任务交替:(1) 奖励模型用真实反馈训多任务 BCE,冻结构成评估器;(2) Policy Gradient —— 非自回归策略梯度,边际贡献奖励 ,损失 ;(3) 支付网络用 Lagrangian 最小化 ex-post regret。
Analysis: EGA 的核心价值是把「竞价机制」从外部规则变成生成模型内部可微的一部分——Token 级竞价引导分配、POI 级支付网络保证 IC。相对 OneRec 的差异在于引入竞价信号、IC 约束与排列感知。局限:RQ-VAE 与 Enc-Dec 针对单一场景,难统一跨场景;标准 Transformer 输入受限 难处理数万长序列;Beam Search 生成大量无效候选增延迟。这催生了 GPR。
8.3.2 GPR:预训练驱动的广告生成
EGA 强调「竞价驱动」; GPR(Generative Pre-trained Recommender) 采用「预训练 + 微调」范式,先在海量无监督数据上学通用兴趣表示,再经价值感知微调与 RL 对齐业务目标。它在微信生态(视频号/朋友圈/公众号/小程序)应对跨场景、超长序列、100ms 实时性挑战。
统一输入表示:四类 Token
GPR 把用户完整行为旅程编码为四类 Token 的混合序列:
- U-Token(User)——静态属性与长期偏好(人口统计、消费力、兴趣标签)
- O-Token(Organic)——浏览的有机内容(短视频 RQ-VAE 语义 ID、文章文本表示、好友动态多模态表示)
- E-Token(Environment)——即时环境(时间、地理位置、设备、场景标识)
- I-Token(Item)——交互过的广告 item(RQ-VAE 语义 ID,含 POI+创意)
这种表示:场景统一(不同场景内容同一套 Token)、时序连贯(跨场景形成时间线)、上下文丰富(每个 I-Token 周围有 O/E-Token 提供上下文)。
RQ-Kmeans+:解决 Codebook Collapse
O/I-Token 量化时传统 RQ-VAE 面临 codebook collapse :随机初始化码本中某些码字从未激活,利用率仅 60–70%。RQ-Kmeans+ 结合 RQ-Kmeans 高质量初始化与 RQ-VAE 端到端优化:
步骤 1 RQ-Kmeans 在残差上 K-means 构建初始码本(保证每码字至少分配到样本,避免死码字)。 步骤 2 用其作 RQ-VAE 初始权重,编码器侧加残差连接 ( 可学),再用标准 RQ-VAE 损失端到端训练。效果:码本利用率从 65% 升至 92%,重构误差降 15%。
异构层次化解码器(HHD)
EGA 的 Enc-Dec 把编码器解码器紧耦合,数万长序列会显存/算力瓶颈。GPR 提出 HHD(Heterogeneous Hierarchical Decoder) ,三层解耦实现「先理解、再推理、后生成」:
第一层 HSD(Sequence-wise Decoder)——意图理解。 用改进 HSTU 架构,含三设计:
- Hybrid Attention Mask——U/O/E-Token(Prompt)区域双向注意力、充分交互;I-Token(Target)区域因果注意力、保证自回归;Target 可看完整 Prompt。
- Token-Aware Normalization——U/O/E/I 四类 Token 分布差异巨大,各分配独立 LayerNorm 与 FFN,投影到各自语义子空间。
- MoR(Mixture-of-Recursions)——同层递归调用自身 次(可学权重 ),不增参却增加推理深度,类似「多轮思考」。
HSD 输出 意图嵌入 。
第二层 PTD(Token-wise Decoder)——推理与生成。 设计「Thinking-Refining-Generation」三段式:
- Thinking :生成 个 Thinking Tokens(可学查询向量经 Cross-Attention 从意图嵌入提取关键信号,过滤无关)。
- Refining :借鉴 Self-Reflection,对 Thinking Tokens 加高斯噪声后条件去噪 Transformer 迭代优化(类似 Stable Diffusion),提升复杂用户生成质量 2–3%。
- Generation :基于 refined 表示自回归生成目标广告语义 ID(3 层 RQ)。
第三层 HTE(Token-wise Evaluator)——价值评估。 在 每一层 Token 生成时就输出价值估计 ,最终广告价值 。HTE 用于 Beam Search 剪枝与 Policy Optimization 的 Critic。
价值引导的 Trie Beam Search
EGA 标准 Beam Search 生成大量无效候选(预算耗尽、定向不匹配、地域限制)。GPR 提出 Value-Guided Trie-based Beam Search ,把价值估计与约束过滤集成进解码:
Trie 树约束。 依用户画像与广告投放约束(年龄/定向/预算/地域)过滤出有效广告子集 ,提取各自 3 层语义 ID 构建 Trie 前缀树。解码第 层时只从 Trie 当前节点子集合采样,而非全码本(),搜索空间从 缩到 。
价值动态调整束宽。 标准 Beam Search 固定束宽 ;GPR 依 HTE 价值动态调整:
价值远高于均值的分支获更宽束宽探索更多,低价值分支提前收缩。实际效果:推理延迟从 150ms 降至 80ms(降 47%)、有效候选占比从 40% 升至 95%、Top-1 准确率提升 3.2%。
左:Trie 前缀树按用户画像与投放约束过滤出有效广告子集,解码只在合法子节点上展开,搜索空间从 缩到 ;右:每层用 HTE 价值估计动态调整束宽——高价值分支被保留、低价值被剪枝。
下面用交互演示感受生成式检索的 Beam Search 解码:从根节点出发,每层在(受 Trie 约束的)候选 Token 间展开分支,HTE 价值高的分支被保留、低价值被剪枝,最终输出有效广告语义 ID 序列。点击「下一步」观察逐层展开。
注意每一步的「剪枝」:未通过 Trie 约束(如地域不符)或 HTE 价值过低的候选在生成早期就被丢弃,这正是 GPR 把「合法性」与「价值」做成解码硬约束、把延迟砍掉近一半的关键。
多阶段训练策略
阶段一 MTP 预训练 :海量微信全场景行为日志(视频号/朋友圈/公众号/广告),目标 ,数十亿用户、数千亿交互,最大 8B 参数。
阶段二 Value-Aware Fine-tuning :冻结 HSD/PTD,只用真实反馈训 HTE 多任务塔(BCE 损失),引入点击/转化业务监督。
阶段三 HEPO(Hierarchy Enhanced Policy Optimization) :同时在 token 级与 item 级做策略梯度。Token 级优势 (方差远小于 item 级);Item 级奖励 ;层次化聚合 。损失:
好处:低方差(token 空间小)、精细控制(定位哪层 token 致低价值)、快速收敛(密集 token 梯度信号)。
设计权衡
GPR 全量上线微信视频号广告,相对级联系统:GMV 与 CTCVR 提升、推理延迟从 200ms+ 降至 80ms、模型从 5 个独立模型简化为 1 个。权衡在于:
- 架构复杂度 vs 场景通用性 :HHD 三层 + Thinking-Refining-Generation 代码量为 EGA 2 倍以上,但换来跨场景统一(视频号/朋友圈/公众号共用一模型)。
- 预训练成本 vs 零样本迁移 :预训练耗数千 GPU 卡数周,但新场景上线只需少量微调。
- 端到端优化 vs 可解释性 :黑盒难定位异常,靠 Thinking Tokens 可视化、HTE 分层价值输出部分缓解。
⚠️ Common Mistakes in 8.3
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 忽略广告的经济学约束 | 「广告也只优化点击率」 | 广告主会博弈出价,需 IC/IR | 用支付网络 + ex-post regret 保 IC |
| 2 | POI 与创意拼接生成 | 「6 个 Token 拼一起自回归」 | 易生成 POI-创意不匹配组合 | 概率分解为先 POI 后创意 |
| 3 | Token 竞价用 avg 聚合 | 「取广告集平均竞价」 | 高竞价信号被低竞价稀释 | 用 max 聚合突出高价值 Token |
| 4 | 直接按生成概率支付 | 「p_i ∝ z(a_i^j)」 | 不可微且难保 IC | 分配/支付解耦,独立支付网络 |
| 5 | 全用 RQ-VAE 致码本坍塌 | 「随机初始化码本端到端」 | 死码字使利用率仅 65% | RQ-Kmeans+ 先高质量初始化 |
| 6 | Beam Search 不约束 | 「全码本 W^3 解码」 | 生成大量无效候选增延迟 | Trie 约束 + HTE 价值引导剪枝 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 三重约束 | IC/IR、POI+创意联合、分配支付解耦 | 广告相对推荐/搜索独有的经济学挑战 |
| EGA | 双解码器 + Token 级 max 竞价 + POI 级支付网络 | 竞价机制与生成模型深度统一 |
| ex-post regret + Lagrangian | 采样近似 regret,对偶更新 λ | 近似保证 IC、平衡收益 |
| 排列感知奖励 | Self-Attention 建模位置外部性 | 广告非独立,point-wise 预估失效 |
| GPR | 四类 Token + RQ-Kmeans+ + HHD + 价值引导 Trie Beam Search | 跨场景、超长序列的统一广告生成 |
| HEPO | token 级 + item 级层次化策略梯度 | 低方差、精细控制、快速收敛 |
❓ FAQ
Q1: 为什么 EGA 的 Token 竞价用 max 而非 avg?
A: 一个语义 Token 可能对应多个广告,其中若有高竞价者,生成该 Token 就有高商业价值,应提升其概率。avg 会把高竞价信号被同组低竞价广告稀释,max 突出价值峰。
Q2: 分配与支付为何必须解耦?
A: 若直接按生成概率支付,概率不可微、且「赢家诅咒」使广告主压价。解耦后,分配用竞价引导生成(可微 Softmax),支付用独立网络学 IC 函数(Sigmoid 保 IR),才可能用数学约束近似保证 IC。
Q3: GPR 的 Trie Beam Search 相比标准 Beam Search 好在哪?
A: 标准 Beam Search 在完整码本 上展开,生成大量无效候选(预算耗尽/定向不符/地域限制)需后处理。Trie 依约束预过滤有效广告,解码早期就只走合法分支;再依 HTE 价值动态调束宽,延迟降 47%、有效候选占比升至 95%。
🔗 前后关联
- 8.1 (端到端生成式推荐)的语义 ID / Enc-Dec / RL 对齐是 EGA、GPR 的方法基础。
- 8.2 (端到端生成式搜索)的强约束检索(KHQE、约束 Beam Search)与 GPR 的 Trie 约束解码一脉相承。
- 6.x (生成式基础)的 RQ-VAE 量化,在本节以 EGA 的 RQ-VAE 与 GPR 的 RQ-Kmeans+ 两种形态出现。
- 9.1–9.3 (生成式思考/推理)将进一步讨论 Thinking Tokens 类「推理步骤」如何提升生成质量,与 GPR 的 PTD Thinking-Refining 阶段互补。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 8.3.1 — Token 级竞价聚合 🟢 Easy
某语义 Token 对应 3 个广告,竞价分别为 。求 (a) max 聚合下的 Token 竞价 ;(b) 若改用 avg 聚合结果是多少;(c) 为何 max 更合理?
💡 Solution (click to reveal)
Approach: 直接套聚合公式。
- (a) 。
- (b) avg = 。
- (c) 该 Token 含一个高竞价广告(),生成它商业价值高,max 把概率质量集中到这个价值峰;avg 被 稀释,弱化了高竞价信号——这正是 max 的设计动机。
Key points:
- max 突出价值峰,avg 平滑掉极端值。
- 生成式广告的竞价聚合本质是「多对多」映射的处理策略。
Problem 8.3.2 — 支付率与 IR 约束 🟢 Easy
某广告主申报竞价 ,支付网络输出支付率 。求实际支付 ,并判断是否满足个体理性(IR)约束 。
💡 Solution (click to reveal)
Approach: 。
。因 Sigmoid 保证 ,有 ,满足 IR 约束。
Key points:
- 支付率经 Sigmoid 天然落在 [0,1],故 自动成立。
- IR 是广告主参与拍卖的基本前提(不会付超过出价)。
Problem 8.3.3 — ex-post regret 直觉 🟡 Medium
广告主 真实估值 ,如实出价 时支付 、pCTR=0.5,效用 。若谎报 ,新支付 、pCTR 不变,效用 。求 ex-post regret ,并说明该机制是否近似满足 IC。
💡 Solution (click to reveal)
Approach: regret = 谎报最大收益 − 如实收益。
。
该机制 不满足 IC:广告主通过谎报(压低出价)获得了更高效用(4 > 3),存在正 regret。EGA 的目标正是通过 Lagrangian 优化把 压到接近 0——本例中支付网络需调整,使如实出价成为最优策略。
Key points:
- 是 IC 成立的判据。
- 正 regret 意味着机制可被博弈,需支付网络学习修正。
Problem 8.3.4 — 价值引导束宽 🔴 Hard
Beam Search 第 层某 Token 价值 ,当前所有分支平均价值 ,温度 ,基础束宽 ,最小束宽 。求该分支下一层束宽 。若另一分支 (低于均值),其束宽又是多少?
💡 Solution (click to reveal)
Approach: 套价值动态调整公式。
分支 1():
分支 2():
答: 高价值分支束宽扩大到约 21.7(探索更多),低价值分支收缩到约 6.77(但仍保 不被完全抛弃)。
Key points:
- 价值越高分支束宽越宽,实现「高价值深探、低价值早收」。
- 保证即使低价值也保留少量探索,避免过早错过。
🏆 Challenge: 设计广告端到端落地论证
某本地生活平台广告系统当前是「召回→排序→创意→竞价→分配」五级级联,跨视频/信息流/搜索三场景各训一模型。请写约 170 字论证:引入 GPR 类端到端生成式架构时,(1) 四类 Token 如何统一三场景;(2) 相比 EGA,GPR 在超长序列与推理效率上靠哪两个设计突破;(3) 需警惕什么新风险?
💡 Hint
(1) 四类 Token(U/O/E/I)把视频、信息流、搜索的内容与广告都用同一套语义体系表示,跨场景行为形成连贯时间线,破数据孤岛与模型碎片化。(2) 超长序列靠 HSD 的 Hybrid Mask + MoR 递归推理与 Q-Former 式压缩;推理效率靠价值引导 Trie Beam Search 在解码早期过滤无效候选,延迟降近半。(3) 新风险:HHD 架构与 Thinking-Refining 范式代码量为 EGA 2 倍以上、训练成本高;端到端黑盒可解释性差,bad case 难定位(需 Thinking Tokens 可视化、HTE 分层价值输出缓解)。
当生成式推荐(参见 1.1、5.3)让模型学会「直接生成」物品序列后,一个更本质的问题浮现:模型 真的在思考 吗?传统推荐模型只是隐式打分或隐式生成的「黑箱」,我们既不知道它依据哪些信号做判断,也无法向用户解释「为什么推荐这个」。本部分沿「从表征到推理、从模仿到自主」的递进逻辑,展示让推荐系统真正「会思考」的三步跃迁。
本部分沿「从表征到推理、从模仿到自主」的三步递进展开:先解决 语义鸿沟 (LC-Rec/PLUM 把物品变成 LLM 可理解的语义索引),再让模型 先思考再推荐 (OneRec-Think 的显式推理链),最后探索 自主推理 (RecZero/RecOne 摆脱人工模板)。各章要点见下表。
本章涵盖
| 章节 | Topic | The Big Idea |
|---|---|---|
| 9.1 | 协同语义与语言语义的统一 | 用层次化语义索引(RQ-VAE)+ 三层对齐,把物品 ID 与语言语义空间打通;PLUM 推进到工业级多模态规模 |
| 9.2 | OneRec-Think 的推理框架 | 三阶段训练(对齐→激活→增强),让模型生成结构化推理链;用 GRPO 与 Think-Ahead 解决质量与延迟 |
| 9.3 | 自主推理的探索 | RecZero 纯强化学习自主摸索推理;RecOne 混合范式兼顾效率与性能上界 |
What You'll Be Able to Do After This Part
- 🟢 解释 协同语义与语言语义的鸿沟,以及为什么「直接用标题替换 ID」不足以解决它
- 🟢 描述LC-Rec 的层次化 RQ-VAE 语义索引与均匀语义映射(最优传输)如何避免索引冲突
- 🟡 复述OneRec-Think 三阶段框架,并说明推理脚手架如何「激活」显式推理
- 🟡 辨析 推荐特定奖励与 GRPO 如何应对推荐的「多有效性」特性
- 🔴 对比OneRec-Think(模仿学习)、RecZero(纯 RL)、RecOne(混合)三种推理范式的取舍
- 完成各节分层练习题,巩固从语义对齐到自主推理的演进主线
核心概念
| Concept | 章节 | Relevance |
|---|---|---|
| 语义索引 / 语义 ID | 9.1 | 让 LLM 既能理解物品、又承载协同信号的表示基石 |
| 均匀语义映射 / 最优传输 | 9.1 | 工业级规模下避免索引冲突的关键机制 |
| 推理脚手架 / 显式推理 | 9.2 | 把黑箱决策变成可审查推理链的核心 |
| 多有效性 + GRPO | 9.2 | 适配「无唯一正确答案」的推荐强化学习 |
| 自主推理 / 混合范式 | 9.3 | 摆脱人工模板、走向自主思考的演进方向 |
前置知识
- 已读 1.1(两种范式与能力演进)、5.3(生成式范式演进,尤其 TIGER 语义 ID 与 OneRec 端到端生成)
- 了解基础概率、向量量化(RQ-VAE)与 Transformer 微调(指令微调 / SFT)概念
本部分偏前沿,公式较多但重在直觉——不必逐行推导,抓住「为什么这样设计」即可。
Tips for This Part
- 把语义索引当作「翻译层」。 它是连接协同世界与语言世界的桥梁,后面所有推理都建立在它之上。
- 区分「会生成」与「会思考」。 5.3 的 OneRec 会生成,但 OneRec-Think 才会解释——这是 9.2 的灵魂。
- 用「模仿 → 自主」的弧线贯穿 9.3。 RecZero/RecOne 不是推翻 OneRec-Think,而是把「思考能力」从人工模板中解放出来。
Let's dive in! 🚀
协同语义与语言语义的统一
📝 Before You Continue: 请先读完 1.1 的两种范式与能力演进、5.3 的 TIGER 语义 ID 与 OneRec 端到端生成。本章是那根「语义 ID」线索的深化——不止「生成」,还要让 LLM 理解这些 ID。
当推荐系统遇上大语言模型(LLM),表面看是「天作之合」:LLM 强大的语言理解与生成能力,似乎天然适合做推荐。但现实泼了一盆冷水——这二者说着 两种完全不同的「语言」。推荐系统靠用户行为数据构建 协同语义 (collaborative semantics),而 LLM 理解的是文本中的 语言语义 (language semantics)。这道鸿沟不跨过去,再强的 LLM 也只是一个看不懂推荐世界的「外行」。
本章我们要解决的核心问题是: 如何构建一种既能被 LLM 理解、又能承载协同语义的物品表示? 答案不是「直接把标题丢给 LLM」,而是一套系统性的语义索引 + 语义对齐方案。
读完本章,你将能够:
- 用 一句话 说清协同语义与语言语义的鸿沟,并指出「标题替换 ID」的两个根本缺陷
- 描述LC-Rec 如何用层次化 RQ-VAE 构建语义索引,并解释「均匀语义映射」如何消解索引冲突
- 复述LC-Rec 三层对齐训练(序列预测 / 索引-语言对齐 / 推荐导向)如何把协同语义注入 LLM
- 说明PLUM 如何把这套思路推进到工业规模(多模态融合 + 持续预训练 + 任务微调)
- 完成 4 道分层练习题,巩固从学术原型到工业落地的语义对齐主线
9.1.0 两种「语言」的隔阂
推荐系统把每个物品表示为一个离散的 ID (如 item_12345)。这个 ID 本身不携带任何语义信息——它的含义完全来自用户行为数据中学习到的 协同模式。通过分析「用户—物品」交互矩阵,模型能捕捉物品间隐含的相似性与关联,这种通过行为学到的表示,就是 协同语义。
而 LLM 理解的是 语言语义 :它从预训练语料中学会了词汇、短语、句子之间的语义关联。当我们把物品 ID 直接喂给 LLM 时,这些离散标识符对它而言是 词表外(Out-of-Vocabulary, OOV) 的符号,无法与任何预训练知识产生关联。
💡 Key Insight: 一种直觉解法是用物品标题替换 ID(让 LLM 读标题)。但这有两个根本问题:第一,LLM 虽能理解标题字面含义,却无法感知该物品在推荐系统中的协同特征(用户群体的集体行为模式);第二,基于候选集的文本生成方式无法扩展到全库检索场景,限制了模型的应用范围。
🧠 Mental Model: 两个说不同语言的人
把推荐系统想象成一位只看「会员编号」的资深店长——他闭着眼知道编号 12345 和 67890 的顾客总一起买东西(协同语义),却说不清编号长什么样。LLM 则是位满腹经纶的图书管理员,能和你聊「塞尔达传说」的剧情(语言语义),却对店长的会员编号一头雾水。要让两人合作,得先造一本「编号 ↔ 内容」的翻译词典——这正是语义索引要做的事。
9.1.1 LC-Rec:层次化语义索引与对齐
LC-Rec (Language-Collaborative Recommendation)提出了一套系统性方案:为每个物品学习一组离散的 语义索引 (Semantic Index),使其同时具备语言可理解性与协同表达能力。它包含两个关键技术模块: 物品索引学习 与 语义对齐训练。
物品索引学习:层次化残差量化
LC-Rec 延续 5.3 介绍的语义 ID 思路,采用 层次化残差向量量化(Residual Vector Quantization, RQ) 构建物品索引。具体而言:
- 先用 LLM 对物品标题与描述编码,得到初始文本嵌入 ——保证索引构建起点是基于语言语义的。
- 训练一个 RQ-VAE,将连续嵌入映射为离散索引序列。编码器把 映射为潜在表示 ,随后进行 层残差量化。在第 层,码本 包含 个可学习的聚类中心:
最终物品被表示为索引序列 ,例如 <a_5><b_2><c_6><d_7>。
这种层次化设计带来两个重要特性: 语义的逐层细化 (从粗粒度类别到精细个体特征)与 相似物品的索引前缀共享 (内容相似的物品倾向共享更多前缀)。这为后续自回归生成提供了结构化先验。
均匀语义映射:用最优传输消解索引冲突
LC-Rec 的关键创新在于 均匀语义映射(Uniform Semantic Mapping)。标准向量量化存在 索引冲突 :多个不同物品可能被映射到相同索引序列——在推荐中这是不可接受的,每个物品必须有唯一标识。现有方法(如 TIGER)通常靠增加索引层解决冲突,但会引入语义无关的噪声。
LC-Rec 从根源上缓解这一问题:在最后一层量化时引入 均匀分布约束 ,确保物品在码本向量上的分配尽可能均衡。这被形式化为一个 最优传输(Optimal Transport) 问题:
其中 为一个批次的残差向量, 表示把残差 分配给第 个码本向量的概率。该优化通过 Sinkhorn-Knopp 算法 求解,在保持语义连续性的同时显著降低索引冲突率。
Analysis: 均匀语义映射的代价是多了一个最优传输求解步骤(Sinkhorn 迭代),但换来「不增加额外索引层即可为绝大多数物品分配唯一语义 ID」——避免了 TIGER 式加层带来的语义噪声。这是表达力与唯一性之间的精巧权衡。
语义对齐训练:三层渐进注入协同语义
获得物品索引后,需要通过 指令微调(Instruction Tuning) 让 LLM 理解这些索引。LC-Rec 设计了三个层次的对齐任务:
第一层·序列物品预测——给定用户历史交互的索引序列,预测下一个物品的索引。由于索引有层次结构,LLM 在自回归生成时可逐层细化(先粗类别、再精细个体),与文本生成机制天然契合。
第二层·显式索引-语言对齐——建立索引与物品的双向对应:
- 索引到文本:给定索引,生成对应标题与描述(如看到
<a_66><b_197><c_236><d_223>生成「Pokémon Moon - Nintendo 3DS」)。 - 文本到索引:给定标题描述,生成对应索引序列。
这种双向对齐类似多模态学习的交叉重建,在两种表示间建立紧密语义桥梁。
第三层·推荐导向的隐式对齐——进一步强化协同语义融合,包含三类任务:
- 非对称预测:打破「输入输出均为索引」的对称,如输入索引、输出标题,迫使模型在协同模式与文本语义间建立深层关联。
- 基于意图的物品预测:从用户评论提取意图(如「寻找开放世界的多人冒险游戏」),预测推荐索引——让模型学会把自然语言需求与协同过滤模式结合。
- 个性化偏好推理:给定交互索引序列,生成对用户偏好的自然语言总结,为可解释推荐打基础。
💡 Key Insight: 经过三层对齐,协同语义与语言语义在 LLM 内部形成统一表示空间,具备层次化语义组织(索引越长描述越精细)、协同-语言融合(比纯文本检索更贴合推荐)、生成式全库检索能力(索引已入词表,无需候选集即可自回归检索)三大特性。
9.1.2 工业级对齐:PLUM 框架
LC-Rec 在学术数据集验证了可行性,但从学术到工业仍有巨大鸿沟。YouTube 每天产生数百万新视频、数十亿交互,面临多模态内容融合、实时增量更新、十亿级检索等挑战。PLUM (Pre-trained Language Models for Recommendations)正是为应对这些挑战而生,通过三阶段(增强型语义 ID 构建 → 领域持续预训练 → 生成式检索微调)实现工业级语义对齐。
多模态与协同信号的融合
LC-Rec 只用文本嵌入,但视频内容的丰富性远超纯文本(游戏直播的吸引力可能更多来自主播声音与画面流畅度)。PLUM 采用 多模态嵌入拼接 融合异构信息:文本编码器、视觉编码器、音频编码器分别提取 、、,简单拼接:
更关键的是,PLUM 显式引入 协同过滤嵌入 弥补内容语义的不足——编码「哪些用户倾向一起观看」的协同模式,再与内容嵌入拼接:
这让语义 ID 不再只是内容标识,而是融合「内容是什么」与「用户如何感知」的双重语义。PLUM 还用 多分辨率码本 (128/256/512/1024)与 渐进式掩码训练 保证层次正确组织。
持续预训练:建立协同-语言双向映射
PLUM 把全部语义 ID token 加入 LLM 词表(4 层 RQ-VAE × 256 = 1024 个新 token),并用 语义引导初始化 为它们赋予有意义的起点(取最近的若干视频标题 LLM 嵌入均值)。随后用三类数据训练:
- 纯语义 ID 序列 (50%):从行为序列采样,预测下一个 ID,学纯粹协同模式。
- 纯领域文本数据 :视频标题/描述/评论/字幕,防语言能力退化并学领域表达。
- ID-文本交错序列 (占元数据语料 60–70%):如「视频
<A37><B12><C5><D8>的标题是:Minecraft 建筑教程」,建立双向桥梁。
一个收获是模型展现出 零样本跨模态理解 :
<A37> → "任天堂相关内容"
<A37><B12> → "任天堂 Switch 游戏"
<A37><B12><C5> → "塞尔达传说系列"
<A37><B12><C5><D8> → "塞尔达传说旷野之息武器收集攻略"
这种能力完全通过大量交错序列隐式学习涌现,证明语义对齐已内化为模型的表示结构。
任务微调与生产验证
任务微调把推荐重定义为 条件生成 :给定用户多模态上下文(历史语义 ID 序列、文本、离散化数值如「完播率:高」),自回归生成推荐视频的语义 ID。PLUM 引入 奖励加权对齐 :
即高奖励交互(长时观看、点赞)代表「强语义关联」,值得深度编码;低奖励(误点、快速退出)可能是噪声,不应过拟合。
PLUM 在 YouTube 长/短视频全面上线,关键收益:语义 ID 唯一性 96.7% (高于 LC-Rec 的 94.0%);有效词汇量覆盖 95% 曝光所需视频数在长视频提升 2.6 倍、短视频提升 13.2 倍;样本效率极高——900M MoE 模型仅需 2.5 亿样本,总训练成本(FLOPs)仅为传统大嵌入表模型(LEM)的 0.55 倍。
📊 Data Point: PLUM 证明即使在十亿级规模、多模态、实时推理的严苛约束下,协同语义与语言语义的统一也完全可行。但它仍是个端到端生成模型——能高效生成推荐,却无法解释为什么。这正是 9.2 要解决的问题。
⚠️ Common Mistakes in 9.1
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为「标题替换 ID」就解决了语义对齐 | 直接把物品标题当 token 喂 LLM 做推荐 | 标题无协同语义,且无法全库检索 | 用语义索引(RQ-VAE)同时承载协同+语言 |
| 2 | 混淆协同语义与语言语义 | 认为 LLM 读懂标题就等于理解推荐 | 标题不含用户群体行为模式(协同信号) | 区分两种语义,靠对齐训练融合二者 |
| 3 | 以为加层总能解决索引冲突 | TIGER 式无限加 RQ 层 | 加层引入语义无关噪声,污染索引含义 | 用均匀语义映射(最优传输)均衡分配 |
| 4 | 把 PLUM 的拼接当注意力融合 | 「PLUM 用跨模态注意力融合」 | PLUM 用简单拼接,让码本自然发现重要模态 | 拼接给予各模态平等机会,更可解释 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 语义鸿沟 | 协同语义(ID)vs 语言语义(文本),ID 对 LLM 是 OOV | 跨不过鸿沟,LLM 看不懂推荐世界 |
| LC-Rec 语义索引 | 层次化 RQ-VAE + 均匀语义映射(最优传输) | 物品同时被 LLM 理解且承载协同信号 |
| 三层对齐 | 序列预测 / 索引-语言 / 推荐导向 | 渐进把协同语义注入 LLM 表示空间 |
| PLUM | 多模态+CF 融合、CPT、奖励加权微调 | 工业级验证,唯一性 96.7%、成本 0.55× |
| 统一表示空间 | 层次组织 / 协同-语言融合 / 全库检索 | 为 9.2 的「会思考」奠定理解基础 |
❓ FAQ
Q1: 为什么不直接用物品标题,非要搞语义索引?
A: 标题只携带语言语义,没有协同信号(用户群体的集体行为);且基于候选集文本生成无法扩展到全库检索。语义索引把两种语义统一到一个可被 LLM 生成/检索的 token 序列里。
Q2: 均匀语义映射和 TIGER 加层有什么区别?
A: TIGER 靠增加 RQ 层避免冲突,但新层带来语义无关噪声;LC-Rec 的均匀语义映射在最后一层加均匀分布约束(Sinkhorn 最优传输),不增层也能给绝大多数物品唯一 ID,更干净。
Q3: PLUM 为什么用「拼接」而不是注意力融合多模态?
A: 拼接给予文本/视觉/音频/协同各模态平等表达机会,让 RQ-VAE 码本自然发现哪种模态对区分视频类别最重要(如音乐视频靠音频、教程靠文本),且更可解释、更省算力。
🔗 前后关联
- 1.1 / 5.3 (范式与生成式演进)语义索引是 TIGER 思路的深化,本章解决「LLM 如何理解索引」。
- 9.2 (OneRec-Think)在「认识物品」的语义对齐基础上,进一步让模型「学会思考」。
- 9.3 (自主推理)RecZero/RecOne 延续语义索引表示,把推理从人工模板解放为自主探索。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 9.1.1 — 辨析两种语义 🟢 Easy
判断以下描述属于 协同语义 还是 语言语义 :
- (a) 物品
item_8842与item_1190常被同一批用户购买。 - (b) 视频标题「塞尔达传说:旷野之息」描述的是开放世界冒险游戏。
- (c) 用户看完 A 后 80% 会看 B(行为共现)。
- (d) 评论区高频词是「治愈」「画风」。
💡 Solution (click to reveal)
Approach: 看信息来自「用户行为」还是「文本内容」。
- (a) 协同语义(共现行为)
- (b) 语言语义(标题文本含义)
- (c) 协同语义(行为转移概率)
- (d) 语言语义(评论文本语义)
Key points:
- 协同语义源于交互矩阵,语言语义源于文本/预训练语料。
- 语义索引的目标是把两者统一进一个表示。
Problem 9.1.2 — RQ-VAE 量化计算 🟢 Easy
已知物品文本嵌入 ,RQ-VAE 编码得 ,初始残差 。第一层码本 中离 最近的码字索引为 。请写出 的选取公式与残差更新式。
💡 Solution (click to reveal)
Approach: 直接套用层次化量化公式。
Key points:
- 每层在码本中找最近码字,再从残差里减掉它。
- 多层迭代得到索引序列 。
Problem 9.1.3 — 索引冲突分析 🟡 Medium
某推荐系统用 TIGER 式 3 层 RQ-VAE 构建语义 ID,但发现两个不同的游戏视频被映射到完全相同的 <a_3><b_1><c_7>。工程师决定加到 5 层解决。请指出这种做法的隐患,并说明 LC-Rec 的均匀语义映射为何是更优解。
💡 Solution (click to reveal)
Approach: 对比「加层」与「均匀映射」两种消冲突思路。
加层隐患: 增加 RQ 层会引入更多码字维度,其中部分层学习到的只是「为了区分而区分」的语义无关噪声,污染索引的层次语义含义,且增加了生成长度与推理成本。
均匀语义映射更优: 它在最后一层引入均匀分布约束(最优传输),用 Sinkhorn-Knopp 让物品在码本向量上分配尽量均衡,从根源降低冲突率,而 不增加额外索引层——保持了索引的语义纯净度与生成效率。
Key points:
- 冲突的本质是码本分配不均,不是层数不够。
- 均衡分配比堆层数更干净、更高效。
Problem 9.1.4 — 设计对齐训练组合 🔴 Hard
你要为一家图书电商的 LLM 推荐系统设计语义对齐训练。请列出你采用的 三类对齐任务 (对应 LC-Rec 三层),并各写一条样本(输入→输出),说明它们分别注入哪类语义。
💡 Solution (click to reveal)
Approach: 套用 LC-Rec 三层对齐,落到图书场景。
- 序列物品预测(协同) :输入用户历史索引序列
<a_2><b_5><c_1> ... <a_2><b_5><c_9>,输出下一个索引<a_2><b_6><c_3>——学协同共现模式。 - 显式索引-语言对齐(双向) :
- 索引→文本:输入
<a_2><b_5><c_3>,输出「《人类简史》— 宏观历史科普」。 - 文本→索引:输入「《人类简史》」,输出
<a_2><b_5><c_3>。
- 索引→文本:输入
- 推荐导向隐式对齐(意图+偏好) :输入意图「想读轻松的历史读物」+ 历史索引,输出推荐索引;或输入历史索引,输出偏好总结「偏好宏观历史、轻学术」。
Key points:
- 三层由浅入深:共现 → 双向语义桥 → 意图/偏好推理。
- 每层都在把协同语义更深层地注入 LLM 表示空间。
🏆 Challenge: 工业落地论证
假设你要为日活千万的短视频平台引入 PLUM 式语义对齐。请写一段 200 字内论证:相比传统大嵌入表模型(LEM),语义对齐方案在 样本效率、长尾覆盖、可解释性 三个维度上为何更优?并指出一个必须前置解决的基础设施问题。
💡 Hint
论据:① 语义对齐的表示空间泛化更好,训练数据需求远低于 LEM(PLUM 仅 2.5 亿 vs LEM 数十亿/天),FLOPs 仅 0.55×;② 语义 ID 区分度更高,长尾内容覆盖率显著提升(短视频 13.2×);③ 索引-文本对齐使推荐可解释。前置问题:必须先把「物品→语义 ID」的量化/对齐基础设施建好(类似 5.3 的语义 ID 流水线),否则 LLM 无 token 可用。
OneRec-Think 的思考框架
📝 Before You Continue: 先读完 9.1 的语义对齐——OneRec-Think 的整套推理建立在「模型已认识物品」之上。也建议回顾 5.3 的 OneRec 端到端生成,本章是它从「会生成」到「会思考」的升级。
当 PLUM 在 YouTube 上验证了协同语义与语言语义可在工业规模统一时,推荐与 LLM 的融合似乎水到渠成。但一个关键问题浮现:这些模型虽然能高效生成推荐,其推理过程仍是 隐式的黑箱——模型推荐一个视频时,我们无法知道它依据了哪些历史行为,也不清楚它如何权衡内容相似性与协同信号。更重要的是,它们无法像 ChatGPT 那样通过 Chain-of-Thought(思维链) 做显式推理——而后者正是 LLM 在复杂任务上突破的核心能力。
OneRec-Think 正是为填补这一空白而生。它不满足于让 LLM 仅仅「认识」物品,而是要让 LLM 先思考再推荐。本章我们剖析它如何让模型从「隐式预测器」变为「显式推理者」。
读完本章,你将能够:
- 描述OneRec-Think 的三阶段训练框架(物品对齐 → 推理激活 → 推理增强)
- 解释 推理脚手架如何用渐进任务「激活」模型的归纳/演绎/反事实推理
- 复述 推荐特定奖励如何应对「多有效性」挑战,以及 GRPO 的相对优势机制
- 说明Think-Ahead 架构如何把密集推理从在线关键路径剥离、满足实时延迟
- 完成 4 道分层练习题,巩固从对齐到增强的推理范式
9.2.0 从「认识物品」到「学会思考」
传统模型直接输出物品 ID,而 OneRec-Think 会先生成一段推理:
用户的观看历史主要围绕国际关系和军事动态展开,
表现出对军事装备和技术进步的强烈兴趣……
因此推荐聚焦中国军事技术进步的视频,
特别是新型 J-35 战斗机首次亮相的内容……
这种显式推理不仅提升可解释性,更重要的是 推理过程本身为决策提供了结构化思考路径 ,让模型更准确捕捉用户意图的多个层次。OneRec-Think 把 自然语言交互、显式推理生成、端到端推荐 统一在同一框架中——用户可对话表达需求,模型基于历史与上下文生成推理,最后直接生成物品语义 ID,无需预定义候选集。
🧠 Mental Model: 从「直觉型评委」到「会写批注的导师」
判别式模型像凭直觉打分的评委,给个分就完事;OneRec-Think 像一位会在卷面上写满批注的导师——先分析学生(用户)的特点,再评价每份答案(候选)的契合度,最后给出推荐并附理由。批注(推理)本身就是决策的一部分,而非事后装饰。
9.2.1 三阶段训练框架
OneRec-Think 的核心是精心设计的 三阶段训练框架 :物品对齐(Itemic Alignment)、推理激活(Reasoning Activation)、推理增强(Reasoning Enhancement)。
物品对齐:让模型「认识」物品
OneRec-Think 继承 LC-Rec/OneRec 的语义 ID 思路,并针对短视频(内容碎片化、行为极快)做优化。它采用 分层表征融合 :文本塔、视觉塔、音频塔、协同塔分别提取特征,再用 注意力加权 动态融合(不同视频各模态重要性差异巨大——美食靠视觉、脱口秀靠音频):
关键创新是 Item-Textual Alignment(物品-文本对齐) :给定不同长度 ID 前缀,生成相应粒度描述:
输入: <item_a_8121> → 输出: 这是一个街头美食类视频
输入: <item_a_8121><item_b_3259> → 输出: 繁华街头市场的美食视频,含各种小吃摊位
输入: <item_a_8121><item_b_3259><item_c_6391> → 输出: 街头市场,小贩叫卖烤串、炒饭...
这种逐层细化训练让 语义 ID 被「锚定」到 LLM 原有语言语义网络中——看到 <item_a_8121> 的神经元激活模式与看到「街头美食」高度相似,为推理激活奠定神经基础。对齐目标结合双向任务:
推理激活:用脚手架「激活」思考
完成对齐后,模型「认识」了物品,但还不会「思考」。类比人类:学生认识了所有公式,不代表会解复杂题——后者需要学会分解问题、选公式、逐步推导。推理脚手架(Reasoning Scaffolding) 扮演「思维训练」角色,分三层渐进激活:
用户画像推理(归纳)——给定历史交互序列,生成结构化兴趣总结:
主要兴趣:幽默短剧、影视解说(>60%)和轻松娱乐;次要兴趣:宠物、传统文化、地方美食
模型需从离散 ID 识别内容主题、统计占比、组织成连贯画像,训练 归纳推理。
候选评估推理(演绎)——给定用户画像与候选物品,生成匹配度推理:
候选聚焦中国军事技术进步(J-35首秀),与用户对军事装备的强烈兴趣高度相关→高度相关
训练 演绎推理 :建立「用户兴趣→物品内容→匹配判断」的三段论链条。
端到端推理式推荐——无候选集下直接从历史生成推荐 ID 与完整推理,额外引入 反事实推理 (当用户需求与历史冲突时如何调整)与 多目标权衡 (相关性 vs 情感需求)。
训练目标为加权三层次损失 。其精髓是 渐进性——像教育学的脚手架教学法:先给明确结构支撑,待模型掌握后逐步撤去,让其独立完成。
推理增强:用强化学习精炼路径
模型能生成推理后,新挑战出现: 如何评价推理质量好坏? 数学题答案非对即错;但推荐中同一用户可能有数十个「正确」选择(科幻、纪录片、搞笑都有效)。这种 多有效性(Multi-Validity) 是推荐区别于传统 NLP 的根本特性——若简单套用监督/强化学习,模型可能因推荐了「不在标签里但用户会喜欢」的物品而受罚,变得过度保守。
OneRec-Think 用 推荐特定奖励函数 综合四维信号:
- :推荐与历史的协同相似度(即使不在标签中,只要协同空间近就给正奖)
- :推荐内容与用户画像的语义匹配度
- :推理文本与最终物品的连贯性(用 NLI 模型判,脱节要罚)
- :真实用户反馈(完播+点赞=1.0,快速划过=-0.5)
典型权重 。基于该奖励,OneRec-Think 用 GRPO 优化:对同一用户采样 条 rollout ,计算相对优势:
💡 Key Insight: GRPO 的精妙在于——模型不需要知道「绝对正确」的推荐是什么,只需学会识别哪些推理相对更好。这特别适合多有效性场景:允许模型同时学习多种有效推理模式,而非收敛到唯一「标准答案」。
训练后涌现三行为: 推理深度自适应 (简单场景简洁、复杂场景细致)、反事实推理出现 (识别需求与历史的冲突)、推理多样性保持 (不同采样角度不同,但都导向合理推荐)。
Analysis: 推理增强的成本是引入奖励模型与 GRPO 循环,工程更复杂;收益是推理更准确、更多样、可解释。它把「多有效性」从障碍变成了优势——只要相对更好就强化。
9.2.2 Think-Ahead:把推理搬离关键路径
OneRec-Think 展现强大能力,但部署难题尖锐:短视频要求 100ms 内返回,而生成完整推理(数十到上百 token)再生成 ID,即使高性能 GPU 也需数百毫秒。
Think-Ahead 架构 的核心理念: 推理可提前在用户行为更新时异步计算,不必等请求到来才思考。 流程:
- 异步推理预计算 :用户产生新行为时,后台触发推理引擎,生成 条推理路径(每条对应候选集 ),缓存在实时特征存储。预算可放宽到 ~500ms。
- 轻量在线选择 :请求到来时,从预计算候选集快速打分择优,用轻量 ranking 模型(基于实时上下文)在 10–20ms 完成。
- 增量推理更新 :新行为与已有路径一致时,仅追加简短更新;显著改变画像时才全量重算。
🧠 Mental Model: 日常决策的类比 你不会每次做决定都从头思考,而是平时积累「我喜欢什么类型的电影」这类结论,决策时快速选用。Think-Ahead 把「平时想」与「当场选」分离,既保思考深度,又满足延迟。
Think-Ahead 在快手全面上线,P99 延迟约 153ms,APP 停留时长提升 0.159%。相比同步方案: P50 延迟降 73% (320→86ms)、P99 降 68% (480→153ms)、推理质量保持率 98.5%、缓存命中率 92.3%。
💡 Key Insight: 对话场景中 OneRec-Think 还能上下文感知——用户表达负面情绪时,模型检测到情感信号,把推荐从一般兴趣转向放松积极内容。这标志着推荐从「被动响应」变「主动理解」。
OneRec-Think 的成功是范式跃迁:从「隐式预测器」到「显式推理者」。但它仍依赖 人工设计的推理模板与任务——这引出了 9.3 的自主推理范式。
⚠️ Common Mistakes in 9.2
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把 OneRec-Think 当纯生成模型 | 「它和 OneRec 一样只是生成 ID」 | 它先生成显式推理链再输出 ID,可解释 | 记住:推理是决策的一部分,非装饰 |
| 2 | 忽视「多有效性」直接套监督学习 | 用 0-1 标签惩罚不在标签中的好推荐 | 推荐无唯一正确答案,会逼模型保守 | 用推荐特定奖励 + GRPO 相对优势 |
| 3 | 以为 GRPO 需要绝对正确答案 | 「GRPO 要标出标准推理」 | GRPO 只比组内相对好坏,无需绝对标准 | 同用户采样 K 条 rollout 比相对优势 |
| 4 | 忘记推理的延迟代价 | 线上同步生成完整推理链 | 数百 ms 远超 100ms 实时要求 | 用 Think-Ahead 异步预计算 + 轻量选择 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 三阶段框架 | 对齐→激活→增强 | 从「认识物品」到「学会思考」再到「精进推理」 |
| 推理脚手架 | 画像(归纳)/评估(演绎)/端到端 | 渐进激活显式推理,可审查可解释 |
| 多有效性 + 奖励 | cf/sem/coh/feedback 四维 | 适配「无唯一正确答案」的推荐 |
| GRPO | 相对优势,无需绝对标准 | 允许多种有效推理模式共存 |
| Think-Ahead | 异步预计算 + 轻量在线选择 | 实时延迟下保留深度推理 |
❓ FAQ
Q1: OneRec-Think 和 5.3 的 OneRec 差在哪?
A: OneRec 直接生成会话列表(会生成但不解释);OneRec-Think 先生成结构化推理链再输出 ID,把「思考」变成决策的一部分,可解释、可审查。
Q2: 为什么 GRPO 比「标标准答案」更适合推荐?
A: 推荐有多有效性——同一用户多个推荐都合理,没有唯一标准答案。GRPO 同用户采样多条 rollout,只比组内相对好坏,避免把「不在标签里的好推荐」误罚成坏。
Q3: Think-Ahead 牺牲了推理质量吗?
A: 几乎不——异步预计算可用更大预算(~500ms)生成更深入推理,在线只做轻量选择。实测推理质量保持率 98.5%,P99 仍 < 150ms。
🔗 前后关联
- 9.1 (语义对齐)物品对齐阶段直接建立在 9.1 的语义索引之上——模型先「认识」才能「思考」。
- 9.3 (自主推理)OneRec-Think 依赖人工模板,RecZero/RecOne 把它解放为自主探索。
- 5.3 (OneRec)本章是 OneRec 端到端生成的「会思考」升级版。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 9.2.1 — 归类三阶段 🟢 Easy
把下列训练活动归入 OneRec-Think 三阶段(物品对齐 / 推理激活 / 推理增强)之一:
- (a) 给定 ID 前缀生成对应粒度描述
- (b) 用 GRPO 按相对奖励更新推理路径
- (c) 从用户历史生成结构化兴趣总结
- (d) 注意力加权融合多模态嵌入得到语义 ID
💡 Solution (click to reveal)
Approach: 对照三阶段职责。
- (a) 物品对齐(Item-Textual Alignment)
- (d) 物品对齐(分层表征融合)
- (c) 推理激活(用户画像推理,归纳)
- (b) 推理增强(GRPO 强化学习)
Key points:
- 对齐=认识物品;激活=学会思考;增强=精炼推理。
- 三者顺序不可颠倒。
Problem 9.2.2 — 多有效性判断 🟢 Easy
某用户历史爱看科幻电影,模型推荐了一部纪录片(用户也喜欢),但该纪录片不在训练标签(标签只记录了用户实际点击的那部喜剧)。若用标准 0-1 监督,会发生什么?GRPO 为何不会?
💡 Solution (click to reveal)
Approach: 用「多有效性」框架分析。
标准监督: 纪录片不在标签中 → 被当作「错误」惩罚 → 模型变保守,不敢推荐训练集外的合理内容。
GRPO: 同一用户采样多条 rollout,比 组内相对 奖励。若纪录片 rollout 的奖励(cf/sem/feedback 综合)高于组平均,相对优势为正,被 强化——它不在乎是否「在标签里」,只在乎相对更好。
Key points:
- 多有效性 = 多个合理推荐并存。
- GRPO 用相对优势绕开「无绝对标准」困境。
Problem 9.2.3 — GRPO 相对优势计算 🟡 Medium
对某一用户采样 4 条推理 rollout,奖励分别为 。请计算组平均与每条的相对优势 ,并指出应增强/抑制哪些。
💡 Solution (click to reveal)
Approach: 先算均值,再逐条减。
组平均:
增强 :rollout 1、3(相对优势为正); 抑制 :rollout 2、4(为负)。
Key points:
- 绝对高低不重要,相对组平均才重要。
- GRPO 同时保留多种有效推理(1 与 3 角度可能不同)。
Problem 9.2.4 — 设计 Think-Ahead 部署 🔴 Hard
你在设计短视频推荐的 Think-Ahead 架构。请写出异步预计算、在线选择、增量更新三环节各自「输入/输出/延迟预算」,并说明缓存命中率 92.3% 意味着什么工程收益。
💡 Solution (click to reveal)
Approach: 按三环节拆解。
- 异步预计算 :输入=用户新行为后的历史 ;输出= 条推理路径 + 对应候选集 ;预算~500ms(后台,不阻塞请求)。
- 在线选择 :输入=预计算候选并集 + 实时上下文;输出=最终推荐 ID;预算 10–20ms(轻量 ranking)。
- 增量更新 :输入=新行为;输出=追加更新或全量重算;仅在画像显著变化时全量重算。
命中率 92.3% 的收益: 绝大多数请求直接用已缓存的推理候选,无需触发全量重算,既省算力又保 P99 < 150ms——把「深度思考」的成本摊到异步空闲时段。
Key points:
- 关键思路:把密集推理移出关键路径。
- 命中率高 = 在线几乎只做轻量选择。
🏆 Challenge: 推理忠实性论证
OneRec-Think 的推理是「先生成」再推荐,存在推理可能为「事后合理化」的风险。请写一段 200 字内,说明你会用哪两类证据(结合本章提到的束搜索一致性 / 交错推理)来验证推理 确实指导 了推荐,而非装饰。
💡 Hint
证据一: 束搜索一致性——对中间推理步骤施加束搜索,若推理文本与最终物品保持强对齐(而非发散),说明推理真在指导生成。证据二: ID-文本交错推理——若物品 token 的内容锚定能稳定约束文本因果阐述的方向,且替换锚定会改变推荐,则证明推理链与生成相互耦合,而非独立事后生成。呼应原文「推理过程真正指导推荐生成,而非事后合理化」。
自主推理的探索
📝 Before You Continue: 先读完 9.2 的 OneRec-Think——它的推理能力高度依赖人工设计的脚手架与模板。本章要问的是:能否摆脱这些人工设计,让模型自主学会思考?
OneRec-Think 通过三阶段框架让模型「先思考再推荐」,但细心读者会发现:它的推理能力很大程度上 依赖人工设计。无论是推理脚手架预定义的 prompt 模板(「分析用户→评估候选→生成推荐」),还是物品对齐的多任务目标,都是研究者基于对推荐场景的理解精心构造的。这像给学生提供了详细解题步骤模板——学生能照做,却难说真正「理解」,更难以在全新问题中自主探索。
这种依赖带来三个深层问题: 推理路径的局限性 (模板约束思考空间)、教师模型的知识瓶颈 (人类认知可能偏差或不完备)、可扩展性的挑战 (每场景设计一套模板成本高)。根源在于 OneRec-Think 本质是 模仿学习(Imitation Learning)——学人类设计的推理示例。而真正的智能应有 探索学习(Exploratory Learning) 能力:在目标指引下通过试错与反馈自主摸索策略。这正是 强化学习(RL) 的哲学。
读完本章,你将能够:
- 解释 为什么 OneRec-Think 属模仿学习,以及依赖人工模板的三大局限
- 描述RecZero 的纯强化学习方案:Think-before-Recommendation 模板 + 规则奖励 + GRPO
- 复述RecZero 涌现的分层推理、负面信号利用、跨领域迁移等能力
- 对比RecOne 混合范式:冷启动 SFT(含对齐/纠偏样本)+ RL 如何兼顾效率与性能上界
- 完成 4 道分层练习题,并体验本章结尾的「推理能力演进」交互演示
9.3.0 从模仿到自主:范式的转变
RecZero 标志推理范式的重要转变: 从依赖人工知识的监督式推理,转向基于任务目标的自主式推理。它提出一个大胆问题:能否让模型在 没有教师指导、没有推理模板 的情况下,仅通过与推荐环境交互,自己学会如何思考?
这像把从未见过推荐任务的 LLM 直接投放到真实环境:系统展示用户历史与物品元信息,模型输出推荐;每次推荐后给奖励信号(如推荐与真实评分的差距)。模型唯一的学习信号就是这个奖励——它不知道「好推理」长什么样,也没有示例告诉它先分析用户再评估物品,只能自己摸索哪种思考带来更高奖励。
🧠 Mental Model: 登山者与安全框架
Think-before-Recommendation 模板像给登山者的通用框架:「先观察地形、再选路线、然后评估风险、最后行动」——规定了步骤与顺序,但怎么观察、选什么路线完全由登山者决定。RecZero 提供足够结构引导探索方向,又保留足够自由让模型发现场景特定的最优策略。
9.3.1 RecZero:纯强化学习的自主推理
Think-before-Recommendation 提示构造
尽管纯 RL,RecZero 仍给模型一个结构化思考空间。提示由四部分组成:
最关键的是 ,定义四个结构化步骤:
分别对应:从历史提取用户兴趣、总结目标物品特征、评估用户-物品匹配度、给出评分预测。注意——模板只定义步骤的 存在与顺序 ,不规定每步写什么、关注哪些特征、如何权衡。这些全留给模型在 RL 中探索。
例如图书场景,模型可能自主发现「用户兴趣的多维性」:
<analyze user> 用户历史含《林肯传》《富兰兰自传》,偏好政治人物生平;
也有《人类简史》,偏好深度历史分析 </analyze user>
<analyze item> 《光荣与梦想》美国断代史,兼顾政治家刻画与时代叙述 </analyze item>
<match> 同时满足政治人物与宏观历史双重兴趣,写作深度契合 </match>
<rate> 4.5分 </rate>
这个「同时考虑多个兴趣维度」的策略并非人工设计,而是模型发现「多维度匹配能获得更高奖励」后逐渐固化的。
基于规则的奖励建模
RecZero 采用极简却有效的奖励:
其中 是真实评分, 是模型在 步的预测。看似简单粗暴,但关键机制是:奖励只评最终评分,而推理路径 与预测 是 联合生成 的,梯度会反向传播到整个推理过程。若某种推理系统性导致更准确预测,模型就强化它。
例如探索初期版本 A「用户喜欢科幻→本书科幻→匹配→4分」(真实 2 分,奖励 -2);后来版本 B 细致分析「用户偏好硬科幻,本书是科幻 romance 核心不符→2分」(奖励 0)。多次对比后,模型学会「仅匹配粗标签不够,需深入分析细分偏好」——这个元认知完全由试错涌现,无人告知。
RecZero 用 GRPO 实施 RL:对同一样本采样 条 rollout ,计算相对优势 ,增强正优势、抑制负优势。模型不需知道绝对正确答案,只需识别哪些推理相对更好。
纯强化学习的涌现能力
经大量交互,RecZero 涌现一系列能力(非监督/模仿获得,纯由奖励驱动):
- 分层推理自动形成 :从初期极简「用户喜欢历史→匹配→4分」,随训练演化出多维度画像与多因素权衡——从粗到细的演化完全由奖励信号驱动。
- 负面信号的利用 :模型学会显式标注「用户曾对恐怖题材评分很低,应避免」——源于发现忽略明确不喜欢的内容会严重降低奖励。
- 上下文敏感的推理调整 :历史少时(冷启动)依赖流行度保守预测;历史丰富时做个性化深度分析。
- 跨领域推理模式迁移 :图书中学的「区分主题与风格」可迁移到电影「区分故事主题与拍摄风格」——说明学到了 通用推理元策略。
Analysis: 纯 RL 的优势是彻底自主、无教师瓶颈;代价是训练初期低效探索——从随机状态靠试错发现有效推理模式,计算与数据成本高。这引出 RecOne 的混合范式。
9.3.2 RecOne:冷启动增强的混合范式
RecZero 证明纯 RL 能让模型自主学会推理,但「从零开始」探索漫长低效。RecOne 的务实折中: 用少量高质量推理示例为模型「冷启动」,再用 RL 自主精进——类比「先教会基本动作,再让学生自己练习升华」。
冷启动样本的精心构造
RecOne 第一阶段是 冷启动监督微调(Cold-start SFT) ,但与传统蒸馏本质不同:只构造少量高质量示例初始化推理能力。两种策略:
- 对齐样本(Aligned) :用预训练教师模型对用户-物品对评分,若预测恰与真实一致,保留完整推理路径:。
- 纠偏样本(Misaligned) :保留教师预测错误的样本,但替换最后 步为正确评分:。这教模型「思路正确但最后一步有误时,提炼有用信息并修正」。
最终冷启动集 ,规模远小于传统蒸馏(数千到数万 vs 数十万),避免过拟合教师表面模式,为 RL 留足优化空间。训练目标为标准条件语言建模 。
强化学习的能力跃迁
第二阶段与 RecZero 完全相同(GRPO + 评分误差奖励),但因有冷启动加持,动态特性截然不同:
- 探索效率飞跃 :从「会推理」状态出发,探索重点放在优化精炼。达到相同性能所需训练步数减少约 60%。
- 性能上界突破 :RecOne 最终显著超越 RecZero——Amazon-book 上 RMSE 降 6.7%、MAE 降 16.8%;Amazon-music 上 RMSE 降 12.2%、MAE 降 29.9%。原因:RL 探索存在 局部最优陷阱——从随机状态易早收敛于「还不错」的简单匹配;冷启动提供更接近全局最优的起点。
- 推理模式多样化 :根据场景灵活切换——信息充分时细粒度多因素分析、冷启动时基于群体统计保守推理、有负面信号时排除式推理。
混合范式的本质
RecOne 揭示深刻洞察: 监督学习和强化学习不是对立,而是互补。监督提供「语言」(推理的基本语法结构),强化提供「智慧」(策略与权衡)。类比人类:在校学解题步骤(监督),真能力来自大量练习试错(强化)。最高效路径是 先掌握基础框架,再通过实践精进。工程上 RecOne 总计算量仅 RecZero 的 40–50%(冷启动数据小、RL 收敛快、避无效采样),成为工业更优选择。
💡 Key Insight: 真正的智能不是记忆而是推理,不是模仿而是理解,不是遵循规则而是创造策略。当推荐具备自主推理,它不再是被动过滤器,而是主动的智能助手——理解深层需求、权衡多维目标、解释决策、持续从反馈学习。
下面用交互演示回顾从「隐式预测」到「显式自主推理」的完整演进:
点击「下一步」或「自动播放」,观察推荐模型如何从语义鸿沟出发,经「认识物品」(LC-Rec/PLUM)、「学会思考」(OneRec-Think)、「独立摸索」(RecZero)走到「混合精进」(RecOne)。
⚠️ Common Mistakes in 9.3
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为 OneRec-Think 已自主推理 | 「OneRec-Think 自主探索推理」 | 它靠人工模板/教师知识,本质是模仿学习 | 区分:模仿(9.2) vs 自主(RecZero) |
| 2 | 把 RecZero 模板当监督 | 「模板规定了每步写什么」 | 模板只定步骤顺序,内容全由模型探索 | 模板=结构引导,非内容监督 |
| 3 | 忽视纯 RL 探索 inefficiency | 直接用 RecZero 从零训大模型 | 初期大量无效探索,成本高 | 用 RecOne 冷启动 + RL 提效 |
| 4 | 以为冷启动=传统蒸馏 | 「RecOne 用百万教师样本」 | 仅数千到数万高质量(含纠偏)样本 | 小样本高质量,留 RL 优化空间 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 模仿学习的局限 | 模板约束/教师瓶颈/难扩展 | 引出自主推理的动机 |
| RecZero 纯 RL | 框架+自由探索, 奖励 r=− | y−ŷ |
| 涌现能力 | 分层/负面信号/上下文敏感/跨域迁移 | 证明 RL 能学通用推理元策略 |
| RecOne 混合 | 冷启动 SFT(对齐+纠偏)+RL | 效率↑60%、性能超 RecZero、成本 40–50% |
| 互补本质 | 监督给「语言」, 强化给「智慧」 | 先框架后精进是最优路径 |
❓ FAQ
Q1: RecZero 没有教师,怎么知道推理好不好?
A: 它只用任务反馈 。奖励只评最终评分,但梯度反向传到整条推理——系统性更准确的推理被强化。无需「好推理」示例。
Q2: 为什么 RecOne(有监督初始化)反而比纯 RL 的 RecZero 更好?
A: RL 探索有局部最优陷阱——从随机状态易早收敛于简单匹配。RecOne 冷启动提供更接近全局最优的起点,使后续探索更有效,最终突破性能上界,且训练步数少 60%。
Q3: 纠偏样本为什么有用?
A: 它保留教师「思路对但最后一步错」的推理,把最后评分替换为正确值。教模型提炼有用信息并修正,而非否定整条思路——像老师批改作业指出「思路对,最后一步误」。
🔗 前后关联
- 9.1 (语义对齐)所有方法都建立在语义索引表示之上——自主推理不改变表示,改变的是「如何使用表示做决策」。
- 9.2 (OneRec-Think)本章是它向「去人工模板」的演进:模仿 → 纯自主 → 混合。
- 10.x (扩散模型)下一章换一条技术线——用扩散的生成/去噪能力解决数据增强与多样性,与推理范式互补。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after yourself.
Problem 9.3.1 — 范式归类 🟢 Easy
判断下列陈述描述哪种范式(模仿学习 / 纯强化学习 / 混合范式):
- (a) 用预定义 prompt 模板引导模型做「用户画像→候选评估→推荐」
- (b) 无任何教师,仅靠评分误差奖励让模型自主摸索推理
- (c) 先用少量高质量(含纠偏)样本 SFT,再 GRPO 自主精进
💡 Solution (click to reveal)
Approach: 对照三种范式定义。
- (a) 模仿学习(OneRec-Think,人工模板)
- (b) 纯强化学习(RecZero)
- (c) 混合范式(RecOne)
Key points:
- 模仿=人工知识;纯RL=无知识自主;混合=先框架后精进。
Problem 9.3.2 — RecZero 奖励计算 🟢 Easy
某 rollout 预测评分 ,真实评分 。请计算 RecZero 的奖励 ,并说明梯度如何影响推理。
💡 Solution (click to reveal)
Approach: 套用规则奖励公式。
梯度影响: 奖励只评最终评分,但推理路径与预测联合生成,负奖励的梯度反向传播到整条推理,抑制「导致高估」的思考方式;若另一 rollout 预测更准(奖励更高),其推理被强化。
Key points:
- 奖励越接近 0(预测越准)越好。
- 好/坏推理通过相对优势被分别强化/抑制。
Problem 9.3.3 — 冷启动样本构造 🟡 Medium
某教师模型对用户-物品对预测评分 4,真实评分也是 4(对齐样本);另一对教师预测 5,真实 3(误预测)。请分别写出这两个样本进入 RecOne 冷启动集的形式(用 / 记号与说明)。
💡 Solution (click to reveal)
Approach: 按对齐/纠偏定义分类。
- 教师预测 4 = 真实 4 → 对齐样本 :,保留完整推理路径(因它导向了正确预测)。
- 教师预测 5 ≠ 真实 3 → 纠偏样本 :,保留前几步推理,仅把 替换为正确评分 3。
Key points:
- 对齐样本:推理→正确答案,整体保留。
- 纠偏样本:思路可取的错答,修最后一步,教模型提炼有用信息。
Problem 9.3.4 — 设计自主推理训练 🔴 Hard
你要为音乐推荐设计 RecOne 式训练。请写出:① 冷启动阶段用哪两类样本及大致规模;② RL 阶段用哪种算法与奖励;③ 相比直接用 RecZero,预期在「训练成本」与「最终性能」上获得什么收益。引用具体数字。
💡 Solution (click to reveal)
Approach: 套用 RecOne 混合范式。
- 冷启动 :对齐样本(教师预测=真实,留完整推理)+ 纠偏样本(教师错但修最后评分步);规模数千到数万条高质量样本(远小于传统蒸馏的百万级)。
- RL 阶段 :GRPO,奖励 ,同用户采样 K 条 rollout 比相对优势。
- 收益 :训练步数减约 60% (探索效率),最终性能超纯 RL——参考 Amazon-music RMSE 降 12.2%、MAE 降 29.9%;总计算量仅 RecZero 的 40–50%。
Key points:
- 冷启动提供「语言」,RL 提供「智慧」。
- 混合范式既避纯 RL 低效,又突破其性能上界。
🏆 Challenge: 开放问题论证
本章指出自主推理仍局限在「单步决策」(给定历史与目标物品预测评分),而真实推荐是「序列决策」(每次推荐影响后续行为,需长期价值)。请写一段 200 字内,论证:若把 RecZero 扩展到序列决策,其奖励函数 需如何改造?并指出一个「推理忠实性」风险。
💡 Hint
改造:单步即时误差奖励需换成 序列级累计奖励 (如多步后的长期互动价值/会话总时长),并引入折扣因子平衡即时与长期。风险:RL 自主形成的推理是黑箱优化的产物,可能「事后合理化」而非真实反映决策依据,难以验证忠实性(faithfulness)——需束搜索一致性或交错推理等证据约束。呼应 9.2 的忠实性讨论与本章结尾开放问题。
生成式推荐的主线(见 1.1、5.3、9.x)让我们看到:模型可以「直接生成」物品序列、甚至「先思考再推荐」。但生成式能力还能解决更实际的工程痛点——数据稀疏、特征缺失、结果趋同。这些恰恰是工业推荐系统常年头疼的问题。
扩散模型(Diffusion Model) 凭借其「先逐步加噪、再学习去噪」的生成范式,为这些痛点提供了独特工具:它不像判别式模型去「打分」,而是在连续潜在空间里多步去噪「雕刻」出目标。本章沿两条主线展开—— 数据增强 (生成伪交互/跨场景样本)与 特征增强与多样性优化 (补全缺失特征、生成多样化 slate)。各章要点见下表。
本章涵盖
| 章节 | Topic | The Big Idea |
|---|---|---|
| 10.1 | 扩散模型基础 | 前向加噪/反向去噪、DDPM、潜在空间扩散、条件生成与两种引导;推荐的特殊设计(噪声尺度、x₀-prediction) |
| 10.2 | 扩散做数据增强 | DiffuASR 生成「前序」序列扩充短序列用户;Diff-MSR 跨场景迁移缓解冷启动 |
| 10.3 | 扩散在推荐的应用 | AsymDiffRec 不对称扩散补全缺失特征;DMSG 条件扩散生成多样化 slate |
What You'll Be Able to Do After This Part
- 🟢 解释 前向扩散与反向去噪的互逆马尔可夫过程,并写出任意 t 直接采样公式
- 🟢 区分 数据空间扩散与潜在空间扩散,说明为何推荐偏好后者
- 🟡 描述ε-prediction 与 x₀-prediction 的差异,以及推荐为何常用后者
- 🟡 复述DiffuASR / Diff-MSR / AsymDiffRec / DMSG 各自如何用扩散解决具体痛点
- 🔴 评析 扩散模型在推荐中的适用边界(延迟、配套基础设施)与未来方向
- 完成各节分层练习题,巩固从基础到落地的扩散推荐主线
核心概念
| Concept | 章节 | Relevance |
|---|---|---|
| 前向/反向过程 | 10.1 | 扩散模型的核心互逆机制 |
| 潜在空间扩散 | 10.1 | 推荐因高维稀疏而更常用 LDM |
| 条件生成 + 引导 | 10.1 | 用用户历史/文本控制生成方向 |
| 序列增强 / 跨场景增强 | 10.2 | 缓解数据稀疏与冷启动 |
| 不对称扩散 / Slate 生成 | 10.3 | 特征补全与多样性优化 |
前置知识
- 已读 1.1(两种范式)、5.3(生成式范式演进,尤其语义 ID 与端到端生成)
- 了解基础概率、变分自编码器(VAE)与 Transformer 注意力机制
本章偏工程应用,公式重在「为什么这样设计」——不必逐行推导,抓住每个方法针对的痛点即可。
Tips for This Part
- 始终带着「痛点」读。 每个扩散方法都对应一个具体工程问题(稀疏/冷启动/缺失/趋同)。
- 区分「空间」。 数据空间 vs 潜在空间、前向空间 vs 反向空间——空间选错设计就错。
- 别把扩散当「替代判别式」。 本章方法是 工具型 生成能力(增强数据/特征/多样性),而非端到端替代排序。
Let's dive in! 🚀
推荐中的扩散模型基础
📝 Before You Continue: 建议先读 1.1 的两种范式、5.3 的生成式范式演进。本章是扩散模型在推荐落地的「技术铺垫」,后续 10.2/10.3 的具体方法都建立在此。
在 5.3 我们已从架构层面讨论过扩散模型与 Transformer 的互补关系。本节系统回顾扩散模型的 核心技术原理 ,并重点讨论将其用于推荐时的 特殊考量与设计选择。理论基础主要来自 DDPM ,而推荐应用以 DiffRec 为代表性工作。
扩散模型的核心思想可以概括为两个互逆的马尔可夫过程: 前向扩散 逐步向数据添加噪声, 反向去噪 学习从噪声中恢复原始数据。读完本节,你将理解这套机制,以及它为何能成为推荐系统的「生成工具」。
读完本节,你将能够:
- 写出 前向扩散的单步转移与任意 t 直接采样公式(重参数化)
- 区分 数据空间扩散与潜在空间扩散,并说明推荐为何偏好后者
- 描述ELBO 训练目标,以及 ε-prediction 与 x₀-prediction 两种参数化
- 解释 推荐的噪声尺度控制、推理起点选择、条件生成与两种引导策略
- 完成 4 道分层练习题,并体验结尾的「前向/反向」交互演示
10.1.0 扩散模型的两类操作空间
扩散模型按操作空间主要分为两大类:
数据空间扩散(Pixel-Space Diffusion)——直接在原始数据空间(图像像素、推荐中的交互向量)进行扩散与去噪。代表是 DDPM。理论上更直接,但因在高维原始空间迭代操作,计算成本高,处理高分辨率数据或长序列时效率尤低。
潜在空间扩散(Latent Diffusion Models, LDM)——先用编码器(VAE/自编码器)把原始数据压缩到低维 潜在表示空间 ,在该空间扩散去噪,最后解码还原。代表是 Stable Diffusion。流程:编码 → 在 上扩散 → 解码 。若维度从 降到 (),计算量可减 倍。
💡 Key Insight: 在推荐场景中,潜在空间扩散应用更普遍,原因有三:① 效率——推荐处理大规模行为序列/物品特征,原始空间操作不可接受;② 语义——潜在空间提供更紧凑、语义化的表示,契合用户兴趣/物品属性建模;③ 灵活性——易与 CF、GNN 等现有架构融合。故本章后续方法多在物品嵌入或用户特征空间扩散,而非直接操作稀疏交互矩阵。
10.1.1 前向加噪与反向去噪过程
前向扩散过程
给定数据样本 ,前向过程通过 步逐步加高斯噪声,构建潜在变量 。每步转移:
其中 控制第 步噪声强度。当 , 趋近标准高斯。利用 重参数化技巧 与高斯可加性,可从 直接采样任意 的加噪数据:
等价地:
其中 ,。这使得训练时可高效采样任意时间步,无需逐步执行前向。
反向去噪过程
反向过程从 出发,通过学习到的去噪网络逐步恢复原始数据。每步去噪转移:
均值 与协方差 由神经网络参数化;实践中协方差常设为固定值 ,重点学习均值。
下面用交互演示直观感受「用户交互向量」如何逐步被加噪为噪声、又如何被去噪恢复:
点击「下一步」或「自动播放」,观察信号格从前向的清晰交互模式,逐步被噪声淹没,再经反向去噪恢复——这正是扩散模型「雕刻」目标数据的全过程。
10.1.2 训练目标与两种参数化
从 ELBO 到简化损失
扩散模型通过最大化 的对数似然下界(ELBO)训练:
重建项衡量从 恢复 的能力;去噪匹配项约束学到的反向转移 与真实后验 对齐。推理时我们不知道 ,故需训练网络 近似这个理想过程。
两种参数化方式
去噪网络可采用两种参数化:
1. 预测噪声 (DDPM 标准):
2. 预测原始数据 :
两者数学等价(),但 推荐场景常用 x₀-prediction。原因:推荐目标是从加噪交互向量恢复原始交互 ,并直接以 作为交互预测分数排序;且随机噪声 方差大,迫使网络估计不稳定目标会增加训练难度。
采样过程
训练完成后:① 从 采样;② 对 迭代去噪:
③ 得到生成样本 。
🧠 Mental Model: 雕塑家与石块
前向扩散像把一块完好的大理石逐渐敲成碎石堆(加噪);反向去噪像雕塑家对照「残影」,一锤一锤把碎石重新雕回人像(去噪)。x₀-prediction 相当于雕塑家每次都直接想象「最终人像长什么样」,比盯着「刚敲掉的那堆碎石」更易上手——这正是推荐偏好它的原因。
10.1.3 推荐场景的特殊设计
与图像生成不同,推荐扩散有两项特殊设计:
噪声尺度控制——标准 DDPM 会把数据扩散至纯高斯(),但推荐中完全丢失历史偏好会增加生成难度。故用噪声尺度参数 限制最大强度,使 时仍保留部分原始信号:
其中 控制整体噪声强度上限, 界定噪声比例随 线性增长的区间(该设计出自 DiffRec,后续推荐扩散工作普遍沿用)。
推理起点选择——推理可从部分加噪状态 ()出发反向去噪,既利用去噪纠错处理原始交互噪声,又保留足够个性化信息。
条件生成与可控性
推荐希望生成受用户历史/上下文控制。条件信息可注入去噪网络:直接拼接、加性融合、或 Transformer 的 cross-attention。条件损失:
推理阶段控制生成方向主要有两策略:
1. Classifier-Guided(分类器引导)——用预训练分类器 梯度推离目标类:
推荐中可用序列推荐模型当「分类器」,引导生成与历史一致的交互序列。
2. Classifier-Free Guidance(无分类器引导)——训练时以概率 把条件 替换为空占位符 ,推理时:
大→更个性化但可能损质量; 小→更多样但个性化低。推荐中 更常用。
条件设计示例(序列推荐) :以用户历史交互序列为条件,用 Transformer 编码器编码为 ,引导扩散生成目标物品嵌入——把序列建模(Transformer)与生成建模(Diffusion)结合,DreamRec 即采用此架构。
Analysis: 扩散模型在推荐中不以端到端替代判别式为主要目标,而是以其生成能力 + 随机采样为两个实际问题提供工具:数据稀疏性与推荐多样性。这是理解 10.2/10.3 的主线。
⚠️ Common Mistakes in 10.1
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 在原始交互矩阵上直接扩散 | 「用 DDPM 在稀疏矩阵上加噪」 | 高维稀疏,计算不可接受 | 用潜在空间扩散(LDM) |
| 2 | 推荐硬套 ε-prediction | 「扩散推荐默认预测噪声」 | 推荐要恢复 x₀ 并排序,x₀ 更贴合 | 用 x₀-prediction 直接输出 |
| 3 | 忽略推荐噪声尺度 | 完全扩散到纯高斯再生成 | 丢失历史偏好,生成更难 | 用尺度 s 保留部分信号 |
| 4 | 把无分类器引导当更复杂 | 「引导都需要额外分类器」 | Classifier-Free 无需分类器 | 区分两类引导,推荐常用 Free |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 前向/反向 | q 加噪 ↔ p_θ 去噪,马尔可夫互逆 | 扩散模型核心机制 |
| 潜在空间扩散 | 编码→扩散→解码,计算降 (d/d')² | 推荐因高维稀疏而常用 |
| 两种参数化 | ε-pred vs x₀-pred(等价) | 推荐常用 x₀-pred 更贴合 |
| 推荐特殊设计 | 噪声尺度 s、中途起点 | 保留个性化、降生成难度 |
| 条件+引导 | 拼接/交叉注意力;两类引导 | 用历史/文本控制生成方向 |
❓ FAQ
Q1: 为什么推荐偏好潜在空间扩散而非数据空间?
A: 推荐交互向量高维稀疏,原始空间迭代去噪计算不可接受;潜在空间更紧凑、语义化,且易与 CF/GNN 融合,满足工业实时性。
Q2: 推荐为什么常用 x₀-prediction?
A: 推荐目标就是恢复用户原始交互并用 排序;x₀-pred 比估计高方差噪声 ε 更稳定、更贴合任务。
Q3: Classifier-Free Guidance 的 γ 怎么调?
A: γ 大→更贴合条件(个性化强)但可能损生成质量/多样性;γ 小→更多样但个性化弱。按业务在「相关性 vs 多样性」间权衡。
🔗 前后关联
- 1.1 / 5.3 (范式与生成式)扩散是生成式家族中「连续空间去噪」一支,与自回归生成互补。
- 10.2 (数据增强)DiffuASR / Diff-MSR 把本节基础用于生成伪交互。
- 10.3 (应用)AsymDiffRec / DMSG 把去噪能力用于特征补全与多样性。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 10.1.1 — 直接采样公式 🟢 Easy
已知 ,第 步的 ,采样噪声 。请写出 的表达式,并说明信号项与噪声项的相对大小。
💡 Solution (click to reveal)
Approach: 套用重参数化公式。
信号项系数 ,噪声项系数 。此时信号略强于噪声(t 较小)。
Key points:
- 系数平方和为 1,保证方差守恒。
- 越小噪声占比越大,t 越大越接近纯噪声。
Problem 10.1.2 — 空间选择判断 🟢 Easy
下列场景应优先用数据空间扩散还是潜在空间扩散?简述理由。
- (a) 对 1024×1024 高清图像去噪
- (b) 对百万维稀疏用户-物品交互矩阵做推荐增强
💡 Solution (click to reveal)
Approach: 按维度与效率判断。
- (a) 数据空间扩散(DDPM 直接在像素空间,图像场景经典)。
- (b) 潜在空间扩散(LDM)——百万维稀疏矩阵直接扩散计算不可接受,应先编码到低维潜在空间再扩散。
Key points:
- 高维/稀疏 → 潜在空间。
- 推荐几乎都用 LDM。
Problem 10.1.3 — 参数化对比 🟡 Medium
某扩散推荐模型用 ε-prediction 训练,但在排序时发现预测分数波动大、效果不稳。请解释可能原因,并说明改用 x₀-prediction 为何更合适(引用方差与任务目标)。
💡 Solution (click to reveal)
Approach: 从参数化差异分析。
原因: ε-prediction 让网络估计所加高斯噪声 ,而 方差大,目标不稳定,导致恢复出的 x₀ 排序分数波动。
改用 x₀-pred: 推荐目标是恢复原始交互 并直接以 作为交互预测分数排序——x₀-pred 的损失 直接优化这个任务目标,且避开高方差噪声估计,训练更稳定、更贴合推荐。
Key points:
- 两者数学等价,但任务适配性不同。
- 推荐「恢复 x₀ 即打分」→ 选 x₀-pred。
Problem 10.1.4 — 设计条件引导 🔴 Hard
你要为序列推荐设计条件扩散:用 Transformer 编码用户历史为条件 ,引导扩散生成下一个物品嵌入。请写出:① 条件如何注入去噪网络(至少两种方式);② Classifier-Free Guidance 的训练与推理公式;③ 若想「更个性化但接受略低多样性」,γ 应调大还是调小。
💡 Solution (click to reveal)
Approach: 套用本节条件生成与引导。
- 注入方式 :直接拼接 ;或加性融合(时间步嵌入相加注入各层);或在 Transformer 中去噪网络用 cross-attention 融合 。
- Classifier-Free :训练时以概率 把 替换为空 ;推理 。
- γ 调大 → 更偏向条件(个性化强),但多样性略降——符合「更个性化、接受略低多样性」。
Key points:
- 条件注入要贯穿去噪各层。
- γ 是相关性 vs 多样性的旋钮。
🏆 Challenge: 推荐延迟论证
扩散模型推理需多步迭代去噪,而工业推荐常要求百毫秒级延迟。请写一段 200 字内,论证:在「数据增强(离线)」与「在线排序」两种用途中,扩散的延迟开销分别是否可接受?并指出 10.3 会用到的一种加速采样技术。
💡 Hint
离线数据增强(如 DiffuASR 生成前序序列)可承受多步去噪,延迟无关紧要;在线排序若每请求多步迭代则难达标——故扩散多用于离线增强/生成,在线慎用。加速技术:DDIM(去确定性少步采样),10.3 的 DMSG 即用其把步数从上千减到 50、毫秒级。呼应 10.3 的延迟设计。
基于扩散的数据增强
📝 Before You Continue: 先读完 10.1 的前向/反向过程、条件生成与引导——本节的 DiffuASR、Diff-MSR 都是把「去噪生成」当作增强工具。
推荐系统面临的核心挑战是 数据稀疏性 :交互数据天然长尾分布——少数热门物品积累大量交互,绝大多数物品记录极少。对新用户(冷启动)和低活跃用户,历史匮乏使偏好建模困难。传统增强(随机裁剪、重排)生成的样本质量有限,难捕捉潜在兴趣模式。
扩散模型的生成能力为此提供新思路:学习数据分布后,可生成高质量伪交互序列扩充训练数据。本节介绍两种代表: DiffuASR 生成用户历史的「前序」序列; Diff-MSR 利用跨场景知识迁移解决冷启动。
读完本节,你将能够:
- 描述DiffuASR 的三组件框架(前向/反向/引导)与 SU-Net 的序列处理
- 解释 舍入(Rounding)如何把连续嵌入映射回离散物品 ID
- 复述Diff-MSR 的「狗像猫」跨场景迁移直觉与四阶段流程
- 对比 两类引导(Classifier-Guided / Classifier-Free)在 DiffuASR 中的应用
- 完成 4 道分层练习题,巩固扩散做数据增强的主线
10.2.0 为什么用扩散做增强
序列推荐通过建模用户历史交互预测下一个物品,但面临 数据稀疏性 (大量用户-物品仅极少交互)与 长尾用户问题 (多数用户历史短于 10 条,效果显著下降)。传统增强难以生成「语义一致」的伪序列。
扩散模型的优势:它不是简单变换已有样本,而是 学习分布后生成新样本——生成的伪交互在语义上与真实历史一致,却补充了缺失的「前序」信息。
🧠 Mental Model: 补写回忆录
短序列用户像只记得最近几页的日记。DiffuASR 不是把现有页复印几份,而是读懂这几页的文风与主题,帮你补写前面可能经历的几页——补写内容与现有日记连贯,却让传记更完整。
10.2.1 序列增强:DiffuASR
DiffuASR 的核心思想:给定原始交互序列 ,生成对应的「前序」序列 (用户在 之前可能产生过的交互)。拼接后得更长更完整的历史,用于训练下游序列推荐模型。
整体框架
DiffuASR 含三个关键组件:
- 前向过程——将目标增强序列的物品嵌入逐步加噪。数据是嵌入矩阵 , 为增强长度, 为嵌入维度。
- 反向过程——从噪声恢复嵌入序列 ,并通过 舍入(Rounding) 映射回离散物品 ID:
(余弦相似度,最近物品即输出)。这一步把连续生成转为可解释的物品序列。 3. 引导过程——确保生成序列与原始序列语义一致。引导信息来自原始序列的聚合表示 。
Sequential U-Net
标准 U-Net 为图像设计,直接用于序列嵌入会丢失序列维度信息。DiffuASR 提出 SU-Net :
- 序列维度当通道 :把 视为 个通道的「图像」。
- 重塑嵌入维度 :每个 维嵌入重塑为 矩阵。
于是输入变成 通道、 的张量,可自然卷积;各通道独立处理,保留序列位置信息。SU-Net 主体含下采样、中间注意力层、上采样;时间步 与条件 通过加性融合注入各 ResNet 块:
为 的正弦位置编码, 经线性变换后加到各层输入,控制去噪方向。
引导策略
DiffuASR 提供两种引导,对应 10.1 的两种条件生成方法:
1. Classifier-Guided——用预训练序列推荐模型当「分类器」。因 是 前序, 首物品 可视为 的「下一个物品」,引导目标是让生成序列正确预测 :
2. Classifier-Free——训练时随机丢弃条件向量,推理时线性组合:
更简洁高效,实际应用更常用。
训练与增强流程
训练 :从原数据集选长度 > 的序列,前 个作增强目标,其余作 ,用真实前序监督扩散学习。增强 :每用户序列执行引导反向去噪,生成前序 ,与原序列拼接形成增强训练数据 。DiffuASR 生成的序列可直接训练任何序列推荐模型,无需改架构,通用性强。
Analysis: DiffuASR 的价值在于「高质量 + 通用」——生成的伪序列语义一致,且与下游模型解耦。代价是需训练扩散+舍入,且生成质量依赖条件引导的强度 γ。
10.2.2 跨场景增强:Diff-MSR
多场景推荐(MSR)中,不同场景数据量悬殊:热门场景海量交互,新兴/垂直(冷启动)场景数据稀疏。导致冷启动场景参数难充分学习,且联合训练时易受热门场景 负迁移 影响。
Diff-MSR 的洞察来自 CV: 一张模糊的狗图可能像猫。在推荐嵌入空间,数据丰富场景的用户-物品嵌入适当加噪后,其「轮廓」可能与冷启动场景样本相似。借此从丰富场景「借」知识增强冷启动。
整体框架(四阶段)
- 预训练——用全场景数据训多场景骨干(如 MMoE),得共享嵌入层(跨场景通用表示)。
- 扩散——对每个冷启动场景训两个扩散模型(正样本/负样本),输入为用户特征与物品属性嵌入拼接 ,学习该场景数据分布。
- 分类——训二分类器判断(加噪)嵌入来自冷启动还是丰富场景。对丰富场景样本不同程度加噪,若被误判为冷启动,说明其「轮廓」相似,可被利用。
- 微调——用三类数据微调冷启动模型:误分类丰富样本去噪得的伪样本、纯高斯生成的伪样本、冷启动真实数据。
分类阶段是关键:对丰富场景嵌入 不同程度加噪得 ,若被误判为冷启动,说明这「模糊」样本在嵌入空间与冷启动相似——用冷启动扩散模型对 去噪,即得高质量冷启动样本。Diff-MSR 设计 分段噪声策略 :前几步保持 较小以保留结构,之后线性增长——轻度加噪仍保留场景特征供判断,重度加噪确保收敛到高斯。
💡 Key Insight: 两类方法共同点——用扩散生成高质量伪交互数据,并用条件控制保证语义一致性。DiffuASR 借历史条件生成前序,Diff-MSR 借场景分布借力跨域。下一节看扩散在特征与多样性上的应用。
⚠️ Common Mistakes in 10.2
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为扩散增强=复制样本 | 「把短序列复制几份当增强」 | 复制不增信息,难补前序 | 用扩散生成语义一致的新前序 |
| 2 | 忽略舍入步骤 | 直接用连续嵌入当推荐 | 下游模型要离散物品 ID | 用 Rounding 映射最近物品 |
| 3 | 混淆两类引导 | 「DiffuASR 必须用分类器引导」 | Classifier-Free 更常用更简洁 | 两者皆可,常用 Free |
| 4 | 误用 Diff-MSR 跨域 | 「冷启动直接用丰富场景原始样本」 | 分布不同会负迁移 | 加噪→误判→去噪生成伪样本 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| DiffuASR | 前向/反向/引导三组件 + SU-Net + Rounding | 生成前序序列扩充短序列用户 |
| SU-Net | 序列当多通道图像 + 条件/时间步加性融合 | 保留序列维度信息 |
| 两类引导 | Classifier / Classifier-Free | 保证生成与原始语义一致 |
| Diff-MSR | 四阶段 + 分段噪声 + 「狗像猫」迁移 | 跨场景借力缓解冷启动 |
| 共同主线 | 生成伪交互 + 条件控语义 | 数据增强型扩散应用 |
❓ FAQ
Q1: DiffuASR 生成的「前序」有什么用?
A: 短序列用户历史不足,预测下一物品难。生成语义一致的前序 与原序列拼接,得到更长历史,提升下游序列推荐效果,且不与下游模型耦合。
Q2: 为什么舍入(Rounding)必要?
A: 扩散在连续嵌入空间去噪,但推荐要离散物品 ID 才能进下游模型。Rounding 取嵌入空间最近物品,把连续结果转回可解释 ID。
Q3: Diff-MSR 为何用「误判」筛选?
A: 丰富场景样本加噪后若被分类器误判为冷启动,说明其轮廓与该场景相似——这样的样本去噪后才是高质量冷启动伪样本,避免直接跨域的负迁移。
🔗 前后关联
- 10.1 (基础)DiffuASR 的引导、SU-Net 的条件注入、Diff-MSR 的扩散均建立在 10.1 机制上。
- 10.3 (应用)从「增强数据」转向「增强特征与多样性」。
- 5.3 / 9.x (生成式主线)扩散是生成式家族的连续空间分支,与自回归/推理互补。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 10.2.1 — 框架归类 🟢 Easy
把下列组件归入 DiffuASR 三组件(前向 / 反向 / 引导)之一:
- (a) 把物品嵌入矩阵逐步加噪
- (b) 用 Avg(原始序列嵌入) 作为条件 c
- (c) 舍入映射回离散物品 ID
💡 Solution (click to reveal)
Approach: 对照三组件职责。
- (a) 前向过程
- (b) 引导过程(条件来自原始序列聚合)
- (c) 反向过程(去噪后 Rounding)
Key points:
- 前向=加噪;反向=去噪+舍入;引导=控语义一致。
Problem 10.2.2 — 舍入计算 🟢 Easy
去噪得某位置连续嵌入 ,物品词表 中三个候选的余弦相似度为:、、。请写出 Rounding 选出的物品。
💡 Solution (click to reveal)
Approach: 取相似度最大的候选。
最大值 0.91 对应 → 输出物品 A。
Key points:
- Rounding = 在词表中找最近邻。
- 把连续嵌入「解码」为离散 ID。
Problem 10.2.3 — SU-Net 设计 🟡 Medium
标准 U-Net 直接用于序列嵌入会丢什么?SU-Net 如何通过「序列当通道」与「嵌入重塑」解决?请说明条件与时间步如何注入。
💡 Solution (click to reveal)
Approach: 对照 SU-Net 设计。
问题: U-Net 为图像设计,直接吃序列嵌入 会丢失序列(位置)维度信息。
解决:
- 把 个位置当作 个 通道 ,序列维度转为通道维;
- 每个 维嵌入重塑为 矩阵,形成 通道 张量,可用卷积且各通道(位置)独立保留。
注入: 时间步 的正弦位置编码 与条件 加性融合 ,经线性变换加到各 ResNet 块输入,控制去噪方向。
Key points:
- 核心是「保序列维度」。
- 条件/时间步加性融合贯穿各层。
Problem 10.2.4 — 设计跨场景增强 🔴 Hard
某平台有「热门电商」与「新上线二手车」两场景,二手车数据极稀疏。请用 Diff-MSR 思路写四阶段流程,并说明「分段噪声策略」为何重要、以及用哪类伪样本微调冷启动模型。
💡 Solution (click to reveal)
Approach: 套用 Diff-MSR 四阶段。
- 预训练 :全场景训 MMoE 得共享嵌入层。
- 扩散 :为二手车场景训正/负样本两个扩散模型,输入为用户+物品属性拼接嵌入。
- 分类 :训二分类器判嵌入来自二手车还是电商;对电商样本不同程度加噪,被误判为二手车的即「轮廓相似」可利用。
- 微调 :用三类数据——误分类电商样本去噪得的伪样本、纯高斯生成的伪样本、二手车真实数据。
分段噪声重要性: 前期小 β 保留结构使分类器能判「轮廓」,后期线性增长确保最终收敛高斯——否则轻度加噪不足以产生可迁移样本、或重度加噪破坏结构。
Key points:
- 「狗像猫」:电商加噪误判为二手车即可借力。
- 伪样本 + 真实数据共同微调,防负迁移。
🏆 Challenge: 增强质量评估
DiffuASR 生成的伪序列若引导强度 γ 过大,可能过度贴合 而缺乏多样性;γ 过小则语义不一致。请写一段 200 字内,设计两个可计算的指标来评估增强数据质量(一个测语义一致性、一个测多样性),并说明如何据此调 γ。
💡 Hint
一致性:生成前序与 在嵌入空间的相似度(如平均余弦),或下游模型在「原+增强」上相对于「仅原」的精度提升。多样性:增强序列间的两两差异(如去重率、嵌入方差),或生成前序不同于训练集中已有前序的比例。γ 过大→一致性高但多样性低,γ 过小→反之;在两者 Pareto 前沿选平衡点的 γ。
特征增强与多样性优化
📝 Before You Continue: 先读完 10.1 与 10.2——本节的 AsymDiffRec、DMSG 把去噪能力从「增强数据」进一步用到「增强特征」与「优化结果」。
10.2 用扩散生成伪交互缓解数据稀疏与冷启动。本节从另两角度探讨扩散的实际价值: 特征增强 与 多样性优化。
工业推荐中, 特征缺失 普遍——用户画像不完整、物品属性缺失,直接拉低预测质量。另一方面,传统确定性推荐倾向推荐相似内容, 多样性不足 损害体验。扩散模型为两者提供新思路:去噪天然适合处理不完整输入,随机采样机制为多样性提供内在支持。本节介绍两种已上线方法: AsymDiffRec 用不对称扩散做特征补全, DMSG 用条件扩散生成多样化推荐列表。
读完本节,你将能够:
- 描述AsymDiffRec 的「离散前向 + 潜在反向」不对称设计及其两类损失
- 解释 为何离散特征 dropout 比高斯噪声更贴合推荐的真实缺失
- 复述DMSG 的 slate 生成流程与 v-prediction 参数化
- 评析 扩散模型在推荐的适用边界(延迟、配套基础设施)
- 完成 4 道分层练习题
10.3.0 从「增强数据」到「增强特征与结果」
已有扩散推荐(如 DiffRec)沿用 CV 的标准做法:对称前向/反向都用高斯噪声。但推荐输入特征多为 离散 的(用户 ID、性别、物品类别),对离散特征潜在表示加连续高斯噪声,得到的加噪表示并不代表另一个真实样本——对高斯噪声鲁棒 ≠ 对推荐真实噪声鲁棒。且对称过程可能让模型过度关注噪声重建、忽略个性化信息。
💡 Key Insight: 把扩散「照搬」到推荐会水土不服。本节的两种方法都针对推荐实际痛点改造扩散过程——而非简单套用图像范式。这是扩散落地推荐的普遍智慧。
🧠 Mental Model: 拼图缺失 vs 模糊照片
标准扩散像给「清晰照片」加雾(高斯噪声),去雾即可。但推荐的特征缺失更像拼图少了几块——不是模糊,是结构性空缺。AsymDiffRec 的离散 dropout 正是模拟「少几块」,比加雾更贴近真实。
10.3.1 特征增强:AsymDiffRec
AsymDiffRec 针对两个痛点提出不对称扩散: 离散数据空间不匹配 (高斯噪声不代表真实样本)与 个性化信息损失 (对称过程重噪声轻个性化)。其核心:前向用 离散特征 dropout 替代高斯噪声,反向从原始特征空间切到潜在表示空间,并用任务导向辅助损失保留个性化。
离散前向过程
给定 个特征的样本 ,前向执行 步特征 dropout,每步随机丢一个特征,得加噪序列 。扩散步数 。
关键:经 步后 是缺失 个特征的样本——与线上特征缺失高度一致(采集不全、隐私设置、服务故障)。故 dropout 作为「噪声」比高斯更贴合实际。
不对称反向过程
AsymDiffRec 的关键创新:反向与前向 不在同一空间。前向在原始特征空间(dropout),反向直接在 潜在表示空间 完成。设特征提取器 ,对加噪样本 先提取 ,去噪函数 以 与步长嵌入 为输入生成去噪表示:
步长嵌入 是二值向量, 表示对应特征缺失,为去噪提供缺失位置信息。训练用重建损失驱动:
不对称优势:若在原始空间反向(重建缺失特征再送提取器),会经历两次信息损失(反向重建 + 特征提取);直接在潜在空间反向避免此问题——推荐最终用的正是潜在表示。
任务导向的辅助损失
仅重建损失不足以保证保留个性化。AsymDiffRec 引入辅助任务损失,直接基于去噪表示预测:
为预测头, 为真实标签。确保去噪表示不仅在 L2 接近完整表示,下游预测也保持良好。
训练流程 :① 采样 ;② 离散前向得 ;③ 不对称反向得 ;④ 联合优化 。
推理流程 :与多数扩散推荐不同,AsymDiffRec 推理也用扩散模块。线上输入 常缺失特征,直接当「加噪样本」,用步长嵌入 标缺失位置,去噪生成补全表示 。因去噪函数是两层简单网络,对延迟影响极小。
📊 Data Point: AsymDiffRec 在工业离线实验中,AUC 相对提升 +0.1%、UAUC +1.68%,优于 CDAE、MultiVAE、自监督学习、DiffRec 等。消融显示重建损失与辅助任务损失缺一不可——去掉辅助损失后 AUC 甚至低于基线,说明保留个性化信息至关重要。
10.3.2 多样性优化:DMSG
音乐播放列表、电商套装等场景需生成一组物品( slate )供整体消费,要考虑物品间协调性与整体质量,是组合优化难题(候选组合数指数级)。传统方法假设用户只与 slate 中一个物品交互(简化为单物品推荐),且确定性检索对相同输入总返回相同结果,缺乏多样性。
DMSG (Diffusion Model for Slate Generation)把 slate 生成建模为条件生成问题,用扩散从文本 prompt 直接生成完整物品 slate。含三核心组件:
- 编码模块——把离散物品序列 经嵌入函数 转为连续表示 。采用预训练固定编码器,不与扩散联合训,提高稳定性、目录更新时只需更新编码器。
- 条件模块——用 Transformer 编码层把文本 prompt 映射为条件 ,经 cross-attention 注入扩散。
- 扩散过程模块——核心生成模块,前向对 slate 潜在表示加噪,反向在条件 引导下恢复;去噪网络为 Diffusion Transformer,用 cross-attention 融合条件。
v-prediction 参数化
10.1 介绍过 ε-prediction 与 x₀-prediction,DMSG 采用第三种: v-prediction——预测「速度」,其中 。由 可反推 与 。其优势:损失权重为「SNR+1」,高低信噪比区域都给合理梯度,训练更稳。损失:
生成与解码
推理时:① 编码 prompt ;② ;③ 迭代条件去噪;④ 最终连续表示经 Rounding 转离散物品序列(每位置取最近物品)。为满足延迟,DMSG 用 DDIM 加速,把推理步从训练时上千减到 50,单次生成毫秒级。
多样性分析
DMSG 在多样性上具天然优势,源于随机采样机制:
- 物品流行度分布——相比 BM25 等确定性检索偏向高频物品,扩散在连续潜在空间的随机采样让低流行度但语义相关的物品也有机会被选中。
- 生成结果新鲜度——相同 prompt 每次生成不同 slate,但质量相近(BERTScore 约 0.8 稳定),且每次含大量新物品。用户反复请求同主题也获不同列表,助内容发现与留存。
Analysis: AsymDiffRec 与 DMSG 共同点——针对推荐实际需求改造扩散过程而非套用图像范式。前者不对称设计解决特征缺失,后者用随机采样解决多样性。两者均已线上验证。但扩散模型距离直接替代判别式在线服务仍有距离:多步去噪的延迟、端到端生成式所需的语义 ID 等配套基础设施,仍是制约大规模落地的现实因素。扩散与 Transformer 的互补、与 RL/多模态的融合,仍是开放方向。
⚠️ Common Mistakes in 10.3
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 照搬对称高斯扩散到推荐 | 「和图像一样加高斯噪声去噪」 | 推荐特征是离散的,高斯不代表真实缺失 | 用 AsymDiffRec 的离散 dropout |
| 2 | 忽略个性化信息损失 | 只用重建损失训练扩散 | 模型重噪声轻个性化,AUC 反降 | 加任务导向辅助损失 L_aux |
| 3 | 以为 DMSG 只用 ε/x₀ 预测 | 「DMSG 套用 DDPM 的 ε-pred」 | DMSG 用 v-prediction 更稳 | 识别 v-pred(SNR+1 权重) |
| 4 | 高估扩散替代判别式 | 「用扩散全面替代排序」 | 多步去噪延迟高、需语义 ID 配套 | 视扩散为增强工具,非端到端替代 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| AsymDiffRec | 离散前向(dropout)+潜在反向+辅助损失 | 解决工业特征缺失,已上线 |
| 不对称设计 | 前向原始空间、反向潜在空间 | 避免两次信息损失 |
| DMSG | 条件扩散 + v-pred + DDIM | 生成多样化 slate,已上线 |
| 多样性来源 | 随机采样→长尾/新鲜度 | 突破确定性检索趋同 |
| 适用边界 | 延迟/配套基建制约大规模落地 | 扩散是工具,非端到端替代 |
❓ FAQ
Q1: 为什么 AsymDiffRec 用离散 dropout 而非高斯噪声?
A: 推荐特征是离散的,高斯加噪得到的表示不代表另一个真实样本;而线上特征缺失是「结构性空缺」,dropout 模拟的正是这种真实缺失,去噪即补全。
Q2: DMSG 的 v-prediction 好在哪?
A: v = αₜε − σₜx₀,其损失权重为 SNR+1,在高/低信噪比区域都给合理梯度,训练比 ε/x₀-pred 更稳。
Q3: 扩散能直接替代判别式排序吗?
A: 目前难——多步迭代去噪带来延迟,且端到端生成式需语义 ID 等配套基建。本章方法是数据/特征/多样性的增强工具,与 Transformer 互补。
🔗 前后关联
- 10.1 (基础)AsymDiffRec 的不对称、DMSG 的 v-pred 与 DDIM 都建立在 10.1 机制上。
- 10.2 (数据增强)同属「扩散作为生成工具」主线,从数据→特征/结果。
- 5.3 / 9.x (生成式主线)扩散是生成式家族连续空间分支,与自回归、显式推理互补共进。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying yourself.
Problem 10.3.1 — 不对称设计判断 🟢 Easy
判断下列描述属于 AsymDiffRec 的「前向」还是「反向」空间:
- (a) 在原始特征空间随机丢弃特征
- (b) 在潜在表示空间用 g([s, z_T]) 去噪
- (c) 步长嵌入 s 标记哪些特征缺失
💡 Solution (click to reveal)
Approach: 对照不对称设计。
- (a) 前向(原始特征空间,离散 dropout)
- (b) 反向(潜在表示空间)
- (c) 反向(步长嵌入用于潜在空间去噪)
Key points:
- 前向=原始空间 dropout;反向=潜在空间去噪。
- 不对称即「两阶段不同空间」。
Problem 10.3.2 — 辅助损失作用 🟢 Easy
AsymDiffRec 去掉 后 AUC 甚至低于基线。请解释原因。
💡 Solution (click to reveal)
Approach: 从个性化信息角度分析。
仅用重建损失 时,去噪表示只在 L2 距离上接近完整表示,但未必保留对下游预测有用的 个性化信息——模型可能重噪声重建、轻个性化。辅助损失 强制去噪表示在预测任务上也好,故去掉后个性化信息流失,AUC 反降。
Key points:
- 重建 ≠ 任务性能好。
- 辅助损失保个性化,缺一不可。
Problem 10.3.3 — v-prediction 推导 🟡 Medium
已知 ,预测得 。请写出由 反推 与 的公式,并说明 v-pred 相比 ε-pred 的稳定性来源。
💡 Solution (click to reveal)
Approach: 套用 v-pred 反推式。
稳定性来源: v-pred 的损失权重为「SNR+1」,在信噪比高(t 小)与低(t 大)区域都给合理梯度,不像 ε-pred 在高噪声区梯度不稳。
Key points:
- v 是 ε 与 x₀ 的线性组合,可双向反推。
- SNR+1 权重是其训练更稳的关键。
Problem 10.3.4 — 设计多样性生成 🔴 Hard
你要为音乐 App 设计 DMSG 式 slate 生成。请写出:① 三组件(编码/条件/扩散)各自的输入输出;② 为何用 v-prediction 与 DDIM;③ 如何验证「多样性」提升(两个指标)。
💡 Solution (click to reveal)
Approach: 套用 DMSG 设计。
- 三组件 :
- 编码:物品序列 → (固定预训练编码器)。
- 条件:文本 prompt → (Transformer 编码)。
- 扩散:条件 引导,Diffusion Transformer 去噪生成 slate 潜在表示。
- 为何 v-pred :损失权重 SNR+1,高低信噪比都稳; 为何 DDIM :把推理步从上千减到 50,毫秒级延迟满足在线。
- 多样性验证 :① 流行度分布——对比 BM25,看低频长尾物品占比是否上升;② 新鲜度——同 prompt 多次生成,看 slate 间差异(新物品比例)且质量(BERTScore≈0.8)稳定。
Key points:
- 随机采样是多样性内在来源。
- v-pred+DDIM 兼顾稳定与延迟。
🏆 Challenge: 适用边界论证
本章指出扩散模型「距离直接替代判别式在线服务仍有距离」。请写一段 200 字内,列举 两个 制约扩散大规模落地推荐的现实因素,并提出一个你认为最有潜力的融合方向(结合 5.3/9.x 的生成式主线)。
💡 Hint
制约因素:① 多步迭代去噪的延迟开销(即使 DDIM 仍高于单步判别式);② 端到端生成式推荐所需的语义 ID / 量化等配套基建尚未普及。融合方向:扩散的去噪生成能力 + Transformer 的序列建模(如 DreamRec 条件扩散)+ 强化学习对齐(呼应 9.2 的 GRPO),形成「生成增强 + 可控对齐」的混合架构;或与 9.x 的语义索引结合,让扩散在语义 ID 空间去噪。
前面的章节分别讲解了召回、排序、重排等核心算法模块。但论文里的模型跑得通,不等于能在真实场景里部署——这是几乎所有推荐系统学习者都会遇到的断层。本部分用一个 端到端的电影推荐系统 项目,把分散的算法串成一个能跑、能服务、能部署的完整系统,回答「如何从零构建一个生产级推荐系统」这个工程问题。
章节
| 章节 | Topic | The Big Idea |
|---|---|---|
| 11.1 | 项目引言与目标 | 厘清离线评估与在线部署的鸿沟,明确技术选型与学习路径 |
| 11.2 | 系统架构设计 | 离线与在线解耦,漏斗式「召回→排序→重排」经典结构 |
| 11.3 | 离线流水线 | 特征工程、YoutubeDNN/DeepFM 训练、向量生成、特征上线与模型部署 |
| 11.4 | 在线流水线 | 冷启动(UCB)、多路召回(Snake Merge)、DeepFM 排序、多样性重排 |
| 11.5 | 前端与交互 | Vue 3 五页面、Pinia 状态、搜索防抖、评分驱动的数据闭环 |
| 11.6 | 部署与运维 | Docker Compose 一键编排五服务,健康检查与排障 |
读完本 Part 你将能够
- 🟢 描述 离线系统与在线系统的职责边界,以及二者如何通过存储层解耦
- 🟢 解释 漏斗式架构为何必需:召回用轻模型筛候选、排序用重模型精打分
- 🟡 实现 YoutubeDNN 召回与 DeepFM 排序的训练闭环,并理解物品向量预计算的意义
- 🟡 设计 冷启动策略(UCB 探索 + 偏好类型 + 热门兜底)与多路召回的融合(Snake Merge)
- 🔴 部署 一个包含 PostgreSQL/Redis/Elasticsearch/后端/前端的多容器系统,并能排查常见问题
- 🟢 完成 各节的分层练习题,巩固工程实现要点
关键概念
| Concept | 章节 | Relevance |
|---|---|---|
| 离线 vs 在线 | 11.2 | 推荐系统工程的基本边界,质量与延迟的取舍 |
| 漏斗式架构(召回→排序→重排) | 11.2 | 工业推荐的主干骨架 |
| 物品向量预计算 | 11.3 | 在线毫秒级向量检索的前提 |
| 冷启动 / UCB | 11.4 | 解决「无行为新用户」的探索-利用平衡 |
| 多路召回 + Snake Merge | 11.4 | 用融合弥补单策略覆盖不足 |
| 数据闭环 | 11.5 | 前端行为反馈驱动特征更新与推荐优化 |
前置条件
- 已读完 1.1 的三阶段流水线认知,理解召回/排序/重排分工
- 了解 2.3 双塔(YoutubeDNN)与 3.x 排序模型(DeepFM)的基本原理
- 具备 Python、基础神经网络与 SQL 常识;了解 Docker 基本概念更佳
本项目代码位于
datawhalechina/fun-rec仓库的web_project/目录,可边读边运行。
给本 Part 的建议
- 先跑通再抠细节。 用 Docker Compose 一键启动完整项目,建立整体直觉。
- 抓住「离线与在线的边界」。 这是工程系统的核心认知框架。
- 关注那些论文里没有的环节 :特征如何跨系统传递、模型如何不停服更新、冷启动如何降级。
Let's build it! 🛠️
项目引言与目标
📝 Before You Continue: 请先读完 1.1 的三阶段流水线认知。本章把前面分散的召回、排序、重排模块整合为一个可运行的系统,重点不在新算法,而在「如何让它们协同工作」。
很多学习者的困惑很真实:论文里的模型看得懂,代码也能跑通,但被问到「如何在真实场景部署一个推荐系统」时却无从下手。这个断层来自 离线实验与在线服务之间的差距——论文只回答「模型好不好」,不回答「系统怎么转」。
读完本章,你将能够:
- 描述离线评估与在线部署在六个维度上的本质差异
- 说明本项目的「功能完整 / 技术真实 / 算法落地 / 架构清晰」四大目标
- 列出后端与前端技术栈,并解释为何选 FastAPI + Vue + PostgreSQL + Redis + Elasticsearch
- 概述从系统架构到部署的五段式学习路径
- 完成 4 道分层练习题,巩固项目全貌认知
11.1.0 项目背景:从「模型好」到「系统转」
前面的章节介绍了推荐系统的各个核心模块——召回、排序、重排。它们构成了基本组件,但如何整合成一个完整系统,论文不教。你遇到的真实问题往往是:
- 当一个用户打开应用,系统如何在 100 毫秒 内返回推荐结果?
- 用户刚刚给一部电影打了分,这个行为 如何立即影响 下一次推荐?
- 模型如何部署?特征存在哪?召回和排序如何 协同 工作?
- 新用户第一次使用、没有任何历史,系统该 推荐什么 ?
这些问题单从某篇论文找不到答案,必须从 系统层面 思考。本章就带你从零构建一个完整的电影推荐系统:用户在浏览器里浏览、搜索、评分,背后是一整套离线训练 + 在线推理 + 容器部署的工程链路。
💡 Key Insight: 工程实践的核心难点不在单个算法,而在把离散模块整合成协同运转的系统。论文给你零件,本章给你装配图。
🧠 Mental Model: 乐高 vs 成品
读各章算法像收集乐高零件——每块都很精巧。但用户要的不是零件,而是一艘能下水航行的船。本 Part 就是把零件拼成船、并让它真正浮起来的过程。
11.1.1 离线与在线的差异
许多读者通过竞赛或论文接触推荐系统,这类场景聚焦 离线评估 ;而本章项目聚焦 端到端部署——让真实用户能用起来。二者区别显著:
| 维度 | 离线实验 | 在线系统 |
|---|---|---|
| 评估方式 | 离线指标(AUC、召回率) | 用户实际可交互 |
| 数据流 | 静态数据集 | 实时用户行为 |
| 延迟要求 | 无(批量处理) | 毫秒级响应 |
| 冷启动 | 通常忽略 | 必须处理 |
| 基础设施 | 本地 Python 脚本 | 数据库、缓存、搜索引擎、容器编排 |
| 最终产出 | 预测结果文件 | 可访问的 Web 应用 |
离线系统从容「生产」:处理全量历史数据、训练模型、计算向量,产出模型文件与向量索引。在线系统实时「服务」:接收请求、调模型、组装结果,在百毫秒级返回。两者通过 存储层 (Redis、共享文件)解耦。
Analysis: 这种解耦是工程上的关键权衡——离线可用更复杂的算法、更大的数据量追求质量;在线只需加载产出物、专注低延迟服务。理解这条边界,就理解了工业推荐系统的一半。
11.1.2 技术选型与数据集
数据集 :选 MovieLens-1M——推荐领域最经典的基准之一,约 100 万条评分、近 4000 部电影、6000 余名用户。规模适中:既能展示完整架构,又不会算力爆炸。还从 IMDB 补充海报、演员、导演等元数据,丰富展示。
后端技术栈
- FastAPI :现代 Python Web 框架,原生异步、自动生成 API 文档
- PostgreSQL :关系库,存用户、电影、评分等核心业务数据
- Redis :内存库,缓存用户画像与实时行为序列
- Elasticsearch :搜索引擎,支撑电影搜索
- 共享文件目录 :存训练好的模型与物品向量
前端技术栈
- Vue.js 3 :渐进式 JS 框架,构建响应式界面
- Tailwind CSS :CSS 框架,快速实现 UI
模型与算法
- 召回 :YoutubeDNN 双塔、物品相似度召回、用户偏好类目召回
- 排序 : DeepFM (融合 FM 二阶交叉 + DNN 高阶非线性)
- 重排 :类目打散 + 年代打散的多样性策略
- 冷启动/探索 :基于 UCB(Upper Confidence Bound) 平衡 exploration 与 exploitation
基础设施
- Docker Compose :容器编排,一键启动所有服务
- uv :Python 包管理器,快速装依赖
11.1.3 学习路径
本章按从宏观到微观、从离线到在线的顺序展开:
- 系统架构设计 (11.2):宏观理解各组件、离线与在线的边界、数据如何流动。
- 离线流水线 (11.3):从原始数据出发,完成特征工程、模型训练、评估、部署。
- 在线流水线 (11.4):构建实时推理服务,实现冷启动、多路召回、排序、重排完整链路。
- 前端与交互 (11.5):设计界面,实现搜索、推荐、评分等核心功能。
- 部署与运维 (11.6):用 Docker Compose 容器化部署,讨论监控、日志、性能优化。
每部分都配有完整代码。读者可边读边实践,也可先跑通项目再逐步理解。
📊 Data Point: 本项目全部可运行代码位于
datawhalechina/fun-rec仓库的web_project/目录,数据集为预处理后的funrec-movielens-1m。
⚠️ Common Mistakes in 11.1
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把离线指标当作上线目标 | 「AUC 高就能直接服务」 | 离线无延迟约束,在线需百毫秒返回 | 区分离线评估与在线服务的六维差异 |
| 2 | 忽视冷启动 | 假设每个用户都有历史 | 新用户无行为,协同过滤/向量召回失效 | 设计独立冷启动流程(见 11.4) |
| 3 | 技术栈过度设计 | 小项目也上 K8s 集群 | 增加运维复杂度,拖慢交付 | 用 Docker Compose 单文件编排即可 |
| 4 | 跳过系统架构直接写代码 | 没画数据流就写服务 | 模块边界模糊,特征传递易乱 | 先读 11.2 建立架构心智模型 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 离线与在线鸿沟 | 评估/数据/延迟/冷启动等六维差异 | 论文不教、但工程必答 |
| 系统目标 | 功能完整/技术真实/算法落地/架构清晰 | 衡量一个项目是否「像工业」 |
| 技术栈 | FastAPI+Vue+PG+Redis+ES+Compose | 贴近工业、可一键复现 |
| 学习路径 | 架构→离线→在线→前端→部署 | 从宏观到微观、从离线到在线 |
❓ FAQ
Q1: 这个项目用生成式模型吗?还是传统判别式?
A: 本项目主线是「判别式三阶段漏斗」(YoutubeDNN 召回 + DeepFM 排序 + 多样性重排),属于经典工业架构。它是下篇生成式推荐概念的工程落点对照——理解它,才能体会 8–10 章生成式架构要替代什么。
Q2: 为什么不直接用一个大模型端到端生成推荐?
A: 本项目的规模与延迟约束下,漏斗架构更高效、可控、可解释。生成式端到端架构(见 8.2)适合更大规模与更复杂需求,但工程复杂度陡增。二者是演进关系,不是取代关系。
Q3: MovieLens-1M 规模够吗?
A: 对教学与架构演示足够。它能在单机跑通完整链路,又包含真实稀疏交互。生产会用更大库,但模块边界不变。
🔗 前后关联
- 1.1(三阶段流水线) 是本项目架构的理论来源——漏斗结构直接落地于此。
- 2.3(双塔 / YoutubeDNN) 与 3.x(DeepFM 排序) 提供本项目召回、排序模型的算法基础。
- 11.2 紧接着展开系统架构,把本节的技术选型落到组件与数据流上。
- 8.2(端到端生成) 展示了本项目架构的「生成式替代方案」,可作为进阶对照。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 11.1.1 — 区分离线/在线 🟢 Easy
判断下列描述属于 离线系统 还是 在线系统 ,并说明理由:
- (i) 每天凌晨批量重算全量电影向量并写入共享目录。
- (ii) 用户打开首页,200ms 内返回个性化推荐列表。
💡 Solution (click to reveal)
答: (i) 离线系统——批量、无延迟约束、产出向量给在线用。(ii) 在线系统——实时请求、百毫秒级延迟、面向真实用户。
Key points:
- 离线重「质量」、在线重「延迟」;二者靠存储层解耦。
- 记忆六维差异表即可快速判断。
Problem 11.1.2 — 技术栈匹配 🟢 Easy
将下列需求匹配到本项目的技术组件:(a) 存用户评分记录;(b) 缓存用户实时行为序列;(c) 支持电影标题模糊搜索;(d) 一键启动五服务。
💡 Solution (click to reveal)
答: (a) PostgreSQL;(b) Redis;(c) Elasticsearch;(d) Docker Compose。
Key points:
- 关系数据用 PG,低延迟特征用 Redis,全文检索用 ES,编排用 Compose。
- 每个组件解决一类明确约束。
Problem 11.1.3 — 冷启动为何单列 🟡 Medium
某产品经理说:「我们的召回模型很准,冷启动不用单独处理,向量召回照样能推荐。」请指出这句话的问题,并说明本项目如何应对。
💡 Solution (click to reveal)
答: 向量召回依赖用户历史行为编码用户向量;新用户无历史,用户向量无法有效生成,召回退化甚至失效。本项目设立独立冷启动流程:用 UCB 探索 + 用户设置偏好类型 + 热门兜底三级策略,待积累行为后过渡到正常链路。
Key points:
- 冷启动是「无行为」导致的结构性失效,无法靠更好的召回模型根治。
- 离线评估通常忽略冷启动,但在线必须处理。
🏆 Challenge: 设计最小可跑系统 🔴 Hard
如果让你用最少组件实现一个「能推荐、能部署」的电影推荐系统,请列出你保留的核心组件(从 PG/Redis/ES/FastAPI/Vue/Compose 中精简),并说明理由(150 字内)。
💡 Hint
最小集:PostgreSQL(存数据与画像)、FastAPI(召回+排序服务)、Vue(展示)、Docker Compose(编排)。Redis 与 ES 在最小版可暂缓——特征可直接查 PG(牺牲延迟),搜索可由 PG 模糊查询替代(牺牲检索质量)。核心是要跑通「请求→召回→排序→返回」闭环。
系统架构设计
📝 Before You Continue: 请先读完 11.1 的技术选型与离/在线差异。本节把那些选型落到组件与数据流上,建立系统的宏观心智模型。
生产级推荐系统由多个子系统协同工作。本节介绍整体设计、核心组件,以及数据如何在组件之间流转。这是后面所有实现章节的「地图」。
读完本章,你将能够:
- 描述 离线系统 (生产)与 在线系统 (服务)的职责边界与解耦方式
- 指出版局架构图中数据存储层、离线流水线、在线流水线、前端四类组件
- 解释离线数据流(CSV → 特征/模型 → 共享目录 + Redis)与在线数据流(请求 → 召回 → 排序 → 重排 → 组装)
- 说清四个关键设计决策:漏斗架构、多路召回融合、冷启动处理、特征存储计算分离
- 完成 4 道分层练习题
11.2.0 离线与在线系统
工业级推荐架构可划分为两部分: 离线系统 与 在线系统。
离线系统 负责「生产」:处理全量历史数据、训练模型、计算物品向量与相似度矩阵。计算时间充裕(小时级甚至天级),追求模型质量而非响应速度,产出模型文件、向量索引、特征字典等。
在线系统 负责「服务」:接收实时请求、调用模型、组装推荐结果并返回。响应时间有限(百毫秒级),需在质量与延迟间平衡,依赖离线产出的模型与特征。
离线系统定期运行(每天/每周),将产出写入共享存储;在线系统从共享存储加载。两者通过 存储层解耦 :离线可用更复杂算法、更大体量;在线专注低延迟服务。
下面用交互演示直观感受离线「生产」与在线「消费」之间的数据与模型流转:从原始评分数据出发,经特征工程、训练、向量预计算,落到存储层,再被在线服务加载并用于实时推理。点击「下一步」观察每一步的产出物如何交接。
注意第五步「存储层交接」:离线写出的 active.json 版本指针与物品向量,正是在线加载阶段的输入——这层解耦让离线可从容重训、在线可毫秒级服务。
11.2.1 整体架构与核心组件
系统由四类核心组件构成,下面逐一展开。
数据存储层
- PostgreSQL(业务数据库) :存用户表(性别/年龄/职业)、电影表(标题/类型/年份/海报)、评分表(评分+时间戳)。
- Redis(特征缓存) :存在线推理所需实时特征——用户画像
user:{id}:profile、行为序列user:{id}:history、物品向量索引。 - 共享文件目录 :存模型文件(user_model、ranking_model)、物品向量矩阵(item_embeddings.npy)、特征编码字典(vocab_dict.pkl)。
- Elasticsearch(搜索引擎) :对电影标题、类型、演员建倒排索引,支撑搜索。
离线流水线
按顺序执行:特征工程 → 召回模型训练(YoutubeDNN)→ 排序模型训练(DeepFM)→ 模型部署 → 特征上线。详见 11.3。
在线流水线
每个请求依次经过:冷启动检测 → 多路召回 → 精准排序 → 多样性重排 → 结果组装。详见 11.4。
前端应用
基于 Vue 3,含首页、电影详情页、搜索页、个人中心四个核心页面(11.5)。
11.2.2 离线数据流
离线流水线把原始评分数据转化为在线可用的模型与特征:
- 特征工程 :从原始评分提取训练特征(用户/物品/行为序列)。
- 召回模型训练 :训练 YoutubeDNN 双塔,学用户/物品向量映射。
- 排序模型训练 :训练 DeepFM,学用户-物品对点击概率。
- 模型部署 :将模型文件写入共享目录供在线加载。
- 特征上线 :将用户画像、行为序列、物品信息写入 Redis。
离线产出物与在线需求的对应关系,是理解整个系统的关键——离线「想清楚怎么算」,在线「快速取来用」。
11.2.3 在线数据流
在线流水线处理每个用户请求,以「打开首页」为例:
- 冷启动检测 :判断是否为新用户(历史行为少于阈值),新用户走冷启动,否则走正常流程。
- 多路召回 :并行执行 YoutubeDNN 向量召回、物品相似度召回、偏好类目召回。
- 精准排序 :用 DeepFM 对候选 CTR 预估、按分排序。
- 多样性重排 :打散策略,避免连续同类/同年电影。
- 结果组装 :查库补全标题、海报等,组装前端响应。
整个流程目标延迟控制在 200 毫秒 以内。
11.2.4 关键设计决策
召回与排序分离(漏斗架构)
理论上可训练一个模型对全库直接打分,但性能不可行:假设库有 10 万部电影,每次请求都排序模型推理,即使每次 1ms 也需 100 秒。
因此采用 漏斗式架构 :召回阶段用轻模型快速筛数百候选,排序阶段用复杂模型对这数百候选精确打分。
多路召回与融合(Snake Merge)
单一召回策略有局限:向量召回可能漏掉模型未捕捉的相关性;协同过滤对新/小众电影覆盖不足;热门推荐缺乏个性化。融合多种策略取长补短。本项目用 Snake Merge(蛇形合并) :从各路轮流取候选,确保每路都有代表进入排序。
冷启动处理
新用户缺乏行为,协同过滤与向量召回失效。本项目设计独立冷启动流程:①交互次数阈值检测;②若设偏好类型,优先推这些类型的优质电影;③否则用热门或 UCB 探索;④随行为积累过渡到正常流程。
特征存储与计算分离
在线推理对延迟敏感。若每次请求都从 PostgreSQL 查历史行为,数据库成瓶颈。故将高频特征预计算写入 Redis:用户画像注册/更新时写,行为序列每次评分后更新,物品向量离线批量写。Redis 读延迟通常 <1ms,比数据库快 1–2 个数量级。
Analysis: 四个决策共同指向一个原则——把重活放离线、把快活放在线、把热点放内存。漏斗解决算力、融合解决覆盖、冷启动解决零样本、存储分离解决延迟。
⚠️ Common Mistakes in 11.2
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 单模型全库打分 | 「直接用一个模型排全库」 | 10万候选 × 推理 = 百秒级,不可服务 | 漏斗:召回缩候选、排序精打分 |
| 2 | 离线在线特征不一致 | 离线用新编码器、在线用旧 | 训练-服务错位,效果骤降 | 共享同一 vocab_dict/编码器 |
| 3 | 每请求查数据库特征 | 实时查 PG 历史行为 | 数据库成延迟瓶颈 | 高频特征预写 Redis |
| 4 | 单路召回 | 只用向量召回 | 覆盖不足、小众/新片漏召 | 多路召回 + Snake Merge 融合 |
| 5 | 冷启动与正常流混一 | 无差异对待新用户 | 新用户体验差、推荐崩 | 独立冷启动检测与三级策略 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 离线/在线解耦 | 离线生产、在线服务,存储层衔接 | 质量与延迟的工程平衡 |
| 四类组件 | PG/Redis/共享目录/ES + 离线/在线/前端 | 系统的物理拼图 |
| 离线数据流 | CSV→特征→训练→部署+上线 | 训练时关注点 |
| 在线数据流 | 请求→召回→排序→重排→组装 | 服务时关注点(<200ms) |
| 四个设计决策 | 漏斗/融合/冷启动/存储分离 | 工程可行性的根基 |
❓ FAQ
Q1: 离线周期跑、在线实时用,会不会「模型过期」?
A: 会,这是工业常态。本项目靠版本指针(active.json)做无感知热更新(见 11.3),离线重训后切换指针即可,无需停服。
Q2: 为什么物品向量离线算、用户向量在线算?
A: 物品库相对静态、数量大,离线一次性算好入库;用户每次请求才确定,必须在线现算。离线建库 + 在线查,正是双塔可规模化的关键(见 2.3)。
Q3: Snake Merge 和简单按分合并有何不同?
A: 按分合并易让某路(如向量召回)霸榜;Snake Merge 轮流取,保证各路代表都进排序,提升多样性与覆盖。
🔗 前后关联
- 11.1 的技术选型在此落成组件与数据流。
- 11.3 深入离线流水线的每一步实现。
- 11.4 深入在线流水线的每一步实现。
- 2.3(双塔)、3.x(DeepFM) 是召回、排序模型的算法依据。
- 4.2(多样性重排) 解释了重排阶段打散策略的理论动机。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 11.2.1 — 画出数据流 🟢 Easy
用一句话描述:离线训练好的 item_embeddings.npy 从哪个组件产生、被哪个组件消费、用在在线哪个阶段?
💡 Solution (click to reveal)
答: 由离线流水线「模型部署」写入共享目录;在线流水线的召回服务(RecallResourceManager)加载它;用于 YoutubeDNN / 物品相似度召回的向量检索阶段。
Key points:
- 离线产出、在线消费的经典例子。
- 体现「存储层解耦」。
Problem 11.2.2 — 漏斗的算力账 🟢 Easy
库有 5 万部电影,召回用轻模型(每候选 0.1ms)筛 200 候选,排序用重模型(每候选 1ms)对 200 候选打分。若直接全库排序需多久?漏斗方案需多久?
💡 Solution (click to reveal)
答: 直接全库排序 = 50000 × 1ms = 50 秒。漏斗 = 召回 50000×0.1ms = 5 秒 + 排序 200×1ms = 0.2 秒 ≈ 5.2 秒。若召回可在预建索引上更快(远小于 5 秒),漏斗优势更明显。
Key points:
- 漏斗把「全库重模型」降为「全库轻模型 + 子集重模型」。
- 实际召回走向量索引,几乎不遍历全库(见 2.3.4)。
Problem 11.2.3 — 为何特征存 Redis 🟡 Medium
产品经理主张「用户特征直接查 PostgreSQL 就行,省得维护 Redis」。请指出风险,并量化说明为何 Redis 更合适。
💡 Solution (click to reveal)
答: 每次推荐请求都要读用户画像+行为序列,若查 PG(典型几 ms~十几 ms),叠加召回/排序/重排后易超 200ms 预算;且 PG 并发高时成瓶颈。Redis 内存读 <1ms,比 PG 快 1–2 个数量级,且支持 List/Hash 自然表达历史序列与画像。代价是多维护一份缓存与一致性,但延迟收益远超成本。
Key points:
- 在线特征「高频、低延迟、结构简单」→ 内存库天然契合。
- PG 适合持久业务数据,不适合热路径特征读取。
🏆 Challenge: 给架构提一个改进 🔴 Hard
基于本架构,提出一个在生产环境中可显著提升推荐质量或稳定性的改进点(如特征实时更新、模型 A/B、在线学习),说明它解决什么问题、需要改动哪一层(150 字内)。
💡 Hint
可选:①实时特征管道——用户评分后近实时更新 Redis 行为序列(而非仅离线批量),提升新鲜度,改动离线「特征上线」+ 在线写回;②模型 A/B——active.json 扩展为多版本分流,改动在线资源加载;③向量检索升级 FAISS——库超百万时替换暴力内积,改动召回服务。任选其一论证即可。
离线流水线
📝 Before You Continue: 请先读完 11.2 的离线数据流与组件边界。本节把这五个环节落成代码:特征工程 → 模型训练 → 向量生成 → 特征上线 → 模型部署。
离线流水线承担推荐系统的「生产」职责,把原始数据变成在线服务所需的模型与特征。整个流程由 特征工程、模型训练、存储部署 三个环节组成,通过统一命令行入口管理,支持按需运行单步或完整流程。
读完本章,你将能够:
- 描述离线目录结构与
pipeline.py的模块化编排方式 - 用 滑动窗口 构建 YoutubeDNN 时序样本,并理解左填充与编码从 1 起始的细节
- 说明排序模型如何用「相对个人均值」定义点击标签、如何混合困难/随机负样本
- 写出 YoutubeDNN 训练后 物品向量预计算 + 归一化 的代码,并解释其意义
- 描述 Redis 特征写入(Hash/List + Pipeline)与模型部署(版本指针)的实现
- 完成 5 道分层练习题,巩固工程要点
11.3.0 代码结构
离线代码位于 web_project/backend/offline/:
offline/
├── pipeline.py # 流水线入口
├── config.py # 配置管理
├── feature/ # 特征工程
│ ├── preprocess_retrieval.py # 召回模型特征处理
│ └── preprocess_ranking.py # 排序模型特征处理
├── training/ # 模型训练
│ ├── train_retrieval.py # 召回模型训练
│ └── train_ranking.py # 排序模型训练
└── storage/ # 存储部署
├── redis_ingest.py # 特征上线
└── local_deploy.py # 模型部署
整个流程由 pipeline.py 统一编排,支持按需运行指定步骤:
# offline/pipeline.py
def main():
parser = argparse.ArgumentParser(description="FunRec Offline Pipeline")
parser.add_argument("--steps", type=str, default="all")
args = parser.parse_args()
steps = args.steps.split(",")
if "all" in steps:
steps = ["retrieval_preprocess", "ranking_preprocess",
"retrieval_training", "ranking_training",
"ingest", "deploy"]
if "retrieval_preprocess" in steps:
run_retrieval_preprocessing()
if "ranking_preprocess" in steps:
run_ranking_preprocessing()
if "retrieval_training" in steps:
run_retrieval_training()
if "ranking_training" in steps:
run_ranking_training()
if "ingest" in steps:
ingest_to_redis(flush=args.flush_redis)
if "deploy" in steps:
deploy_local()
这种模块化设计便于调试:可只重训排序模型而不动召回。配置集中在 config.py,用环境变量切换数据路径与服务地址:
class Config:
# 数据路径
TEMP_DIR = Path(os.getenv("FUNREC_PROCESSED_DATA_PATH")) / "web_project"
DATASET_DIR = Path(os.getenv("FUNREC_RAW_DATA_PATH"))
# 特征工程参数
MAX_SEQ_LEN = 10 # 历史序列最大长度
EMB_DIM = 16 # Embedding 维度
NEG_SAMPLE_SIZE = 20 # 负采样数量
# 训练参数
BATCH_SIZE = 128
EPOCHS = 3
LEARNING_RATE = 0.001
# 存储服务配置
DEPLOY_DIR = TEMP_DIR / "deployed_models" # 模型部署目录
REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379/0")
11.3.1 特征工程
特征工程最耗时也最关键。好特征大幅提升效果,特征错误常导致模型完全失效。本项目为召回与排序分别构建样本。
原始数据加载
MovieLens-1M 含三张核心表:users.pkl(6040 用户:性别/年龄/职业/邮编)、movies.pkl(3883 电影:标题/类型/年份)、ratings.pkl(约 100 万评分:用户ID/电影ID/评分/时间戳)。
def load_raw_data():
df_movies = pd.read_pickle(config.DATASET_DIR / "movies.pkl")
df_ratings = pd.read_pickle(config.DATASET_DIR / "ratings.pkl")
df_users = pd.read_pickle(config.DATASET_DIR / "users.pkl")
return df_movies, df_ratings, df_users
召回模型的特征处理
类别特征编码 :推荐特征多为类别型(user_id、movie_id、gender、genres),需编码为整数输入 Embedding。
def process_features(df_movies, df_ratings, df_users):
user_sparse_feature_columns = ["user_id", "gender", "age", "occupation", "zip_code"]
user_vocab = {}
for feat_name in user_sparse_feature_columns:
label_encoder = LabelEncoder()
new_user_feature_df[feat_name + "_encode"] = (
label_encoder.fit_transform(new_user_feature_df[feat_name]) + 1
) # ← KEY LINE: 编码从 1 开始,0 预留未知/填充
user_vocab[feat_name] = label_encoder.classes_
# 电影侧类似,genres 为列表需逐元素 transform
...
💡 Key Insight: 所有编码值从 1 开始,0 预留给未知值与填充。Embedding 第 0 行专门表示「不存在/未知」,避免把未知特征误当有效 ID。
行为序列构建 :YoutubeDNN 核心是「预测用户下一个会看的电影」,故用滑动窗口构建样本——给定前 次观影,预测第 次。
def generate_train_eval_samples(data_df, user_columns, item_columns,
max_hist_seq_len=10, padding_value=0):
data_df.sort_values("timestamp", inplace=True) # ← KEY LINE: 严格按时间排序,杜绝未来泄露
...
for user_id, grouped_feats in data_df.groupby("user_id"):
if len(grouped_feats["movie_id"]) < 2:
continue
len_hist_seq = len(grouped_feats["movie_id"])
# 测试集:用最后一条
...
# 训练集:滑动窗口
for i in range(1, len_hist_seq - 1):
train_data_dict["user_id"].append(user_id)
for col in item_columns:
train_data_dict["hist_" + col].append(
add_padding(grouped_feats[col].tolist()[:i],
padding_value, max_hist_seq_len)) # ← KEY LINE: 前 i 条作为历史,第 i 条作目标
train_data_dict[col].append(grouped_feats[col].tolist()[i])
时序划分模拟真实场景:模型只能用过去信息预测未来。随机划分会造成未来信息泄露,离线指标虚高、线上失效。
序列填充 :不同用户历史长度不同,模型需定长输入。采用 左填充 ,短序列左侧补零:
def add_padding(val, padding_value, max_seq_len):
if isinstance(val, (list, tuple, np.ndarray)):
if len(val) > 0 and isinstance(val[0], (list, tuple, np.ndarray)):
val = list(itertools.chain(*val))[-max_seq_len:]
else:
val = list(val)[-max_seq_len:]
return [padding_value] * (max_seq_len - len(val)) + val # ← KEY LINE: 左侧补零,最近行为在右
else:
return val
左填充让最近行为总在序列右侧,符合时间顺序,对 RNN/Transformer 更自然。
排序模型的特征处理
排序模型(DeepFM)是 CTR 预估:输入用户-物品对,输出点击概率,需构造正负样本。
标签定义 :MovieLens 只有评分无点击信号,按评分相对个人均值定义:
user_avg_ratings = df_ratings.groupby("user_id")["rating"].mean().reset_index()
df_ratings = df_ratings.merge(user_avg_ratings, on="user_id", how="left")
df_ratings['is_click'] = (
df_ratings['rating'] >= df_ratings['user_avg_rating'] - 1
).astype(int) # ← KEY LINE: 高于个人均值-1 视为正样本
这种方式考虑用户评分偏好差异(有人普遍高分、有人严格),用相对偏移减少个体差异。
负样本采样 :正样本来自评分,负样本需构造。混合两种策略:
- 困难负样本(Hard Negatives) :用户曝光但未正向交互的物品——「难」分。
- 随机负样本(Random Negatives) :从未交互物品随机采样——扩充数量。
本项目用 1:3 正负比例(1 困难 + 2 随机)。generate_negative_samples 先建每用户困难负样本池,再从未交互集中随机采样。比例需权衡:过多导致不平衡、过少模型难分辨。
训练/测试集划分 :同样用 时序划分 :
def split_train_test(df_final, test_ratio=0.2, by_time=True):
if by_time and "timestamp" in df_final.columns:
df_final = df_final.sort_values("timestamp")
split_idx = int(len(df_final) * (1 - test_ratio))
train_df = df_final.iloc[:split_idx]
test_df = df_final.iloc[split_idx:] # ← KEY LINE: 较早样本训练、较晚样本测试
else:
from sklearn.model_selection import train_test_split
train_df, test_df = train_test_split(df_final, test_size=test_ratio)
return train_df, test_df
11.3.2 召回模型训练(YoutubeDNN)
召回从全库快速筛候选。本项目用 YoutubeDNN 双塔(见 2.3):用户塔编码用户、物品塔编码物品,内积表匹配。
模型配置 要点:
model_config_dict = {
"features": {
"emb_dim": 16, "max_seq_len": 10, "task_names": ["movie_id"],
"features": [
{"name": "user_id", "group": ["user_dnn"], "vocab_size": ...},
{"name": "movie_id", "group": ["target_item"], "vocab_size": ...},
{"name": "hist_movie_id", "emb_name": "movie_id", # ← KEY LINE: 历史与目标共享 Embedding
"group": ["raw_hist_seq"], "combiner": "mean", "vocab_size": ...},
]
},
"training": {
"build_function": "funrec.models.youtubednn.build_youtubednn_model",
"model_params": {"emb_dim": 16, "neg_sample": 20, "dnn_units": [64, 32]},
"loss": "sampledsoftmaxloss", "batch_size": 128, "epochs": 3, # ← KEY LINE: Sampled Softmax 应对大词表
},
}
三点要点:① Embedding 共享——历史电影 ID 与目标电影同表,减参数且同空间;② 序列聚合——mean 把变长序列压成定维(注意力更优但更贵);③ Sampled Softmax——物品 3000+,完整 Softmax 太贵,只对正负样本算损失。
训练流程 封装在 run_retrieval_training:
def run_retrieval_training():
train_eval_samples = pickle.load(open(config.TRAIN_DATA_PATH, "rb"))
feature_dict = pickle.load(open(config.FEATURE_DICT_PATH, "rb"))
...
models = train_model(cfg.training, feature_columns, processed_data)
metrics = evaluate_model(models, processed_data, cfg.evaluation, feature_columns)
print(build_metrics_table(metrics))
user_model = models[1]
item_model = models[2]
user_model.save(config.SAVED_MODELS_DIR / "user_model")
item_model.save(config.SAVED_MODELS_DIR / "item_model") # ← KEY LINE: 分别保存用户塔与物品塔
YoutubeDNN 返回三模型:完整、用户塔、物品塔。在线只需用户塔(实时算用户向量)+ 预计算物品向量(物品塔生成)。
物品向量生成——离线预计算全量物品向量:
vocab_dict = pickle.load(open(config.VOCAB_DICT_PATH, "rb"))
all_movie_ids = sorted(list(vocab_dict["movie_id"]))
encoded_ids = np.arange(1, len(all_movie_ids) + 1)
item_inputs = {"movie_id": encoded_ids}
embeddings = item_model.predict(item_inputs, verbose=0)
embeddings = embeddings / np.linalg.norm(embeddings, axis=1, keepdims=True) # ← KEY LINE: 归一化,内积≡余弦相似度
np.save(config.ITEM_EMB_PATH, embeddings)
np.save(config.MOVIE_IDS_PATH, np.array(all_movie_ids))
归一化后内积等价于余弦相似度,取值 ,解释直观、便于设阈值。
11.3.3 排序模型训练(DeepFM)
排序对召回候选精确打分。本项目用 DeepFM (见 3.x),结合 FM 二阶交叉与 DNN 高阶非线性。
模型配置 不需要区分塔,所有特征同输入:
model_config_dict = {
"features": {
"emb_dim": 16, "task_names": ["is_click"],
"features": [
{"name": "user_id", "group": ["deepfm", "linear"], "vocab_size": ...}, # ← KEY LINE: 同特征进两组
{"name": "movie_id", "group": ["deepfm", "linear"], "vocab_size": ...},
{"name": "genres", "group": ["deepfm", "linear"], "vocab_size": ...},
...
]
},
"training": {
"build_function": "funrec.models.deepfm.build_deepfm_model",
"model_params": {"dnn_units": [128, 64, 32], "dropout_rate": 0.1},
"loss": ["binary_crossentropy"], "metrics": ["binary_accuracy", "AUC"],
"batch_size": 128, "epochs": 3, "validation_split": 0.1,
},
}
group 字段指定特征归属:deepfm 参与 FM 二阶交叉,linear 参与一阶线性。两者都放,模型同时学一阶效应与二阶交互。
训练流程 与召回类似,但保存主模型与配置(供在线推理复用编码器):
def run_ranking_training():
...
models = train_model(cfg.training, feature_columns, processed_data)
main_model = models[0]
metrics = evaluate_model(models, processed_data, cfg.evaluation, feature_columns)
print(build_metrics_table(metrics))
main_model.save(config.RANKING_MODEL_PATH)
pickle.dump({
"feature_dict": feature_dict,
"feature_columns": [fc.name for fc in feature_columns],
"model_config": model_config_dict,
}, open(config.TEMP_DIR / "ranking_model_config.pkl", "wb")) # ← KEY LINE: 存配置供在线复用编码器
排序评估常用 AUC (ROC 曲线下面积),衡量区分正负样本能力,不受正负比例影响——反映把用户喜欢的排在前的能力。
11.3.4 特征上线与模型部署
训练完需把产出部署到在线可访问的存储:Redis 存用户特征,共享目录存模型文件。
Redis 特征写入
def ingest_to_redis(flush: bool = False):
r = redis.Redis.from_url(config.REDIS_URL, decode_responses=True)
if flush:
r.flushdb()
df_movies, df_ratings, df_users = load_raw_data()
pipeline = r.pipeline()
for _, row in df_users.iterrows():
user_id = row['user_id']
key = f"user:{user_id}:profile"
profile_data = {"gender": row["gender"], "age": row["age"],
"occupation": row["occupation"], "zip_code": row["zip_code"]}
pipeline.hset(key, mapping=profile_data) # ← KEY LINE: 用户画像存 Hash
if _ % 1000 == 0:
pipeline.execute() # ← KEY LINE: 批量执行,减少网络往返
pipeline.execute()
# 行为历史(List)+ 偏好类目(Top3,写回 profile)
df_ratings.sort_values("timestamp", inplace=True)
grouped = df_ratings.groupby("user_id")
for user_id, group in grouped:
history_key = f"user:{user_id}:history"
movie_ids = group["movie_id"].tolist()
pipeline.delete(history_key)
for i in range(0, len(movie_ids), 1000):
chunk = movie_ids[i:i+1000]
pipeline.rpush(history_key, *chunk) # ← KEY LINE: 行为序列存 List,保时序
...
top_3 = [g for g, c in Counter(all_genres).most_common(3)]
pipeline.hset(f"user:{user_id}:profile", "frequent_genres", ",".join(top_3))
pipeline.execute()
用户画像用 Hash(键 user:{id}:profile),行为历史用 List(保时间序),偏好类目统计 Top3 存回 profile。Pipeline 批量执行 是关键优化:Redis 命令快,但每次网络往返有开销,打包发送显著提升写入速度。
本地模型部署
模型文件大(几十~几百 MB),不适存 Redis,用共享目录管理。召回部署含用户塔模型、物品向量、词表,并用 active.json 版本指针支持热更新:
def deploy_recall_models(deploy_dir: Path):
recall_dir = deploy_dir / "recall"
recall_dir.mkdir(parents=True, exist_ok=True)
shutil.copy2(config.VOCAB_DICT_PATH, recall_dir / "vocab_dict.pkl")
shutil.copy2(config.ITEM_EMB_PATH, recall_dir / "item_embeddings.npy")
user_model_path = config.SAVED_MODELS_DIR / "user_model"
model_deploy_dir = deploy_dir / "model" / "user_recall" / "v1"
model_deploy_dir.mkdir(parents=True, exist_ok=True)
shutil.copytree(user_model_path, model_deploy_dir / "user_model")
version_info = {"version": "v1", "path": "model/user_recall/v1/user_model"}
with open(deploy_dir / "model" / "user_recall" / "active.json", "w") as f:
json.dump(version_info, f) # ← KEY LINE: 版本指针,在线据此加载
版本管理是生产重要功能:通过 active.json 指针,在线服务知道该加载哪个版本;更新时先部署新版本文件、再更新指针,实现 无感知热更新。排序部署同理(写入 ranking/active.json)。
Analysis: 离线的「部署」本质是产出物治理——不仅要算对模型,还要以在线可加载、可热更、可回滚的方式落地。版本指针 + 共享目录是轻量却工业标准的做法。
⚠️ Common Mistakes in 11.3
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 随机划分代替时序 | train_test_split 不按时间 | 未来信息泄露,离线虚高、线上垮 | 严格按 timestamp 时序划分 |
| 2 | 编码从 0 起 | LabelEncoder 默认从 0 | 0 与「未知/填充」冲突,Embedding 误用 | 编码统一 +1,0 留未知 |
| 3 | 物品向量不归一化 | 直接存原始向量 | 内积非余弦,阈值难设、解释差 | 离线归一化,内积≡余弦 |
| 4 | 负样本全随机 | 只用随机负样本 | 缺困难样本,模型分辨力弱 | 困难:随机=1:2,总比例 1:3 |
| 5 | 模型部署忘存配置 | 只存权重不存编码器/特征列 | 在线无法复原输入编码 | 同存 feature_dict/配置 pkl |
| 6 | 逐条写 Redis | 循环 hset 不批量 | 网络往返爆炸,写入极慢 | 用 pipeline 批量执行 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 模块化流水线 | pipeline.py 按步编排、可单跑 | 便于调试与增量更新 |
| 滑动窗口样本 | 前 k 预测 k+1,左填充定长 | 模拟真实「预测下一部」 |
| 时序划分 | 按 timestamp 训练/测试切分 | 防未来泄露 |
| 物品向量预计算 | 离线 predict + 归一化 | 在线毫秒级向量检索 |
| 负样本 1:3 | 困难+随机混合 | 平衡分辨力与数量 |
| Redis + 版本指针 | Hash/List + active.json | 在线快取 + 无感知热更 |
❓ FAQ
Q1: 为什么召回要单独存用户塔和物品塔?
A: 在线只需用户塔(实时算用户向量)和预计算物品向量(离线批量生成)。物品塔本身不在线用,但用于离线产出向量,故都存档以备重训。
Q2: 为什么标签用「相对个人均值-1」而不是绝对阈值?
A: 用户评分尺度不同(有人爱打 4-5,有人爱打 2-3)。相对个人均值的定义把「对这个人而言算高」作为正样本,消除个体差异,标签更稳。
Q3: 版本指针 active.json 解决了什么?
A: 在线服务加载模型时读它决定版本,离线重训后先部署 v2 再改指针,实现不停服热更新与一键回滚。
🔗 前后关联
- 2.3(双塔) 解释 YoutubeDNN 结构与 Sampled Softmax 原理。
- 3.x(DeepFM) 解释 FM+DNN 结构与 AUC 评估。
- 11.2 给出离线数据流与组件边界。
- 11.4 消费本节产出的物品向量、编码器与模型。
- 11.6 的离线流程命令
make run-offline-pipeline即跑本节全部步骤。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 11.3.1 — 时序划分的意义 🟢 Easy
为何排序模型要用时序划分而非随机划分?若用随机划分,离线 AUC 与线上效果会怎样?
💡 Solution (click to reveal)
答: 随机划分会把未来行为混入训练,模型「偷看」了答案,离线 AUC 偏高但线上失效(真实只能看历史)。时序划分保证训练只用过去、测试用未来,评估结果贴近线上。
Key points:
- 未来信息泄露是离线-线上落差的主因之一。
- 任何带时间属性的推荐数据都应时序划分。
Problem 11.3.2 — 左填充的作用 🟢 Easy
为何采用左填充而非右填充?若某用户历史为 [A,B,C](时间序),MAX_SEQ_LEN=5,左填充后序列是什么?
💡 Solution (click to reveal)
答: 左填充使最近行为在序列右侧,符合时间顺序,对 RNN/Transformer 更自然。填充后 = [0,0,A,B,C](左侧补两个 0)。
Key points:
- 0 是填充位,模型学其「无信息」。
- 最近行为靠右,注意力/池化更聚焦近期。
Problem 11.3.3 — 物品向量归一化 🟡 Medium
物品向量归一化后,用户向量 与物品向量 的内积取值范围是多少?若未归一化,设阈值过滤相似候选会遇到什么困难?
💡 Solution (click to reveal)
答: 归一化后 ,内积 ,解释直观、阈值好设(如 >0.5)。未归一化时内积受模长影响,同方向但模不同的向量内积可能差异巨大,阈值无统一意义,且无法直接当余弦用。
Key points:
- 归一化让内积 ≡ 余弦相似度。
- 在线检索(ANN)也依赖此一致性(见 2.3.4)。
Problem 11.3.4 — 负样本比例 🟡 Medium
本项目正负比 1:3(1 困难 + 2 随机)。若改成 1:10(主要靠随机),模型可能有什么问题?若改成 1:0(无负样本)会怎样?
💡 Solution (click to reveal)
答: 1:10 过度靠简单随机负样本,模型只学「区分明显不相关」,对困难样本的辨别力下降,CTR 预估偏粗。1:0 即无负样本,Sampled Softmax/二分类失去学习目标,模型无法学到「什么是负」,完全失效。
Key points:
- 负样本是分类学习的必要一半。
- 困难负样本提升分辨边界,随机负样本保证数量。
🏆 Challenge: 设计一次热更新 🔴 Hard
假设线上 DeepFM 模型要升级到 v2,且不能停服、要能回滚。请基于 active.json 机制,描述离线侧与在线侧各自需要做什么(150 字内)。
💡 Hint
离线:训练 v2 → 部署到 model/ranking/v2/,暂不改指针。在线:服务加载时读 ranking/active.json;切换时先改指针指向 v2(热更新),观察指标;若异常,把指针改回 v1 即回滚。关键是「先部署新文件、后翻指针」,全程在线只读指针,无需重启。
在线流水线
📝 Before You Continue: 请先读完 11.3,理解离线产出了什么(物品向量、编码器、用户塔/排序模型)。本节消费这些产出,把请求变成推荐列表。
在线流水线要在百毫秒级延迟内完成从用户请求到推荐结果的全链路。整个流程封装在统一推荐管线中,按「冷启动检测 → 多路召回 → 精准排序 → 多样性重排」顺序执行,各阶段候选数量与启停开关由配置集中控制。
读完本章,你将能够:
- 描述
RecommendationPipeline与PipelineConfig如何串起全链路 - 解释冷启动检测阈值与 UCB 探索-利用公式,并写出分数计算与状态更新代码
- 描述三路召回(YoutubeDNN / I2I / 偏好类目)与 Snake Merge 融合
- 写出 DeepFM 批量排序、特征编码复用、异步执行与降级策略
- 解释连续打散(Consecutive Dispersion)如何保序地提升多样性
- 完成 5 道分层练习题
11.4.0 代码结构
在线代码位于 web_project/backend/online/:
online/
├── pipeline.py # 推荐主流程
├── cold_start/ # 冷启动处理
│ ├── detector.py # 冷启动检测
│ ├── service.py # 冷启动服务
│ ├── ucb_genre.py # UCB 类型探索
│ └── preferred_genre.py # 偏好类型策略
├── recall/ # 多路召回
│ ├── service.py # 召回服务与融合
│ ├── youtubednn.py # YoutubeDNN 召回
│ ├── item_based.py # 物品相似度召回
│ └── trending.py # 热门召回
├── ranking/ # 排序模型
│ ├── service.py # 排序服务
│ └── deepfm.py # DeepFM 排序
└── reranking/ # 重排策略
├── service.py # 重排服务
└── dispersion.py # 打散策略
离线产出物(共享目录模型、Redis 特征、物品向量)是在线基础。在线需 200ms 内完成,要求推理快、访问高效、阶段协同。
主流程封装在 RecommendationPipeline:
下面用交互演示走完一次推荐请求的完整链路:从用户请求到达,经冷启动检测、多路召回、Snake Merge 融合、DeepFM 排序、多样性重排,到结果组装返回。点击「下一步」观察候选规模如何逐级缩小。
注意漏斗右侧的候选计数:全库候选经召回缩到 100、排序缩到 20,整个过程目标延迟 < 200ms——这正是工业漏斗架构的工程意义。
class RecommendationPipeline:
def __init__(self):
self.recall_service = get_recall_service()
self.ranking_service = get_ranking_service()
self.reranking_service = get_reranking_service()
self.cold_start_service = get_cold_start_service()
async def recommend(self, user_features, item_features_provider=None, config=None):
config = config or PipelineConfig()
if config.enable_cold_start and self._is_cold_start(user_features, config):
return await self._cold_start_recommend(user_features, item_features_provider, config)
candidates = await self._recall(user_features, config.recall_top_k)
ranked_items, ranking_strategy = await self._rank(
user_features, candidates, item_features_provider, config.ranking_top_k)
reranked_items, reranking_strategies = await self._rerank(
ranked_items, user_features, item_features_provider)
return RecommendationResult(items=reranked_items, ...)
PipelineConfig 集中控制各阶段行为:
@dataclass
class PipelineConfig:
recall_top_k: int = 100 # 召回阶段返回候选数
ranking_top_k: int = 20 # 排序阶段返回结果数
enable_ranking: bool = True # 是否启用排序模型
enable_reranking: bool = True # 是否启用重排
enable_cold_start: bool = True
cold_start_threshold: int = 5 # 交互少于此值视为冷启动用户
cold_start_top_k: int = 20
11.4.1 冷启动检测与处理
冷启动是经典难题:新用户无行为数据,协同过滤与向量召回都失效。本项目用独立冷启动模块处理。
冷启动检测 很简单——历史交互少于阈值即冷启动用户:
class ColdStartDetector:
def __init__(self, threshold: int = 5):
self.threshold = threshold
def is_cold_start(self, user_features: Dict[str, Any]) -> bool:
hist_movie_ids = user_features.get("hist_movie_ids", [])
if not hist_movie_ids:
return True
return len(hist_movie_ids) < self.threshold # ← KEY LINE: 交互次数 < 阈值 → 冷启动
阈值需权衡:太低用户偏好未稳就进正常流;太高用户久等不到个性化。默认 5 次。
三种策略 由 ColdStartService 统一管理:
class ColdStartService:
def __init__(self):
self.detector = ColdStartDetector(threshold=5)
self.strategies = [
UCBGenreStrategy(), # 优先级 1:UCB 探索
PreferredGenreStrategy(), # 优先级 2:用户偏好
PopularRecentStrategy(), # 优先级 3:热门兜底
]
async def recommend(self, user_features, top_k=20):
applicable = [s for s in self.strategies if s.can_handle(user_features)]
if has_ucb_data:
allocations = self._get_ucb_weighted_allocation(applicable, top_k)
elif has_preferences:
allocations = self._get_preference_weighted_allocation(applicable, top_k)
else:
allocations = self._get_fallback_allocation(applicable, top_k)
results = await asyncio.gather(*[self._run_strategy(s, user_features, k)
for s, k in allocations if k > 0])
return self._merge_results(results, top_k)
配额随用户状态动态分配:有评分记录时 UCB 获 70%;只有偏好设置时偏好策略获 80%;什么都没有则全用热门。
UCB 类型探索 解决探索-利用(Exploration vs Exploitation)问题:
其中 是类型 的历史平均评分, 是总推荐次数, 是类型 被推荐次数, 是探索系数。第一项 利用 (平均分越高越好),第二项 探索 (推荐越少的不确定越大、奖励越高)。
class UCBGenreStrategy(ColdStartStrategy):
def _calculate_ucb_scores(self, stats, total_n):
scores = {}
for genre in self.available_genres:
if genre in stats and stats[genre]["n"] > 0:
n = stats[genre]["n"]
avg_reward = stats[genre]["reward"] / n
exploration_bonus = self.exploration_c * math.sqrt(
math.log(total_n + 1) / (n + 1e-6)) # ← KEY LINE: 探索奖励随被推荐次数递减
scores[genre] = avg_reward + exploration_bonus
else:
scores[genre] = 1.0 + self.exploration_c * 2 # ← KEY LINE: 未探索类型给最高探索分
return scores
UCB 统计存 Redis(键 user:{user_id}:genre_ucb),用户评分时更新:
def update_ucb_genre_stats(user_id, movie_genres, rating):
normalized_reward = rating / 10.0
key = f"user:{user_id}:genre_ucb"
for genre in movie_genres:
current_raw = redis_client.hget(key, genre)
if current_raw:
current = json.loads(current_raw)
current["n"] = current.get("n", 0) + 1
current["reward"] = current.get("reward", 0) + normalized_reward
else:
current = {"n": 1, "reward": normalized_reward}
redis_client.hset(key, genre, json.dumps(current)) # ← KEY LINE: 增量更新类型统计
优点:随评分增多,UCB「利用」成分增加;对未接触类型仍给机会,避免信息茧房。
偏好类型策略 若有 preferred_genres,用 Elasticsearch 查这些类型的高评分电影(avg_rating>=6.0、rating_count>=20)。
11.4.2 多路召回
有足够历史行为的用户进入正常流程。第一阶段召回,从全库快速筛候选。
为何多路召回 :单一策略有局限——向量召回可能漏掉模型未捕捉的相关性(如新上映小众片样本少、表征不准);协同过滤对小众覆盖不足;热门缺乏个性化。思路是「别把鸡蛋放一个篮子」,多策略并行再合并。
class RecallService:
def __init__(self):
self.strategies = [
UserPreferenceRecallStrategy(), # 用户偏好类目召回
ItemEmbeddingRecallStrategy(), # 物品相似度召回
YouTubeDNNRecallStrategy(), # 向量召回
]
YoutubeDNN 向量召回 :在线算用户向量,再在物品向量空间检索最相似电影。
class YouTubeDNNRecallStrategy(RecallStrategy):
def preprocess_user(self, user_features, max_hist_len=10):
inputs = {}
encoders = self.resource_manager.encoders
for feat in ["user_id", "gender", "age", "occupation", "zip_code"]:
raw_val = user_features.get(feat)
if raw_val is not None and feat in encoders:
try:
val = encoders[feat].transform([str(raw_val)])[0] + 1 # ← KEY LINE: 复用离线编码器,+1 对齐
except:
val = 0
else:
val = 0
inputs[feat] = np.array([val])
# 历史序列:编码电影ID + 展开类型,左填充定长
...
return inputs
def _recall_sync(self, user_context, k):
model_inputs = self.preprocess_user(user_context)
user_emb = self.resource_manager.user_model.predict(model_inputs, verbose=0)
user_emb = user_emb / np.linalg.norm(user_emb, axis=1, keepdims=True)
scores = np.dot(user_emb, self.resource_manager.item_embedding_matrix.T)[0] # ← KEY LINE: 内积≡余弦
top_indices = np.argsort(scores)[::-1][:k]
...
用户与物品向量都归一化,内积等价于余弦。库仅 3000+ 时直接内积即可;超百万时用 FAISS 加速。
物品相似度召回(I2I) :用户刚看什么就推相似的——捕捉即时兴趣,复用 YoutubeDNN 物品向量(向量本身蕴含协同过滤信息)。
class ItemEmbeddingRecallStrategy(RecallStrategy):
async def recall(self, user_context, k):
hist_movie_ids = user_context.get("hist_movie_ids", [])
if not hist_movie_ids:
return []
last_movie_id = hist_movie_ids[0] # ← KEY LINE: 取最近观看的电影作种子
enc_idx = movie_le.transform([last_movie_id])[0] + 1
target_emb = self.resource_manager.item_embedding_matrix[enc_idx]
target_emb = target_emb / np.linalg.norm(target_emb)
scores = np.dot(self.resource_manager.item_embedding_matrix, target_emb)
top_indices = np.argsort(scores)[::-1][:k+2]
...
用户偏好类目召回 :统计用户偏好类型(离线算 Top3 存 Redis),从这些类型召回热门。优点稳定——即使用户最近偶尔偏差,仍推长期喜欢类型。
Snake Merge 多路融合 :简单按分合并会让某路霸榜。Snake Merge 从各路轮流取候选,确保每路有代表进排序:
def _merge_results_round_robin(self, results_list, top_k):
merged_candidates = []
seen_movie_ids = set()
sources = [r if r else [] for r in results_list]
source_pointers = [0] * len(sources)
direction = 1
current_idx = 0
while len(merged_candidates) < top_k:
all_exhausted = all(source_pointers[i] >= len(sources[i])
for i in range(len(sources)))
if all_exhausted:
break
src_list = sources[current_idx]
ptr = source_pointers[current_idx]
if ptr < len(src_list):
item = src_list[ptr]
source_pointers[current_idx] += 1
mid = item["movie_id"]
if mid not in seen_movie_ids: # ← KEY LINE: 去重,避免跨路重复
merged_candidates.append(item)
seen_movie_ids.add(mid)
current_idx += direction
if direction == 1 and current_idx >= len(sources):
direction = -1
current_idx = len(sources) - 1
elif direction == -1 and current_idx < 0:
direction = 1
current_idx = 0
return merged_candidates
名称来自遍历顺序:三路 A、B、C 合并顺序 A→B→C→C→B→A→A→B→C…,像蛇来回穿梭。
11.4.3 精准排序(DeepFM)
召回筛约 100 候选,但其顺序由召回分决定、不够精准。排序用 DeepFM 对候选做 CTR 预估、重排。
在线推理核心是特征构造——每用户-候选对编码成模型输入:
class DeepFMRankingStrategy(RankingStrategy):
def _prepare_batch_inputs(self, user_features, candidates):
rm = self.resource_manager
batch_size = len(candidates)
inputs = {}
for feat in rm.user_features: # ← KEY LINE: 用户特征所有候选共享,复制
raw_val = user_features.get(feat)
encoded_val = rm.encode_feature(feat, raw_val)
inputs[feat] = np.full(batch_size, encoded_val, dtype=np.int32)
for feat in rm.item_features: # ← KEY LINE: 物品特征每候选不同
encoded_values = [rm.encode_feature(feat, c.get(feat)) for c in candidates]
inputs[feat] = np.array(encoded_values, dtype=np.int32)
return inputs
特征编码复用离线保存的 LabelEncoder, 编码从 1 起、0 留未知 ,与训练一致:
def encode_feature(self, feat_name, raw_value):
if raw_value is None:
return 0
encoder = self.encoders.get(feat_name)
if encoder is None:
return 0
try:
if isinstance(encoder.classes_[0], str) and not isinstance(raw_value, str):
raw_value = str(raw_value)
if raw_value in encoder.classes_:
return int(encoder.transform([raw_value])[0]) + 1 # ← KEY LINE: 与离线编码严格一致
else:
return 0
except Exception:
return 0
准备好输入后批量预测:
def _rank_sync(self, user_features, candidates):
inputs = self._prepare_batch_inputs(user_features, candidates)
predictions = self.resource_manager.ranking_model.predict(
inputs, verbose=0, batch_size=min(len(candidates), 256)) # ← KEY LINE: 批量预测,利用向量化
if predictions.ndim > 1:
predictions = predictions.flatten()
ranked_results = []
for i, candidate in enumerate(candidates):
ranked_results.append({
"movie_id": candidate["movie_id"],
"score": float(predictions[i]), # CTR 预测分
"recall_score": candidate.get("score", 0.0),
"recall_type": candidate.get("recall_type"),
})
ranked_results.sort(key=lambda x: x["score"], reverse=True) # ← KEY LINE: 按 CTR 分重排
return ranked_results
批量预测对 100 候选通常 10–30ms。模型推理是 CPU 密集,放线程池避免阻塞事件循环;模型不可用时 降级 到 FallbackRankingStrategy,直接用召回分排序,保证高可用。
11.4.4 多样性重排
召回排序后列表可能多样性不足(如动作片占比高,排序把动作片全排前)。适度多样性提升满意度与留存。
连续打散(Consecutive Dispersion) :不允许超过 个相同属性连续出现。如 ,[动作,动作,动作,喜剧] → [动作,动作,喜剧,动作]。
class ConsecutiveDispersionStrategy(RerankingStrategy):
def _can_add(self, item, result):
if len(result) < self._max_consecutive:
return True
item_key = self._feature_extractor(item)
if item_key is None:
return True
recent_keys = [self._feature_extractor(r)
for r in result[-(self._max_consecutive - 1):]]
return not all(k == item_key for k in recent_keys) # ← KEY LINE: 最近 N-1 全同则不可加
async def rerank(self, items, user_features=None):
if len(items) <= self._max_consecutive:
return items
result, deferred = [], []
for item in items:
if self._can_add(item, result):
result.append(item)
self._try_insert_deferred(result, deferred) # ← KEY LINE: 优先插可加入的候选
else:
deferred.append(item)
result.extend(deferred) # 剩余追加末尾
return result
预定义两类: 类型打散 (取首类型)与 年代打散 (按 10 年分桶,如 1990s)。
class GenreDispersionStrategy(ConsecutiveDispersionStrategy):
def __init__(self, max_consecutive=2):
super().__init__(_extract_genre, max_consecutive, "genre_dispersion")
class DecadeDispersionStrategy(ConsecutiveDispersionStrategy):
def __init__(self, max_consecutive=2):
super().__init__(_extract_decade, max_consecutive, "decade_dispersion")
策略链组合——按顺序执行,输出作下一输入:
class RerankingService:
def __init__(self):
self._strategies = [
GenreDispersionStrategy(max_consecutive=2),
DecadeDispersionStrategy(max_consecutive=2),
]
async def rerank(self, items, user_features=None):
if not items or not self._enabled:
return items
result = items
for strategy in self._strategies:
if strategy.is_ready:
result = await strategy.rerank(result, user_features)
return result
重要特性是 保序性 :满足连续约束前提下尽量保原序,高分仍靠前、仅微调位置——既保相关性又增多样性。
11.4.5 API 集成与服务启动
组件开发完后整合进 FastAPI,对外提供 HTTP 接口。
推荐 API 核心逻辑:
@router.post("/recommend")
async def get_recommendations(request, db=Depends(get_db), current_user=Depends(get_current_user)):
pipeline = get_pipeline()
if not pipeline.is_ready:
raise HTTPException(status_code=503, detail="Recommendation service not ready")
user_features = await build_user_features(current_user, db)
async def item_features_provider(movie_ids):
movies = await get_movies_by_ids(db, movie_ids)
return {m.id: {"movie_id": m.id, "genres": m.genres.split("|") if m.genres else [],
"year": m.year, "isAdult": m.is_adult} for m in movies}
config = PipelineConfig(recall_top_k=request.recall_top_k or 100,
ranking_top_k=request.top_k or 20, enable_cold_start=True)
result = await pipeline.recommend(user_features=user_features,
item_features_provider=item_features_provider, config=config)
movie_ids = [item.movie_id for item in result.items]
movies = await get_movies_by_ids(db, movie_ids)
movie_map = {m.id: m for m in movies}
return {
"recommendations": [{
"movie_id": item.movie_id, "title": movie_map[item.movie_id].title,
"poster_url": movie_map[item.movie_id].poster_url,
"genres": movie_map[item.movie_id].genres, "year": movie_map[item.movie_id].year,
"score": item.score, "recall_type": item.recall_type,
} for item in result.items if item.movie_id in movie_map],
"is_cold_start": result.is_cold_start, "ranking_strategy": result.ranking_strategy,
}
要点:①用户特征从 DB+Redis 组装;②item_features_provider 回调 惰性加载 物品特征,避免召回阶段加载用不到的数据;③流程返回 ID+分,需查库补标题/海报。
资源加载与单例模式——模型大,应在进程级共享,RecallResourceManager 用单例 + 惰性加载:
class RecallResourceManager:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._initialized = False
return cls._instance
def __init__(self):
if self._initialized:
return
self.user_model = None
self.item_embedding_matrix = None
self.encoders = {}
self._initialized = True
def _ensure_resources_loaded(self):
if self.user_model is not None:
return
self._load_from_local() # ← KEY LINE: 首次使用才加载
def _load_from_local(self):
deploy_dir = Path(os.getenv("MODEL_DEPLOY_DIR"))
with open(deploy_dir / "model" / "user_recall" / "active.json") as f:
version_info = json.load(f) # ← KEY LINE: 读版本指针决定加载哪版
self.user_model = tf.keras.models.load_model(deploy_dir / version_info["path"])
self.item_embedding_matrix = np.load(deploy_dir / "item_embeddings.npy")
with open(deploy_dir / "vocab_dict.pkl", "rb") as f:
self.encoders = pickle.load(f)
健康检查 /health 暴露各组件状态,便于监控:
def get_health_status(self):
return {
"cold_start": {"available": ..., "ready": self.is_cold_start_ready, ...},
"recall": {"available": ..., "strategies": len(self.recall_service.strategies)},
"ranking": {"available": ..., "ready": self.is_ranking_ready, ...},
"reranking": {"available": ..., "ready": self.is_reranking_ready, ...},
}
Analysis: 在线链路的工程价值在「毫秒级 + 高可用」——批量预测、线程池异步、模型降级、单例缓存、版本指针热加载,每一处都为这两点服务。这也是论文里永远不会写、却决定系统能否上线的细节。
⚠️ Common Mistakes in 11.4
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 编码与离线不一致 | 在线用默认 LabelEncoder | 输入空间错位,预测全乱 | 复用同一编码器/词表 |
| 2 | 冷启动阈值乱设 | 阈值=50 | 用户久等不到个性化 | 默认 5,按业务调 |
| 3 | 单路召回不融合 | 只用向量召回 | 覆盖/多样性不足 | 多路 + Snake Merge |
| 4 | 排序无降级 | 模型挂就 503 | 可用性崩 | FallbackRankingStrategy |
| 5 | 打散破坏保序 | 全局重排 | 高分被挤后 | 连续约束下保序 |
| 6 | 每请求重载模型 | 无单例 | 内存爆炸、延迟高 | 单例 + 惰性加载 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 管线编排 | Pipeline + Config 串全链路 | 各阶段可控、可关 |
| 冷启动 UCB | 利用+探索公式,Redis 增量统计 | 解决零样本探索-利用 |
| 多路召回 | 向量/I2I/偏好 + Snake Merge | 覆盖与多样性兼得 |
| 排序 | DeepFM 批量 CTR 预估 + 降级 | 精准且高可用 |
| 多样性重排 | 连续打散 + 保序 | 相关性与多样性平衡 |
| 资源单例 | 版本指针 + 惰性加载 | 毫秒级 + 热更新 |
❓ FAQ
Q1: 冷启动阈值 5 是怎么定的?
A: 经验值。太低用户偏好未稳就进正常流(召回/排序仍弱),太高用户久等不到个性化。按业务交互密度调,高频场景可降、低频可升。
Q2: Snake Merge 和直接拼接去重有何不同?
A: 直接拼接按分排序再截前 K,强路易霸榜;Snake Merge 轮流取,结构性保证每路都有代表进排序,多样性更好。
Q3: 排序模型挂了为什么不直接报错?
A: 推荐系统可用性优先。降级用召回分排序,用户仍能拿到(质量略降的)结果,远比 503 好。这是「优雅降级」原则。
🔗 前后关联
- 11.3 提供物品向量、编码器、模型,是在线所有召回/排序的输入。
- 2.3(双塔) 与 3.x(DeepFM) 是召回、排序模型的算法依据。
- 4.2(多样性重排) 解释打散策略的理论动机;本项目是其实例。
- 11.5 的推荐 API 即调用本节
pipeline.recommend。 - 11.6 讨论如何让这整套在线服务容器化稳定运行。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 11.4.1 — 冷启动判定 🟢 Easy
某用户历史观影 [101, 202, 303](3 部),cold_start_threshold=5。is_cold_start 返回什么?若他又评了 3 部(共 6 部)呢?
💡 Solution (click to reveal)
答: 3 < 5 → 返回 True(冷启动)。共 6 部时 6 >= 5 → 返回 False(走正常流程)。
Key points:
- 阈值比较是「少于阈值即冷启动」。
- 随行为积累自然过渡到正常流。
Problem 11.4.2 — UCB 探索项 🟢 Easy
UCB 公式中,类型 A 被推荐 100 次、类型 B 被推荐 2 次,其余相同( 大)。仅看探索项 ,哪类得分更高?
💡 Solution (click to reveal)
答: B 的探索项 = ,A 的 = 。分母小则值大,故 B 探索奖励更高。这正是「推荐少的类型给更高探索机会」,避免信息茧房。
Key points:
- 探索项随 增大而减小。
- 未探索类型(n=0)给最高探索分。
Problem 11.4.3 — Snake Merge 顺序 🟡 Medium
三路召回 A、B、C 各返回候选 [a1,a2]、[b1,b2]、[c1,c2],top_k=4,且所有 movie_id 不重复。Snake Merge 合并的前 4 个(去重后)依次是什么?
💡 Solution (click to reveal)
答: 顺序 A→B→C→C→B→A…。取 a1,b1,c1,再返回 C 取 c2。前 4 个 = [a1, b1, c1, c2]。
Key points:
- 蛇形在末端反向,保证各路轮流。
- 去重避免跨路重复进排序。
Problem 11.4.4 — 编码一致性 🟡 Medium
离线 LabelEncoder 对 gender 类别为 ["F","M"](transform 得 0/1,+1 后 1/2)。在线收到原始值 "M",encode_feature 返回什么?若收到训练未见过的 "X" 呢?
💡 Solution (click to reveal)
答: "M" → transform 得 1,+1 后返回 2(与离线一致)。"X" 不在 classes_ → 返回 0(未知值),与离线 padding 语义一致,模型不会崩。
Key points:
- 在线必须复用离线同一编码器,+1 对齐。
- 未知值统一编 0,保证鲁棒。
🏆 Challenge: 设计降级链 🔴 Hard
若某次请求中召回正常、但排序模型加载失败、且用户非冷启动。请描述系统应走哪条路径、返回质量如何,并指出一个可能比「直接召回分排序」更好的降级方案(150 字内)。
💡 Hint
路径:冷启动检测 False → 多路召回得候选 → 排序失败触发 FallbackRankingStrategy(按召回分排序)→ 重排 → 返回。质量:相关性下降(无 CTR 精排)但可用。更好方案:用 I2I/偏好召回分作粗排权重,或对未失败的小模型(如逻辑回归)兜底,而非纯召回分,提升个性化。
前端与交互
📝 Before You Continue: 请先读完 11.4 的推荐 API。本节展示前端如何调用该 API,并把用户行为反馈回系统形成闭环。
前端是用户与推荐系统的入口:浏览、查看推荐、搜索、评分。这些行为被采集反馈到后端,影响未来推荐——所以前端不仅是展示层,也是 数据采集层。
读完本章,你将能够:
- 列出前端技术栈(Vue 3 / Tailwind / Pinia / Vue Router / Axios)与五类核心页面
- 用路由
meta+beforeEach守卫实现登录/游客权限控制 - 描述 MovieCard / MovieRow / StarRating 三个核心组件的设计要点
- 解释首页如何按登录状态条件渲染「For You」、登录后自动加载推荐
- 用 Pinia 集中管理认证状态、用防抖(debounce)控制搜索请求频率
- 说明注册页偏好类型如何驱动冷启动策略
- 完成 4 道分层练习题
11.5.0 前端概述
本项目前端技术栈:
| 技术 | 用途 |
|---|---|
| Vue.js 3 | 渐进式 JS 框架,用 Composition API |
| Tailwind CSS | CSS 框架,类名快速写样式 |
| Pinia | 状态管理库,管用户认证状态 |
| Vue Router | 路由管理,处理页面导航 |
| Axios | HTTP 客户端,与后端 API 通信 |
核心页面:首页(个性化推荐/热门/分类)、电影详情页(信息+评分)、认证页(登录/注册)、个人中心(历史/偏好)、搜索(全局实时搜索)。
💡 Key Insight: 前端不只是「把推荐结果画出来」——用户的评分、浏览、搜索经前端采集回后端,构成「用户行为 → 特征更新 → 推荐优化」闭环。这是系统能持续变好的关键。
11.5.1 项目结构与路由配置
目录结构:components/(可复用)、views/(页面级)、services/(API)、stores/(状态)。
const routes = [
{ path: '/', name: 'Home', component: Home },
{ path: '/movie/:id', name: 'MovieDetail', component: MovieDetail, props: true },
{ path: '/auth', name: 'Auth', component: Auth, meta: { guest: true } },
{ path: '/profile', name: 'Profile', component: Profile, meta: { requiresAuth: true } },
]
meta 标记访问权限,导航守卫 beforeEach 在跳转前检查:
router.beforeEach((to, from, next) => {
const token = localStorage.getItem('token')
if (to.meta.requiresAuth && !token) {
next('/auth') // ← KEY LINE: 未登录 → 跳登录
} else if (to.meta.guest && token) {
next('/') // ← KEY LINE: 已登录不能访问登录页
} else {
next()
}
})
权限逻辑集中在路由层,页面组件无需各自检查登录。
11.5.2 核心组件设计
电影卡片 MovieCard :最基础单元,接收 movie 与 width,显示海报/标题/年份/评分。设计要点:整卡用 <router-link> 可点击;loading="lazy" 懒加载图;@error 监听失败显示占位;group-hover 悬停显详情。
电影横向列表 MovieRow :把多个卡片组织成可横滚列表(类 Netflix)。用 ref 引用 DOM 滚动容器,据滚动位置动态显箭头:
import { ref } from 'vue'
const scrollContainer = ref(null)
const showLeftArrow = ref(false)
const showRightArrow = ref(true)
const updateArrows = () => {
const { scrollLeft, scrollWidth, clientWidth } = scrollContainer.value
showLeftArrow.value = scrollLeft > 0
showRightArrow.value = scrollLeft < scrollWidth - clientWidth - 10 // ← KEY LINE: 据滚动位置控制箭头
}
评分组件 StarRating :10 分制星级。维护 hoverRating(悬停位)与 userRating(已存分),星色按二者决定:
const hoverRating = ref(0)
const userRating = ref(0)
const getStarClass = (star) => {
const currentRating = hoverRating.value || userRating.value // ← KEY LINE: 悬停优先于已存分
return star <= currentRating ? 'text-yellow-400' : 'text-gray-600'
}
11.5.3 首页
首页分 Hero Banner + 多个电影行。按登录状态决定是否加载个性化推荐,用 watch 监听状态变化:
import { ref, watch, onMounted } from 'vue'
import { useAuthStore } from '../stores/auth'
import { movieApi } from '../services/api'
const authStore = useAuthStore()
const forYouMovies = ref([])
const loadingForYou = ref(false)
const fetchRecommendations = async () => {
if (!authStore.isAuthenticated) return
loadingForYou.value = true
try {
const response = await movieApi.getRecommendations(authStore.user.user_id)
forYouMovies.value = response.data
} finally {
loadingForYou.value = false
}
}
watch(() => authStore.isAuthenticated, (isAuthenticated) => {
if (isAuthenticated) {
fetchRecommendations() // ← KEY LINE: 登录后自动加载推荐
} else {
forYouMovies.value = [] // ← KEY LINE: 登出清空列表
}
})
要点:①「For You」行仅对登录用户显示;②响应式——登录自动加载、登出清空;③Hero Banner 优先用个性化推荐首部,否则用热门。
11.5.4 电影详情页
展示单部电影完整信息。useRoute 取 URL 参数(/movie/123 → route.params.id)。数据加载容错:基本信息必需,演员可选:
import { useRoute } from 'vue-router'
const route = useRoute()
const fetchMovieDetails = async () => {
const movieId = route.params.id // ← KEY LINE: 从路由取电影 ID
const movieResponse = await movieApi.getMovie(movieId)
movie.value = movieResponse.data
try {
const castResponse = await movieApi.getMovieCast(movieId)
cast.value = castResponse.data.cast
} catch (error) {
// 静默处理:无演员数据不影响显示
}
}
const handleRated = (rating) => {
fetchMovieDetails() // ← KEY LINE: 评分后刷新以更新平均评分
}
用户评分被后端记录,影响该用户未来推荐。
11.5.5 API 集成与状态管理
API 服务封装——通信统一在 src/services/api.js,用 Axios 实例:
import axios from 'axios'
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'
const api = axios.create({ baseURL: `${API_BASE_URL}/api`, timeout: 10000 }) // ← KEY LINE: 统一定时与 baseURL
export const movieApi = {
getRecommendations(userId, topK = 20) {
const token = localStorage.getItem('token')
return api.post('/recommendations/recommend',
{ user_id: userId },
{ headers: { 'Authorization': `Bearer ${token}` }, params: { top_k: topK } }
).then(response => ({ ...response, data: response.data.items })) // ← KEY LINE: 取 items 数组
},
}
需认证的 API 从 localStorage 读 token 加请求头,认证逻辑集中在 API 层。
用户状态管理——登录态需跨组件共享(首页决定显隐、详情页判能否评分、导航栏显信息)。用 Pinia Store:
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useAuthStore = defineStore('auth', () => {
const user = ref(JSON.parse(localStorage.getItem('user') || 'null')) // ← KEY LINE: 从 localStorage 恢复
const token = ref(localStorage.getItem('token'))
const isAuthenticated = computed(() => !!token.value && !!user.value) // ← KEY LINE: 计算属性驱动响应式
async function login(email, password) {
const response = await axios.post(`${API_BASE_URL}/api/auth/login`, { email, password })
token.value = response.data.access_token
localStorage.setItem('token', token.value)
await fetchProfile()
return { success: true }
}
function logout() {
user.value = null; token.value = null
localStorage.removeItem('token'); localStorage.removeItem('user')
}
return { user, token, isAuthenticated, login, logout }
})
设计要点:①持久化——token/user 存 localStorage,刷新后保持登录;②响应式——isAuthenticated 变化自动触发依赖组件重渲染;③集中——登录/登出逻辑统一。
11.5.6 搜索功能实现
搜索入口在导航栏,支持点击或 Ctrl+K 打开。实时搜索若每字符都请求会刷爆 API——用 防抖(debounce) :停输 300ms 再发请求。
import { ref, watch } from 'vue'
import { searchApi } from '../services/api'
const searchQuery = ref('')
const searchResults = ref([])
let searchTimeout = null
watch(searchQuery, (newQuery) => {
if (searchTimeout) clearTimeout(searchTimeout)
if (!newQuery.trim()) { searchResults.value = []; return }
isSearching.value = true
searchTimeout = setTimeout(async () => { // ← KEY LINE: 停输 300ms 才真正请求
const results = await searchApi.searchMovies(newQuery.trim())
searchResults.value = results
isSearching.value = false
}, 300)
})
连续输入每次重置定时器,仅停输 300ms 后发起——既响应快又省请求。搜索调后端 Elasticsearch,支持标题/类型/简介模糊匹配。
11.5.7 用户认证与冷启动
认证页含登录/注册表单,isSignup 切换。注册表单有「偏好类型」字段——与冷启动相关:新用户无历史,系统优先按偏好类型推荐。用 reactive 管多字段表单:
import { reactive, ref } from 'vue'
const isSignup = ref(false)
const signupForm = reactive({
email: '', password: '', gender: '', age: '',
preferred_genres: [], // ← KEY LINE: 偏好类型列表,驱动冷启动
})
const toggleGenre = (genreName) => {
const index = signupForm.preferred_genres.indexOf(genreName)
if (index === -1) signupForm.preferred_genres.push(genreName)
else signupForm.preferred_genres.splice(index, 1)
}
用户注册选的偏好类型存入数据库,供在线冷启动模块的 PreferredGenreStrategy 使用(见 11.4)。
Analysis: 前端的价值超越「画图」。它通过 Pinia 统一状态、防抖控流、路由守卫控权限、评分采集闭环,把「用户」真正接入推荐系统的反馈回路——这正是离线模型「活」成在线系统的最后一环。
⚠️ Common Mistakes in 11.5
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 登录态用 props 层层传 | 每页单独传 user | 繁琐易漏、不同步 | Pinia 集中管理 |
| 2 | 搜索无防抖 | 每字符发请求 | 刷爆 API、卡顿 | 300ms 防抖 |
| 3 | 路由无守卫 | 未登录能进 /profile | 越权、空数据报错 | beforeEach 校验 meta |
| 4 | 偏好类型不入库 | 注册完即丢 | 冷启动无个性化 | 存库供 PreferredGenreStrategy |
| 5 | 评分后不刷新 | 平均分不更新 | 用户困惑 | handleRated 重拉详情 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 技术栈 | Vue3/Tailwind/Pinia/Router/Axios | 贴近工业的轻量前端 |
| 路由守卫 | meta + beforeEach | 权限集中、页面解耦 |
| 核心组件 | Card/Row/StarRating | 可复用、响应式 |
| 条件渲染 | 登录才显 For You | 个性化 vs 游客 |
| Pinia | 状态持久化 + 响应式 | 跨组件共享登录态 |
| 防抖 | 停输 300ms 才请求 | 控搜索请求频率 |
| 数据闭环 | 评分/浏览/搜索回写 | 系统持续变好 |
❓ FAQ
Q1: 为什么用 Pinia 而不是 props 传登录态?
A: 登录态跨多组件(首页、详情、导航栏),props 层层传繁琐且易不同步。Pinia 单一 Store + 计算属性,任意组件
useAuthStore()即用,自动响应式。
Q2: 防抖 300ms 会不会让用户觉得慢?
A: 不会——300ms 远小于人感知阈值,且只在「停止输入」后才请求,用户仍在打字时不打断。相比每字符请求,省了大量无效调用。
Q3: 前端怎么影响推荐?
A: 评分写回后端 → 更新 Redis 行为序列与 UCB 统计 → 下次请求召回/排序/冷启动读新特征。前端是闭环的采集端。
🔗 前后关联
- 11.4 的
/recommend接口即本节movieApi.getRecommendations调用对象。 - 11.4 的
PreferredGenreStrategy消费本节注册时存的preferred_genres。 - 11.1 的技术选型在此落地为前端栈。
- 11.6 把前端(Nginx 多阶段构建)容器化部署。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 11.5.1 — 路由守卫 🟢 Easy
用户已登录(有 token),直接访问 /auth 登录页,路由守卫会怎样?若未登录访问 /profile 呢?
💡 Solution (click to reveal)
答: 已登录访问 /auth(guest 页)→ to.meta.guest && token 命中 → next('/') 跳首页。未登录访问 /profile(requiresAuth)→ to.meta.requiresAuth && !token 命中 → next('/auth') 跳登录。
Key points:
- meta 标记权限,守卫统一裁决。
- 已登录不重复看登录页,未登录先认证。
Problem 11.5.2 — 防抖行为 🟢 Easy
用户输入「蜘蛛侠」三字,每字间隔 50ms,防抖 300ms。实际发几次搜索请求?若每字间隔 400ms 呢?
💡 Solution (click to reveal)
答: 每字 50ms:每次输入重置定时器,从未停满 300ms,仅在最后停 300ms 后发 1 次。每字 400ms:每次停够 300ms,发 3 次(每字一次)。
Key points:
- 防抖只在「停止输入」后触发。
- 输入越连续,请求越少。
Problem 11.5.3 — Pinia 响应式 🟡 Medium
useAuthStore 中 isAuthenticated 是 computed(() => !!token.value && !!user.value)。用户登录后 token.value 被赋值,哪些依赖 isAuthenticated 的组件会怎样?
💡 Solution (click to reveal)
答: 赋值时 token.value 变 → isAuthenticated 重算为 true → 所有 watch/computed 依赖它的组件(首页 For You、导航栏)自动重渲染,首页 watch 触发 fetchRecommendations 加载个性化推荐。
Key points:
- 计算属性驱动响应式更新。
- 一处改、处处同步,无需手动通知。
🏆 Challenge: 补全数据闭环 🔴 Hard
从「用户在详情页给电影打 4 分」出发,列出该行为经前端→后端→存储→下一次推荐的完整链路环节(含涉及的具体组件/键),说明闭环如何形成(150 字内)。
💡 Hint
前端 StarRating 调 movieApi → 后端写评分表 + 更新 Redis user:{id}:history(rpush)与 genre_ucb 统计 → 下次首页请求经 pipeline.recommend:冷启动检测(行为已增)、多路召回(I2I 用新历史)、排序(DeepFM 用新特征)、重排 → 返回更新后的列表。前端评分即闭环采集端。
部署与运维
📝 Before You Continue: 请先读完 11.5 与 11.4。本节把它们容器化编排成一个可一键启动、可监控、可排障的系统。
前面完成了离线、在线、前端的开发,可在本地跑通。但如何在其他机器快速复现?本节用 Docker Compose 做容器化部署。
读完本章,你将能够:
- 解释为何用 Docker Compose(环境一致/快速启动/隔离/易扩展)
- 读懂
docker-compose.yaml中五个服务的配置,理解容器间用服务名 DNS 通信 - 描述前端多阶段构建(Node 构建 + Nginx 服务)如何减小镜像
- 执行完整启动流程:启基础设施 → 跑离线 → 导数据 → 建索引 → 访问
- 用
docker compose ps、健康检查、redis-cli排查常见问题 - 完成 4 道分层练习题
11.6.0 为什么用 Docker Compose
本项目依赖五个服务:PostgreSQL(业务数据)、Redis(特征缓存)、Elasticsearch(搜索)、后端 API、前端应用。模型文件经共享目录在离/在线间传递。
手动部署需每台机装 PG/Redis/ES、配网络、处理版本兼容——繁琐易错、环境差异致各种问题。Docker Compose 用 声明式 YAML 描述所有服务及依赖,一条命令启动全系统。优势:
- 环境一致性 :容器含全部依赖,开发/测试/生产环境一致。
- 快速启动 :
docker compose up按依赖顺序自动起,免手动装配。 - 隔离与安全 :各服务独立容器,互不干扰。
- 易于扩展 :加服务只需改配置,不动现有。
11.6.1 Docker Compose 配置详解
docker-compose.yaml 定义六个服务(含后端构建)。逐一介绍。
数据库 PostgreSQL :
services:
postgres:
image: postgres:15-alpine
container_name: funrec-postgres
environment:
POSTGRES_USER: funrec
POSTGRES_PASSWORD: funrec123
POSTGRES_DB: funrec_db
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data # ← KEY LINE: 命名卷持久化数据
networks:
- funrec-network
volumes 命名卷 postgres_data 持久化数据,容器删数据仍在;networks 使其能与其他服务通信。
缓存 Redis :
redis:
image: redis:7-alpine
container_name: funrec-redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- funrec-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5 # ← KEY LINE: 连续失败才判不健康
healthcheck 定期 redis-cli ping,连续 5 次超时(每次 3s)判不健康,依赖它的服务可等其健康再起。
搜索 Elasticsearch :
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:9.2.0
container_name: funrec-elasticsearch
environment:
- discovery.type=single-node # ← KEY LINE: 单节点模式,适合开发
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms512m -Xmx512m" # ← KEY LINE: 限制 JVM 堆,防开发机内存爆
ports:
- "9200:9200"
- "9300:9300"
volumes:
- elasticsearch_data:/usr/share/elasticsearch/data
networks:
- funrec-network
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:9200/_cluster/health || exit 1"]
interval: 30s
timeout: 10s
retries: 5
后端 FastAPI :
backend:
build:
context: ./backend
dockerfile: dockerfile
container_name: funrec-backend
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://funrec:funrec123@postgres:5432/funrec_db
- REDIS_URL=redis://redis:6379/0
- ELASTICSEARCH_URL=http://elasticsearch:9200
- MODEL_DEPLOY_DIR=/app/tmp/web_project/deployed_models
volumes:
- ./backend:/app
- ../tmp:/app/tmp
- ${FUNREC_RAW_DATA_PATH}:/data
depends_on:
- postgres
- elasticsearch
- redis
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
networks:
- funrec-network
注意数据库/Redis 地址用 服务名 (如 postgres、redis)而非 localhost——容器间靠 Docker DNS 解析。后端 Dockerfile 分层构建(先装依赖再拷代码),改码不重装依赖:
FROM python:3.11-slim
WORKDIR /app
RUN apt-get update && apt-get install -y gcc postgresql-client curl \
&& rm -rf /var/lib/apt/lists/*
RUN pip install uv
COPY pyproject.toml ./
RUN uv pip install --system -e . # ← KEY LINE: 先装依赖层,利用缓存
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
前端(多阶段构建) :先 Node 构建静态文件,再 Nginx 服务:
frontend:
build:
context: ./frontend
dockerfile: dockerfile
container_name: funrec-frontend
ports:
- "3000:80"
depends_on:
- backend
networks:
- funrec-network
Dockerfile 多阶段——最终镜像仅含构建产物 + Nginx,不含 Node/开发依赖:
# 构建阶段
FROM node:22-alpine as build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build # ← KEY LINE: 生成 dist 静态产物
# 生产阶段
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html # ← KEY LINE: 仅拷产物,镜像更小
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
网络与数据 :末尾定义共享网络与命名卷:
volumes:
postgres_data:
redis_data:
elasticsearch_data:
networks:
funrec-network:
driver: bridge # ← KEY LINE: 同桥接网络,服务名互通
11.6.2 环境准备与启动流程
前置条件 :安装 Docker、Docker Compose(Desktop 内置)、uv(pip install uv)。验证:
docker --version
docker compose version
uv --version
数据准备 :下载 funrec-movielens-1m.zip 解压,记录绝对路径(含 movies.pkl/ratings.pkl/users.pkl/image/)。
获取代码 :本项目全部代码位于 datawhalechina/fun-rec 仓库的 web_project/ 目录:
git clone https://github.com/datawhalechina/fun-rec.git
cd fun-rec/web_project
环境变量 :复制 .env.example 为 .env 并设数据路径:
cd web_project
cp .env.example .env
# 编辑 .env:
# FUNREC_RAW_DATA_PATH=/path/to/funrec-movielens-1m
# FUNREC_PROCESSED_DATA_PATH=/path/to/funrec-processed
FUNREC_PROCESSED_DATA_PATH 存特征工程与训练中间产物,需可写。
启动基础设施 :
docker compose up --build # 首次构建镜像
docker compose up -d --build # 后台运行
docker compose logs -f backend # 看后端日志
运行离线流程 (训练模型、初始化数据):
cd backend
uv sync
make run-offline-pipeline
依次执行:特征工程 → 训练 YoutubeDNN/DeepFM → 特征上线 Redis → 模型部署共享目录(约 10–20 分钟)。
加载数据到数据库 :
make ingest-data-to-database # 建表 + 导入用户/电影/评分 + 建测试用户
索引电影到 Elasticsearch :
make index-movies-to-elasticsearch # 标题/类型/演员可搜索
访问应用 :
| 服务 | 地址 | 说明 |
|---|---|---|
| 前端 | http://localhost:3000 | 用户界面 |
| 后端 API | http://localhost:8000 | API 服务 |
| API 文档 | http://localhost:8000/docs | Swagger |
| Elasticsearch | http://localhost:9200 | 搜索服务 |
测试账号:test@funrec.com / test123456。登录后可见个性化推荐、搜索、详情、评分。
11.6.3 服务健康检查与调试
检查状态 :
docker compose ps
# NAME STATUS PORTS ... 全部应为 Up
某服务 Exited/Restarting 即启动失败,查日志。
验证各服务 :
curl http://localhost:8000/health # 后端 → {"status": "healthy"}
docker exec -it funrec-postgres pg_isready -U funrec # PG → accepting connections
docker exec -it funrec-redis redis-cli ping # Redis → PONG
curl http://localhost:9200 # ES → 版本信息
查 Redis 数据 (验证特征上线):
docker exec -it funrec-redis redis-cli hget user:6041:profile frequent_genres
docker exec -it funrec-redis redis-cli llen user:6041:history
常见问题排查 :
- 容器启动失败 →
docker compose logs backend;查 .env 路径、端口占用、依赖未就绪。 - 数据库连接失败 →
docker compose logs postgres,看ready to accept connections。 - 模型加载失败 →
ls ${FUNREC_PROCESSED_DATA_PATH}/web_project/deployed_models/;无文件则重跑离线流程。 - 搜索无结果 →
curl http://localhost:9200/_cat/indices;无movies索引则重跑索引命令。
Analysis: 部署的难点不在「写配置」,而在「让五服务按依赖顺序健康起来、并能快速定位故障」。健康检查(healthcheck)、命名卷、服务名 DNS、日志与
redis-cli探查,共同构成可观测、可恢复的交付基线。
⚠️ Common Mistakes in 11.6
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 容器间用 localhost | backend 连 localhost:5432 | 容器内 localhost 是自身,非 PG | 用服务名 postgres |
| 2 | 不挂持久卷 | 容器删数据丢 | 命名卷才持久化 | 挂 postgres_data 等卷 |
| 3 | ES 不限内存 | 默认堆吃满开发机 | 卡顿/OOM | ES_JAVA_OPTS 限 512m |
| 4 | 忘跑离线流程 | 直接访问推荐 → 空 | 无模型/特征 | 先 make run-offline-pipeline |
| 5 | 前端不构建 | 只拷源码不 npm run build | Nginx 无 dist | 多阶段构建生成 dist |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| Compose 价值 | 一致/快启/隔离/易扩 | 一键复现多服务系统 |
| 服务名 DNS | postgres/redis 互访 | 容器间通信基础 |
| 持久卷 | 命名卷存数据 | 容器删数据不丢 |
| 多阶段构建 | Node 构建 + Nginx 服务 | 前端镜像最小 |
| 启动流程 | 启设施→离线→导数→索引→访问 | 顺序不可乱 |
| 健康与排障 | healthcheck + logs + cli | 可观测可恢复 |
❓ FAQ
Q1: 为什么后端用服务名而不是宿主机 IP?
A: 同一 Docker 网络内,Compose 内置 DNS 把服务名解析到容器 IP。用
localhost在容器内指向自身而非 PG,必然连不上。服务名是容器间通信的正确方式。
Q2: 模型文件怎么从离线容器到在线容器?
A: 经共享目录(卷挂载):离线
deploy_local写deployed_models/,在线RecallResourceManager从同挂载路径读,靠active.json指版本。本质是「文件传递」而非「网络调用」。
Q3: 前端多阶段构建省了什么?
A: 最终镜像只含
dist/+ Nginx,不含 Node.js 与node_modules等开发依赖,镜像体积与攻击面都小,生产更安全更快。
🔗 前后关联
- 11.3 的
make run-offline-pipeline即本节离线步骤的入口。 - 11.4 在线服务经
MODEL_DEPLOY_DIR卷加载本节部署的模型。 - 11.5 前端经本节 Nginx 多阶段构建提供静态服务。
- 11.1 的技术选型(PG/Redis/ES/Compose)在此落成运维配置。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 11.6.1 — 容器通信 🟢 Easy
后端 DATABASE_URL 写 postgresql://funrec:funrec123@localhost:5432/funrec_db 会怎样?正确写法是什么?
💡 Solution (click to reveal)
答: 容器内 localhost 指向后端自身,连不到 PostgreSQL,启动报连接拒绝。正确用服务名:@postgres:5432(Compose DNS 解析到 PG 容器)。
Key points:
- 容器网络内用服务名互访。
- localhost 在容器里是「自己」。
Problem 11.6.2 — 数据持久化 🟢 Easy
若不挂 postgres_data 命名卷,容器 docker compose down 后数据会怎样?挂卷后呢?
💡 Solution (click to reveal)
答: 不挂卷:容器文件系统随删而失,用户/电影/评分全丢,下次需重新 ingest-data-to-database。挂命名卷:数据存宿主机卷,容器删重建后数据仍在。
Key points:
- 有状态服务必须挂持久卷。
- 卷与容器生命周期解耦。
Problem 11.6.3 — 启动顺序 🟡 Medium
若跳过 make run-offline-pipeline 直接访问前端首页推荐,会发生什么?给出根因与最小修复步骤。
💡 Solution (click to reveal)
答: 后端 /health 可能 healthy(服务起了),但推荐 API 加载不到模型/物品向量 → RecallResourceManager 资源缺失,召回失败或返回空。根因:在线依赖离线产出的模型与特征。修复:cd backend && uv sync && make run-offline-pipeline,再 make ingest-data-to-database 与 make index-movies-to-elasticsearch。
Key points:
- 离线是「生产」、在线是「消费」,顺序不能反。
- 健康 ≠ 功能就绪,需验证资源存在。
🏆 Challenge: 加一个缓存预热 🔴 Hard
生产希望后端启动时主动把热门电影向量与高频用户画像预热进 Redis,减少首屏冷请求延迟。请基于本章组件,指出这一改动要动哪一层、需注意什么(150 字内)。
💡 Hint
改动在线服务启动钩子(如 RecallResourceManager._ensure_resources_loaded 后):批量从 PG 读高频用户画像/历史写入 Redis,热门电影向量本就在 item_embeddings.npy 直接加载。注意:预热要在依赖的 PG/Redis 健康后做(depends_on + 重试),且只预热热点避免 Redis 膨胀;可用后台任务不阻塞启动。
推荐与广告共享同一套技术底座——召回、排序、特征工程、点击率预估——但广告在这之上叠加了一层推荐系统没有的东西: 经济学机制。广告位是稀缺资源,每一次展示都要在多个广告主之间分配,并向赢家收取费用;分配规则与定价规则的设计,直接决定了广告主「怎么出价才划算」,进而决定了整个市场的稳定性与平台的长期收益。
本部分以刘鹏《计算广告学》公开课体系为骨架、近年 KDD/SIGIR/RecSys 工业论文为延伸。阅读主线有两条:
- 机制主线(12.1 → 12.7):从生态全景与计费模式出发,压轴在竞价机制(GFP/GSP/VCG 的权衡),再沿智能出价、校准、开闭环、在线分配展开——这一条回答「广告主的钱怎么收、怎么花」。
- 工程全景主线(12.8 → 12.11):定向、检索、数据交易、实验与反作弊,补齐从业者需要的基础设施知识。
末尾两章(12.12 合约广告、12.13 信息流与原生广告)回补产品形态:前者是 12.7 在线分配算法的商业前置,后者是与推荐工程结合最深的一章。各章要点见下表。
💡 Key Insight: 推荐系统优化的是「单个用户与物品的匹配」,广告系统在此基础上还要优化「多个广告主之间的博弈规则」。机制设计是广告与推荐的最大分水岭——理解了 GFP → GSP → VCG 这条主线,你才能读懂 8.3 中 EGA 为何要把激励相容(IC)约束嵌入生成过程。
本章涵盖
| 章节 | Topic | The Big Idea |
|---|---|---|
| 12.1 | 计算广告全景与生态 | 从「广告主↔媒体直签」到「DSP-ADX-SSP 程序化交易」,投放模式三次跃迁,每一步都在整合供需、细化竞价粒度 |
| 12.2 | 计费模式与核心指标 | CPT→CPM→CPC→CPA 的谱系本质是 风险归属 的转移;eCPM 是统一度量衡,平台按它排序、广告主按它博弈 |
| 12.3 | 竞价机制:从一价到二价 | 一价(GFP)无稳定均衡、二价(GSP)成为工业主流、VCG 说真话但难落地——机制设计在稳定性与激励兼容之间的权衡 |
| 12.4 | 智能出价与预算控制 | oCPC/oCPM 平台代管出价、预算 pacing 的 PID 反馈控制、一价市场 bid shading 最大化期望 surplus——出价栈四层逐层展开 |
| 12.5 | 广告系统中的偏差与校准 | 位置偏差(PAL)、样本选择偏差(ESMM)、胜出偏差与延迟反馈;Platt/保序回归校准体系——预测的绝对精度是广告系统的地基 |
| 12.6 | 开环广告与闭环广告 | 转化是否发生在平台可观测域内,决定平台能做多深的优化——闭环训练深度 pCVR、做深度转化出价,开环困于归因与隐私 |
| 12.7 | 在线分配与流量管理 | 保量合约写成二部图带约束优化:紧凑分配方案用 级对偶变量恢复 级分配率,HWM 是工程上真实在用的启发式 |
| 12.8 | 受众定向技术 | t(c)/t(u)/t(a,u) 三类标签:上下文打标、行为定向泊松 GLM 建模与时间衰减、人口属性预测——主题模型已成历史,embedding/LLM 打标是现在 |
| 12.9 | 广告检索与语义召回 | 从十亿候选到毫秒竞价:布尔两层索引 + WAND 剪枝保 Top-K,DSSM/双塔语义召回演进到 HNSW/IVF-PQ 多路召回 |
| 12.10 | 数据加工与交易 | 第一方/第二方/第三方数据的加工链路与交易闭环;cookie 映射已死,CDP + UID2 + clean room 是合规时代的答案 |
| 12.11 | 实验框架与反作弊 | 分层实验保证「度量可信」,异常检测 + 设备指纹 + 图分析保证「流量真实」——广告系统的两条底线 |
| 12.12 | 合约广告:产品形态与售卖模式 | 「先有广告位后有广告」:CPT/CPD 排期与轮替、从卖位置到卖人群的售卖演进——保量合约的商业逻辑是 12.7 在线分配的前置 |
| 12.13 | 信息流与原生广告 | 广告与内容形态的融合:信息流混排是「与推荐工程同构」的问题,激励视频、oCPX 产品链路与原生 RTB 的合流 |
What You'll Be Able to Do After This Part
- 🟢 解释 广告与推荐的本质差异:非同质匹配、转化终点、回报率导向,以及机制设计约束
- 🟢 描述 DSP / ADX / SSP / DMP 各自的职责与一次 RTB 竞价的完整时序
- 🟡 辨析 各计费模式下的风险归属:谁做决策、谁承担效果不确定性
- 🟡 推导 eCPM 排序逻辑与 GSP 支付公式
- 🔴 证明 单坑位二价拍卖下如实出价是占优策略,并说明多坑位 GSP 为何失去严格激励兼容
- 🔴 对比 GSP 与 VCG 的收费水平、均衡性质与工业可行性,理解程序化市场「回到一价」的动因
- 🔴 推导 期望 surplus 的最优出价逻辑,解释 bid shading 为何同时改善广告主 ROI 与 DSP surplus
- 🔴 设计 位置偏差(PAL)与样本选择偏差(ESMM)的治理方案,并用可靠性图与 ECE 评估校准质量
- 🔴 辨析 开环/闭环的本质判据,说明闭环为何支撑深度转化出价、开环为何必须依赖回传与归因模型,以及 ATT/SKAN 如何让确定性归因坍缩
- 🔴 建模 在线分配问题:写出供给/需求约束与紧凑方案的恢复公式 ,解释 HWM 的优先级折减逻辑
- 🔴 设计 受众定向标签体系:区分 t(c)/t(u)/t(a,u) 的适用场景,用泊松 GLM + 时间衰减给行为兴趣打分,说清 reach/CTR 权衡
- 🔴 优化 广告检索漏斗:解释布尔表达式两层索引与 WAND 剪枝为何能把十亿候选压到毫秒级,比较 LSH/图索引 ANN 的取舍
- 🔴 辨析 数据合规边界:划分三方数据、指出 cookie 映射为何失效,说清 GDPR/PIPL 约束下 DMP→CDP 与 clean room 的演进逻辑
- 🔴 对抗 广告作弊:识别 click flooding/click injection 等手法的动机与痕迹,用分层实验与异常检测守住「度量可信、流量真实」两条底线
- 🔴 理解 合约售卖逻辑:说清 CPT/CPD/轮替/排期的产品语义,解释「卖位置→卖人群」如何让流量可拆分售卖,并把它与 12.7 的保量分配衔接
- 🔴 融合 广告与内容:分析信息流混排的体验-收益权衡,区分各原生形态的适用场景,走通 oCPX 从转化追踪到按转化优化的产品闭环
- 🏆 用交互式竞价模拟器验证「虚报出价会发生什么」、用 bid shading 模拟器找最优出价、用归因模拟器对比五种归因模型的功劳分配、用在线分配模拟器跑通 HWM 规划与执行,完成各节分层练习题
核心概念
| Concept | 章节 | Relevance |
|---|---|---|
| 广告有效性模型 | 12.1 | 曝光→关注→理解→接受→保持→决策,广告效果的六阶段地图 |
| 程序化交易生态(DSP/ADX/SSP/DMP) | 12.1 | 现代广告投放的基础设施 |
| RTB 实时竞价 | 12.1 | 按次展示粒度的开放竞价,Cookie Mapping 是前置条件 |
| eCPM | 12.2 | 跨计费模式统一排序的度量衡 |
| 担保式投送(GD)与在线分配 | 12.7 | 合约广告的二部图优化框架:紧凑分配方案 + HWM |
| 紧凑分配方案 / SHALE | 12.7 | 只存合约级对偶变量 α,恢复分配率;原始对偶迭代求解并支持增量合约 |
| 位置拍卖(Position Auction) | 12.3 | 多坑位广告分配与计价的统一模型 |
| 广义第二高价(GSP) | 12.3 | 搜索广告二十年的主流定价机制 |
| VCG 机制 | 12.3 | 理论最优的 truth-telling 定价,工业落地的取舍基准 |
| 激励相容(IC)/ 个体理性(IR) | 12.3 | 机制设计两大性质,8.3 EGA 的核心约束 |
| 预算平滑消耗(Budget Pacing) | 12.4 | PID/PI 反馈控制让消耗进度沿 轨迹推进 |
| Bid Shading | 12.4 | 一价拍卖下的出价下压策略,赢率与利润的乘积最优 |
| 位置偏差与 PAL | 12.5 | 点击 = 被看到 × 相关;双塔解耦、线上只用 pCTR 塔 |
| ESMM | 12.5 | pCTCVR = pCTR × pCVR 全空间建模,同时解决 SSB 与数据稀疏 |
| 校准(Calibration) | 12.5 | Platt scaling / 保序回归把分数后处理为真实概率,PCOC/ECE 度量 |
| 闭环 / 开环广告 | 12.6 | 转化是否发生在平台可观测域内的二分,决定优化深度的上限 |
| 受众定向标签体系 t(c)/t(u)/t(a,u) | 12.8 | 上下文/用户/组合三类定向标签的分类框架 |
| 行为定向泊松建模 | 12.8 | 兴趣强度 h~Poisson(λt),时间衰减 λ(d)=αλ(d−1)+w·x 在线更新 |
| 布尔表达式检索与 WAND | 12.9 | 两层倒排 + 上界剪枝,Top-K 广告检索的工业骨架 |
| 语义召回 / ANN | 12.9 | DSSM→双塔→HNSW/IVF-PQ,从关键词匹配走向向量检索 |
| 三方数据与 DMP | 12.10 | 第一/二/三方数据划分,DMP 加工人群包供 DSP 出价 |
| CDP 与 clean room | 12.10 | 后 cookie 时代的一一方数据基建与「可用不可见」合规交易 |
| 分层实验 | 12.11 | 流量分层正交切分,让多个实验并行且互不污染 |
| click flooding / click injection | 12.11 | 两类典型归因作弊手法及其识别信号 |
| CPT / CPD / 轮替 | 12.12 | 广告位按天售卖的三件套:独占、排期与随机起始序号轮播 |
| 从卖位置到卖人群 | 12.12 | 定向标签让广告位可拆分售卖,催生保量合约与在线分配 |
| 信息流混排 | 12.13 | 广告与自然内容按统一分数竞争位置——与推荐工程同构的问题 |
| 激励视频 | 12.13 | 用户主动换权益的完播形态,eCPM 最高 |
| oCPX 产品链路 | 12.13 | 转化追踪 + 转化出价 + 预算表达(bid/cost cap)的产品闭环 |
| 归因(Attribution) | 12.6 | 识别转化由哪个渠道带来的分配规则,是约定而非客观测量 |
| SKAdNetwork(SKAN) | 12.6 | Apple 隐私保护归因:聚合、延迟、群组匿名,开环归因的确定性坍缩 |
前置知识
- 已读完 1.1 (推荐系统是什么)——本部分经常以推荐系统为参照系做对比
- 了解基本的概率与期望值计算(),12.3 有少量博弈论推导,不需要先修博弈论
- 12.3 的 IC/IR 与 8.3 (端到端生成式广告)互为镜像:先读其一再读另一,理解会加深
本部分定位为专题补充,不依赖下篇生成式主线的任何章节;但 12.3 的机制设计视角会反过来照亮 8.3 中 EGA「分配与支付解耦」的设计动机。
Tips for This Part
- 带着「谁承担风险」读 12.2。 每种计费模式都可以用一句话概括:决策权在谁手里、效果不确定性由谁兜底。这条线索比死记公式有效得多。
- 12.3 动手算,别只看。 GSP 支付公式 看似简单,坑位点击率折算极易出错。先手推一遍 12.3.3 的三坑位数值例子,再玩交互模拟器。
- 把机制当「制度」而不是「公式」。 一价、二价的差异不在代数,而在它们激励出的广告主行为:震荡追逐 vs 稳定均衡。读完 12.3 你应该能向别人解释清楚 1998 年 Overture 的市场为什么乱、2002 年 Google 改了什么。
Let's dive in! 🚀
计算广告全景与生态
📝 Before You Continue: 建议先读 1.1「推荐系统是什么」——本章将从推荐系统工程师的视角切入广告,你熟悉的召回、排序、CTR 模型在广告场景都有对应物,但多了一层推荐系统没有的经济学约束。
你已经知道推荐系统如何从海量物品中为用户挑选最合适的内容:召回缩小候选集、排序预估偏好、重排平衡体验。现在换一个问题——如果「被推荐的物品」不再是平台自己的商品,而是广告主付费投放的广告,系统会发生什么变化?
答案远不止「把物品换成广告」这么直接。广告引入了第三个利益方(广告主),带来了 竞价 这一推荐系统不存在的机制;广告的交易方式经历了从线下直签到毫秒级实时竞价的完整演进;广告的定向技术与推荐系统的召回技术同源却又不完全相同。本章带你俯瞰 计算广告(Computational Advertising) 的全景:它是什么、它的根本问题、它的生态如何运转、它的技术如何一步步走向程序化交易。这些内容是后续章节(CTR 预估、竞价机制、机制设计)的地图。
读完本章,你将能够:
- 说出广告定义的三要素与广告有效性模型的六个阶段,并区分品牌广告与效果广告
- 陈述计算广告的根本问题( 三元匹配最大化 ROI),并解释它与推荐系统的三点本质差异
- 说出广告系统价值公式的四个因子,以及投放模式 1.0 → 3.0 演进中每一代解决了什么问题
- 描述程序化生态中 ADX / DSP / SSP / DMP / Trading Desk 各自的职责与 RTB 的两阶段流程
- 举例说明定向技术的三个阶段与广告形态演进的主线,并解释信息流广告为何是平衡效果与体验的正面典型
- 完成 5 道分层练习题,检验对广告生态全景的理解
12.1.0 广告是什么:定义、分类与有效性模型
我们从定义出发。广告是由 已确定的出资人(Sponsor) 通过各种 媒介(媒体,Publisher) ,面向 受众(Audience) 进行的、有关产品(商品、服务和观点)的,通常是有偿的、有组织的、综合的、劝服性的 非人员 信息传播活动。
这个略显绕口的定义里有三个要素值得你逐个咀嚼。出资人 意味着广告有明确的付费方,这与推荐系统里「平台自己决定推什么」截然不同——广告主是一个有独立利益的博弈方。媒介 是广告的载体,从传统媒体到互联网产品,媒介掌握着用户的注意力。受众 是信息触达的对象,也是推荐系统一直在建模的用户。而定义中「非人员」三个字藏着一个关键点:广告的 本质是完成较低成本的用户接触——不依赖面对面的人员推销,用可复制、可规模化的媒介把产品信息送达潜在消费者,这正是广告相对于人员销售的成本优势。
品牌广告 vs 效果广告
按投放诉求,广告分为两大类。品牌广告(Brand Awareness) 注重长期影响,目标是让受众记住品牌、建立认知,典型如汽车、快消品的大型投放; 效果广告(Direct Response) 以短期转化行为为诉求,追求用户点击、注册、下单等可度量的即时效果。这两类的度量方式完全不同——品牌广告看曝光与认知度,效果广告看点击率与转化率。你会看到,后续章节讨论的竞价、CTR 预估等计算技术主要围绕效果广告展开,但品牌广告的「展示也是一种用户接触」的价值不应被低估。
广告有效性模型:从曝光到决策
一条广告要产生效果,需要穿越一条漏斗。广告有效性模型 把这一过程分为六个阶段,并归入三个大组:
- 选择阶段(被看见) : 曝光(Exposure)——广告位所在的页面天然决定; 关注(Attention)——广告要不干扰用户的正常行为、给出推荐原因、符合用户兴趣或需求,用户才会注意到它。
- 解释阶段(被理解) : 理解(Comprehension)——广告内容要落在用户能理解的兴趣范围内,理解门槛不能太高; 接受(Acceptance)——用户对广告和广告位的认可度,决定了信息是否被接纳为态度。
- 态度阶段(被记住并行动) : 保持(Retention)——广告的艺术性带来记忆效果; 决策(Decision)——最终购买行为落在价格敏感的可接受范围内。
这个漏斗对你应该很眼熟——它就是推荐系统里「曝光 → 点击 → 转化」漏斗的精细化版本。但注意一个差别:推荐系统漏斗里用户「点击」就基本完成了系统目标,而广告漏斗的最底层是「购买」,广告主真正付费购买的是贯穿整条漏斗的用户接触。
🧠 Mental Model: 广告是「花钱买的推荐位」
把信息流里的一条广告看作「平台花钱都买不来的推荐位被广告主买走了」。系统面临的任务仍是匹配(什么广告适合这个用户),但匹配的物品池是付费进入的,且每次展示都直接产生真金白银的收入。理解了这一点,你就能理解为什么广告系统的每个技术决策都比推荐系统多一层「钱」的约束。
Analysis: 在线广告的渠道谱系——硬广、SEM(搜索引擎营销)、导航、直通车、返利网——转化率逐级升高,但位于谱系前端的硬广能吸引更多潜在客户、抬高后续渠道的转化率。不能因为硬广点击率低就放弃它:展示本身就是一种有价值的用户接触。这提醒我们,评估广告渠道不能只看单点转化率,要看整条转化链路的协同。
12.1.1 计算广告的根本问题:三元匹配与 ROI
推荐系统的核心是「用户 × 物品」的匹配;计算广告把这个匹配扩展成三元。在线广告中的计算问题,是关于 (用户)、(上下文)与 (广告)三者的匹配,以最大化 ROI(Return on Investment,投资回报率)为目标的优化问题 :
其中 是推荐系统里相对次要的一维(场景),在广告里却举足轻重——同一个用户在搜索页看到「跑鞋」广告和在新闻页看到的最佳广告完全不同,上下文本身就携带强烈的意图信号。而 ROI 的拆解方式直接决定了市场结构:把投入看做固定、优化回报,回报包括 点击率 与 点击价值 (二者乘积即 eCPM ,千次展示期望收益)。于是按「谁来动态决定哪一项」,市场分成三类:
- CPM 市场 (按展示付费):eCPM 固定,点击率与点击价值的决策(与风险)全部交给广告主;
- CPC 市场 (按点击付费):点击价值由广告主判断(出价),点击率动态预估(平台更了解流量质量,如 Google);
- CPA/CPS 市场 (按行为/销售付费):两者均动态,相当于平台做全部决策,风险归于平台——淘宝广告平台以此为基础,因为其广告主(卖家)的服务流程大致相同。
与推荐系统的三点本质差异
作为推荐系统背景的读者,你需要特别留意广告与推荐的三点差异:
- 同质 vs 非同质匹配 :推荐是同质匹配——候选物品都在同一个「内容池」里竞争,系统用统一的标准打分;广告可以非同质——不同广告主的投放目标(品牌曝光、点击、转化)与出价不同,匹配时要同时考虑「内容适配」与「商业回报」,不能用单一相关度分数一刀切。
- 终点 vs 下游 :推荐可以做 Downstream 优化——用户点击了物品,后续还有停留、加购、复购等持续优化的空间;广告是终点,一次转化完成后这次投放的使命即告结束,优化目标收敛在本次展示上。
- 兴趣多样性 vs 回报率 :推荐要满足用户多样的兴趣,探索与多样性本身就是价值;广告追求回报率,同时必须守住安全与质量的底线——一条高回报但低俗的广告对媒介是长期伤害。
💡 Key Insight: 推荐系统优化的是「用户满意度」这一相对单一的目标(体验即价值);广告系统要在用户、广告主、媒介(平台)三方利益之间找平衡。你之后学到的所有广告机制设计(竞价、计费、分配),本质上都是在回答「三方利益如何均衡」这个问题。
广告系统价值公式
从系统视角,互联网广告系统发展的终极目标是价值最大化,可以把广告系统的价值分解为四个因子的乘积:
这四个因子是理解整个广告技术演进的总纲: 转化效率 靠广告形式与定向技术提升(12.1.4、12.1.5); 计价机制 靠竞价模式让价格市场化地逼近价值(12.2、12.3 展开); 资源量 取决于用户基数与使用时长,但盲目加广告位是饮鸩止渴——必须平衡用户价值与广告利益; 投放效率 靠交易链路的程序化演进(12.1.2、12.1.3)。本章后续内容就是这个公式四个因子的逐个展开。
还有几个常见误区值得提前澄清:「越精准的广告给市场带来的价值越大」不一定成立;媒体利益与广告主利益是相关博弈的关系,并非零和也并非一致;「精准投放 + 大数据可以显著提高营收」同样不一定——覆盖率过低的数据来源并非不需要,人群覆盖与精准度之间存在权衡。
12.1.2 投放模式演进:从直签到程序化交易
有了价值公式做总纲,我们先看「投放效率」因子的演进。广告主与媒介如何达成交易?三代投放模式给出了答案。
1.0:广告主 ↔ 媒体直签
最原始的模式是广告主直接与媒体签订广告合约。对一个要在多个媒体投放的广告主,这意味着要与每家媒体分别谈判、签约、对账——效率非常低下。市场自发演化出广告分销商、广告代理等中间商来改善交易的低效,但整体上仍是低效的广告交易模式:交易粒度粗(按天、按位置卖)、信息不透明、议价成本高。
2.0:广告网络(Ad Network)
广告网络(Ad Network) 的出现开始整合供需双方的需求:它聚合多家媒体的剩余流量,为广告主提供更丰富的供应方资源,同时提供人群标签帮助广告主制定定向规则。广告网络有两个关键特征:一是 卖人群不卖广告位——它淡化广告位的概念,把不同媒体的流量按受众标签打包售卖;二是在计价上, CPC(按点击付费)是最合适的计价方式——网络层面的流量质量参差不齐,按点击计价把「曝光是否有效」的判断留给了系统,广告主只为点击买单。
但广告网络是一个 封闭系统 ,其整合能力仍然有限:一方面,媒体为了避免劣质广告伤害网站用户体验,并不倾向于把优质资源接入广告网络;另一方面,供应方巨头会自建广告网络整合旗下分散的供应方资源(如腾讯的广点通)。广告主也需要向广告网络「清晰描述」自己的投放需求,定制化用户划分不被支持——这正是下一代模式要解决的问题。
3.0:程序化交易(DSP-ADX-SSP-DMP)
第三代模式把供需双方的整合推向全网。广告主通过 DSP(Demand-Side Platform,需求方平台) 接触全网供应方资源,交易经 ADX(Ad Exchange,广告交易平台) 以实时竞价方式完成,媒体端由 SSP(Supply-Side Platform,供应方平台) 管理流量。在这一模式下,DSP 甚至能够帮助广告主制定最合适的定向规则,并完成 最低粒度(单次展示) 的自动交易——投放从「买断一个位置一个月」精细化到「为这一次展示出一次价」。
图中展示了 3.0 模式的完整生态:需求侧(广告主 / Trading Desk / DSP)、交易中枢(ADX)、供给侧(SSP / 媒体)与数据侧(DMP)各就各位。值得注意的是 DMP 的角色——它把数据也变成了可交易的资产,为 DSP 的精准出价供给弹药。
Analysis: 三代模式的演进逻辑一以贯之:交易粒度越来越细(月 → 天 → 展示)、参与方越来越专业(媒介 → 广告网络 → DSP/ADX/SSP 分工)、数据流动越来越开放(封闭网络 → 全网竞价)。但每一代都在解决上一代的问题时引入新的代价——3.0 的代价是时延与隐私(12.1.3 详述)。
12.1.3 程序化生态与 RTB:一次展示的旅程
现在我们深入 3.0 生态内部,看每个角色的职责,以及一次实时竞价如何在约 100 毫秒内完成。
生态角色分工
- ADX(Ad Exchange,广告交易平台) :交易中枢,用 实时竞价(Real-Time Bidding, RTB) 方式连接广告与(上下文、用户),按照 展示 粒度上的竞价向广告主收取费用。代表:RightMedia、AdECN、Google AdX、OpenX。
- DSP(Demand-Side Platform,需求方平台) :交易市场需求方技术,提供定制化用户划分、跨媒体流量采购、通过 ROI 估计支持 RTB 出价。DSP 还需解决两个核心算法问题: 竞价行情预估(Bid Landscape Prediction)——预测流量以决定采买策略,因为 DSP 拿到的流量是其出价的函数; 点击价值估计——训练数据稀疏且与广告主类型强相关,原则是用较大的偏差换较小的方差、充分利用广告商类型的层级结构。代表:InviteMedia(功能型)、MediaMath(优化型)。
- SSP(Supply-Side Platform,供应方平台) :提供媒体端的用户划分和售卖能力,可灵活接入多种变现方式,核心功能是 收益管理(Yield Optimizer)——统一优化 Premium Sales、Network 和 RTB 流量,以优化媒体利益为目标,主要在广告位和时间维度上做 eCPM 估计与流量分配。代表:AdMeld、Rubicon、Pubmatic。
- DMP(Data Management Platform,数据管理平台) :为网站提供数据加工和对外交易能力,加工跨媒体用户标签在交易市场售卖;其关键特征是 定制化用户划分 + 统一的外部数据接口。代表:BlueKai、AudienceScience。
- Trading Desk(广告购买平台) :面向需求方的工具,允许广告商跨 Ad Network 购买广告,关键特征是连接不同媒体和广告网络(Universal Marketplace)与非 RTB Campaign 的 ROI 优化能力,经常由代理公司孵化。典型如 EfficientFrontier(组合优化,被 Adobe 收购)。
RTB 的两阶段流程
RTB 的运转分两个阶段。第一阶段是 Cookie Mapping(用户身份匹配) :由 DSP 发起,在需求方网站选择性加载 iframe,建立「媒体 Cookie ↔ DSP 用户 ID」的对照表,Mapping 表存在 Demand 端。这是竞价的前提——ADX 广播询价时携带的是媒体侧 Cookie,DSP 只有查 Mapping 表才能识别出「这是我的哪个用户」。第二阶段是 Ad Call(广告请求与竞价) :用户访问媒体触发广告请求,ADX 向各 DSP 广播询价请求,DSP 估算后返回出价,最高者赢得这次展示。
如图,从用户访问页面到广告渲染,中间要经过 SSP 封装请求、ADX 广播询价、多家 DSP 并行出价、竞价结算、返回广告共七步。这条链路存在两笔不可忽视的代价: 时延——相比直返广告多了一次 Round Trip,竞价链路必须压在约 100ms 预算内,否则用户可感知白屏; 隐私——询价请求携带用户标识与页面信息广播给多家 DSP,存在浏览数据泄露风险。此外,DSP 数量较多时,ADX 侧的服务与带宽成本也是工程上必须优化的问题。
Analysis: RTB 用「每次展示单独竞价」换取了极致的交易粒度,代价是每次展示都要付出一次全链路通信成本。这解释了为什么程序化生态后来演化出优选(Preferred Deal)等非完全竞价的交易方式——不是所有流量都值得付出 RTB 的通信成本。
OpenRTB:竞价通信的行业协议
上面七步链路里,ADX 与各家 DSP 素不相识却能协同,靠的是 OpenRTB——IAB 制定的实时竞价通信规范。它把链路中的两类消息标准化: Bid Request(ADX → DSP 的询价,携带展示机会的描述:广告位尺寸与位置、页面/应用上下文、用户标识、底价、设备信息等)与 Bid Response(DSP → ADX 的出价,携带出价、创意素材引用与监测打点 URL)。协议的关键工程约束有两条:其一,序列化采用 JSON,因为约 100ms 的时延预算里序列化与传输都是开销;其二,出价与素材解耦——响应里只传素材 ID 或 URL,素材由 ADX/SSP 端按展示尺寸动态渲染,这既压缩了响应体,也支持媒体侧的原生渲染。国内市场因历史沿革多采用类似结构的自有协议,但字段语义与 OpenRTB 高度对应——学会了 OpenRTB 的字段设计(哪些信息给出价方、哪些信息不出),也就理解了竞价协议在「信息充分性」与「隐私、成本」之间的取舍逻辑。
交易方式谱系
程序化时代的流量交易并非只有 RTB 一种,而是一个从「最粗」到「最细」的谱系:
| 交易方式 | 交易形态 | 特点 |
|---|---|---|
| Premium Sale(优先销售) | 担保投送(Guaranteed Delivery,经 Ad Server) | 合约约定展示量,未完成需补偿;CPT 结算;量优先于质 |
| Preferred Deal(优选) | 一对一议价 | 广告主按约定价格优先挑选流量,无需公开竞价 |
| 网络优化(Network Optimization) | 接入 Ad Network | 媒体把流量交给网络整体变现,组合优化 |
| RTB(实时竞价) | ADX 开放竞价 | 单次展示粒度,多家 DSP 同时出价,价高者得 |
从上到下,交易粒度越来越细、确定性越来越低、价格发现越来越充分。担保式投送 基于合约——约定展示量未完成需要补偿,采用 CPM 结算,投送由服务端决策,其算法基础是点击率预测和流量预测下的 在线分配(Online Allocation) 问题; RTB 则把定价完全交给市场。SSP 的收益管理器所做的,正是在这几种方式间为每次流量选择变现价值最高的通道。
12.1.4 定向技术三阶段:从规则到系统
回到价值公式的「转化效率」因子。定向(Targeting) 的专业叫法就是「受众与广告的匹配度」,核心目标是从广大受众中找到广告的目标受众。定向技术的发展大致分为三个阶段。
第一阶段:规则定向
广告主基于时间、地理位置、频道等产品属性设定规则进行「定向」(严格说这只是筛选)。这是 CPT 与展示量广告时代的标配:广告主圈定「早高峰 + 一线城市 + 体育频道」,系统按规则匹配流量。它的颗粒度取决于媒介的产品化程度,与用户个体几乎无关。
第二阶段:数据定向
广告主基于用户个人属性、行为记录等 用户数据 制定定向规则,包括: 人口属性定向 (年龄、性别)、上下文定向 (根据页面内容判断场景,其工程实现是 Near-line 上下文系统——在线 Cache 存储 URL→特征表,未命中则触发爬虫与特征提取)、行为定向 (基于用户行为日志)、搜索关键词定向。数据定向的颗粒度从「产品位」细化到了「用户个体」,是广告网络「卖人群」的技术前提。
行为定向背后有一张行为强度谱系:按信息强度排序的重要原始行为包括——成交(Transaction)、预成交(Pre-transaction,如浏览)、付费搜索点击、广告点击、搜索点击、分享、页面浏览、广告浏览。两个规律值得记住: 越靠近 demand(需求成交)的行为对转化越有贡献;越主动的行为越有效。用户主动搜索远比被动浏览广告携带更强的意图信号。
第三阶段:系统定向
广告主不再定义明确规则,由 系统 分析广告主已有的目标受众,再从供应方的用户中找到合适的受众。这是定向从「人定规则」到「机器学习」的跃迁,也是与推荐系统技术交汇最深的地带:
- 重定向(Retargeting) :广告主提供受众信息(如通过在广告主网站植入 Cookie 收集到的访客),系统从供应方流量中找回这些「老顾客」。决定重定向效果的核心因素,是广告主提供的受众与供应方受众的 重合度——但随着开放式广告系统成熟,广告主通过 DSP 几乎可以从全网找回这些人。重定向还有两个重要延伸:
- 个性化重定向(Personalized Retargeting) :重定向的纵向延伸——找回老用户后,针对这个用户推送 商品粒度 的个性化广告:推荐他购物车里的商品、去掉已购买的东西、或推荐相关新品。对广告主而言,这相当于一个 站外推荐引擎(Offsite Recommendation)——把站内推荐橱窗放到媒体的广告位里去。你会发现这就是推荐系统的排序技术在广告场景的直接复用。
- 搜索重定向(Search Retargeting) :重定向的横向延伸——分析广告主从搜索引擎来源的流量数据,将搜索过特定关键词的用户定向到广告主网站。严格说它更接近新客推荐而非重定向。
- 新客推荐(Look-alike) :广告主提供 种子用户 (seed audience),DSP 通过行为相似性在供应方受众中找到与种子相似的潜在新用户。它可视为扩展的重定向与广告商自定义标签。两个实践要点:在同样的触达(reach)水平下,Look-alike 的效果好于通用标签定向;应尽量利用非 Demand 端数据,避免在竞争对手之间「盗卖」用户。Look-alike 的固有问题在于「类似」是黑盒概念,难以清晰定义和量化。
有价值的数据来源
系统定向的效果取决于数据质量。五类有价值的数据来源,按用途分别是:
- 用户标识 :除上下文和地域外各种定向的基础,需要长期积累;可通过多家第三方 ID 绑定优化;
- 用户行为 :业界公认的有效行为数据,使用时需去除网络热点话题带来的偏差;
- 广告商数据 :广告主网站的 Cookie 植入可用于 Retargeting,对接广告商的种子人群可做 Look-alike;
- 用户属性与精确地理位置 :非媒体广告网络很难自行获取,需第三方数据对接;
- 社交网络 :朋友关系为用户兴趣和属性的平滑提供了机会——朋友的兴趣是预测用户兴趣的优质信号。
Analysis: 定向三阶段的演进与推荐系统的技术演进高度同构:规则定向对应早期的运营规则推荐,数据定向对应标签体系与内容理解,系统定向(个性化重定向、Look-alike)则直接就是召回 + 排序的机器学习问题。差异在于:广告定向多了「广告商数据」这一外部信号源,且 Look-alike 面临的正样本稀疏问题比推荐系统更极端。
12.1.5 广告形态演进:从卖位置到卖注意力
「转化效率」因子的另一半是 广告形式。广告形态的演进同样是一条清晰的主线,下表整理了完整的演进谱系(依据源材料的对比表):
| 形态 | 受众端形式 | 定向方式 | 收费方式 | 提升之处 |
|---|---|---|---|---|
| CPT 广告 | 不限 | 简单定向:时段、地理 | CPT 按展示时间收费 | — |
| 展示量广告 | 不限 | 简单定向:时段、地理 | CPM 按曝光量收费 | 按曝光量收费,广告开始向「面向效果」方向进化 |
| 搜索广告 | 搜索结果页:结果列表 / 页面其他位置 | 中级定向:关键词 | 竞价单价 × 点击量 | 关键词提供更好的定向方式 |
| 社交网络广告 | 不限 | 简单定向:时段、地理 | 不限 | 用户在社交网络停留时间更久,适合持续曝光 |
| 精准定向广告 | 不限 | 高级定向:用户信息、频道定向 | 竞价单价 × 点击量 | 从「数量」到「质量」 |
| 上下文广告 | 不限 | 高级定向:页面内容、行为信息、用户信息 | 竞价单价 × 点击量 | 不再依赖单一关键词,分析页面内容提供更多定向信息 |
| 信息流广告 | 通常在阅读信息流中,和用户消费内容相似 | 高级定向 | 竞价单价 × 点击量 | 开始尝试将内容和广告融合:增强广告曝光,同时降低广告对用户体验的伤害 |
| 一般竞价广告 | 不限 | 高级定向 | 竞价单价 × 点击量 | 能使用多种信息进行复杂定向,整合多种媒体多种广告形式 |
| 植入式原生广告 | 融入产品内容 / 服务 | 高级定向 | 竞价单价 × 点击 | 广告和内容更加深度融合 |
| 程序化交易广告 | 不限 | 高级定向 | 实时竞价单价 × 点击 | 实时竞价,进一步提高广告效果转化效率 |
如图,这条阶梯由两股力量共同推动: 形式演进 (内容与广告融合,信息流与原生降低对体验的伤害)和 机制演进 (从卖位置到卖人群,CPT/CPM 到 RTB 实时竞价)。两条线在顶端的「程序化交易 + 原生化」处汇合。
信息流广告:平衡效果与体验的正面典型
在这条演进线中, 信息流广告(Feed Ads / Native Ads) 值得单独强调。好的广告形式能够平衡广告效果和用户体验,信息流广告是一个正面典型。它的形态与用户消费的内容高度相似、混排在阅读信息流中,得益于技术进步才成为可能。它「平衡」的逻辑体现在两端:对广告主,信息流原生形态提升了关注与接受(对应有效性模型的选择与解释阶段),曝光不被用户主动屏蔽;对用户,广告不打断阅读节奏、不造成突兀的体验损伤。这正呼应了价值公式中「资源量」因子的告诫——广告资源总量与用户使用情况成正比,只有保护用户体验,使用时长这个分母才能持续增长。
💡 Key Insight: 广告形态演进的本质是「广告离内容越来越近,交易离展示越来越近」。前者解决的是用户接受度问题(有效性漏斗的前半段),后者解决的是定价精度问题(价值公式中的计价机制因子)。信息流广告恰好站在两条线的交点上——它既是形式融合的产物,又是精准定向与程序化竞价的主要载体。
Analysis: 广告形式相对成熟(条幅、视频、文字链),通常不是广告系统需要考虑的问题——决定广告效果的第一要素是广告创意的设计。但「科学化营销」的思路正在改变这一点:广告系统开始尝试辅助广告主优化营销策略。对算法工程师而言,更可靠的发力点仍是定向技术(受众与广告匹配)与计价机制,即本章 12.1.4 与后续 12.2/12.3 的内容。
⚠️ Common Mistakes in 12.1
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把广告当作「带价格的推荐」 | 「广告排序就是 CTR 排序加个出价」 | 广告存在三方利益(用户/广告主/媒介)博弈,出价使匹配非同质 | 用 eCPM 视角统一点击率与点击价值,兼顾三方均衡 |
| 2 | 认为「越精准价值越大」「精准+大数据必然增收」 | 盲目追求人群覆盖极窄的定向 | 人群覆盖过低的数据来源同样有价值,覆盖与精准存在权衡 | 评估定向价值时同时看 reach 与质量 |
| 3 | 混淆广告网络与 ADX | 「Ad Network 就是小型 Ad Exchange」 | 广告网络是封闭系统、卖人群、CPC 计价;ADX 是开放实时竞价、按展示竞价 | 记住 2.0 封闭网络 vs 3.0 开放交易的边界 |
| 4 | 忽略 Cookie Mapping 的前置地位 | 「DSP 收到询价就能识别用户」 | ADX 询价携带媒体 Cookie,DSP 必须先查 Mapping 表映射到自己的用户 ID | 把 Cookie Mapping 理解为 RTB 的第 0 步 |
| 5 | 以为 RTB 只有多出价方竞价这一步 | 「RTB 就是 ADX 收出价取最高」 | RTB 含 Cookie Mapping 与 Ad Call 两个阶段,且有时延(约 100ms 预算)与隐私两笔代价 | 用七步时序图理解完整链路 |
| 6 | 把个性化重定向等同于「找回老客」 | 「重定向就是给访问过的人再推广告」 | 个性化重定向要推商品粒度广告、剔除已购、推荐相关新品,本质是站外推荐引擎 | 把它看作推荐系统排序技术在广告位上的复用 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 广告定义 | 出资人 / 媒介 / 受众三要素,本质是低成本用户接触 | 「非人员」传播的成本优势是广告商业模式的根基 |
| 有效性模型 | 曝光→关注→理解→接受→保持→决策,三阶段分组 | 广告效果评估与形式设计的框架,对应推荐漏斗但更细 |
| 根本问题 | 匹配最大化 ROI | 上下文是一等公民,且匹配因出价而非同质 |
| 与推荐的差异 | 同质 vs 非同质、终点 vs 下游、兴趣多样性 vs 回报率 | 推荐背景工程师迁移到广告的认知锚点 |
| 价值公式 | 转化效率 × 计价机制 × 资源量 × 投放效率 | 理解广告技术演进的总纲 |
| 投放模式 1.0–3.0 | 直签 → 广告网络(卖人群、CPC)→ 程序化交易(DSP-ADX-SSP-DMP) | 每代解决上代问题的同时引入新代价(封闭性/时延/隐私) |
| RTB | Cookie Mapping + Ad Call 两阶段,七步时序,约 100ms 预算 | 程序化交易的核心机制与工程约束 |
| 交易方式谱系 | Premium Sale(担保投送)→ 优选 → 网络优化 → RTB | 不同流量匹配不同交易粒度,SSP 收益管理做路由 |
| 定向三阶段 | 规则定向 → 数据定向 → 系统定向(重定向/Look-alike) | 个性化重定向 = 站外推荐引擎,与推荐技术直接同源 |
| 信息流广告 | 内容与广告融合,平衡效果与用户体验的正面典型 | 形式演进与机制演进的交汇点 |
❓ FAQ
Q1: CPC 和 CPA 市场分别由谁承担点击率预估的风险?
A: CPC 市场中点击价值由广告主以出价形式申报,点击率由平台动态预估,风险主要在平台预估能力;CPA/CPS 市场中点击率与点击价值均动态、决策全在平台,转化风险完全归于平台——因此只有广告主转化流程高度一致的市场(如淘宝)才适合以 CPA/CPS 为基础。
Q2: 为什么广告网络不易支持定制化用户划分,而 DSP 可以?
A: 广告网络是封闭系统,广告主只能使用网络预置的标签「清晰描述」需求;DSP 拥有定制化用户划分能力,可对接广告商数据(种子人群、Cookie 植入),在全网流量上按广告主自己的受众定义出价——这正是从 2.0 走向 3.0 的核心驱动力。
Q3: 搜索重定向和个性化重定向、新客推荐分别是什么关系?
A: 个性化重定向是重定向的纵向延伸,面向已触达用户做商品粒度的个性化推送(站外推荐引擎);搜索重定向是横向延伸,把搜索过相关关键词的用户引到广告主网站,严格说它面向的是未触达用户,性质更接近新客推荐。
🔗 前后关联
- 12.2 (点击率预估)将展开本章反复出现的「点击率动态预估」——广告排序需要准确的 CTR 绝对值而不仅是相对排序,这正是回归任务的价值。
- 12.3 (竞价与机制设计)承接交易方式谱系:GSP/VCG 定价、位置拍卖与 eCPM 排序的机制细节。
- 2.x (召回)的 ItemCF / 向量召回与本章定向技术同构:重定向与 Look-alike 本质是「以人群为 query 的召回」。
- 3.x (排序模型)的 CTR 模型(如 DeepFM、DIN)直接服务于广告的 eCPM 排序,工业实践可参考延伸阅读中的阿里妈妈 DIN / DIEN 与美团搜索广告排序。
- 8.3 (端到端生成式广告)展示了竞价机制与生成模型统一的前沿形态,可视为本章程序化生态在模型层的前瞻。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 12.1.1 — 广告定义与分类 🟢 Easy
判断下列 4 条陈述的对错,并各用一句话说明理由:(a) 广告定义中的「非人员」意味着广告不需要出资人;(b) 品牌广告的典型度量是短期转化率;(c) 有效性模型中「关注」属于选择阶段;(d) 硬广点击率低所以应该被放弃。
💡 Solution (click to reveal)
Approach: 逐条对照 12.1.0 的定义与模型。
- (a) 错。广告三要素是出资人、媒介、受众;「非人员」强调不依赖面对面人员推销、完成低成本用户接触,出资人仍是必需要素。
- (b) 错。品牌广告(Brand Awareness)注重长期影响与认知建立;短期转化行为诉求是效果广告(Direct Response)的特征。
- (c) 对。选择阶段包含曝光与关注(被看见),解释阶段包含理解与接受,态度阶段包含保持与决策。
- (d) 错。在线广告渠道中硬广一端虽转化率低,但能吸引更多潜在客户、抬高后续渠道(SEM、直通车等)的转化率——展示本身就是一种有价值的用户接触。
Key points:
- 三要素缺一不可,「非人员」是成本优势的来源。
- 漏斗评估要看整条链路协同,不能只看单点指标。
Problem 12.1.2 — CPM/CPC/CPA 的风险分配 🟢 Easy
某广告平台正决定采用哪种计价市场。广告主希望「只为最终销售付费」,平台对自己的 CTR 预估能力有信心、但对不同广告主的转化流程差异没有把握。请回答:(a) CPA/CPS 市场中点击率与点击价值的决策分别由谁承担?(b) 为什么淘宝广告平台可以采取 CPA/CPS 作为基础?(c) 本例中平台更应选择哪种市场?
💡 Solution (click to reveal)
Approach: 用「谁动态决定哪一项」分析风险归属。
- (a) CPA/CPS 市场中点击率与点击价值均动态,相当于平台做全部决策,风险归于平台。
- (b) 淘宝的广告主(卖家)服务流程大致相同,平台对不同广告主的转化链路有一致的把握,风险可控。
- (c) 平台对 CTR 预估有信心但对广告主转化差异没有把握,而 CPC 市场恰是「点击价值由广告主判断(出价)、点击率由平台动态预估」——各自动态决定自己最了解的一项,故选 CPC。
Key points:
- CPM:决策与风险全在广告主;CPC:各管一半;CPA/CPS:决策与风险全在平台。
- 计价机制的选择本质是风险与信息优势的匹配。
Problem 12.1.3 — RTB 链路与时延代价 🟡 Medium
请按发生顺序排列 RTB 一次展示的 7 个步骤(用编号 ①–⑦):① DSP 估算 eCPM 并出价;② 用户访问媒体页面触发广告请求;③ ADX 向各 DSP 广播询价;④ SSP 封装流量信息发起广告请求;⑤ 竞价结算,最高出价者赢得展示;⑥ 返回竞价胜出的广告;⑦ 广告渲染展示给用户。并回答:为什么说 RTB 存在「两笔代价」?
💡 Solution (click to reveal)
Approach: 对照 RTB 时序图(Ad Call 阶段)。
正确顺序:② → ④ → ③ → ① → ⑤ → ⑥ → ⑦。
两笔代价:
- 时延 :相比直返广告,RTB 多一次 Round Trip(ADX 与 DSP 间的询价/出价往返),整个链路必须压在约 100ms 预算内,否则用户可感知白屏。
- 隐私 :询价请求携带用户标识与页面信息广播给多家 DSP,存在浏览数据泄露风险。
此外别忘了前置条件:这一切都建立在 Cookie Mapping(DSP 发起、在需求方网站加载 iframe、Mapping 表存于 Demand 端)之上,没有身份对照,DSP 收到询价也无法识别用户。
Key points:
- Cookie Mapping 是第 0 步,Ad Call 才是每次展示的竞价流程。
- 交易粒度(单次展示)与通信成本是 RTB 的内在权衡。
Problem 12.1.4 — 定向方案选择 🔴 Hard
某跨境电商找到你做投放顾问,它的三种诉求与可选定向技术如下,请为每个诉求选择最合适的技术并说明理由:(a) 「上个月加购物车但没下单的用户,我想分别推购物车里的商品和同类新品」;(b) 「我们有一批 5 万高价值老客的名单,想找更多像他们的人」;(c) 「预算有限,只想投给最近在搜索引擎搜过『海淘奶粉』的人」。
💡 Solution (click to reveal)
Approach: 按定向对象(已触达用户 / 种子扩展 / 搜索行为)匹配技术。
- (a) 个性化重定向 (重定向的纵向延伸)。对象是广告主站内已触达用户(通过 Cookie 植入识别),推送商品粒度广告:购物车商品催单、已购剔除、同类新品推荐——本质是把站内推荐橱窗放到媒体广告位中(站外推荐引擎)。
- (b) 新客推荐(Look-alike)。以 5 万老客为种子用户,DSP 通过行为相似性在供应方受众中找潜在新用户;同样 reach 水平下效果好于通用标签。注意尽量利用非 Demand 端数据,避免在竞争对手间盗卖用户;同时「类似」是黑盒,效果需实验验证。
- (c) 搜索重定向。分析广告主从搜索引擎来源的流量数据,把搜索过特定关键词的用户定向到广告主网站;严格说它面向未触达用户,性质更接近新客推荐,但以搜索词为信号,意图强度高、预算效率好。
Key points:
- 选择定向技术的第一问:目标受众是「已触达」还是「未触达」?
- 行为强度谱系:越靠近 demand、越主动的行为,对转化贡献越大——搜索点击强于广告点击强于页面浏览。
🏆 Challenge: 为一个新广告产品规划交易方式组合
你负责一款日活千万的资讯 App 的广告变现。产品有首页开屏、信息流混排、文章底部三种广告位,广告主构成是 60% 品牌广告主 + 40% 效果广告主。请写约 180 字,说明你会如何为三种广告位在「Premium Sale(担保投送)/ Preferred Deal / 网络优化 / RTB」谱系上分配交易方式,并说明信息流广告位在形式设计上应注意什么。
💡 Hint
参考分配思路:开屏曝光量大、独占性强,适合品牌广告主做 Premium Sale(担保投送,CPT/CPM 结算,量优先于质,需以流量预测与在线分配保合约量完成);信息流流量最大但单次价值分散,适合接入 RTB 开放竞价以充分价格发现(同时保留 Preferred Deal 给议价能力强的头部广告主优先挑选优质流量);文章底部长尾流量单价低,接入 Ad Network 做网络优化即可,省去 RTB 通信成本。信息流形式上应让广告与用户消费的内容形态相似(图文卡片混排)、不打断阅读节奏——信息流广告正是「平衡广告效果与用户体验的正面典型」,用户体验保护的是「使用时长→资源量」这个长期分母。核心逻辑:不同广告位流量特征不同,SSP 收益管理应在谱系上为每次流量选 eCPM 最高的变现通道。
计费模式与核心指标
📝 Before You Continue: 建议先读完 12.1(广告生态全景),了解广告主、媒体、平台在交易链路中的角色分工;本章 12.2.4 的点击率建模与 Part 3 的排序模型一脉相承,若你已读过 3.x 的 CTR 模型,可以把本章看作它们在广告场景下的「经济学重述」。
你在搜索框里输入「跑鞋」,结果页的第一条是广告——它凭什么出现在那个位置?平台这一次展示预期收多少钱?这些问题背后没有玄妙的算法黑盒,答案写在两样东西里: 计费模式(Billing Model) 决定谁在哪个环节付钱, 核心指标(Metrics) 决定系统用什么尺子比较候选广告。
推荐系统优化的是用户体验与业务目标的模糊组合,而广告系统从第一天起就把「钱」写进了目标函数。计费模式像一部 宪法 :它规定了广告主与媒体之间风险的归属,此后系统里的检索、排序、流量预测、探索策略,都必须在这部宪法的框架下工作。换一种计费模式,整个技术栈的形态都会随之改变。
本章我们从广告主与媒体的价值模型冲突出发,走过从 CPT 到 CPS 的计费谱系,建立以 eCPM 为统一度量衡的排序逻辑,再进入合约广告的在线分配与点击率预估的工程细节。这些内容是 12.3 竞价机制的地基——先弄清「怎么算账」,才能理解「怎么定价」。
读完本章,你将能够:
- 列举 CPT/CPD、CPM、CPC、CPA/CPS 各计费模式的计费公式、关键决策方与风险归属
- 用 CTR、CVR、ROI 三个指标刻画广告效果,并用 完成跨计费模式的排序计算
- 说明品牌广告与效果广告在计费方式与交易方式上的分野
- 描述 担保式投送(GD) 与 在线分配 的二部图结构及其求解思路
- 解释点击率预估为何是回归问题而非排序问题,以及冷启动 back-off 与 E&E 的应对策略
- 完成 5 道分层练习题,打通从指标换算到 GSP 支付的计算链路
12.2.0 为什么计费模式是广告系统的「宪法」
任何商业产品都要回答「怎么收钱」,但在线广告的特别之处在于: 计费单位的选择,本质上是在分配「效果不确定性」带来的风险。广告从展示到点击、再到转化,每往后走一步,不确定性都更大;在哪一步收费,就等于把这一步之后的所有风险推给了某一方。所以说计费模式是广告系统的宪法——它先于一切算法,定义了博弈的规则。
先站在 广告主(Advertiser) 这一边看。广告主的价值模型核心是 按最终效果反推单次广告的价值。假设卖一辆车的营销成本是 2000 元,而从广告展示到最终完成购买的转化率是 0.1%,那么一次广告展示的价值就是 元——无论媒体觉得自己的首页 banner 多么黄金,广告主心里那杆秤只认这个数。现实中的计算当然更复杂,但原理不变:从钱的方向倒推。按这个逻辑, CPA(Cost Per Action,按行为付费) 甚至 CPS(Cost Per Sales,按销售付费) 的计价模式是最贴合广告主价值模型的。
再站到 媒体/供应方(Supply Side) 这一边。媒体关心的不是广告主能卖多少车,而是 单位广告资源能产生多少收入——首页 banner 今天值多少钱,明天还值多少钱。由此自然产生了 CPT(Cost Per Time,包时段付费)、CPM(Cost Per Mille,千次展示付费) 这类「卖资源」的计价模型:把广告位当作待出租的商铺,计量直接、收入稳定。
显然,双方对「广告资源用量」的认知是不同的,必然存在博弈——要警惕的一个误区是,媒体利益与广告主利益是 相关博弈 的关系,而非一致。博弈的最终结果,是广告计量演化出两大类。效果广告(Direct Response) :供应方根据广告效果计算广告量,这种模式最初是从广告主利益出发的——早期它确实可能伤害供应方,因为广告创意不佳时,即使分配了大量曝光,点击率依然很低。但随着技术发展,这一问题已被克服:系统通过对广告点击率等数据的分析,自动降低这些「低利润」广告的投放比例,或要求广告主提高出价。品牌广告(Brand Awareness) :根据展示量计费,这对供应方来说更直接,对没有直接转化目标的广告需求(如新品认知)也更适用。
🧠 Mental Model: 商铺出租的三种收租方式
把媒体想成房东。CPT 是「整栋包租」:租客付固定租金,生意好坏与房东无关,风险全在租客。CPC 是「按进店人数收费」:房东得想办法引来可能进店的人流,租客则为每个进店的人买单。CPS 则是「纯提成伙计」:卖出才分成,卖不出分文不取——风险全在替他吆喝的平台一方。计费模式谱系上的每一次移动,本质上都是风险在房东与租客之间的重新分配。
Analysis: 计费模式的选择并非纯技术决策,而取决于双方的数据能力与对转化链路的掌控。当平台对「从展示到成交」的全链路有足够掌控力、且广告主(卖家)的服务流程大体相同时——例如淘宝的广告平台——CPA/CPS 类结算才真正可行。链路越不可控,计费单位就越要往展示端收缩。
12.2.1 计费模式谱系:从买时段到买销售
有了「风险归属」这把钥匙,我们可以把主流计费模式排成一条谱系:从按时间买断,到按展示、按点击、按行为、按销售付费。计费单位离最终转化越近,广告主的价值模型越贴合,平台承担的风险也越大。
CPT(Cost Per Time,包时段付费)与 CPD(Cost Per Day,包天付费) 是谱系最左端。国内很多网站至今仍按「一个月多少钱」的固定收费模式售卖广告位,阿里妈妈的按周计费广告、门户网站的包月广告都属于此类。它粗糙——展示给了谁、有没有人看,一概不知,无法保障客户的利益;但也省心,能给网站带来稳定收入,因此常见于 合约的品牌广告 ,出现在各个网站的核心 banner 模块。相比 CPS,CPD 对合作的基础条件没有过高要求、容易促成双方合作;劣势在于长期合作中不如 CPS 实时有效。
CPM(Cost Per Mille,千次展示付费) 向效果迈出了第一步:
其中「消耗」即广告主投放广告的花费。CPM 意为每千人印象成本,按曝光量收费,让广告开始向「面向效果」方向进化,也是 RTB(实时竞价)系统的常见计费方式。CPC(Cost Per Click,每点击付费) 再进一步:
关键词广告等依据效果付费的形式一般采用这种定价模式,同样是 RTB 中的主流计费方式。CPA(Cost Per Action,按行为付费) 则根据每个访问者对网络广告所采取的行动收费,行为有特别定义——形成一次交易、获得一个注册用户等。CPS(Cost Per Sales,按销售付费) 按实际销售产品的提成换算广告刊登金额,广告主为规避广告费用风险,按照点击之后产生的实际销售提成付费,常见于网络联盟中各个小网站的计费。
dCPM(dynamic CPM,动态千次展示付费) 值得单独一说。它是 DSP(需求方平台)普遍采用的结算体系:与市场上讲的固定 CPM(相应地称为 flat CPM)不同,dCPM 基于 RTB 技术诞生,指的是 每一次 impression 的出价都是变化的。其每次出价均依据广告主广告投放的效果(一般是 CPS)来实时计算,以得出对广告主最有利的价格,从而保证广告主的利益;同时又因为以 impression 与媒体结算,也确保了媒体的收益。一句话概括:对媒体按展示结算、对广告主按效果优化——dCPM 正是我们在 12.2.0 说的双方博弈的一个工程化解法。
如图,谱系左端风险压在广告主肩上,右端压在平台肩上,CPC 居中平衡。更精确地说,可以用「谁做关键决策」来标注风险归属: CPM 市场里 eCPM 固定,相当于决策(与风险)全部交给广告主——平台保证展示,展示之后能否带来点击与转化,平台概不负责。CPC 市场是折中 :点击价值由广告主判断(体现在出价),点击率则由更了解流量的平台动态预估(如 Google)——平台用 CTR 预测来管理自己承担的那部分风险。CPA/CPS 市场两者均动态,相当于平台做决策,风险归于平台 ;淘宝广告平台采取此类结算,正因为其广告主(卖家)的服务流程大致相同,平台对转化链路的掌控足够强。
| 计费模式 | 计费单位 | 谁做关键决策 | 风险归属 | 典型场景 |
|---|---|---|---|---|
| CPT/CPD | 时段 / 天 | 媒体定价,广告主买断 | 广告主 | 品牌包段、核心 banner |
| CPM | 千次展示 | 平台保量,eCPM 固定 | 广告主 | RTB 展示竞价、GD 合约 |
| CPC | 每次点击 | 广告主定点击价值,平台预估 CTR | 双方共担(折中) | 关键词广告、广告网络 |
| CPA | 每次行为 | 平台 | 平台 | 服务流程标准化的生态(如淘宝) |
| CPS | 每次销售 | 平台 | 平台 | 网络联盟、返利 |
💡 Key Insight: 经济学有句话叫「价格围绕价值上下波动」,好的定价机制应当让价格无限逼近价值。但广告主与供应方对「价值」的认知天然错位,静态定价谈不拢,于是市场给出的答案是——让市场自己定价。竞价模式是目前双方都能认可的定价方式,其核心问题是如何让更多的需求方参与竞价、如何提供更细粒度的竞价,这正是 12.3 的主题。
12.2.2 核心指标体系:eCPM 统一度量衡
计费模式定了规矩,还需要一套指标来度量「规矩执行得怎么样」。三个最基础的效果指标构成了广告数据分析的通用语言。
CTR(Click-Through Rate,点击率) 衡量一个广告在多次展现中用户的平均点击次数:
CVR(Conversion Rate,转化率) 衡量用户的点击和最后下单之间的关系:
ROI(Return On Investment,投资回报率) 衡量广告主花钱打广告带来的成交额与广告花费之间的关系:
这三个指标层层递进:CTR 是平台的「供给侧指标」——它决定了流量质量;CVR 连接点击与转化,刻画需求端的成色;ROI 则是广告主最终投票的依据——ROI 长期低于 1(或行业可接受阈值)的广告主会用脚投票,撤走预算。
问题来了:当 CPC 计费的广告和 CPM 计费的广告同场竞技时,平台怎么比较它们?答案是 eCPM(effective CPM,千次展示期望收益)——每千次展示的期望收益,它把所有计费模式折算到同一把尺子上:
- CPC 计费下 :。其中 pCTR 是平台对这次展示点击率的预估,bid 是广告主按点击出的价;两者相乘即「每次展示的期望收入」,再乘 1000 折算到千次展示。
- CPM 计费下 :。千次展示本身就要付这么多钱,期望收益就是出价本身。
于是平台的排序逻辑水到渠成: 对每次展示机会,把所有候选广告折算成 eCPM,按 eCPM 降序排列 ,依次分配展示位。看一个数值例子:广告 A 出价 2.0 元、pCTR 3%,广告 B 出价 5.0 元、pCTR 1%,广告 C 出价 1.0 元、pCTR 8%。三个广告的 eCPM 分别是 元、 元、 元。出价最高的 B 反而垫底——它的点击概率太低,赢下这次展示对平台而言并不划算;最终 C 胜出。
如图所示,eCPM 是广告市场的「通用货币」:无论候选来自哪种计费模式,先兑换成 eCPM 才能同台比较。这也解释了为什么 12.2.0 说计费模式是宪法——eCPM 公式的形态完全由计费模式决定,而 pCTR 是否准确(12.2.4)直接决定这把尺子准不准。
🧠 Mental Model: 机场货币兑换柜台
想象一个免税店同时收美元、欧元、日元。收银台不会拿三种货币直接比大小,而是先按汇率全部折成美元再标价。eCPM 就是广告交易的汇率柜台:CPC 的「美元」、CPM 的「欧元」、CPA 的「日元」,统统折成「每千次展示期望多少收益」。汇率(pCTR、bid)一旦算错,标价就失真——这正是下一节 CTR 预估的分量所在。
最后把 12.2.0 的两大广告形态在此收拢: 品牌广告按展示量计费、以合约方式交易 (CPT/CPD/CPM,注重长期影响), 效果广告按效果计费、以竞价方式交易 (CPC/CPA/CPS,追求短期转化行为)。两类广告在投放时机、创意形态、系统模块上分流,但只要进入同一个广告位,平台仍然用 eCPM 这把尺子统一裁决。
12.2.3 合约广告与在线分配:先保量,再保质
竞价是现代广告的主角,但在它之前,合约广告统治了互联网广告的第一个十年,至今仍占据高端品牌预算。理解它是理解整个广告系统演化的必要一环。
担保式投送(Guaranteed Delivery, GD) 是合约广告的核心机制,其要点可以概括为: 基于合约的广告机制,约定的展示量未完成需要补偿 ;采用「量优先于质」的方式——先把量保住,再谈优化;以 CPM 结算 ;投送由 服务端决策 (而非竞价时实时决定)。GD 的受众定向建立在两项预测技术之上: 点击率预测 与 流量预测——前者估计「展示给某人群的效果」,后者估计「未来某类流量有多少」,二者共同支撑「能否在合约期内完成保量」的承诺。
合约广告的技术核心是 在线分配(Online Allocation) 问题:把广告与流量的匹配建模为 Ad → (Context, User) 的二部图优化。图的一侧是携带定向条件的广告合约,另一侧是 (上下文, 用户) 联合刻画的一次次流量供给;每次展示到来时,系统要在「满足各广告主合约量」的约束下完成分配。目标函数可根据需要调整(如最大化总收益或总点击),经典解法是 通过构造对偶问题求解——把每个合约的量约束转化为对偶变量(影子价格),在线分配时按「收益减影子价格」的净值得失做决策。
如图,合约①(汽车品牌,定向男性 25–40 岁)可以匹配 (体育频道, 男性用户) 的流量,也能从 (首页信息流, 全量用户) 中筛出定向人群;合约③定向不限,则与所有供给节点相连。分配算法要在流量预测给出的供给量之上,为每条流量选一个「既能完成保量、又尽量高价值」的合约。
流量预测 本身是个有趣的问题:它可以视为以广告 为 Query、对 空间进行检索的 反向检索问题。困难在于 联合空间规模过大,需对 、 分别处理——这与正向的「以用户请求检索广告」恰好是同一枚硬币的两面。
Analysis: 在线分配与竞价(12.3)的分工可以这样理解:合约的定向粒度粗(按人群包、频道售卖),竞价的定向粒度细(到单次展示、单次出价);合约卖确定性(保量、补偿),竞价卖不确定性(价高者得)。GD 的缺点是受众定向分类不够细致,且合约销售中品牌广告主对曝光有独占要求(如竞品排斥),进一步收紧了分配的自由度。当一个市场的流量供给和需求都足够稠密时,粗粒度合约会逐步让位于细粒度竞价——这就是广告形态从展示量合约走向 RTB 的经济学动因。
12.2.4 点击率预测:承接排序模型的新使命
12.2.2 已经埋下伏笔:CPC 计费下 eCPM = pCTR × bid × 1000,点击率预估的准确度直接决定排序这把尺子准不准。现在我们把 CTR 预估当作一个独立的建模问题来看——它与你在 Part 3 见过的排序模型既同源、又不同命。
CTR 预测的标准形式是概率模型 :给定广告 、用户 、上下文 ,估计用户点击的概率。你可能会想:这不就是 Part 3 的点击率模型换个场景吗?模型结构确实可以复用,但 任务性质变了——回归比排序更合适。推荐系统的排序模型只需保证候选间相对顺序正确(AUC 高即可),而广告的实际排序依据是 eCPM:CTR 预估要 乘以出价 之后再比较。一个系统性高估CTR 的模型,会把低出价广告推到不该有的高位;系统性低估则相反。换言之,广告系统需要的是 尽可能准确的 CTR 绝对值 ,而不仅是候选间的相对排序正确——这是 CTR 建模区别于推荐排序的第一性原理。
新广告冷启动:层级结构 back-off
新广告上线时没有任何点击统计,pCTR 从何而来?答案是 利用广告的层级结构 : creative → solution → campaign → advertiser (创意 → 投放单元 → 广告计划 → 广告主)。新创意没有统计,但它所属的 campaign 可能有;campaign 也没有,就再往上退到 advertiser 一层,用同广告主历史广告的 CTR 及广告标签来估计。这种 back-off(回退) 策略与推荐系统处理新物品的思路一致:用结构先验弥补统计缺失。
动态特性:动态特征与在线学习的权衡
广告市场的分布变化极快——素材疲劳、季节波动、突发热点都会让昨天训练的模型今天失准。应对之道有两个方向,各有代价。动态特征 :在标签组合维度上聚合点击反馈统计,作为特征喂给模型(即多层次点击反馈),特点是「快速调整特征」——模型不动、特征实时变;其优势是工程架构扩展性强、对新 组合有较强的 back-off,缺点是在线特征存储量大、更新要求高。在线学习 :让模型本身随新数据流式更新,「快速调整模型」,代价是训练与服务的工程复杂度。工业系统常两者并用:动态特征兜住短周期波动,在线学习跟上中长期漂移。
探索与利用:为长尾组合积累统计量
无论特征多好、模型多新,都绕不开一个冷峻的事实: 组合空间近乎无限,绝大多数组合从未获得过展示,其 CTR 无从估计。E&E(Exploration & Exploitation,探索与利用) 框架的任务就是:为长尾 组合创造合适的展示机会以累积统计量,从而更准确地估计 CTR、提升整体广告收入。探索不是做慈善——今天的「浪费」是一次投资,为的是明天更准的预估;但探索的量和有效性需要严格控制,否则直接侵蚀当下收益。三种经典策略:
- ε-greedy :以 ε 比例的流量随机探索,其余流量利用当前最优。实现最简单,探索效率也最低。
- UCB(Upper Confidence Bound,上置信界) :为每个候选计算期望收益的上置信界,选 UCB 最大的 arm;被选择次数越多,UCB 越接近真实期望收益——天然兼顾「没试过的要多试」与「表现好的要多用」。
- Contextual Bandit(上下文老虎机) :对每次展示,用 arm 的 特征矢量 代替 arm 本身做决策,实现降维——不必为每个具体广告单独估计,而是在特征空间中泛化,恰好呼应 back-off 的层级思想。
Analysis: E&E 的三种策略在广告场景中的适用性:ε-greedy 适合作为保底策略或冷启动初期;UCB 在候选集合较小时收益明确,但候选数巨大时上界计算与存储都是负担;Contextual Bandit 用特征降维绕开了候选爆炸,是现代广告系统探索模块的主流形态。共同的原则是:探索流量必须「花在刀刃上」——优先探索那些一旦估准、期望收益提升最大的长尾组合。
到这里,一次广告请求的决策链已经完整:候选广告经定向检索进入排序,pCTR 模型给出点击概率,与出价相乘折算成 eCPM,降序排列后由高到低分配展示。但请注意——eCPM 排序只是入场券,它决定谁上场;真正决定平台「收多少钱」的,是竞价机制。同一个 eCPM 第一名,按 GSP(广义第二高价)机制支付的价格可能与自己的出价相去甚远。谁该付多少、为什么诚实出价可能是(也可能不是)最优策略、VCG 如何用「外部性」定价——这些问题属于机制设计的领地,我们在 12.3 展开。
⚠️ Common Mistakes in 12.2
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把 CTR 预估当排序问题 | 「AUC 够高就行,绝对值无所谓」 | 广告按 eCPM 排序,CTR 要乘以出价;系统性高估/低估都会改变排序与计费 | 按回归/校准问题评估,关注预估绝对值与真实值的偏差 |
| 2 | 混淆 eCPM 与 CPM | 「eCPM 就是千次展示成本」 | CPM 是计费模式(成本口径),eCPM 是千次展示 期望收益 (收入口径),是排序的统一度量衡 | 记住 e = expected / effective,eCPM 服务于平台排序决策 |
| 3 | 认为 CPA/CPS 对平台更优 | 「按效果收费平台肯定赚得多」 | CPA/CPS 下点击率与价值皆动态,决策与风险全归平台,转化链路不可控时平台血亏 | 只有链路掌控强、服务流程标准化的生态(如淘宝)才适用 |
| 4 | 认为越精准的广告市场价值越大 | 「精准投放 + 大数据必然显著提高营收」 | 媒体与广告主是相关博弈关系,精准投放的收益归属取决于计费与定价机制 | 从风险归属与博弈角度分析每一方的激励 |
| 5 | 忽视 dCPM 与 flat CPM 的区别 | 「dCPM 不就是 CPM 吗」 | flat CPM 千次价格固定;dCPM 每次印象的出价都随投放效果实时变化 | 区分「与媒体按展示结算」和「对广告主按效果优化」两个口径 |
| 6 | 合约分配只做 CTR 预测、不做流量预测 | 「模型够准就能完成保量」 | GD 的量约束靠流量预测支撑;供给估计错了,保量承诺必然落空 | 在线分配 = 点击率预测 + 流量预测,二者缺一不可 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 计费模式即宪法 | 计费单位决定风险归属:广告主按效果反推价值,媒体关心单位资源收入 | 一切广告算法都在计费模式划定的博弈规则下工作 |
| 计费谱系 | CPT/CPD → CPM → CPC → CPA/CPS,风险从广告主渐移向平台 | 选错计费模式的平台会把风险揽到自己身上 |
| 三大指标 | CTR=点击/展现,CVR=下单/点击,ROI=下单金额/消耗 | 广告数据分析的通用语言 |
| eCPM | CPC 下 = pCTR×bid×1000;CPM 下 = 出价;按其降序排序 | 跨计费模式的统一度量衡,排序的尺子 |
| GD 与在线分配 | 保量、未完成需补偿、量优先于质、CPM 结算;Ad→(Context,User) 二部图,对偶求解 | 合约广告的技术核心,与竞价形成粗/细粒度互补 |
| CTR 预估 | 回归而非排序(需要绝对值准确);冷启动用 creative→advertiser 层级 back-off;动态特征 vs 在线学习;E&E 积累长尾统计 | eCPM 排序的准确性完全依赖 pCTR 的校准 |
❓ FAQ
Q1: CPC 计费下,平台如何管理自己承担的风险?
A: 平台对点击率更了解(如 Google),通过 CTR 预估把「展示后会不会被点击」的不确定性管起来:对 pCTR 低的广告降低展示比例或要求更高出价。这正是 CPC 被称为风险折中点的原因——广告主判断点击价值并出价,平台预估点击率并兜住流量质量。
Q2: 为什么 CPM 计费下 eCPM 就等于出价?
A: CPM 计费按千次展示收费,广告主的出价本身就是「千次展示愿意付的钱」,也就是平台千次展示的期望收益,无需再乘 pCTR。这也意味着 CPM 市场的 eCPM 固定,决策与风险全部交给了广告主。
Q3: 合约广告与竞价广告的本质区别是什么?
A: 三点:交易方式上,合约是提前协商的担保式售卖,竞价是实时交易;计费上,合约以 CPM 展示量结算、量优先于质,竞价按 CPC/CPA 等效果计费;定向粒度上,合约按人群包/频道等粗粒度售卖且品牌主有独占要求,竞价可细到单次展示。市场供需越稠密,越有利于细粒度竞价。
🔗 前后关联
- 12.1 (广告生态全景)中的广告主、媒体、平台角色分工,是本章风险归属分析的前提。
- 12.3 (竞价机制)承接本章结尾:eCPM 排序决定谁上场,GSP/VCG 等机制决定收多少钱。
- 3.x (排序模型)的 CTR 模型结构是本章 pCTR 建模的基础,但广告场景对绝对值校准提出了更高要求。
- 8.3 (端到端生成式广告)把竞价机制内嵌进生成模型,可视为本章 eCPM 排序与 12.3 竞价机制在前沿架构下的统一。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 12.2.1 — 指标换算 🟢 Easy
某电商广告主一天消耗 600 元,获得 150,000 次展示、3,000 次点击、120 个订单,订单总金额 3,600 元。请计算 CPM、CPC、CTR、CVR、ROI。
Sample Input: 消耗 600 元;展示 150,000;点击 3,000;订单 120;下单金额 3,600 元
Sample Output: CPM = 4 元,CPC = 0.2 元,CTR = 2%,CVR = 4%,ROI = 6
💡 Solution (click to reveal)
Approach: 直接套用五个指标的公式。
Key points:
- CPM 与 CPC 互为倒数关系换算:,代入 验证一致。
- ROI = 6 意味着每花 1 元广告费带来 6 元成交额——这是广告主续投的核心依据。
Problem 12.2.2 — eCPM 排序 🟡 Medium
某广告位一次请求收到三个 CPC 计费的候选:广告 A 出价 1.5 元、pCTR 2%;广告 B 出价 6.0 元、pCTR 0.5%;广告 C 出价 3.0 元、pCTR 1.2%。请计算各自的 eCPM 并给出展示顺序。若还有一个 CPM 计费的广告 D 直接出价 40 元(千次展示),它应排在第几位?
💡 Solution (click to reveal)
Approach: CPC 计费用 ,CPM 计费 eCPM 即出价。
- A: 元
- B: 元
- C: 元
- D:CPM 计费,eCPM = 40 元
降序排列: D(40)> C(36)> A(30)= B(30)。A 与 B eCPM 相同,可按次要规则(如质量分、出价)打破平局。
Key points:
- eCPM 让不同计费模式的广告同台竞技:D 不需要乘 pCTR,因为它的期望收益与点击无关。
- B 出价最高(6 元)却与出价最低的 A 并列垫底——高出价救不了低点击率。
Problem 12.2.3 — CTR 预估的校准问题 🟡 Medium
模型甲与模型乙在同一个广告位上 AUC 完全相同(候选间相对顺序一致),但模型甲对所有广告的 pCTR 系统性低估一半(真实 CTR 2% 时预估 1%)。在 CPC 计费、存在 CPM 广告竞争的环境下,这会对排序和平台收入造成什么影响?
💡 Solution (click to reveal)
Approach: eCPM = pCTR × bid × 1000,pCTR 被低估一半等价于所有 CPC 广告的 eCPM 被砍半。
排序上:CPC 广告的 eCPM 整体下移,本应胜过高 eCPM CPM 广告(如出价 40 元)的优质 CPC 广告可能落败——例:某广告真实 ,被低估后只剩 30,输给了 40 元的 CPM 广告。收入上:平台错失期望收益更高的展示,同时低点击率广告的惩罚也被同比例弱化,流量质量下滑。
Key points:
- 这就是「回归比排序更合适」的原因:AUC 衡量相对序,而 eCPM 排序需要 CTR 绝对值准确。
- 广告系统对 CTR 模型的校准(calibration)要求,是它区别于推荐排序模型的关键工程约束。
Problem 12.2.4 — UCB 探索策略 🔴 Hard
某 E&E 模块用 UCB 管理两个候选广告的探索。目前总请求 次:广告甲被选 100 次、平均点击率 0.10;广告乙被选 10 次、平均点击率 0.08。按 计算两者的 UCB(),判断下一次展示选谁,并解释为什么平均点击率更低的反而可能胜出。
💡 Solution (click to reveal)
Approach: 分别计算置信半径 再加均值。
- 甲:,
- 乙:,
下一次展示选 广告乙。乙平均点击率虽低,但只被试了 10 次,估计的不确定性(置信半径)极大,其真实点击率可能远高于当前观测——UCB 为长尾组合创造展示机会以累积统计量,正是 E&E 的核心动机。随着乙被选择次数增多,其半径收缩,UCB 将逐渐逼近真实期望。
Key points:
- UCB 项 = 均值 + 不确定度,天然平衡探索(半径大)与利用(均值高)。
- 探索的量必须严格控制:本例中若把大部分流量都给乙,短期收入会受损——E&E 是投资而非慈善。
🏆 Challenge: eCPM 排序 + GSP 支付
某广告位(CPC 计费)有三个候选:广告 A 出价 3.0 元、pCTR 2%;广告 B 出价 4.0 元、pCTR 1%;广告 C 出价 2.0 元、pCTR 2.5%。(a) 计算 eCPM 并给出排序;(b) 若采用 GSP(广义第二高价)机制,胜者按「下一名的 eCPM 折算到自己计费口径」支付,即支付 CPC = 下一名 eCPM ÷ 胜者 pCTR ÷ 1000,求胜者的实际点击单价;(c) 验证该单价不超过胜者出价(个体理性),并说明 GSP 的完整博弈性质在 12.3 哪里展开。
💡 Hint
(a) A:;B:;C:。排序 A > C > B。
(b) 胜者 A 支付 = 下一名 C 的 eCPM ÷ (A 的 pCTR × 1000) = 元/点击。
(c) 满足个体理性——广告主永远不会支付超过自己的出价。注意支付价由 下一名 的 eCPM 与 自己 的 pCTR共同决定:这正是「eCPM 排序决定谁上场、竞价机制决定收多少钱」的含义。GSP 并非 truth-telling(与 VCG 不同),广告主有压价博弈的激励,完整的机制分析(VCG、GSP 的均衡性质)见 12.3。
竞价机制:从一价到二价
📝 Before You Continue: 本章需先读 12.2(eCPM 与计费模式)——所有排序与支付公式都建立在 eCPM 口径之上。本章引入的 IC/IR 概念会在 8.3(端到端生成式广告 EGA)中被深度使用,建议两章对照阅读。
搜索结果页最顶上那几条广告位,每个值多少钱?这个问题没有「正确答案」——它取决于一次拍卖怎么设计。广告系统价值 = 广告转化效率 × 计价机制 × 广告资源量 × 投放效率,计价机制是四大支柱中最「制度性」的一个:它不优化任何模型,却决定了所有参与者的行为方式。经济学告诉我们「价格围绕价值上下波动」,而一个好的 竞价机制(Auction Mechanism) 应当让价格无限逼近其价值。
这条路走得并不平坦。1998 年 Overture 首创付费搜索时采用一价拍卖,结果广告主们陷入了永不停歇的出价追逐战;2002 年 Google 引入二价思想后市场才稳定下来;而到 2019 年前后,程序化交易的头部交易所又集体回到了一价。一价 → 二价 → 再回一价,这个循环的每一步都蕴含着机制设计的深层逻辑。
读完本章,你将能够:
- 用 位置拍卖(Position Auction) 模型描述多坑位广告的分配与计价,写出期望价值 与 eCPM 排序规则
- 解释 广义第一高价(GFP) 为何不存在稳定的纯策略纳什均衡,并逐步推演两人出价的震荡循环
- 证明单坑位 二价拍卖(Vickrey Auction) 下如实出价是占优策略,并给出 激励兼容(IC) 与 个体理性(IR) 的形式化定义
- 手算 广义第二高价(GSP) 与 VCG 在多坑位下的支付与效用,说清二者在 truth-telling 与收费水平上的差异
- 用交互式模拟器亲手验证「虚报会发生什么」,完成 5 道分层练习题
12.3.0 位置拍卖模型:把「卖广告」变成数学问题
我们先建立一个能统一描述所有竞价场景的框架。设页面上有 个广告坑位、 个参与竞价的广告主;广告主 对「一次点击」有 真实估值(Valuation) (这是他的私人信息,平台看不到),并向平台提交 出价(Bid) (CPC 口径,即声称每次点击愿意付多少钱)。坑位有天然的优劣:位置越靠前越容易被点击,我们用 位置点击率 刻画, 是坑位 的点击率。
于是广告主 拿到坑位 的期望价值为:
一次点击值 元,坑位 以概率 产生点击,二者相乘就是这次展示对广告主的期望价值。这个模型叫 位置拍卖(Position Auction) :多个广告主竞争多个有次序的坑位,坑位之间的唯一差异是点击率。对展示广告(CPM 结算)只有一个坑位,,模型退化为单坑位拍卖;搜索广告的信息流广告位、电商的推荐坑位,都是 的情形。
平台怎么看?平台看不到 ,只能按申报的出价计算每个组合的期望收益,即 12.2 引入的统一口径:
把广告主按出价从高到低排、依次配到点击率从高到低的坑位,总 eCPM 最大(排序不等式的直接推论)。所以无论采用哪种定价机制, 分配规则 几乎总是「按出价(乘以质量分)排序」——真正让各家机制分道扬镳的,是 定价规则 :赢家到底付多少钱。
🧠 Mental Model: 排座位收费
把广告位想成教室里有次序的座位:前排看得清(高 CTR),后排看不清(低 CTR)。每个学生(广告主)心里都有前排座位值多少钱的底价(),但报名(出价 )时可以撒谎。老师(平台)按报名高低排座位,然后收学费。关键在于学费怎么定:按「你自己报的价」收,学生就会疯狂试探底线;按「刚好压过你后面那个人」收,报真实底价才不吃亏。本章的全部内容,就是这一句直觉的严格化。
任何竞价机制都可以拆成两半: 分配规则(Allocation Rule) 决定「谁赢哪个坑」, 定价规则(Pricing Rule) 决定「付多少」。分配规则决定市场的效率(好广告是否拿到好位置),定价规则决定市场的诚实度(广告主是否愿意报出真实估值)。接下来的三节,我们将看到同一套分配规则配上三种不同定价规则——一价、二价、外部性定价——会导出截然不同的市场形态。
Analysis: 位置拍卖模型有两个简化假设:坑位点击率只与位置有关(真实系统还要乘以广告自身的质量分,即 排序);广告主估值在一次拍卖内不变。尽管如此,它足以揭示机制设计的全部分歧点——分配与定价的分离、激励与稳定的权衡,后续所有工业复杂度都是围绕这个骨架做的加法。
12.3.1 一价拍卖 GFP 的失败:为什么「付自己出的价」行不通
最直觉的定价规则是 一价拍卖(First-Price Auction) :谁出价高谁赢,赢家按自己的出价支付。推广到多个坑位就是 广义第一高价(Generalized First Price, GFP) :按出价排序分配坑位,每个人按自己的出价付钱。1998 年 Overture 用这套机制开创了付费搜索,也在随后几年里让整个市场陷入了 chronic 的震荡。
问题出在哪?在一价下,你的支付与你的申报完全绑定——报高了自己多付,报低了自己省钱。假设单坑位、两个广告主 A 和 B,估值分别为 、(元/次点击)。每一轮拍卖的出价动态如下:
| 轮次 | A 的出价 | B 的出价 | 领先者 | 领先者该轮效用(元/点击) |
|---|---|---|---|---|
| 1 | 1.00 | 1.01 | B | 0.04 |
| 2 | 1.02 | 1.03 | B | 0.02 |
| 3 | 1.04 | 1.05 | B | 0.00(贴到估值,无利可图) |
| 4 | 1.04 | 0.90 (崩落回撤) | A | 0.06 |
| 5 | 0.91 (压价到刚好压制) | 0.90 | A | 0.19 |
| 6 | 0.91 | 0.92 | B | 0.13 |
| 7 | 0.93 | 0.92 | A | 0.17 |
| … | 缓慢爬升,逼近 1.05 后再次崩落 |
注意每一轮的两个细节:落后者永远只比对手 高一丁点 (0.01)就足以抢走坑位;而领先者一旦发现对手回撤,立刻把出价砍到刚好压过对手(1.04 → 0.91)。价格呈锯齿状循环:爬升—逼近估值—崩落—再爬升,永不收敛。
这个追逐没有终点,我们可以严格说明原因。纯策略纳什均衡(Pure-Strategy Nash Equilibrium) 要求存在一个出价组合,任何一方单独改变出价都无法获益。检验任意组合 、:只要两者差距大于最小加价单位,赢家 A 就可以降到 依然获胜并省下真金白银——偏离有利;而只要 B 的估值高于 A 的当前出价,B 加价 即可夺回坑位——偏离同样有利。两条修正规则互相追逐,永远不存在「双方都不想动」的组合。这正是刘鹏笔记中的结论:一价拍卖容易导致价格频繁波动的「纳什不均衡」。
图中蓝线是 A 的出价、黄线是 B 的出价,虚线是两人的估值上限。可以看到出价互相追逐着爬升,贴到估值后崩落,然后再爬升——市场永远在寻找一个不存在的平衡点。
市场层面的后果是系统性的。平台收入随出价锯齿剧烈波动,无法预测;广告主必须七乘二十四小时盯着对手调价,运营成本高企(当年甚至催生了专门的自动出价代理);更糟的是,出价不再传达任何真实信息——你看到的 只是对手上一轮试探的结果,与他的真实估值 毫无关系。GFP 的失败告诉我们: 机制不是中性的容器,定价规则本身就在塑造参与者的行为。
Analysis: GFP 的教训在机制设计史上极为经典:分配效率没问题(出价高者得高位),坏的只是激励结构。它同时也解释了为什么「让广告主自己优化出价」在一价下行不通——出价是最优反应函数的迭代,而非一个可静态优化的参数。修复方向因此清晰:把「支付」与「申报」解耦,让谎报无利可图。
12.3.2 二价拍卖与激励兼容:让说真话成为最优策略
修复方案由经济学家 William Vickrey 于 1961 年提出(他因此获得 1996 年诺贝尔经济学奖)。二价拍卖(Second-Price Auction) ,也叫 Vickrey 拍卖 :出价最高者赢,但按 第二高出价 支付。单坑位下,赢家支付的是「别人的价」,而不是「自己报的价」。
为什么这一改动如此关键?我们证明:在二价下,如实出价 是 占优策略(Dominant Strategy)——无论别人怎么出,说真话都不比任何谎报差。设你的估值为 ,其他广告主的最高出价为 ,考察两个偏离方向:
- 出低价 :你的支付本来就跟自己的出价无关(赢了付 ),所以出低唯一改变的,是那些 的局面——这些局你按真话本可以赢且效用 ,现在却白丢了。赢面缩水,支付没变, 只会变差。
- 出高价 :多赢来的都是那些 的局面——你赢了,但要付 ,效用 ,比不赢(效用 0)更惨。原本能赢的局面支付照旧, 也只会变差。
两个方向都堵死,恰好按估值出价同时避免了「白丢赢面」和「亏本赢」两种错误。支付与申报解耦,申报才敢暴露真话——这是二价拍卖全部魔力的来源。
🧠 Mental Model: 精明的举牌代理
二价拍卖等价于你委托一位绝对精明的代理去现场举牌:你告诉他你的底价 ,他永远只把价加到「刚好赢过在场最高出价」为止。你不用猜对手、不用留利润空间——报出真实底价,代理自动帮你省到极限。密封二价拍卖只是把这个代理做成了制度。
这个性质有正式名字,它们是贯穿本章与 8.3 的两个核心概念。激励兼容(Incentive Compatibility, IC) :如实报告估值是占优策略,形式化地,对任意谎报 :
个体理性(Individual Rationality, IR) :参与拍卖不会让理性的参与者吃亏,即支付不超过申报价值 ,效用非负。IC 保证「说真话不亏」,IR 保证「参与不亏」——二者合起来,市场才有稳定的诚实参与者。
💡 Key Insight: 8.3 的 EGA 把 IC 量化为 ex-post regret(谎报最多能多赚多少,IC regret = 0)并写进损失函数,用 Sigmoid 支付率保证的正是 IR。本章的定义是那套端到端 machinery 的经济学原点——机制设计正从「后处理规则」变成「可微的模型约束」。
Analysis: 二价的严格 IC 只在单坑位成立。坑位一多,「按第二高出价支付」无法直接推广——不同坑位点击率不同,支付必须跨位置折算,而这个推广(下一节的 GSP)恰好丢掉了占优策略性质。单坑位是机制设计的实验室,多坑位才是工业战场。
12.3.3 广义第二高价 GSP:多坑位的工程折中
多坑位下怎么把二价思想推广? 广义第二高价(Generalized Second Price, GSP) 给出工业界沿用二十年的答案:仍按出价(eCPM)排序分配坑位,但第 名广告主 按「下一名的 eCPM 折算到自己点击率」支付。CPC 计费下,第 位(坑位点击率 ,下一名出价 、坑位点击率 )的每点击支付为:
末位没有「下一名的坑位」可参照,按 最低保留价(Reserve Price) 支付。直觉有三层。其一:你抢占坑位 ,把下一名挤到了坑位 ,你造成的「展示机会损失」以 eCPM 计就是 ,除以 折算成你的每次点击单价。其二:——你付的 eCPM 恰好等于下一名在其位置上的 eCPM,即 保住第 名所需的最小 eCPM。其三:你的支付只取决于下一名的出价,与你自己的申报解耦了一半——这正是二价思想的残留。
给一个完整数值例子。三个坑位 ,保留价 ;三个广告主甲、乙、丙估值分别为 (先假设如实出价以便对比机制,)。按出价排序:甲 坑位 1、乙 坑位 2、丙 坑位 3。支付与效用逐一可算:
| 坑位 | CTR | 广告主 | 出价 | 支付 (元/点击) | eCPM 支付 | 效用 |
|---|---|---|---|---|---|---|
| 1 | 0.40 | 甲 | 4.0 | 0.60 | ||
| 2 | 0.20 | 乙 | 3.0 | 0.20 | ||
| 3 | 0.10 | 丙 | 2.0 | 保留价 | 0.05 |
甲出价 4 元却只付 1.5 元——省下的 2.5 元正是二价机制给「敢报真话」的奖励。
但 GSP 有一个必须诚实地面对的缺陷: 它不是严格 truth-telling 的。刘鹏笔记的原话是:GSP「整体市场不是 Truth-telling 的,与 VCG 相比会收取广告主更多的费用」。用一个两坑位反例看清「说真话不必最优」。设 ,保留价 ;甲 、乙 ,均如实出价。甲占坑位 1,支付 ,效用 。但若甲把出价降到 2.0(主动落到坑位 2),只需付保留价 0.20,效用变为 ——说真话不是最优策略。GSP 下最优出价依赖对手的出价,不存在占优策略;当坑位间点击率差距小、下一名出价又高时,主动降档反而更划算。
那 GSP 为什么没有像 GFP 一样崩掉?因为它在博弈层面仍有秩序。GSP 存在 对称纳什均衡(Symmetric Nash Equilibrium, SNE) ,且该均衡是 无妒忌(Envy-free) 的:均衡中每个广告主都不想与相邻位置的人互换——若你顶到上一位,就得支付上一位的价位,效用不会提高。无妒忌意味着没有人有动机去抢别人的位置,市场得以稳定。也正是在均衡意义上,GSP 与 VCG 的收费差异显现:GSP 的均衡出价系统性高于真实估值,VCG 结算位于均衡收费区间的下界,因此 GSP 在多数均衡下 收取广告主更多费用。
Analysis: GSP 的胜利是工程折中的胜利。计算上,每次清算只需下一名的出价与两个坑位的 CTR,无需任何全局信息,毫秒级出价服务毫无压力;语义上,「你的价格由你后面的人决定」广告主一听就懂。理论性质(严格 IC)换工程性质(简单、稳健、可解释),这笔交易在二十年的工业实践中被证明是划算的——直到程序化时代多中介链路打破了这个平衡(见 12.3.5)。
12.3.4 VCG 机制:为「外部性」定价
如果说 GSP 是工程折中, VCG 机制(Vickrey-Clarke-Groves Mechanism) 就是理论最优解。它的定价哲学一句话可以说完: 每个广告主的收费,等于他给其他所有参与者造成的外部性损害——「你不在场,其他人本可多赚多少」。你被分配到坑位 ,就把你身后所有人往下挤了一位(甚至挤出榜单),每个人因此损失的价值之和,就是你该付的总账:
每点击支付再按坑位点击率折算:(实际系统再与保留价取大)。
🧠 Mental Model: 用地补偿
一块地多个申请人竞拍,VCG 的规则是:赢家不按自己出价付钱,而是补偿所有落选者因此损失的价值合计。你占用这块地的社会成本,就是别人失去它的机会成本——为机会成本付费,而不是为「赢」付费。
先验证一个关键退化:单坑位下 VCG 恰好等于二价。你在场时其他人福利为 0;你不在场时,第二名拿到唯一坑位,福利为 。外部性 ,折算到每点击支付 ——正是第二高出价。二价拍卖是 VCG 的单坑位特例。
再算一个两坑位的完整例子。广告主甲、乙、丙估值 ,如实出价;坑位 (丙落榜)。分配仍是甲 坑位 1、乙 坑位 2。逐个计算外部性:
甲(坑位 1) :没有甲时,乙升至坑位 1()、丙升至坑位 2(),他人福利合计 ;有甲时,乙在坑位 2()、丙落榜(),合计 。外部性 ,每点击支付 ,效用 。
乙(坑位 2) :没有乙时,丙拿到坑位 2(),甲不动(),合计 ;有乙时,丙落榜,合计 。外部性 ,每点击支付 ,效用 。
丙(落榜) :没有丙时其他人不变,外部性为 0,支付 0,效用 0。
注意乙的账单为什么这么算:他损害的不是甲(甲反正拿坑位 1),而是被挤落榜的丙——VCG 精确到「每个人的位移」,而 GSP 只看下一名的出价折算,这就是两者的全部差距。
VCG 最诱人的性质是: 整体市场是 truth-telling 的 (刘鹏笔记原文)——如实出价是占优策略,且对任意坑位数成立。证明的关键是一个漂亮的改写。把效用展开:
第二项是个常数——「没有你时他人的福利」根本不取决于你怎么申报。于是最大化个人效用等价于最大化第一项,即 真实的社会总福利。而机制按你的申报选择「申报福利最大」的分配;当你如实申报时,机制恰好选到真实福利最大的分配——你的私心与社会的公心在数学上被对齐了。谎报只会诱导机制选一个「你以为好、实际不好」的分配。
Analysis: VCG 的工业处境是「理论满分、落地困难」。计算上,每个赢家都要做一次「除他之外的全局重排」,每次广告请求的服务端开销是 量级,在毫秒级出价链路里代价不菲。信息上,外部性计算需要知道所有参与者的完整收益结构,多级中介的程序化市场根本拿不全。认知上,「你付的是你给别人造成的损失」对广告主太反直觉,账单难以解释、销售难以推销。因此工业界长期偏好 GSP,Meta(Facebook)是少数大规模坚持 VCG 的主流平台。
12.3.5 GSP vs VCG 对比与「回到一价」
三种机制摆在一起,差异一目了然:
| 维度 | GFP(广义一价) | GSP(广义二价) | VCG |
|---|---|---|---|
| Truth-telling | 否,虚报有利可图 | 否,非严格 IC(但存在对称纳什均衡) | 是,占优策略 IC |
| 收费水平 | 支付 = 己方出价,剧烈波动 | 多数均衡下高于 VCG | 按外部性定价,同等分配下更低 |
| 实现复杂度 | 最低(排序即清算) | 低:只需下一名出价与两个坑位 CTR | 高:每赢家一次「除他重排」 |
| 均衡稳定性 | 无纯策略纳什均衡,震荡 | 对称 NE,无妒忌,稳定 | 占优策略均衡,最强稳定 |
| 工业采用 | 早期付费搜索,已被淘汰 | 搜索/展示广告长期主流 | 少数平台(Meta 等) |
静态对比之外,值得亲手做实验。下面的交互式模拟器里有三位广告主,你可以修改每个人的出价与估值,分别在 GFP、GSP、VCG 三种机制下观察分配、支付与效用 ;还可以步进演练「压低出价」「抬高出价」之后会发生什么,验证二价/VCG 下说真话效用最大。
建议按模拟器的默认剧本走一遍:B 压低出价(GFP 下反而有利,二价系下受损)、B 抬高出价(GSP 下效用不变——无妒忌的体现,VCG 下受损)、C 抬高出价(三种机制下都吃亏,且 GSP 下还连累无辜的 A 与 B)。走完你会对「定价规则塑造行为」有肌肉记忆。
📌 行业动态:2019 年前后,Google 等头部 ADX 全面从二价转向一价拍卖,以下是这一转变的前因后果(写作时点的公开行业信息,时间线以行业报道为准)。
故事到这里本该结束,但程序化交易改写了结局。随着 头部竞价(Header Bidding) 与程序化公开竞价普及,一次展示要经过 SSP → ADX → DSP 的多级链路转售,每一级都可能抽取佣金——二价拍卖的「第二高价」在多级转售后变得不透明:DSP 赢了竞价,却算不清自己最终按谁的「第二价」付了多少。于是 2019 年前后,Google 等头部 ADX 全面转向 一价拍卖(First-Price Auction) :出价即支付,账单清清楚楚。
一价回归的代价是 truth-telling 不再由机制保证——出价直接等于支付,虚高就多付,机制的诚实性约束消失了。缺口由算法补上: 出价遮蔽(Bid Shading) 成为 DSP 的核心竞争力——用历史竞价数据估计「以出价 赢得流量的概率分布」,在出价与赢率之间做期望优化,把出价压到接近「能赢的最低价」。历史完成了讽刺的循环:一价因不稳定被二价取代,二价因不透明又被一价收回——只是这一次的「一价」,配上的是统计学习驱动的智能出价,而非 GFP 时代的裸博弈。
Analysis: 机制选择的深层规律在此显形:机制的理论性质(IC、稳定、收费)从来不是唯一的决策维度,还需要考虑信息结构(谁能看见什么)、链路复杂度(几级中介)与参与者认知成本(账单能不能看懂)。GFP 死于激励,VCG 困于复杂,GSP 赢在平衡,一价回归靠算法接管激励——每一次轮换都是当时的约束条件下最不坏的选择。
12.3.6 与推荐系统的合流
回望本章,竞价正是广告与推荐的最大分水岭。推荐系统是单边优化:内容不会谎报自己的价值,系统只需对齐用户兴趣;广告是三方博弈——用户要体验、广告主要 ROI、平台要收入,且广告主的估值是私人信息。有私人信息才有谎报的可能,有谎报的可能才需要机制设计——推荐工程师转型广告的第一课,往往就是补上这一章的博弈论视角。
但两条技术路线正在合流。第一个方向是 智能出价(Smart Bidding) :OCPC 等产品让广告主只报目标转化成本,平台代为出价,把出价换算进排序模型——bid 不再是排序分数的后处理乘子,而是作为特征与校准项进入模型,eCPM 约束被嵌入排序本身。第二个方向更彻底:8.3 的 EGA 把 Token 级竞价嵌入生成过程——分配用竞价引导生成概率,支付用独立网络学习满足 IC 的支付函数,ex-post regret 作为约束写进 Lagrangian 优化。二价拍卖「支付与申报解耦」的核心思想,在生成模型里以「分配与支付解耦」的形态重生。
机制设计的角色因此发生了根本迁移:从 后处理规则 (排序完成后跑一遍拍卖清算)变为 端到端约束 (把 IC/IR 写进损失函数、把支付函数变成可学习的网络)。这一趋势对推荐工程师是个好消息——你在 3.x 练就的排序建模能力依然是地基,而本章的机制设计语言(IC、IR、外部性、均衡)正在成为广告算法的准入门槛。读懂拍卖,才读得懂广告系统的经济学骨架。
⚠️ Common Mistakes in 12.3
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为 GSP 是严格激励兼容的 | 「GSP 是二价,大家都会说真话」 | 二价的占优策略性质只在单坑位成立;跨坑位折算后说真话不必最优 | 区分「单坑位二价(严格 IC)」与「GSP(非严格 IC,靠 SNE 稳定)」 |
| 2 | 把 VCG 的外部性算成自己的收益损失 | 「我不在场我少赚多少就付多少」 | VCG 收的是你 对别人 造成的损害,不是你自己的机会成本 | 永远用「其他人总福利之差」计算,与自己的估值无关 |
| 3 | 认为一价天然说真话 | 「付自己出的价,虚报没意义」 | 一价下出价与支付绑定,压价省钱、抬价抢位都有利可图 | 一价下 truth-telling 由 bid shading 策略补位,机制不保证 |
| 4 | GSP 跨坑位支付不做 CTR 折算 | 「第 1 名直接付第 2 名的出价 3 元」 | 不同坑位点击率不同,直接照搬会算错 eCPM 口径 | 回到 eCPM 口径: |
| 5 | 混淆保留价与第二高价 | 「只有一人出价时付第二高价」 | 无人竞争时没有「第二价」,末位/唯一赢家按保留价支付 | 末位支付 ,无下一名时付 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 位置拍卖 | ,按 eCPM 排序分配 | 多坑位广告计价的统一框架 |
| 分配 + 定价二分 | 分配规则定效率,定价规则定诚实度 | 读懂一切竞价机制的钥匙 |
| GFP(一价) | 支付 = 己方出价 | 无纯策略 NE,市场震荡,被淘汰 |
| 二价 / Vickrey | 赢家付第二高价 | 单坑位严格 IC:说真话是占优策略 |
| GSP | ,末位付保留价 | 工业主流;SNE 稳定、无妒忌,但非 truth-telling |
| VCG | 支付 = 对他人的外部性损害 | 整体 truth-telling;计算与认知成本高,落地少 |
| 一价回归 | Header Bidding 后 ADX 转一价,bid shading 补位 | 机制性质可被算法与市场结构重新分配 |
❓ FAQ
Q1: GSP 与单坑位二价差在哪?
A: 单坑位下「下一名」没有位置折算问题,GSP 退化为二价。多坑位下支付必须跨位置按 CTR 折算(),而这个推广丢掉了严格 IC——二价的占优策略性质无法跨坑位延续,GSP 的稳定靠对称纳什均衡而非占优策略。
Q2: 既然 VCG 理论性质更好,工业界为什么不买账?
A: 三个原因:计算复杂(每个赢家一次全局重排,出价链路扛不住)、需要全局信息(多级中介市场拿不全所有参与者的收益结构)、广告主难理解(为「别人的损失」付费,账单解释成本高)。机制落地不只看理论,还要看工程代价与认知成本——GSP 恰好卡在折中点。
Q3: 一价回归后,DSP 怎么避免当冤大头?
A: 机制不再替你「只付第二价」,DSP 只能自己做 bid shading:用历史竞价数据估计「出价 赢得流量的概率」,在赢率与支付之间做期望优化,把出价压到接近能赢的最低点。出价策略从「报真实估值」变成一个统计学习问题,这正是它成为 DSP 核心竞争力的原因。
🔗 前后关联
- 12.2 (eCPM 与计费模式)——本章所有支付公式都以 eCPM 为统一口径,GSP 的「按下一名 eCPM 折算」直接建立在 12.2 的 CPC/CPM 换算之上。
- 8.3 (端到端生成式广告 EGA)——本章的 IC/IR 定义在 EGA 中被量化为 ex-post regret 并写进损失函数;EGA 的「分配与支付解耦」正是二价思想「支付与申报解耦」的端到端重生。
- 3.x (精准偏好预测)——pCTR 预估追求的是绝对精度而非相对排序,因为它直接进入 eCPM 排序与 GSP 折算定价,估偏一点价格就算错。
- 5.3 (生成式范式演进)——端到端生成式的整体脉络是理解 12.3.6「机制嵌入模型」趋势的背景板。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 12.3.1 — 位置拍卖与 eCPM 排序 🟢 Easy
广告主 A 估值 、出价 ;广告主 B 估值 、出价 (均 CPC 口径)。坑位点击率 、。 (a) 按平台排序规则,各广告主拿到哪个坑位? (b) 两人对所获坑位的期望价值 各是多少? (c) 若这是展示广告(单坑位),谁赢?用 eCPM 验证。
💡 Solution (click to reveal)
Approach: 按 eCPM 排序,高出价者配高点击率坑位。
- (a) ,故 B 坑位 1,A 坑位 2。
- (b) ;。
- (c) 单坑位时 B 赢。eCPM 验证:。
Key points:
- 分配按申报出价而非估值——估值是私人信息,平台不可见。
- 期望价值用估值算(广告主视角),排序用出价算(平台视角),二者不可混用。
Problem 12.3.2 — GSP 三坑位完整支付计算 🟢 Easy
三个广告主出价 ,估值 ;坑位 CTR ,保留价 。求每人的每点击支付、eCPM 支付与效用。
💡 Solution (click to reveal)
Approach: 逐位套用 ,末位付保留价。
| 坑位 | 广告主 | 支付(元/点击) | eCPM 支付 | 效用 |
|---|---|---|---|---|
| 1 | 1 | 0.60 | ||
| 2 | 2 | 0.10 | ||
| 3 | 3 | 0.03 |
Key points:
- 第 1 名出价 5 元只付 1.5 元——支付与申报解耦是二价系的标志。
- 末位没有「下一名折算」,直接按保留价结算。
Problem 12.3.3 — VCG 两坑位外部性计算 🟡 Medium
广告主甲、乙、丙估值 ,如实出价;两个坑位 。 (a) 计算甲、乙的 VCG 每点击支付与效用(丙落榜付 0)。 (b) 验证:若只有一个坑位,甲的每点击支付恰为第二高出价。
💡 Solution (click to reveal)
Approach: 对每个赢家计算「无他时他人福利 − 有他时他人福利」。
- (a) 甲(坑位 1) :无甲时乙 坑位 1()、丙 坑位 2(),合计 ;有甲时乙 坑位 2()、丙落榜(),合计 。,每点击支付 ,效用 。 乙(坑位 2) :无乙时丙 坑位 2()、甲不动(),合计 ;有乙时合计 。,每点击支付 ,效用 。
- (b) 单坑位时甲的外部性 乙本可获得的福利 ,每点击支付 ,即第二高出价。VCG 在单坑位退化为二价。
Key points:
- 乙损害的是被挤落榜的丙,而非甲——外部性按「每个人的位移」精确计账。
- 效用改写 是 VCG truth-telling 的证明骨架。
Problem 12.3.4 — GSP 非严格 IC 的构造性验证 🔴 Hard
沿用 12.3.3 的反例设定:两坑位 ,保留价 ;甲 、乙 。 (a) 双方如实出价时,甲的效用是多少? (b) 甲改出 2.0 时的效用是多少?这说明什么? (c) 若乙实际只出 1.0,甲出 2.0 与出 4.0 哪个更优?由此说明 GSP 为什么不存在占优策略。
💡 Solution (click to reveal)
Approach: 分情况计算效用,检验「同一策略在不同对手出价下的表现」。
- (a) 甲占坑位 1,,效用 。
- (b) 甲落到坑位 2,付保留价 ,效用 。说真话不是最优——GSP 非严格 IC。
- (c) 乙出 1.0 时:甲出 2.0 占坑位 1(),效用 ;甲若降到坑位 2 只得 。同一策略「降到 2.0」在 (b) 中更优、在 (c) 中更差——最优出价依赖对手出价,不存在对所有对手出价都最优的策略,即无占优策略。
Key points:
- 非严格 IC 的可操作判据:能构造一组对手出价使真话非最优。
- GSP 的博弈本质:广告主在「抢高位多付」与「退低位省付」之间做对手依赖的权衡,均衡由 SNE 刻画。
🏆 Problem 12.3.5 — 证明:单坑位二价下偏离估值出价不增效用
设单坑位二价拍卖,你的估值 ,其他广告主最高出价 ,你的出价 。效用:赢则 ,输则 。证明对任意 与任意 :,且结论是「不增效用」而非「严格更优」。
💡 Solution (click to reveal)
Approach: 按偏离方向分两种情形,比较胜负边界 与 相对 的位置。
记按出价 的效用为 ,按真话 的效用为 。注意支付始终是 (与 无关),效用差异只来自胜负变化。
情形一 (出低)。 与 只在 区间不同:此区间内 故出低者输,;而 ,说真话者赢,。其余区间( 或 )二者胜负相同、支付相同,效用相等。故 。
情形二 (出高)。差异区间为 :出高者赢但付 ,;说真话者输,。其余区间效用相等。故 。
两情形合并:对一切 有 ,即 是弱占优策略。注意当 时任何 的效用与真话相同(都是 ),当 时任何 也同样不输——所以真话是「不劣于一切谎报」,而非「严格优于一切谎报」。
Key points:
- 证明骨架:支付与申报解耦 效用差异仅来自胜负边界 两个偏离方向各输一段区间。
- 这正是 8.3 中 ex-post regret 为零的特例: 对一切 成立。
智能出价与预算控制
📝 Before You Continue: 本章需先读 12.2(eCPM 与计费模式)——出价公式的口径建立在 eCPM 之上;以及 12.3(竞价机制)——bid shading 的问题意识直接来自一价拍卖的回归。本章反复出现的「预测精度」伏笔,将在 12.5(预估偏差与校准)中正面展开。
12.3 的结尾留下了一个悬念:一价拍卖回归后,机制不再替广告主「只付第二价」,出价策略随之成为 DSP 的核心竞争力。但出价远不只是「在一价下压价」这一个动作——它是一条完整的决策流水线:广告主说想要什么(目标),模型估计流量值多少(价值),预算决定今天能花多少(约束),机制决定出价该怎么报(适配)。这条流水线上任何一环算错,最后递给交易所的数字就是错的。
本章把这条流水线逐层拆开。我们先看广告主的目标如何变成一次展示的出价(oCPC/oCPM 转化出价),再看预算如何在一天之内被平滑地花完(Budget Pacing),然后处理一价市场下「出价该压多低」的统计问题(Bid Shading),最后把所有环节串成一次 bid request 的完整决策链。你会看到:这一章的每一个模块,本质上都是「预测」与「控制」在钱上的应用。
读完本章,你将能够:
- 写出转化出价的核心公式 ,并解释 oCPM 如何把转化风险从广告主转移到平台
- 说明预算平滑消耗的动机与参照轨迹 ,对比概率节流与出价缩放两种实现
- 用 PID/PI 反馈控制的视角解释 pacing 乘子 的整定逻辑,说明工程上为何普遍砍掉 D 项
- 推导一价拍卖下期望 surplus 最大化 的逻辑,描述 Verizon DDN 如何用 log-normal 分布与黄金分割搜索毫秒级求出最优出价
- 画出一次 bid request 从定向到提交出价的完整决策链,指出误差如何在链路中传导,完成 5 道分层练习题
12.4.0 从手工出价到智能出价
我们先回顾出价这件工作的历史分工。在 GFP 时代,出价完全掌握在广告主(或其出价代理)手里:你在 12.3.1 见过那场永不收敛的追逐战——出价是最优反应函数的迭代,广告主七乘二十四小时盯盘也追不上市场。即便到了 GSP 时代,「报一个合适的 CPC 出价」仍然要求广告主回答一个他们其实答不好的问题:这次点击值多少钱?答案取决于点击率、转化率、客单价——这些数据大部分握在平台手里。信息不对称决定了出价权的归属: 谁更懂流量,谁就该出价。
于是出价栈在平台侧逐层生长,最终形成现代 DSP 的标准形态。整条链路可以概括为四个环节的接力: 广告主目标 (target CPA / ROI)→ 价值估计 (pCTR × pCVR × targetCPA 折算成单次展示的价值)→ 预算约束 (pacing 控制消耗节奏)→ 市场机制适配 (bid shading 适配一价市场)。注意这四个环节回答的是四个不同的问题:想要什么、值多少、花多快、怎么报——它们彼此耦合,却由不同的模块、不同的算法各自负责。
图中每一层只消费上层的输出与自己的外部输入:价值估计层拿广告主的 targetCPA 与 pCTR/pCVR 预测相乘,bid shading 层拿价值出价与赢价分布相博弈,pacing 层拿遮蔽后的出价乘上一个预算乘子。分层的意义在于工程隔离——每个模块可以独立迭代、独立监控——但代价是误差也会沿箭头逐层向下传导,这一点我们在 12.4.4 再正面讨论。
🧠 Mental Model: 从「自己开车」到「导航代驾」
手工出价像自己开车:广告主手握方向盘(出价),凭经验(行业平均 CPC)猜路况(流量质量),堵车(竞争激烈)就猛踩油门(抬价)。智能出价是代驾加导航:广告主只报目的地(target CPA),平台的模型负责认路(pCTR/pCVR 预估)、控速(pacing)、选匝道(bid shading)。你不需要会开车,但你最好把目的地说清楚——报错 target CPA,代驾会忠实地把你送错地方。
本章接下来的四节就按这条栈逐层展开:12.4.1 讲目标如何变成价值(前两层),12.4.2 讲预算约束(第四层),12.4.3 讲机制适配(第三层),12.4.4 把它们重新拧成一个整体。
12.4.1 转化出价 oCPC/oCPM:平台用预测能力换定价权
出价栈的第一层飞跃,是把广告主的输入从「每次点击出多少钱」升级为「每个转化愿意花多少钱」。转化出价(oCPC / oCPM,optimized CPC/CPM) 的出价公式是 12.2 eCPM 口径的自然延伸:既然按转化出价,就把转化成本折算回千次展示收益——
其中 (实践中即 target CPA)是广告主申报的每次转化目标成本,pCTR 与 pCVR 由平台的预测模型给出。公式的读法很直白:一千次展示 × 每次展示的点击概率 × 每次点击的转化概率 × 每次转化的价值,等于这千次展示的期望收益。广告主只报一个数(target CPA), 每一次展示的具体出价由平台代管——这就是 12.3.6 预告的智能出价(Smart Bidding)的核心形态。
这一步棋要放在 12.2 的风险归属谱系里看才显出分量。12.2.1 的结论是:计费单位离转化越近,平台承担的风险越大——CPM 下风险全在广告主,CPC 下平台用 CTR 预测管理自己那份风险,CPA/CPS 下平台把决策与风险全部揽下。oCPM 正是这条链条的终点: 平台接管了转化风险,而接管的前提是 pCVR 预估足够准。预测准,平台敢承诺「按转化成本达标」;预测不准,平台就会为高估的流量付真金白银。延续 12.2 的说法:这是平台用预测能力换定价权——预测越准,能代管的出价层越深,从广告主手里换来的控制权越大。
工业实践为此设计了两阶段投放流程。冷启动阶段沿用普通 CPC 出价:新广告没有转化统计,pCVR 模型对它毫无把握,此时贸然按转化出价等于闭眼押注;CPC 出价先帮广告积累转化数据。待转化样本足够、模型置信后,再切换到转化出价。你会发现这正是 12.2.4 冷启动 back-off 与 E&E 思想在出价层的落地——先用便宜的探索积累统计量,置信之后再交给最优策略。
Analysis: 转化出价把预测的绝对精度推到了计费环节。在 oCPM 下,pCTR × pCVR 不仅决定排序,还直接决定平台向广告主收多少钱(按展示计费、按转化目标优化):系统性高估 pCVR,平台收不到目标成本、广告主超支;系统性低估,广告主的流量被压缩、平台收入受损。Alibaba 的系统化描述(Gai et al., SIGIR 2022)明确指出:预估不准会同时伤害用户体验、广告主营销目标与平台收入三方——这不是排序优劣问题,而是「算错钱」的问题。
深度转化与 LTV 出价:把「转化」的定义再往后推
target CPA 优化的「转化」到哪儿为止,决定了出价栈能替广告主管理多深的漏斗。深度转化出价(deep conversion bidding) 把优化目标从「一次激活」推向「激活后的关键行为」:游戏行业的次日留存/7 日付费、电商的复购、金融的开户绑卡。机制上它没有新公式——仍是 ,只是把 pCVR 换成了 深度转化率预估。真正的难点在数据侧:深度行为的发生滞后激活数天,样本的标签成熟要等延迟窗口走完,这就把 12.5 的 延迟反馈(delayed feedback) 问题从「校准」推到了「出价」——平台必须在不完整的标签流上实时出价,同时用延迟建模(如重要性采样、多任务存活式结构)修正有偏样本。
再往前一步是 LTV 出价:广告主申报的不是「每次转化值多少钱」而是「一个用户生命周期值多少钱」。对于长留存、高复购的行业(游戏、订阅制产品),激活当次的 CPA 口径严重低估用户价值——愿意为高 LTV 用户出高价的广告主,在 CPA 市场上反而抢不到量。LTV 出价把 替换为 的预估,难点是 LTV 的分布重尾而样本稀少:头部用户贡献了大部分价值,均值回归的预估会系统性低估高价值人群、高估低价值人群。工业上的通用配方是把 LTV 拆成「留存概率 × 每期价值」两段分别建模,再相乘还原;预估的零膨胀与重尾,与 12.5 校准一章的问题是同一族。
💡 Key Insight: 从 CPC 到 CPA 到深度转化再到 LTV,出价栈的演进只有一条主线:把广告主商业价值中「可被机器预估的部分」不断前移到竞价公式里。每前移一步,平台就多接管一层广告主的决策——也多承担一层预估误差的风险。深度转化与 LTV 出价是这条主线的当前边界,再往后(如 ROI 出价、利润出价)受限于平台对广告主后端数据的可见性,即 12.6 开闭环二分法的约束。
12.4.2 预算控制(Budget Pacing):让钱花得又慢又准
有了价值出价,还差一个约束:预算。广告主通常设日预算,而流量在一天内分布极不均匀——晚高峰的流量无论数量还是质量都远超凌晨。如果对预算放任不管会发生什么?出价高的广告会在凌晨到早盘就把预算烧光,因为那时它对每一次展示都出最高价;等晚高峰的高转化流量到来,广告已经「下班」了。预算平滑消耗(Budget Pacing) 要解决的就是这个问题:把预算在投放期内均匀花完——既避免前置消耗错过晚高峰优质流量,也让广告持续在线、触达更广受众(Xu et al., KDD 2015)。过慢同样有害:花不完预算等于放弃了本可获得的流量与转化。
平滑消耗需要一个「什么算均匀」的数学表达,即 参照轨迹(Reference Trajectory) :
其中 是目标总消耗(或展示量), 是投放期长。它就是一条从原点到 的直线,含义是「消耗进度与时间进度同步」:上午十点过了全天的 40%,就应该花掉预算的 40%。实际消耗曲线 与 的偏离就是控制误差,pacing 系统的任务是让 紧紧咬住 。
实现平滑有两种工程路线。概率节流(Probabilistic Throttling) :对每次竞价请求以概率 决定参与、以 直接放弃——LinkedIn 的预算 pacing 系统(Agarwal et al., KDD 2014)采用此路线;它实现简单,但「放弃」是 0/1 的硬门控,白白丢掉了「调低出价继续参与」的空间。出价缩放(Bid Scaling) :用 pacing 乘子 缩放出价,——保留参与度、牺牲单次竞争力;预算紧张时压低 ,同一笔预算能撑更久,还能自然避开「出价虚高白付钱」的展示。两种路线工业界都有部署,也可以只对「是否进入竞价」做门控;出价缩放与出价逻辑耦合更深,但也正是它让 pacing 成为出价栈的一层而非外挂的限速器。
两种路线殊途同归的地方是控制结构:这是一个标准的反馈控制回路。误差 (参照轨迹与实际消耗之差)喂给控制器,控制器输出操作量,操作量作用于出价(或参与概率),实际消耗再被观测回来与参照比较。工业界普遍采用 PID 控制器(Proportional–Integral–Derivative Controller) 的框架来整定,三项各有清晰的语义:
- P(比例) :即时响应——误差一出现立刻按比例调整,但纯 P 控制会留下稳态偏差;
- I(积分) :消除稳态偏差——误差累积多久就纠正多久,预算落后越多补得越狠;
- D(微分) :超前抑制——误差的变化率提供「即将超支/超速」的预警。
工程上普遍砍掉 D 项、只用 PI 控制 :广告展示请求是离散的阶跃信号,D 项对阶跃与噪声极度敏感,会把放大后的噪声注入出价。PI 的输出再经 sigmoid 压缩到 ,恰好落在 pacing 乘子(或参与概率)的取值范围。更进一步,误差可取对数比形式 ,使不同规模的投放计划可以共用同一套控制增益——一个日预算百元的小计划与日预算百万的大计划,用同样的参数都能稳定收敛。
🧠 Mental Model: 定速巡航
预算 pacing 就是广告投放的定速巡航:设定目标速度(参照轨迹),系统持续对比当前车速(实际消耗)与目标,脚下自动补油门(α 升高)或收油门(α 压低)。P 是「看到掉速就补一脚」,I 是「一直慢就一直补」,D 是「预感到要超速提前松油」——但在颠簸路面(离散的竞价请求)上,D 这只脚只会把颠簸踩成抽搐,所以工程师干脆把它卸了。
这条技术路线上有一串值得记住的工业坐标。Yahoo 的 Smart Pacing(Xu et al., KDD 2015)为每个投放计划学习投放节奏,离线(历史数据初始化)与在线(实时更新)结合,在真实 DSP 系统部署并实验验证了平滑性与效果目标的同步改善;更早的 Lee et al.(ADKDD 2013)研究了 RTB 下平滑预算交付的出价优化。Zhang et al.(WSDM 2016)率先把 PID 控制引入 RTB 出价;Verizon Media 的 DSP 采用积分控制加前馈补偿;Twitter/X 把 pacing 做成独立服务、内部跑 PID 控制;Roku 以五分钟为周期调节「挑剔度」;Adobe 与 Google 则以专利形式保护各自的 PID 出价引擎。控制论在这件事上完成了一次跨行业的静默胜利——大家语言不同(节奏、乘子、挑剔度),内核都是同一个反馈回路。
Analysis: pacing 的控制周期通常在分钟级而非请求级:消耗统计有延迟,控制增益整定不当会振荡(预算忽紧忽松)。更微妙的是 pacing 与出价的耦合——乘子压低出价会改变竞得的流量分布(便宜流量占比上升),进而改变实际消耗速率,形成一条环内有环的通路。把 pacing 当成独立于出价的限速器,是这一层最常见的误读。
12.4.3 一价拍卖下的 Bid Shading:赢率与利润的倒 U 权衡
现在处理 12.3.5 埋下的最后一个问题:一价市场里出价到底该怎么报。一价拍卖下「出价即支付」,如果你的出价 恰好等于估值 ,那么赢下拍卖的瞬间利润 ——赢了等于白干。所以理性的出价必须 向下遮蔽 :把出价压到估值之下。但压得太低又会输掉本该赢的拍卖。这就是 出价遮蔽(Bid Shading) 的核心权衡:赢率与利润此消彼长,我们要找的是二者乘积的最大点。
形式化地,设一次展示机会对你的价值为 (由出价栈上层给出的价值出价),你出价 ,则 期望剩余(Expected Surplus) 为:
是出价 的赢率。问题在于:这个赢率函数怎么来的?这里有一个决定方法成败的洞察: 要估计赢率的分布,而不是赢率的点估计。赢率由竞争对手的出价决定——具体说,由「最低赢价」(minimum winning price,即刚好能赢下此次拍卖的价格)的分布 决定:。用点估计(预测一个「市场价」再打折)在任何单次拍卖上都可能严重偏离;用分布建模(估计整个 CDF)则天然表达了竞争格局的不确定性,对拍卖间的波动更稳健。
图中三条曲线把权衡讲透了:蓝线赢率 随出价单调上升,黄线单位利润 随出价单调下降,绿线乘积 呈倒 U 形——两端皆输( 赢率崩塌, 利润归零),最优出价 藏在中间。下面的交互式模拟器允许你亲手拖动估值与出价,按四步剧本体验这条曲线。
建议按剧本顺序走:情形一先验证「按估值出价利润为零」,情形二看遮蔽过度如何让赢率崩塌,情形三落在 surplus 峰值,情形四引入估值噪声、观察峰值附近的平坦区为何意味着鲁棒性。走完之后拖动滑块自由探索,注意 总是落在 的内部而非边界。
工业实现的最完整范本是 Verizon Media 的 DDN(Deep Distribution Network) (Zhou et al., KDD 2021)。它用网络直接输出最低赢价的分布参数,其中 log-normal 分布 对赢价的长尾拟合最好;训练用极大似然处理公开拍卖的完整观测,用 生存分析(Survival Analysis) 处理封闭拍卖的 删失数据(Censored Data)——你只观察到「是否赢了」与「赢时的最低赢价」,输掉的拍卖里真实赢价永远不可见,这正是删失结构。基于分布的数学性质,DDN 证明了 surplus 函数存在唯一全局最优,因此可以用 黄金分割搜索(Golden Section Search) 这种无需梯度的极值搜索在毫秒级求出 ——每次拍卖都要做一遍这个优化,速度就是一切。
💡 Key Insight: DDN 在 Verizon DSP 生产系统日服务数千亿次请求。线上 A/B 结果:surplus 提升 14.3%,广告主 ROI 同步改善——CPM 与 CPC 口径提升 2.4%、CPA 口径提升 8.6%。注意这两个方向的改善同时发生:bid shading 不是「平台让利」,压低出价既降低了赢家的支付(广告主侧),又提高了每次赢拍的利润(DSP 侧),前提是压得准。
系统工程约束决定了这套方法的形态。DSP 对一次 bid request 的总响应预算约 20ms,定向、pCTR/pCVR 预估、内部竞价、bid shading、pacing 各模块串行执行,每个模块分到的延迟被严格压缩;DDN 因此采用每天离线训练一次、模型文件加载到线上 bidder 的架构,把在线开销压缩到一次分布参数查询加一次黄金分割搜索。最后,当估值与竞争分布的估计噪声都很大时,点估计式的最优化会失稳——Stanford 与 Yahoo 的后续工作(Qu et al., 2024)用 KL 散度不确定性集 构造 max-min 分布鲁棒优化,让出价对估计误差免疫;这条路线我们一句话带过,思路与 12.4.4 的噪声传导一脉相承。
Analysis: bid shading 的方法论迁移值得留意:它把「定价问题」变成了「分布估计 + 一维优化」问题。分布估计(log-normal + 删失处理)离线完成,一维优化(黄金分割搜索)在线完成——这种「重的离线、轻的在线」的切分,是所有毫秒级决策系统的通用架构模式,你在 12.2.4 动态特征与在线学习的权衡里见过同一逻辑。
12.4.4 出价栈整合:一次 bid request 的完整决策链
四层模块各就各位,现在让一次真实的 bid request 走完全程。请求从 ADX 到达 DSP 后,决策链依次是: 定向过滤 (广告主的受众、地域、时段条件先筛掉不相干的投放计划)→ pCTR/pCVR 预估 (对每个候选估计点击与转化概率)→ 价值出价 ( 折算出这次展示对这个广告主值多少)→ bid shading (拿价值出价与赢价分布博弈,压到最优 )→ pacing 乘子 (预算约束再乘上 )→ 提交出价。从请求到出价的全部工作必须在约 20ms 内串行完成。
模块化带来了迭代效率,也带来了一条必须正视的误差传导链。pCTR 高估 10%,价值出价就虚高 10%,bid shading 拿着被污染的 去优化 surplus,最优点整体偏移,pacing 的消耗速率随之失真——任何一环的误差都会无损地传导到最终出价。更麻烦的是双向耦合:pacing 乘子改变了竞得的流量分布,这个分布恰是 bid shading 赢价估计的训练数据来源。因此 DDN 论文特别强调,shading 算法必须对上游模块的噪声与变化有韧性——这也是 12.4.3 末尾分布鲁棒思路的另一个动机。
🧠 Mental Model: 传话游戏
出价栈像一列传话的队伍:目标层把「每次转化值 40 元」传给价值层,价值层换算成「这次展示值 0.04 元」传给 shading 层,shading 层压成「出 0.028 元」传给 pacing 层,pacing 层再乘个折扣递出去。队伍里任何一个人听岔了 10%,后面所有人都忠实地放大或缩小这 10%——最后递出的数看起来精确到小数点后三位,其实从第一棒就歪了。整条链路没有「局部正确」这回事,只有「整体校准」。
到这里,本章与 12.2、12.3 的拼图可以合上了。12.2 给了系统度量衡(eCPM)与风险归属的宪法,12.3 给了市场机制(拍卖怎么分怎么收),本章给出了黏合二者的出价栈——目标变成价值,价值适配机制,机制受制于预算。而贯穿三章的同一条主线此刻显形: 这条链路的每一层都在消费预测的输出,预测的「绝对精度」而非「相对排序」是整条链路的地基。pCTR/pCVR 的系统性偏差会让平台算错钱、让 shading 压错价、让 pacing 追错轨迹。预测为什么会偏、偏差如何度量与修正——这正是 12.5(预估偏差与校准)的主题,也是本 Part 的收官一环。
⚠️ Common Mistakes in 12.4
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把 oCPM 当成一种计费方式而非风险转移 | 「oCPM 不就是按展示计费吗」 | 计费口径仍是 CPM,真正的变化是平台接管转化风险并代管出价——这是 12.2 风险谱系从 CPC 到 CPA 的实质跨越 | 理解为「平台用 pCVR 预测能力换取出价定价权」,预测不准平台自己亏 |
| 2 | 以为 pacing 只是限速器 | 「预算花太快就随机丢弃请求」 | pacing 乘子直接改变出价,进而改变竞得流量分布,与出价逻辑双向耦合 | 用反馈控制视角建模:参照轨迹 + 误差 + PI 控制器闭环 |
| 3 | 认为 bid shading 是纯粹的损失 | 「压低出价就是少赚钱」 | 压价同时提高每次赢拍的利润并降低支付,DDN 线上 surplus +14.3%、广告主 ROI 同步提升 | 记住优化目标是 的乘积最大,不是赢率最大 |
| 4 | bid shading 用赢率的点估计 | 「预测市场均价再打八折」 | 单次拍卖的赢价波动极大,点估计在个体层面系统性偏离 | 估计最低赢价的分布(CDF),log-normal + 删失数据处理 |
| 5 | 新广告上线直接切转化出价 | 「oCPC 效果好,冷启动就用」 | pCVR 对零转化样本的广告毫无把握,贸然代管出价等于盲赌 | 遵循两阶段:CPC 出价积累转化数据,模型置信后再切换 |
| 6 | 认为砍掉 D 项是工程偷懒 | 「完整 PID 才专业」 | 展示请求是离散阶跃信号,D 项放大噪声会把抖动注入出价 | 工业标准就是 PI:P 即时响应 + I 消稳态偏差,输出 sigmoid 压缩 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 出价栈全景 | 目标(CPA/ROI)→ 价值估计 → 预算约束(pacing)→ 机制适配(shading)四层接力 | 现代智能出价的统一心智模型,各层可独立迭代但误差逐层传导 |
| oCPC/oCPM | ;平台代管出价,两阶段冷启动 | 平台用预测能力换定价权,把转化风险从广告主转移到自己身上 |
| Budget Pacing | 参照轨迹 ;概率节流 vs 出价缩放 ;PI 控制 + sigmoid | 避免前置消耗错过优质流量,是反馈控制在广告系统的标准落地 |
| Bid Shading | 倒 U 峰值;估计赢价分布而非点估计 | 一价时代的 DSP 核心竞争力,同时改善利润与广告主 ROI |
| DDN(KDD'21) | log-normal 赢价分布、生存分析处理删失、黄金分割搜索毫秒级求 ;surplus +14.3% | 「重的离线、轻的在线」架构范式,日服务数千亿次请求 |
| 误差传导链 | 定向→预估→价值→shading→pacing 串行,任何一环偏差直达最终出价 | 引出 12.5:预测的绝对精度是整条链路的地基 |
❓ FAQ
Q1: oCPC 与 oCPM 有什么区别?
A: 优化目标相同(按 target CPA 代管出价),区别在计费口径与风险细节:oCPC 按点击计费、oCPM 按展示计费。oCPM 下平台对「展示→转化」的全链路负责,风险接管更彻底——这要求 pCVR 预估足够准,否则平台为高估的流量买单。二者共享同一套出价公式,只是计费点不同。
Q2: 概率节流与出价缩放,该选哪个?
A: 概率节流(LinkedIn 路线)实现简单、控制直接,但 0/1 门控丢掉了「降价继续参与」的空间;出价缩放()保留参与度、能在预算紧张时自然避开虚高展示,但与出价逻辑耦合更深。工业界两者都有部署,混合方案(门控 + 缩放)也常见;预算越紧张、流量异质性越强,出价缩放的优势越明显。
Q3: 为什么 bid shading 一定要用分布而不是点估计?
A: 单次拍卖的最低赢价波动极大,点估计只给出「平均市场价」,在个体层面系统性偏离——按均价打折会在便宜流量上出价过高(白付钱)、在贵流量上出价过低(错失)。分布(CDF)完整刻画了竞争格局的不确定性, 的优化天然对拍卖间波动稳健;DDN 的线上提升(surplus +14.3%)也正是在把点估计基线换成分布后取得的。
🔗 前后关联
- 12.2 (eCPM 与计费模式)——本章出价公式完全建立在 eCPM 口径之上;oCPM 的风险转移是 12.2 风险归属谱系(CPM→CPC→CPA)的终点,两阶段冷启动则是 12.2.4 E&E 与 back-off 思想的出价层落地。
- 12.3 (竞价机制)——一价回归(12.3.5)催生了 bid shading 的全部问题意识;「按估值出价利润为零」直接来自一价「出价即支付」的定价规则。
- 12.5 (预估偏差与校准)——本章反复埋下的伏笔在此正面展开:pCTR/pCVR 的系统性偏差沿出价栈传导,算错排序只是小事,算错钱才是大事。
- 8.3 (端到端生成式广告 EGA)——本章的出价栈是「机制作为后处理规则」形态的巅峰;EGA 把分配与支付端到端地学进模型,可视为这条栈的范式级压缩。
- 3.x (精准偏好预测)——pCTR/pCVR 模型结构源于排序模型,但进入出价栈后绝对精度(校准)成为硬约束,这是广告场景对推荐模型的独特改造。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 12.4.1 — oCPM 出价计算 🟢 Easy
某电商投放计划设置 target CPA = 40 元。平台对某次展示预估 pCTR = 2%、pCVR = 5%。 (a) 计算该次展示的 eCPM 出价。 (b) 若广告主把 target CPA 提高到 50 元,出价如何变化?这说明 target CPA 扮演什么角色? (c) 平台 pCVR 被系统性高估一倍(真实 2.5%、预估 5%),这会带来什么后果?
💡 Solution (click to reveal)
Approach: 套用 。
- (a) 元(千次展示)。
- (b) 出价线性升至 元。target CPA 是出价栈唯一由广告主输入的「价值锚」:它乘在所有预测概率之前,直接缩放整条出价——广告主报的不是出价,是价值标尺。
- (c) 真实期望 eCPM 只有 元,平台却按 40 元出价并(oCPM 下)向广告主按高估口径计费:广告主实际转化成本飙升到 target 的两倍,平台短期多收但广告主流失。这正是「预测精度直接决定计费合理性」的含义。
Key points:
- 出价公式的每个因子错一倍,出价就错一倍——线性结构没有误差对冲。
- oCPM 下高估 pCVR 的账单由广告主先垫付、由平台的留存率偿还。
Problem 12.4.2 — 参照轨迹与 pacing 误差 🟢 Easy
某投放计划日预算 元,投放期 小时。中午 12 点时实际累计消耗 元。 (a) 此刻的参照消耗 是多少?绝对误差与相对误差各是多少? (b) pacing 系统此刻应把乘子 调高还是调低?哪个控制项(P 还是 I)在主导这个纠正? (c) 若对数比误差定义为 ,计算此刻的 值。
💡 Solution (click to reveal)
Approach: 参照轨迹 ,与实际消耗逐点比较。
- (a) 元。绝对误差 元(超支),相对误差 。
- (b) 消耗偏快,应 调低 (压低出价、减缓竞得)。瞬时看是 P 项在纠正(当前误差为正 → 按比例负向调节);若超支持续了一上午,I 项累积了正的误差积分、也在持续压 ——PI 协作:P 管当下的 20%,I 管历史欠账。
- (c) 。符号约定为「超支为负、落后为正」时不影响控制方向;对数形式的要点在 12.4.2——它让日预算 60 元与 600 万元的计划可以用同一套增益。
Key points:
- 参照轨迹是「进度与时间同步」的直线,一切 pacing 控制都围绕咬住它展开。
- P 响应当下、I 消除稳态偏差——本例中两项同向发力。
Problem 12.4.3 — 手算期望 surplus 与最优出价 🟡 Medium
估值 元。竞价的最低赢价分布为离散三点:以概率 0.5 落在 2 元、概率 0.3 落在 4 元、概率 0.2 落在 6 元(出价恰好等于赢价时算赢)。 (a) 写出赢率函数 在 处的取值。 (b) 计算这四个出价点的期望 surplus ,哪个最优? (c) 讨论 区间内 的行为:它恒定吗?由此说明离散分布的最优出价落在哪里,以及为什么连续分布(如 log-normal)的峰值附近才有「平坦区」。
💡 Solution (click to reveal)
Approach: 赢率 = 赢价分布的 CDF;surplus = 单位利润 × 赢率,逐点计算。
- (a) ;;;。
- (b) 逐点:: ;: ;: ;: 。最优是 ,——比按估值出价(surplus 为 0)与遮蔽不足()都好。
- (c) 时赢率保持 0.5(没跨过下一个赢价台阶 4),但利润 随 递减,故 从 处的 单调降到 处的 ——并不平坦。离散分布的最优出价落在赢率跳变的台阶沿():刚买到新赢率就停手。连续分布(如 log-normal)没有台阶, 是光滑倒 U,峰值附近才是真正的平坦区——峰值处 的小偏差几乎不损失 surplus,这为噪声环境下的鲁棒出价留出安全边际(对应模拟器情形四)。
Key points:
- 赢率即最低赢价的 CDF——分布估计是 surplus 优化的输入,不是可选项。
- 离散分布在台阶处出现「出价刚过门槛」的最优点;连续分布则给出光滑倒 U 与平坦峰值。
Problem 12.4.4 — PI 控制器行为分析 🔴 Hard
某 pacing 系统采用 PI 控制:,误差 (正 = 消耗落后)。投放首日流量突发(一次大批量展示涌入),单步误差 从 0 跳到很大的正值后又回落。 (a) 纯 P 控制()下,系统最终停在什么状态?为什么? (b) 加入 I 项后,突发期累积的误差积分会在事后造成什么现象?如何缓解? (c) 从控制论角度解释:为什么把误差改为对数比 后,同一组 能同时服务日预算悬殊的不同计划?
💡 Solution (click to reveal)
Approach: 逐项分析 P/I 的动态特性,再考察误差度量选择的影响。
- (a) 纯 P 控制存在 稳态偏差 : 与误差成正比,误差为零则纠正力为零——消耗追上参照之前,纠正力会随误差缩小而衰减,系统停在「略落后于轨迹、 略高于中性值」的平衡点,永远差一口气。这正是必须引入 I 项的原因。
- (b) 突发期的误差积分在事后持续推高 ,造成 超调 (overshoot):流量已恢复,系统却仍在加价,消耗冲过参照轨迹,误差变负、积分回落——典型的积分饱和(integral windup)振荡。缓解手段:积分限幅(clamp)、误差只在偏离方向上累积、或用泄漏积分。
- (c) 线性误差 的量纲是钱:日预算 6000 元的计划偏差 600 元与日预算 60 元的计划偏差 600 元,是两个完全不同严重度的事件,却需要同一组增益做出同样强度的反应——不可能。对数比把误差归一到「相对偏离」: 只看消耗与参照的 比例 , 的偏离无论计划大小都产生同样的 ,增益于是可以跨计划复用,一套参数服务全部投放。
Key points:
- P 留稳态偏差、I 消偏差但会 windup——PI 的工程是一门「配平」的艺术。
- 误差度量的归一化(对数比)是多规模系统共用控制器的关键,比调参技巧更本质。
🏆 Problem 12.4.5 — 推导 E[S] 的最优性条件
设最低赢价分布 有密度 (,在 上严格递增)。证明: (a) 且 ,从而最优出价若存在必在 内部取到; (b) 内部最优 满足一阶条件 ,即 ; (c) 解释 的经济含义,并说明它为何把 推向估值 之下。
💡 Solution (click to reveal)
Approach: 边界值直接代入;内部极值对 求导并令其为零。
- (a) (赢率为零);(利润为零)。两端为零、函数非负且在 内取正值(例如取 使 且 ,则 ),故最大值在内部某点 达到——「最优出价严格低于估值」由此得证。
- (b) 求导:。令其为零得 ,整理即 。
- (c) 是 逆风险率 (Mills 比率的倒数关系项):衡量「再多出一块钱能买到的边际赢率」的倒数。一阶条件读作:最优时,估值 = 出价 + 「竞争压力补偿」——市场越难赢( 大,说明赢率已高、边际赢率 递减),补偿越大,但你 永远不需要出到 ,因为 ( 严格递增保证),所以 。这与 DDN 的结论一致:在 log-normal 等常见分布族上,surplus 函数有唯一全局最优,黄金分割搜索恰好能找到它。
Key points:
- 证明骨架:边界为零 + 内部为正 ⇒ 内部最优;这是「遮蔽必然发生」的最简形式化论证。
- 一阶条件 是 12.3 二价思想在一价的回声:二价机制自动替你支付的「第二价」,在一价下要靠分布估计自己算出来。
广告系统中的偏差与校准
📝 Before You Continue: 本章需先读 12.2(eCPM 与 CTR 预估——预测值如何进入排序算术)与 12.4(智能出价——出价栈如何逐层消费 pCTR/pCVR 预测值)。本章与 Part 3 的排序模型直接衔接:同样的模型结构,在推荐里可以只当「排序键」用,在广告里必须当「概率」用——这一字之差引出本章的全部内容。
假设你训练了一个 AUC 0.80 的 CTR 模型,放在推荐系统里,这是足以自豪的成绩。现在把它原封不动搬进广告系统,会发生什么?很可能是一场事故:模型对每个广告的预估都系统性高出真实值一倍,候选之间的相对顺序完美保持(AUC 不变),但每一次 eCPM 计算、每一次出价换算、每一张账单都错了。推荐系统惩罚「排错序」,广告系统额外惩罚「报错数」——而后者在模型论文的评估表格里几乎没有席位。
本章是 Part 12 测量系统的核心章,讨论的是每天都在工业界以真金白银发生的主题: 偏差(Bias)与校准(Calibration)。前面几章里,12.2 建立了 eCPM 这把尺子,12.3 设计了竞价机制,12.4 让平台代广告主出价——所有这些机制消费的都是模型的预测值。预测值本身准不准、系统性的偏差从哪里来、如何测量与修正,就是本章要搭建的「测量系统」。测量是机制与出价的地基。
读完本章,你将能够:
- 区分 校准(Calibration) 与 判别力(Discrimination) ,解释为何高 AUC 的模型可能给出完全不能用的 eCPM
- 用 examination 假设分解 位置偏差(Position Bias) ,对比「位置作特征 / IPW / PAL」三类去偏方案的适用与代价
- 定义 样本选择偏差(SSB) 与数据稀疏,写出 ESMM 的全空间建模目标与损失,说明 CVR 塔为何是「隐式学习」
- 描述 胜出偏差 与 延迟反馈 如何污染训练与校准标签,以及探索流量为何是无偏信号的来源
- 用 Platt scaling 与保序回归(PAVA)在独立验证集上做校准,用可靠性图、ECE、PCOC 评估校准质量
- 完成 5 道分层练习题,打通从 ECE 手算到 PAVA 拟合的完整链路
12.5.0 广告预测为什么比推荐更苛刻:从相对序到绝对值
推荐系统排序阶段的评估是「宽容」的。排序只关心候选之间的相对顺序:把所有分数平方、取对数、乘以任意正常数,排序结果与 AUC 纹丝不动——AUC 对分数的 单调变换不变。正因如此,推荐模型可以采用各种「只保序、不保值」的结构与损失(双塔内积、pairwise 排序损失等),只要序对,业务指标就对。你在 Part 3 见过的大多数排序模型,都建立在这条「相对序就够用」的假设上。
广告系统打破了这个安全区。按转化出价的场景(OCPC/CPA,见 12.4)下,平台的排序算术是:
pCTR、pCVR 的 绝对值 直接参与乘法(AdaCalib,Wei et al., SIGIR 2022 对这一模式的总结)。12.4 的智能出价栈更进一步:目标转化成本约束、预算 pacing、ROI 优化器,每一层都在对这些预测值做算术。预测值每偏一分,钱就算错一分——这里的「错」不是隐喻,是账单上可以直接核对的差额。
更麻烦的是,乘法会放大偏差。pCTR 高估 10%、pCVR 高估 10%,看似各自「还行」,乘积却高估 21%()。一条出价链上串着多个 AUC 都不错的模型,链路末端的校准偏差仍可能大得离谱——这就是多分数相乘模式的宿命: 判别力的优秀掩盖不了校准的失真,反而把它层层放大。
由此必须严格区分两个正交的概念。判别力(Discrimination) :模型能否把正例排在负例前面,由 AUC 类指标度量。校准(Calibration) :模型打 0.7 分的那组样本,是否真的约有 70% 为正——预测的绝对值是否可信。二者互不保证:Guo et al.(2017)的系统研究发现,现代深度模型普遍 过度自信(Overconfidence)——判别力提升的同时,预测值系统性偏离真实概率。AUC 0.80 但整体估值翻倍的模型,就是「排序完美、计费灾难」的典型。
失准的后果沿 12.4 的出价栈逐级传导: 出价错 (OCPC 用失真的 pCVR 换算出错误 bid)→ 排序错 (eCPM 尺子失真,好广告落榜、差广告上位)→ 计费错 (GSP 按失真的 pCTR 折算支付,见 12.3)→ 预算预测错 (pacing 的花速预估全部失真)。阿里妈妈的工程实践把这总结得很直白:AUC 只衡量排序质量、忽略预测值的绝对大小;而 绝对精度(size-accuracy) 对精确出价、竞价稳定、混投公平性至关重要——过度预估或不足预估,都会给平台或广告主造成直接的收入损失。
🧠 Mental Model: 摸额头与体温计
推荐排序像用手摸额头:你只需要判断「比平时热」,相对比较就足够下「要不要休息」的结论。广告系统像给病人开药:剂量按 38.5°C 这个绝对数字计算,高估一度药量就翻倍。同一套「温度感知」,推荐只需给出序,广告必须给出数——本章的全部内容,就是把「摸额头的模型」改造成「体温计」的工程学。
Analysis: 判断你的场景需要判别力还是校准,看预测值是否进入算术:只用于排序(召回、推荐精排)→ 判别力优先;用于出价、计费、预算控制、ROI 结算(广告、LTV 建模)→ 校准是一等公民。工业广告系统通常两头都要:先用判别力强的主干模型保序,再叠加独立的校准模块保真——这正是 12.5.4 的主题。
12.5.1 位置偏差:点击 = 被看到 × 值得点击
先看最古老也最顽固的一种偏差。位置 1 的广告点击率天然高于位置 5,其中相当一部分与「广告好不好」无关,只与「位置好不好」有关。麻烦在于训练数据来自「按当前策略排好序」的日志:好位置给了系统认为好的广告,于是「位置效应」与「广告质量」在日志里纠缠不清,模型会把位置红利误记为广告自身的功劳。这就是 位置偏差(Position Bias)。
主流方法把它形式化为 检验假设(Examination Hypothesis,也称浏览假设) :
一句话: 点击 = 被看到 × 值得点击。它附带两个隐含假设:是否被看到只与位置有关;被看到之后是否点击与位置无关。前者把「曝光的可见性」抽成位置的函数,后者把「用户的兴趣判断」留给广告本身——偏差治理的全部方案,都是围绕怎么把这两项拆开。
方案一:位置作为特征。 工业界使用最广的做法:把位置编号作为特征喂给模型,靠数据自己学。问题出在推理时刻——位置恰恰是排序的 输出 而非输入,打分时广告还没被分配位置,只能填一个默认值(比如「第一名」或「平均位置」)。不同默认值导出不同结果,效果次优(Guo et al., RecSys 2019 对这一困境的分析)。胜在实现成本几乎为零,很多系统「明知次优仍在用」。
方案二:逆倾向加权。 逆倾向加权(Inverse Propensity Weighting, IPW) 对不同位置的样本按倾向分的倒数加权:位置靠后、天然倾向低的样本权重高,加权后还原「无位置偏爱的虚拟分布」。理论优雅,难点在 倾向分(Propensity Score) 的估计——要估准就得跑随机展示流量(把广告随机放到各位置),而随机流量伤害用户体验与收入。学术界研究丰富,工业落地则慎之又慎。
方案三:PAL 结构化解耦。 华为提出的 PAL(position-bias-aware learning) (Guo et al., RecSys 2019)直接按 examination 假设把模型拆成两个可乘模块:
训练时两塔 联合 优化:乘积 bCTR 与真实点击标签计算损失、端到端更新;线上只用 pCTR 塔——位置信息止步于训练期,ProbSeen 塔仅承担分解职责。这样 pCTR 塔学到的就是「剥离位置效应后的广告质量概率」。华为的 AB 测试显示 CTR 与 CVR 相对基线提升 +3%~35%。
左图是 examination 假设:位置决定「被看到」的概率,被看到之后才轮到「值得点击」发挥作用;右图是 PAL 的双塔结构——训练期 ProbSeen 与 pCTR 相乘对齐点击标签,线上只走 pCTR 塔,位置由排序结果决定、不能作为输入。
| 方案 | 思路 | 优点 | 代价 / 风险 |
|---|---|---|---|
| 位置作为特征 | 位置进模型,靠数据学 | 实现最简单,工业最广 | 推理时位置未知,默认值困境,次优 |
| IPW | 按倾向分倒数加权样本 | 理论无偏性清晰 | 倾向分难估;随机流量伤体验 |
| PAL | ProbSeen × pCTR 双塔解耦 | 联合训练、线上只走 pCTR 塔 | 依赖 examination 假设成立 |
最后补一类更精细的建模。级联模型(Cascade Model) 放弃「各位置独立」的假设:用户从前往后顺序浏览,点击即停止,每次会话至多一次点击;某个位置被查看的概率与它前面位置展示的内容相关——前面被点走了,后面的请求根本不会发出。examination 假设可以看作级联模型的「各位置独立、与内容无关」简化版;级联建模更贴近搜索页的真实浏览行为,代价是模型与数据处理的复杂度。
Analysis: 位置偏差若不处理,会直接污染校准:模型学到的是「带位置先验的条件点击概率」,而线上出价需要的是「无位置条件的广告质量概率」。二者的差距就是校准曲线上的系统性偏移。记住这个伏笔——12.5.4 的结论「先去偏、再校准」正源于此。
12.5.2 样本选择偏差与 ESMM:训练空间 ≠ 推理空间
第二类偏差藏在 CVR 模型的训练流程里。传统 CVR 模型用 点击样本 训练——转化标签只能在点击之后产生,天经地义。但推理时呢?eCPM 公式里 pCVR 挂在 每一次曝光 上,模型必须对全部曝光打分。于是 训练空间(点击空间)成了推理空间(曝光空间)的真子集 ,两个分布不一致——这就是 样本选择偏差(Sample Selection Bias, SSB) :你在一个被「用户点了」这个事件筛选过的子空间里学规律,却要把规律外推到全空间。
与 SSB 结伴而来的是 数据稀疏(Data Sparsity, DS)。点击本身就是小概率事件:淘宝公开数据集里,点击样本仅占全部曝光的 约 4% ;转化又建立在点击之上,稀上加稀。CVR 模型的训练样本量比 CTR 低一到三个数量级,直接训练极易过拟合。SSB 让模型学偏,DS 让模型学不稳——ESMM 就是同时对付这两兄弟的设计。
ESMM(Entire Space Multi-task Model,全空间多任务模型) (Ma et al., 阿里,SIGIR 2018)的出发点是行为序列的链式法则:
关键观察:pCTR(曝光 → 点击)与 pCTCVR(曝光 → 转化)都定义在 全曝光空间 ,点击与转化标签在每一次曝光上都可以监督(点了没/转化了没)。于是用两个「全员可算」的量,把只能在点击子空间定义的 pCVR「夹」出来——训练直接发生在推理空间里,SSB 从结构上消失。
底层是全部曝光样本上的共享 Embedding,向上分出 CTR 塔与 CVR 塔,两塔输出相乘得到 pCTCVR;两个损失(L_ctr 对点击标签、L_ctcvr 对转化标签)都在全曝光空间计算——训练空间与推理空间重合,SSB 被绕开。
架构上有三个值得咀嚼的细节。其一,双塔共享 Embedding :CVR 塔从海量 CTR 样本迁移特征表示,稀疏问题 DS 直接受益。其二,用乘法而不是除法 :若按 显式相除,pCTR 很小时(点击本就是小概率)数值会爆炸,且商不保证落在 ;乘法形式天然规避这两个坑。其三,损失结构 :
其中 是全曝光空间, 是点击标签、 是转化标签,、 分别是 pCTR 与 pCVR。注意损失里 没有 CVR 的直接监督项——pCVR 是中间变量,被 隐式学习 :CVR 塔的参数仅由 经由乘积回传的梯度更新,而 CTR 塔与共享 Embedding 由两项共同更新。
效果如何?公开数据集上,CVR 任务 AUC 绝对提升 2.56%——要知道工业界 CTR/CVR 模型 0.1% 的提升已算显著,2.56% 是罕见的量级;生产数据集规模达 89 亿样本。更难得的是稳健性:随训练集缩小(采样率下降),ESMM 性能保持稳定,优于过采样与 UNBIAS 等基线——共享 Embedding 的迁移让它在数据越稀疏时越显价值。
🧠 Mental Model: 先笔试后面试
「面试通过率」只能在被笔试筛过的人群里观测,但你招聘时想给所有报名者一个「最终录用概率」。ESMM 的做法:分别统计笔试通过率(全报名者可算)与「笔试 + 面试」综合通过率(全报名者可算),面试通过率作为两者的关系被隐式导出。两个全员可监督的量拼出观测不到的中间量,这就是全空间建模的全部直觉。
Analysis: ESMM 的适用前提是任务间存在明确的序列依赖(曝光 → 点击 → 转化的漏斗),链式法则才成立;若是平行任务(如「点赞」与「收藏」),乘积分解失去意义,应改用其他多任务结构。另外注意:ESMM 解决的是「标签空间」的偏差(哪些样本能拿到标签),不处理「位置带来的点击偏差」(12.5.1)——生产系统里两类偏差往往叠加,需要 PAL 与 ESMM 组合使用。
12.5.3 胜出偏差与延迟反馈:标签本身的两种污染
第三类偏差更隐蔽:它不在样本空间里,而在 标签的生成过程 里。竞价系统的日志只记录赢家——只有赢得竞价的广告才能展示,才有机会产生点击与转化;输家的「假如展示给我会怎样」永远观测不到。这就是 胜出偏差(Winner's Bias) ,选择偏差在竞价场景的具体形态:训练与校准用的标签,天然来自「系统认为最优」的那个分配,是一份有偏的账本。模型在这份账本上越学越深,偏差就滚得越大——系统越是只把流量给自己喜欢的广告,就越看不见其他广告的真实成色。
破局要靠 探索流量(Exploration Traffic) :刻意让一部分「本会输的广告」偶尔赢,为输家产生无偏的反馈信号。这给了 12.2.4 的 E&E 框架又一重身份:探索不只是为了估准长尾 CTR,更是为整个学习系统供给 无偏标签——没有探索流量的竞价系统,是在用自己的输出训练自己的输入,闭环越来越紧,视野越来越窄。
第四类偏差与时间有关。转化常常在点击后数小时、甚至数天才发生,而系统等不起——这就是 延迟反馈(Delayed Feedback)。应对的核心纪律是:校准必须指定明确的 标签窗口(Label Window) ,例如「点击看 1 天、转化看 7 天」,并严格按窗口口径取数。窗口太短,标签尚未成熟(后期回流的转化被漏记),按其校准必然系统性低估;窗口太长,数据时效性又跟不上分布漂移。未等标签成熟就校准,等于用一把还在变形的尺子去量东西——校准曲线学到的不是真实基率,而是「截断的基率」。
Analysis: 这两类偏差与 12.5.1、12.5.2 有本质区别:位置偏差与 SSB 是「样本空间」的问题(哪些样本进入训练),胜出偏差与延迟反馈是「标签生成」的问题(进入训练的样本拿什么标签)。校准模块对此无能为力——它只能忠实反映「给它什么分布,它就校准到什么分布」。因此 12.5.4 的结论是「先去偏、再校准」,顺序不能反。
12.5.4 校准方法与工业实践:给预估装上后处理恒温槽
现在进入本章的工程主菜。校准(Calibration) 要的是这样一个等式:
即模型打 分的那组样本中,恰好约有 是正例——「说 70% 就真是 70%」。先盘一盘偏差从哪来。其一,深度模型普遍过度自信 (Guo et al., 2017),判别力越强的模型未必越诚实。其二,负采样改变基率 :训练时下采样负例(正例占比被人为抬高),模型的输出反映的是 训练分布的基率 而非线上真实基率,直接上线必然高估。其三,分布漂移(Distribution Drift) :流量结构、广告库、用户行为持续变化,加上训练-服务偏斜,昨天量好的尺子今天就不准了。
校准质量怎么测? 可靠性图(Reliability Diagram) :把预测概率分桶,横轴是桶的平均预测值,纵轴是桶内真实正例率,点落在对角线上即校准完美。数值化版本是 期望校准误差(Expected Calibration Error, ECE) :
其中 是第 个桶, 是桶内实际正例率, 是桶内平均预测值。解读可靠性图有个必须警惕的坑:稀疏的高分桶(如 0.9–1.0 区间)样本极少、噪声极大,单点偏离对角线未必是失真——看图要叠加每桶的样本量。
红色曲线是典型的过度自信模型:预测 0.9 的桶实际正例率只有 0.70,各桶系统性低于对角线;经保序回归校准后(绿色曲线),各桶贴近对角线,ECE 显著下降。
两类经典的后处理校准方法,分别适配不同数据量级。Platt scaling :对原始分数拟合一个 logistic 变换 ,只有两个参数,适合小样本、失真形态为平滑单调压缩的情形。保序回归(Isotonic Regression) :拟合自由形状的单调阶梯函数,由 PAVA(Pool Adjacent Violators Algorithm,池相邻违反者算法) 求解——按预测值排序后,凡相邻桶违反单调性即合并取均值,反复合并直到序列单调。它更灵活、适合大样本,但在稀疏区域(极高/极低分桶)容易过拟合噪声。二者的共同纪律: 模型冻结后,在独立验证集上拟合——用训练集拟合校准曲线等于让曲线记忆训练噪声与训练基率,是有偏的。
工业界怎么落地的?三个标志性案例。
- Google (McMahan et al., KDD'13,《Ad Click Prediction: a View from the Trenches》):CTR 校准使用 保序回归——大规模数据下阶梯函数的灵活性胜过两参数的 logistic。
- Facebook (He et al., ADKDD'14,《Practical Lessons from Predicting Clicks on Ads at Facebook》):不用保序回归,而是用负采样下的 先验修正(Prior Correction)——若负例以比例 下采样,直接用闭式公式把输出恢复到真实基率:,零成本、无需拟合。
- 阿里妈妈 :校准模块与预测/排序模块 解耦 ,即插即用、可独立快速响应分布漂移;算法一路演进——SIR (平滑保序回归:分桶 + 保序 + 线性缩放)→ Bayes-SIR (贝叶斯先验解决冷启动与稀疏)→ RTW-BSIR (实时波动修正,对抗分布漂移)→ PCCEM (用点击后短期信号预测长期转化,正面应对延迟反馈),自 2018 年起线上部署。
评估校准不能只看一个全局数。工业指标体系通常包括: PCOC (预测 CTR 与后验 CTR 之比,越接近 1 越好)、Cal-N (多簇 PCOC 聚合的偏差度量)、GC-N (分维度加权的校准指标)。ECE 看整体形状,PCOC 看整体比值,Cal-N/GC-N 看分片——因为 全局校准会掩盖分片失真 :整体 PCOC = 1,可能一半流量高估、另一半低估,互相抵消。AdaCalib(Wei et al., SIGIR 2022)正是把校准推进到 field-level(字段级)细粒度:用学习到的保序函数族加上后验统计自适应引导,让每个特征切片都被单独校准。
最后是运维视角,也是校准与普通「模型模块」最大的不同。校准 不是一次性工程 :流量组合与用户行为持续变化,需要在近期留出日志上以 小时级/天级高频重拟合——独立于节奏慢得多的全模型再训练。线上要有护栏:持续监控 observed-vs-predicted 比率 (实际点击率 ÷ 预估点击率),偏离 1 超过阈值即告警、触发重拟合。并且要 分 segment 校准 (按流量切片、广告行业、设备等维度分别拟合),对抗前面说的「全局掩盖分片」。再重复一遍本章最重要的操作纪律: 先去偏、再校准——最伤害校准的正是位置偏差与选择偏差,当标签与样本本身有偏时,校准模块只会忠实地把模型校准到那个「有偏的世界」。
Analysis: 校准模块的工程魅力在于「小而快」:不动主干模型、只修正「分数 → 概率」的映射,因此可以高频重拟合、独立灰度、按 segment 滚动。这与 12.2.4 讨论的「动态特征 vs 在线学习」是同一个哲学——把变化快的部分从变化慢的部分里拆出来,各自按自己的节奏迭代。机制(12.3)与出价(12.4)按季度演进,主干模型按天演进,校准按小时演进:一个成熟的广告系统,是多个不同节拍器的合奏。
12.5.5 测量是机制与出价的地基
把本章的教训放回 Part 12 的全景,你会看到一条自我强化的误差回路: 校准误差 → eCPM 算术失真 → 竞价排序错位、计费不公(12.3 的 GSP 支付按失真的 pCTR 折算)→ pacing 花速预测失稳(12.4)→ 预算消耗节奏紊乱 → 反过来改变流量的探索比例与曝光分布 → 反塑标签分布。误差绕了一圈,开始喂养自己的来源——这就是为什么偏差治理不能是「一个模块的事」:它是一条环形的链路,任何一环的失准都会沿着环放大,最终回到起点污染训练数据本身。
于是可以给 Part 12 一个乘法总结: 广告系统 = 机制设计(12.3)× 出价策略(12.4)× 测量系统(本章)。机制决定「规则怎么定」,出价决定「预测怎么花」,测量决定「预测本身准不准」。前两者的一切精妙——GSP 的无妒忌均衡、VCG 的外部性定价、OCPC 的成本约束——全部建立在「预测值 ≈ 真实概率」的假设之上。测量是地基:地基晃一寸,上面的经济学大厦就摇一尺。12.1 的生态全景里,平台向广告主承诺「帮你更高效地花钱」;兑现承诺的最后一公里,正是这套看不见的测量系统。
不过,这个乘法还漏掉了一个更底层的变量: 平台到底能观测到多少转化数据。测量系统再准,若转化发生在平台域外、连标签都拿不全,一切精度都无从谈起。这根轴——开环与闭环——由 12.6 来收束整个 Part 12。
最后一个视角,留给推荐与广告的合流。推荐系统正在「广告化」:流量分配、保量合约、多样性约束——机制设计的语言正进入推荐排序;广告系统也在「推荐化」:机制约束被写进模型端到端学习,8.3 的 EGA 就是「分配与支付都变成可微网络」的尝试。但无论两条路线怎么合流,它们共享同一个底座:表示学习(Part 3)+ 测量科学(本章)。对工程师而言,理解「模型的分数在什么条件下才是一个概率」,是从推荐工程师走向广告算法工程师的最后一课——也是让机器的判断可以被托付真金白银的前提。
⚠️ Common Mistakes in 12.5
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为 AUC 高预估就够用 | 「模型 AUC 0.80,直接接进出价栈」 | AUC 只衡量相对序,对分数单调变换不变;eCPM/出价/计费消费的是绝对值,系统性高估照样算错钱 | 同时监控 PCOC/ECE 等校准指标,预测值进入算术前过校准模块 |
| 2 | 把校准当训练的一部分而非独立后处理 | 「模型最后一层加个 sigmoid,就算校准了」 | 校准是「分数→概率」的映射修正,需在独立验证集上高频重拟合;与主干混训会互相污染、跟不上漂移 | 主干冻结后在留出集上拟合校准曲线,独立部署、独立更新 |
| 3 | 用训练集拟合校准曲线 | 「训练收敛后在训练集上跑保序回归」 | 校准曲线记忆训练噪声与训练基率,线上分布一变就系统性失真 | 必须用独立验证集(近期留出日志)拟合校准曲线 |
| 4 | 忽视负采样带来的基率漂移 | 「负例下采样 10 倍训练,模型输出直接上线」 | 训练分布的正例占比被人为抬高,输出反映训练基率而非线上基率 | Facebook 式先验修正闭式恢复,或负采样后在真实分布上重校准 |
| 5 | PAL 上线时仍把位置喂进 pCTR 塔 | 「位置特征保留,线上统一填第 1 名」 | 位置是排序的输出而非输入;填默认值让模型带上线下的位置先验,预估有偏 | PAL 推理只走 pCTR 塔,位置信息止步于训练期分解 |
| 6 | 标签窗口未成熟就校准 | 「转化窗口 7 天,上线第 3 天就重拟合校准」 | 后期转化尚未回流,标签系统性偏低,校准曲线学到截断的错误基率 | 固定标签窗口口径,只用窗口已成熟的数据进入校准拟合集 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 校准 ≠ 判别力 | 判别力 = 相对序(AUC,单调变换不变);校准 = 绝对值可信();二者正交 | 高 AUC 模型可以校准很差;广告的算术消费绝对值 |
| 偏差放大 | :多分数相乘放大各模型的校准偏差 | 各模型 AUC 都不错,链路末端仍可能严重失真 |
| 位置偏差 | examination 假设 ;位置作特征 / IPW / PAL 三方案 | PAL(Guo et al., RecSys 2019):ProbSeen × pCTR 联合训练、线上只走 pCTR 塔,AB +3%~35% |
| SSB 与 ESMM | 点击空间训练 ≠ 曝光空间推理;ESMM 用 pCTCVR = pCTR × pCVR 全空间建模、双塔共享 embedding | 同时解决 SSB 与 DS(点击仅占曝光约 4%);CVR 无直接损失项、隐式学习;CVR AUC 绝对 +2.56% |
| 胜出偏差与延迟反馈 | 日志只记录赢家;转化晚到须固定标签窗口(1 天点击/7 天转化) | 探索流量供给无偏标签;未成熟标签校准必然有偏 |
| 校准方法 | Platt scaling(小样本)vs 保序回归 PAVA(大样本、稀疏区易过拟合);均需独立验证集 | Google 用保序回归、Facebook 用负采样先验修正、阿里妈妈 SIR→Bayes-SIR→RTW-BSIR→PCCEM(2018 年起部署) |
| 校准运维 | 小时/天级高频重拟合;observed-vs-predicted 护栏;分 segment 校准(PCOC/Cal-N/GC-N) | 先去偏再校准——位置偏差与选择偏差最伤校准 |
❓ FAQ
Q1: AUC 和校准到底哪个更重要?
A: 取决于预测值的用途。只用于排序(召回、推荐精排)时判别力优先,分数整体乘个常数无所谓;一旦进入算术(出价、计费、预算控制),校准就是生死线。工业广告系统的标准姿势是「判别力强的主干 + 独立高频校准的后处理」,两头都要、各按各的节奏迭代。
Q2: ESMM 的损失里没有 CVR 项,CVR 塔真的能学到东西吗?
A: 能。 衡量 与 的差异,对 (pCVR)的偏导非零,梯度经乘积回传到 CVR 塔——这就是「隐式学习」的含义。代价是 CVR 塔的信号不如直接监督干净,收益是它天然在全曝光空间训练,绕开了 SSB;配合共享 embedding 从 CTR 样本迁移表示,稀疏问题 DS 也一并缓解。
Q3: 负采样之后,为什么不能直接相信模型输出?怎么修?
A: 下采样负例把训练分布的正例占比人为抬高,模型学到的是「训练基率」下的概率。修法两条:闭式的先验修正 (Facebook ADKDD'14, 为负例保留比例,零成本);或在真实分布的验证集上重校准。前者快、后者稳,工业上常并行使用互为校验。
🔗 前后关联
- 12.2 (计费模式与核心指标)——eCPM 这把尺子的刻度由 pCTR 决定;12.2.4 埋下的「回归比排序更合适」伏笔在本章展开为完整的校准方法论。
- 12.3 (竞价机制)——GSP 支付按下一名 eCPM 除以自己 pCTR 折算,校准失真直接导致计费不公;机制的一切理论性质都假设预测值可信。
- 12.4 (智能出价)——出价栈逐层消费 pCTR/pCVR,是本章「误差传导链条」的主战场;校准护栏是 pacing 稳定的前提。
- 3.x (排序模型)——模型结构同源,但广告场景对绝对值校准提出了额外要求;本章可视为 Part 3 的「概率化补完」。
- 8.3 (EGA)——机制约束端到端化之后,校准仍是从模型分数到经济量的翻译层;生成式广告同样逃不开「分数必须是概率」的测量纪律。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 12.5.1 — 用 PCOC 诊断系统性低估 🟢 Easy
某广告分片上,模型预估的平均 pCTR 为 0.020;100 万次曝光实际产生 26,000 次点击。同场有一个 CPM 计费的竞争广告,出价 45 元。 (a) 计算 PCOC(预估 CTR ÷ 后验 CTR),判断偏差方向与幅度。 (b) 一个 bid 为 2.0 元的 CPC 广告,真实 CTR 与模型预估一致成比例。它在本次竞价的结局如何?本应如何?
💡 Solution (click to reveal)
Approach: PCOC = 预估均值 ÷ 后验均值;再用预估与真实 pCTR 分别算 eCPM 比较竞价结果。
- (a) 后验 CTR = 26,000 / 1,000,000 = 0.026。PCOC = 0.020 / 0.026 ≈ 0.77 ,模型系统性 低估约 23%。
- (b) 该 CPC 广告真实 eCPM = 元;模型预估 eCPM = 元 ,竞价 落败。但按真实值 52 > 45,它 本应胜出——低估让平台错失了期望收益更高的展示。
Key points:
- PCOC 偏离 1 的方向直接指示高估/低估,是线上最常用的校准护栏指标。
- 校准偏差改变的不只是「报数」,而是竞价结果与平台收入——这就是 12.5.0 后果链条的第一环。
Problem 12.5.2 — examination 分解与去偏排序 🟡 Medium
位置 1 与位置 2 的被看到概率分别为 、。日志显示:广告甲在位置 1 观测 CTR 为 4.5%,广告乙在位置 2 观测 CTR 为 2.4%。 (a) 按 examination 假设计算两广告的 。 (b) 若直接按观测 CTR 排序,会把甲的优势高估多少倍?这对出价换算意味着什么?
💡 Solution (click to reveal)
Approach: 观测 CTR = ,相除即得去偏后的相关性。
- (a) 甲:;乙:。
- (b) 观测序:甲/乙 = 倍;去偏后真实质量比 = 倍。直接按观测 CTR 排序会把甲的优势高估约 倍——位置红利被记进了广告质量。在出价换算(eCPM = pCTR × bid × 1000)中,这等效于系统性高估高位广告、低估低位广告,换坑位后的收益预测全部失真。
Key points:
- examination 分解是「去偏版 A/B 比较」的最小工具:除以位置倾向即可复原可比质量。
- 位置偏差伤害的不只是排序,还有一切以 pCTR 为输入的算术——这正是 12.5.4「先去偏再校准」的原因。
Problem 12.5.3 — ESMM 的乘法结构与梯度来源 🟡 Medium
ESMM 中某曝光样本的模型输出:pCTR ,pCTCVR 。 (a) 该样本的 pCVR 是多少? (b) 为什么 ESMM 不直接按 相除建模,而要坚持乘法结构? (c) 损失 中没有 CVR 的直接监督项。请说明 CVR 塔参数的梯度从哪里来,并解释「隐式学习」的确切含义。
💡 Solution (click to reveal)
Approach: 链式法则 + 乘积的偏导数。
- (a) (此处是事后换算,不是建模方式)。
- (b) 相除有两个坑:pCTR 很小时(点击本就是小概率事件,如 0.001),商数值爆炸且可能大于 1,违反概率值域;乘法则保证 且数值稳定。
- (c) 度量转化标签 与 的差异。对 CVR 塔参数 ,梯度 ,经乘积回传——CVR 塔仅由 更新 ;CTR 塔与共享 embedding 由两项共同更新。「隐式学习」指 pCVR 没有自己的标签与损失,只作为中间变量被乘积的偏差驱动。
Key points:
- 乘法结构一举三得:全空间训练(绕开 SSB)、数值稳定、值域合法。
- 即使 CTR 塔已把点击预测得很好,CVR 塔仍有梯度——转化标签与 的残差就是它的学习信号。
Problem 12.5.4 — Facebook 负采样先验修正 🔴 Hard
为加速训练,负例以保留比例 下采样(每 10 个负例保留 1 个)。线上某广告的模型输出 (训练分布口径)。 (a) 从「下采样改变了正例占比」出发,推导先验修正公式 ,并计算修正后的概率。 (b) 若不做修正,预估会朝哪个方向偏、大约错多少倍? (c) 除了闭式修正,还有什么等价手段?各自的适用条件是什么?
💡 Solution (click to reveal)
Approach: 写出下采样后训练分布的正例占比与真实占比的关系,反解。
- (a) 设真实正例概率为 。下采样后训练分布中:正例质量 、负例质量 ,故 。反解 :,代数变换后恰等于 。代入 :。
- (b) 不修正时高估: vs 真实 ,高估约 9.5 倍 (odds 被放大约 倍,概率越大放大的绝对差越大)。出价、eCPM、预算消耗全部按虚高的 10 倍量级计算。
- (c) 等价手段:在 真实分布的验证集 上重校准(Platt scaling 或保序回归),拟合时自然恢复基率——适合分布复杂、失真非单一基率偏移的情形;闭式先验修正胜在零成本、可解释,适合「纯基率漂移」的情形。工业上两者并行、互为校验。
Key points:
- 修正公式的推导起点永远是把「训练分布的构成」写出来,再反解真实分布。
- 这正是 Common Mistakes 第 4 条的定量版:负采样不是免费的午餐,输出必须换算回线上口径。
🏆 Problem 12.5.5 — 手算 ECE 与 PAVA 保序校准
给定 8 个样本(按预测值升序):
| 预测值 | 0.1 | 0.2 | 0.3 | 0.4 | 0.6 | 0.7 | 0.8 | 0.9 |
|---|---|---|---|---|---|---|---|---|
| 真实标签 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 |
(a) 以 与 两桶计算 ECE。 (b) 对全部 8 个点执行 PAVA 算法拟合保序校准,写出每一步的合并与最终每个预测值的校准输出。 (c) 用校准后的值重算两桶 ECE。 (d) 指出上述「在同一份数据上拟合又评估」的做法在工程上的漏洞,以及 PAVA 输出 0 与 1 这种极端阶梯的风险。
💡 Solution (click to reveal)
Approach: ECE 按桶加权;PAVA 按预测排序后反复合并违反单调的相邻块。
(a) 桶 1 :conf ,acc ,。桶 2 :conf ,acc ,。
(b) 初始块均值序列(按预测排序):。检查单调性:位置 6→7 出现 的违反。合并块 ,均值 。新序列:,已单调,PAVA 终止。校准输出:
| 原预测 | 0.1 | 0.2 | 0.3 | 0.4 | 0.6 | 0.7 | 0.8 | 0.9 |
|---|---|---|---|---|---|---|---|---|
| 校准值 | 0 | 0 | 0 | 0 | 2/3 | 2/3 | 2/3 | 1 |
(c) 桶 1:conf ,acc ,diff 。桶 2:conf ,acc ,diff 。——校准后完美贴合。
(d) 两个漏洞。其一, 数据泄漏 :校准曲线在同一份数据上拟合与评估,ECE = 0 有过拟合成分——工程上必须在独立验证集上拟合、在另一批数据上评估。其二, 稀疏区的极端阶梯 :PAVA 给出 0 与 1 这样的硬边界,在样本稀疏的高分/低分区极不稳定(本例每桶只有 4 个样本);阿里妈妈用平滑(SIR)与贝叶斯先验(Bayes-SIR)正是为了缓解这一点,小样本场景也可退回参数更少的 Platt scaling。
Key points:
- PAVA 的本质:反复合并「相邻违反者」取均值,直到均值序列单调——它是保序回归的最优解。
- ECE 依赖分桶方式;工程上同时看可靠性图(叠加样本量)、PCOC 与分片指标,避免单一数字误导。
开环广告与闭环广告
📝 Before You Continue: 本章需先读 12.4(智能出价与预算控制)——oCPM 与深度转化出价的公式是本章「闭环能做什么」的地基;以及 12.5(预估偏差与校准)——归因与延迟反馈是本章「开环为什么难」的前置。本章从数据可观测性视角,为整个 Part 12 收束。
前五章讲完了一件事的四个侧面:怎么投放(12.1)、怎么计费(12.2)、怎么定价(12.3)、怎么出价(12.4)、怎么测量(12.5)。但所有这些精妙机制都踩着一个未被明说的假设——平台能观察到多少转化数据。设想同一个 oCPM 出价公式:,在抖音小店里,用户下单支付全在平台眼皮底下,pCVR 模型每天有海量转化标签可学;可一旦广告主投的是「App 下载」,用户跳出抖音、在 App Store 里点了下载按钮,抖音根本看不见那一下「转化」到底发生了没有。同一个公式,前一个场景里 pCVR 是实打实的观测,后一个场景里 pCVR 是半猜半等。
这一章讨论的,就是这条把广告世界一分为二的线: 转化行为是否发生在平台可观测的域内。域内是 闭环广告(Closed-loop Advertising) ,域外是 开环广告(Open-loop Advertising)。你会看到这条线如何决定了一个平台能做多深的优化、能报多贵的价格、能兑现多大的承诺,也会看到隐私浪潮如何把这条线越推越偏向「平台自己闭环」。
读完本章,你将能够:
- 用「转化是否在平台可观测域内」这条标准,把任意一个广告场景归类为闭环或开环,并说清它影响的不是广告形式而是数据链路
- 解释闭环为何让平台能训练深度 pCVR 模型、做深度转化出价(付费/ROI/次留/7 日 ROI),以及「越投越准」的正向循环如何推高 eCPM
- 描述开环归因的完整流程(clickid 下发 → 回传 → ip+ua 兜底)与六种归因模型的分配规则,说清 MMP 为何能对抗重复计数
- 说明 ATT、SKAdNetwork、Android Privacy Sandbox 如何让确定性归因坍缩,以及开环场景下的混合归因策略
- 描述开环工程实战的六层基础设施:回传协议设计(clickid/幂等/乱序)、MMP 多路匹配与反作弊、SKAN 落地(Conversion Value 编码/聚合建模)、延迟反馈与样本偏差的三族解法、半闭环的激励回传机制、增量测量(geo 实验/MMM)
- 用一张对比表串联闭环 vs 开环在出价目标、数据可得性、延迟反馈、模型训练、归因确定性上的全面差异,完成分层练习题
12.6.0 广告的第二根轴:数据可观测性
12.1 的生态全景里,我们把广告按「投放模式的演进」切了三刀:直签、广告网络、程序化交易。那是一条关于 交易结构 的轴。现在引入第二条轴,与交易结构正交: 数据可观测性(Data Observability)——广告主想要的转化,到底发生在平台的视线之内,还是视线之外。两根轴拼起来,才是一张完整的广告地图:你既要知道流量是怎么买来的(12.1),也要知道转化是怎么被看见的(本章)。
这条轴的两端有业界通用的名字。闭环广告(Closed-loop Advertising) ,也叫 内循环 :广告曝光、点击、下单、支付这一整条链路都在平台自己的生态里完成,数据一步也不离开平台。典型形态是抖音小店、快手小店的电商闭环,或 Facebook Shops 里的站内购买——用户在信息流里看到广告,点进去直接进商品页,下单支付都在 App 内。开环广告(Open-loop Advertising) ,也叫 外循环 :转化发生在平台之外,用户从广告点击出发,跳出平台去 App Store 下载、去品牌官网注册、去线下门店消费。平台的视线在这里断了——它能确认「用户点了广告」,却无法确认「用户到底下载了没有、买没买」。
这里有一个必须先钉死的认知: 开环 vs 闭环不是广告形式的区别,而是数据链路是否闭合的区别。原生广告、信息流广告这些「形式」并不天然属于任何一端——同样是信息流里的一条广告,投「抖音小店商品」就是闭环,投「某款手游的 App 下载」就是开环。判断标准只有一个:用户完成转化时,平台能不能直接观测到。这条标准的威力在于它是个二分的开关:链路闭合,后链路的每一层转化(下单、支付、复购、次留)都是平台的训练数据;链路断开,平台手里就只剩「点击」这一个相对可靠的信号,再往后全靠广告主愿不愿意、能不能回传。
左图闭环链路里,四个环节都收在「平台域」的方框内,转化数据沿着实线箭头即时回流,模型与出价都能拿到完整标签。右图开环链路里,「曝光→点击」还在平台内,但「转化」这一步从方框跳了出去,指向 App Store、品牌官网、线下门店——平台与转化之间只剩一条需要广告主回传的虚线,且随时可能断裂。
🧠 Mental Model: 账本在谁手里
闭环广告像在自家店里收银:每一笔成交都记在自己的账本上,今天卖了什么、谁买的、买完又买了什么,翻账本就知道。开环广告像在别人的店里埋单:你只能看着顾客走进门(点击),至于他在里头买了没有、买了多少,得靠店主事后发微信告诉你(回传)。账本在谁手里,决定了你第二天能多聪明地进货。
这一节确立了本章的判据,接下来四节沿着这条轴的两端分别展开。12.6.0 确立判据;12.6.1 讲闭环为什么是「更好的那一端」;12.6.2 与 12.6.3 讲开环的归因与隐私两大难关;12.6.4 全景对比表;12.6.5 是面向工程师的开环实战六层;12.6.6 回到 Part 12 的整体收束。
12.6.1 为什么闭环改变一切
12.6.1 为什么闭环改变一切
闭环的价值不在「形式好看」,而在它补上了前五章所有机制最渴望的一样东西: 完整的转化标签。回想 12.4 的结论——oCPM 的本质是平台用预测能力换定价权,平台敢接转化出价,前提是 pCVR 预估足够准。而 pCVR 要准,前提是有转化标签可学。闭环场景里,这个前提天然成立:曝光、点击、下单、支付每一步都发生在平台域内,平台能直接观测到「这个用户点了广告之后,到底有没有付费」。于是它才能训练真正的深度 pCVR 模型,才敢承诺 深度转化出价——付费单出价、付费 ROI 出价、激活-次留双出价、7 日 ROI 出价这些后链路目标。
这一层差别把出价目标劈成了两个世界。开环场景下,平台只能做 浅层目标 :点击、激活、表单提交、注册——因为再往后的转化它看不见。闭环场景下,平台能做 深层目标 :付费、ROI、次留、7 日 ROI——因为这些行为就发生在它的域内。12.4.1 的 oCPM 两阶段实践(先 CPC 冷启动积累转化、再切转化出价)在这里获得了一个新解读:冷启动要积累的「转化数据」,闭环平台靠自己的全链路观测就能拿到,开环平台却只能等广告主的稀疏回传慢慢攒。
更深一层,闭环触发了一个 正向循环。平台用付费用户的完整行为训练深度模型,模型越准,就越能把广告分发给「更可能付费」的人,投放效果越好,广告主越愿意加预算,平台又拿到更多转化数据,模型再进一步——「越投越准」的飞轮转起来了。这条飞轮的终点,是 12.2 风险谱系的最深端:平台甚至敢按「付费」这个最接近钱的目标来代管出价,把转化风险几乎全部揽到自己身上。源材料里头条/抖音的行业口径把这层价值说得很直白:以付费用户为训练数据的模型,稳定后通投效果优异、前端出价更高, eCPM 普遍高出约 20%(行业口径)——广告主买到更优质的流量,平台的千次展示收益也更高,这是一个双边都受益的结构。
这解释了超级 App(抖音、快手、淘宝)广告增长的底层逻辑。它们不满足于做「流量中转站」,而是拼命把交易搬到自己的生态里——建小店、开直播带货、做本地生活——因为每多圈住一段转化链路,就多一份别人拿不到的训练数据。当一家平台同时拥有「海量流量」和「完整转化观测」两样东西时,它的广告系统就能做别的平台做不了的深度优化,这构成了近乎不可逾越的护城河。12.1 的生态演进讲的是「谁能买到流量」,本章补上的是「谁能看见转化」——后者才是现代广告竞争里更稀缺的资源。
🧠 Mental Model: 越投越准的复利
闭环广告像一门有复利的生意:第一笔转化数据是本金,模型是利率,每轮投放都用「本金 + 利息」去赚下一轮更大的转化数据。开环广告则像按次结清、拿不到账本的生意——每次投放结束,你能确定的就是「点了多少下」,本金都攒不下来,谈何复利。数据可观测性,就是这个行业里真正的复利来源。
Analysis: 闭环的「约 20% eCPM 溢价」要放在口径里读:它是第三方行业转述的头条/抖音口径,反映的是「深度模型 + 全链路数据」带来的整体收益提升,不同行业、不同类目会有波动。可把它当作趋势证据,而非放之四海皆准的常数。另需注意:闭环的深度转化出价并非没有门槛——深度后链路事件(如付费)转化稀疏、延迟更高,需要数据积累,这也是快手等平台对「付费 ROI 出价、7 日 ROI 出价」产品要求加白的原因(12.6.4 的对比表会再回到这一点)。
12.6.2 开环的归因难题
现在把镜头转向开环那一端。转化发生在域外,平台看不见,于是横亘在广告主和平台之间的问题是: 这一次转化,到底该算谁的功劳? 这就是 归因(Attribution)——在广告行为链路里,识别「关键行为」究竟由哪个广告、哪个渠道带来。闭环场景下这个问题几乎不存在(转化就发生在平台内,链路唯一);开环场景下它成了一个必须靠基础设施去解决的问题。
归因的前提是平台能拿到「转化确实发生了」这条消息,而这条消息要靠广告主 回传。完整流程分三步。第一步, 广告触点追踪 :用户点击或看到广告时,媒体通过监测链接下发 clickid、广告 id、ip、ua 等参数,给这次曝光或点击盖一个独一无二的戳。第二步, 转化行为回传 :用户完成激活、注册、下单等转化时,广告主的 App 或网站通过 SDK / API 把设备 ID、clickid、时间戳回传给媒体平台——「这个用户是我要的」。第三步, 兜底归因 :拿不到设备 ID 时,退而用 ip + ua 做模糊匹配,精度随之下降。回传不仅是为了「算清账」,还是平台做相似人群探索(Look-alike)与放量判断的依据:媒体要知道哪些流量真的有效,才知道该把预算往哪加。
拿到「谁在哪一步转化」之后,还要决定「功劳怎么分」——这就是 归因模型(Attribution Model)。注意它的本质:归因不是客观事实的测量,而是一套 分配规则 的约定。同一条用户旅程,换一个模型,结论可能截然相反。常见的归因模型谱系如下表:
| 模型 | 功劳分配规则 | 适用场景 |
|---|---|---|
| 最后点击(Last-click) | 100% 给转化前最后一次触点 | 简单直效,移动端默认 |
| 首次点击(First-click) | 100% 给第一次触点 | 度量漏斗顶部的发现/种草 |
| 线性(Linear) | 所有触点均分 | 认为每次互动价值相等 |
| 时间衰减(Time-decay) | 越接近转化的触点分得越多 | 短周期意图驱动 |
| 位置加权(Position-based) | 首尾触点多分、中间少分(U 型) | 兼顾发现与收口 |
| 数据驱动(Data-driven) | 算法基于观测到的贡献自动分配 | 高量级、多渠道 |
同一条「广告A曝光 → 广告B点击 → 广告C点击 → 转化下单」的旅程,五种模型给出五种答案:最后点击把功劳全给 C,首次点击全给 A,线性三人均分,时间衰减按「离转化远近」递减,位置加权把首尾(A、C)抬高、中间(B)压平。这不是谁对谁错,而是「你相信哪个环节更值钱」的立场选择——下面这个交互式模拟器让你亲手切换模型,步进看同一旅程的结论如何翻转。
建议按剧本走:先在「设定」步看清这条三条触点的旅程,然后依次切到最后点击、首次点击、线性、时间衰减、位置加权,观察横向条形图里功劳的分配如何被同一段旅程「重新洗牌」。最后一步的总结会告诉你,为什么说「归因是一种分配规则,而非客观事实」。
归因还有一个「谁来算」的问题。自归因(Self-attribution) :平台或媒体自己完成归因,宣称「这次安装是我带来的」——苹果搜索广告、部分头部平台采用此方式。非自归因 :广告主自行匹配用户与媒体信息,独立完成归因。问题在于,如果每家广告网络都「自己说自己赢」,同时跑多个网络时,各家报告的安装数加起来会远超真实安装量——常达真实安装量的 200%~300%。于是第三方中立仲裁者登场: 移动归因伙伴(Mobile Measurement Partner, MMP) ,如 AppsFlyer、Adjust、Branch、Singular、Kochava。MMP 站在广告主与各广告网络之间,用统一的口径判定每一次转化该记给谁,把「老王卖瓜」的重复计数压下去。
🧠 Mental Model: 法官 vs 当事人
归因模型是「怎么判案」的规则(最后点击 = 只信最后一击;线性 = 人人有份),MMP 是「谁来当法官」的制度安排。让广告网络自己归因,等于让当事人自己写判决书——每一家都觉得自己才是促成转化的关键先生,加起来自然超过 100%。MMP 的存在价值,就是把判决权从当事人手里,转移到中立的第三方。
Analysis: 归因模型的选择本质是一个业务假设,而不是一个可被「算出来」的最优解:最后点击适合决策链短、即点即买的场景;首次点击适合重品牌曝光、决策周期长的品类;数据驱动归因最「聪明」,但它需要大量可观测的转化数据才能学出可信的贡献——这恰恰在开环、尤其隐私受限的开环场景下最难满足。因此选归因模型,先问「我的转化链路多长、数据够不够」再问「哪个模型更准」。
12.6.3 隐私浪潮让开环更难
开环归因的地基是一样东西: 设备级的确定性标识。平台靠 IDFA、GAID 这类广告标识符把「广告点击」和「后来的转化」绑到同一个用户身上。这条地基在 2021 年前后开始塌陷,第一块塌下来的是苹果的 ATT(App Tracking Transparency,应用追踪透明度) :iOS 14.5 起,App 要访问 IDFA 必须弹窗获得用户授权。结果绝大多数用户拒绝——opt-in 比例仅约 25% ,设备级标识随之大面积坍缩。确定性归因赖以为生的「唯一用户 ID」没了,开环场景的测量精度应声下跌。
苹果随后给出的替代品是 SKAdNetwork(SKAN) :一套由 Apple 自己校验安装、以聚合且延迟的方式回传转化数据的隐私保护归因框架。它的设计处处透着「反确定性」:数据是 聚合 的而非用户级;回传带有 随机计时器延迟 ;粒度受限;还有 群组匿名(Crowd Anonymity)——安装量太小时回传更少信息,防止单个用户被反向定位。转化则通过 conversion value 上报,App 用 updateConversionValue 记录用户互动。SKAN 4.0 进一步把回传结构化:引入粗/细两种转化值,并设 三次回传窗口(约 0–2 天、3–7 天、8–35 天) ,允许随转化进程多次回传;层级 source identifier 用 4 位分层编码(前 2 位活动、第 3 位位置、第 4 位屏位等),随群组匿名级别升高返回更多位。注意:SKAN 不是 IDFA 的等价替代,它是「用确定性换隐私」的全新契约。
Android 侧也在走同一条路。Android Privacy Sandbox (2024+)是 Google 的无 cookie 归因方案: Attribution Reporting API 提供事件级与聚合两种归因报告,聚合报告自带 差分隐私 噪声;Topics API 则用于基于兴趣的广告。三家平台殊途同归:都把「你是谁」从归因信号里抹掉,只留下加了噪声的「有一群人做了某件事」。
这套隐私浪潮的实用后果是: 开环的确定性归因彻底坍缩,只能退而求其次地「混搭」。iOS 上,广告主与 MMP 如今必须混合使用三层信号:SKAN 的聚合回传(隐私但模糊、延迟)+ 少数 opt-in 用户授权后的确定性数据(精确但样本小)+ 用这两者训练出的建模估计(把模糊补齐成可用的预测)。接受了更多的噪声,也就接受了「每一分钱花在哪」这件事从精确记账退化成带误差的估算。正是这种「看得越来越模糊」的处境,把整个行业推向两个方向:能闭环的,拼命把转化圈回自己的域内(闭环化);不能闭环的,则转向第一方数据战略——不再依赖跨 App 追踪,而是经营自己与用户直接发生的、合法合规的数据关系。
🧠 Mental Model: 磨砂玻璃
IDFA 时代的归因像透明玻璃:点广告的人、装 App 的人,看得一清二楚。ATT 之后换上了磨砂玻璃:你只能看见「有人进来了」,看不清是谁。SKAN 则是玻璃上再加一层百叶窗:每隔一阵子,Apple 掀开一条缝,给你看一个模糊的、加了噪声的、迟到的结果。广告主和 MMP 能做的,就是透过这三层遮挡,把「到底发生了什么」尽可能拼回来——拼得越像,越接近过去的确定性。
Analysis: 隐私浪潮对开环的打击是结构性的,而非一次性的政策摩擦:ATT 砍掉的是「唯一标识」,SKAN 砍掉的是「及时性与颗粒度」,Privacy Sandbox 砍掉的是「无噪的事件级回传」。三者叠加意味着开环的测量精度有一个被制度锁死的上限——这不是靠更好的算法能完全补回来的。这也是为什么本章把「数据可观测性」拔高为与机制、出价、测量并列的第四根支柱:当测量信号本身被制度性削弱时,谁能用第一方数据重建观测,谁就掌握了下一个十年的主动权。
12.6.4 闭环 vs 开环技术差异全景
把前面三节的差异收拢成一张表,闭环与开环的分野就不再是抽象概念,而是一串可逐项核对的技术差异。
| 维度 | 闭环广告(内循环) | 开环广告(外循环) |
|---|---|---|
| 出价目标 | 深层:付费/ROI/次留/7 日 ROI | 浅层:点击/激活/表单/注册 |
| 数据可得性 | 全链路在平台域内,直接观测 | 转化在域外,依赖广告主回传 |
| 延迟反馈严重度 | 低:平台即时可见,标签窗口可控 | 高:回传延迟 + SKAN 随机延迟,标签晚到 |
| 模型训练 | 直接训练深度 pCVR / pDeepCVR | 靠稀疏回传标签,多为浅层模型 |
| 归因确定性 | 确定性:设备级、链路唯一 | 概率性/聚合:SKAN 群组匿名、ip+ua 兜底 |
这张表不是孤立的清单,它把前几章的伏笔逐条收了回来。出价目标 一栏,对应 12.4.1 的 oCPM 深度转化出价——闭环才有资格做「付费/ROI」这类后链路目标,开环只能停在「激活/表单」。延迟反馈严重度 一栏,对应 12.5.3 的延迟反馈与标签窗口:闭环里转化即时可见、标签窗口好定,开环里转化既要等广告主回传、又要等 SKAN 的随机延迟,标签成熟的时间被拉长且不可控——「未等标签成熟就校准」的风险在开环里被成倍放大。模型训练 与 归因确定性 两栏,则对应 12.5.2 的样本选择偏差与 12.5.3 的胜出偏差:开环模型能拿到的转化标签稀疏且有偏,训练空间与推理空间的裂缝比闭环宽得多。
阶梯左半是开环也能做的浅层目标——曝光、点击、激活、表单、注册,平台只需观察前链路行为即可出价;跨越那条「闭环才能做的深度目标」分界线后,是付费、ROI、次留、7 日 ROI 这些必须看见后链路转化的深层目标。阶梯逐级升高,对应平台对转化数据的观测要求也逐级加深,这正是「数据可观测性决定优化深度」的可视化表达。
这里要补一个容易被忽略的工程细节:深度目标的门槛不只是「能观测」,还有「观测够不够密」。付费、次留这类后链路事件天然稀疏、延迟高,oCPX 类产品通常要求累计转化数达到门槛才能开深度目标——这也是 12.4.1 两阶段冷启动思想在后链路目标上的复现。闭环只是把「攒够数据」这件事变得可行且快,并不能让稀疏事件变稠密。
12.6.5 开环广告工程实战:把断掉的链路工程化地接回来
前几节从概念与机制层面刻画了开环的困境。这一节换一个视角:假设你就是开环广告平台的工程师,链路已经断了,怎么用一整套基础设施把它尽量接回来。这条工程链路自下而上分六层:回传协议、MMP 仲裁、隐私框架落地、稀疏标签下的建模、半闭环的折中优化、以及顶端的增量测量。
第一层:回传协议与触点标识工程
回传听起来只是「广告主发个 HTTP 请求」,工程上却是一整套 协议设计。触点侧,媒体在用户点击/曝光时通过监测 URL 下发的参数是一个元组:clickid(本次触点的全局唯一 ID)、广告 id / 创意 id / 投放计划 id(归因到哪一层由这些字段决定)、ip + ua(无设备 ID 时的兜底匹配键)、时间戳。转化侧,广告主回传的 payload 要包含:设备标识(iOS 的 IDFA/CAID、Android 的 OAID/GAID——注意开环场景下媒体能拿到什么设备标识,直接决定匹配精度)、clickid 原样回传(若 App 内能解析落地页参数)、转化事件类型与层级(激活→注册→首购→复购的事件流)、金额与时间。
这里有三个工程上必须想清楚的设计决策。其一,匹配键的层级:clickid 匹配是确定性的(同一个戳),但要求「点击时的浏览器/落地页上下文」与「转化时的 App 上下文」能被串联——Web→App 的跨越(点击在浏览器、激活在 App)会让 clickid 断链,这是指纹方案(如 Alipay/微信 clickid 的各家私有方案)存在的理由。其二,回传的时效与语义:实时回传(转化后秒级)服务于平台的在线学习与出价控制;批量回传(小时/天级)服务于对账。两者字段可以相同,但平台必须区分消费方。其三,幂等与乱序:网络重试会导致同一转化被回传多次(重复),跨事件流回传会乱序(付费先于激活到达);回传接收端必须按「设备 × 事件类型 × 去重键」做幂等,并按事件时间戳(而非到达时间)重排漏斗。
第二层:MMP 的仲裁机制与反作弊
MMP 作为中立第三方,其核心资产是 唯一的设备标识视角:广告主的所有渠道(抖音、快手、苹果搜索广告、Facebook……)的点击日志与转化日志都汇总到 MMP,由它按统一规则判定记功。判定流程是一次 多路匹配:安装事件到达 MMP 后,先查设备 ID 是否出现在任一渠道的点击日志中(确定性匹配,带归因窗口约束,如点击后 7 天内的安装才记功);查不到再退化为概率匹配(ip+ua+模糊指纹);都查不到则记为自然量。归因窗口本身就是协议参数:点击窗口(常见 7 天)、曝光窗口(常见 1 天)分开设置,窗口越长、该渠道「抢功」的机会越多——这也是渠道间扯皮的常客。
MMP 的反作弊职责同样关键。它要校验点击的 真实性(点击密度异常、点击到安装间隔过短的 click flooding 特征)、曝光劫持与点击注入(12.11 的两类归因作弊在 MMP 侧表现为归因分布的异常集中)、以及 回传造假(某些渠道伪造设备 ID 批量「认领」自然量)。工程手段包括:设备指纹去重、点击-安装时间分布监控、以及与媒体侧日志的对账差异监控。
第三层:SKAN 的落地工程
SKAN 的官方协议只有几页,落地到投放系统却是一大块工程。要处理的硬约束有四条:Postback 的接收方与签名验证(SKAN postback 发给广告主配置的 MMP/自有端点,需验签防伪);Conversion Value 的编码设计——SKAN 3.x 只有 6 bit(64 个值),SKAN 4.x 有 coarse(low/medium/high 三档)与 fine(64 值)两层,广告主必须把「想观测的漏斗进度」压进这几个 bit,这是典型的 信息压缩 问题(例如:fence 1 用 fine 编码「激活后第 0/1/2/3 天的留存+付费标志」,coarse 编码付费金额分档);三次回传窗口的期待管理(0–2 / 3–7 / 8–35 天,且实际到达还叠加随机延迟);Crowd Anonymity 的不确定性(安装量小时连 source identifier 的位数都会缩水)。落地侧因此演化出一套 SKAN 侧的建模管线:用同期 opt-in 用户的确定性数据训练「SKAN 聚合分布 → 真实漏斗」的映射模型(如用小样本校准的混合模型或贝叶斯估计),把聚合、带噪、延迟的 postback 流还原成可优化的预估信号。这套「从聚合数据反推个体级预估」的技术栈,与差分隐私下的频率估计(噪声去除)是同一族问题。
第四层:稀疏延迟标签下的开环建模
开环给模型工程师的真实处境是:标签稀疏、延迟、有偏。三个困难分别有对应的武器。
延迟反馈:付费/深度转化在点击后数天乃至数周才发生,等待标签成熟会让模型永远滞后,立即使用又会把「未转化」错标成「负样本」。主流解法有三族——重要性采样(Zhang et al., CIKM 2016 把「标签是否已成熟」视为一种抽样机制,对早期观测重加权)、多任务「假负样本校正」(Chen et al., 2020 模型「最终会转化」与「已观测到转化」两个过程)、以及流式场景下的数据复制/纠错(延迟反馈下的实时 FTRL 更新框架)。选型的关键判断是 延迟分布的形状:电商下单分钟级,激活当天级,付费/次留数天级——延迟越长,等待式方案越不可行。
样本选择偏差:开环模型的训练数据只有「回传了转化的广告主」贡献的样本,推理时却要服务所有广告;且回传意愿与广告主质量相关(效果好的更愿意回传),偏差方向难以先验判断。ESMM 式的多任务结构(12.5.2)能缓解「点击→转化」这一段的偏差,但「是否回传」这一段要靠对回传行为本身建模(倾向得分加权)或干脆以平台内浅层目标为代理做迁移。
标签噪声:MMP 归因错误、归因窗口切换、渠道抢功,都会让转化标签本身有噪声。工程上的底线做法是监控 归因口径稳定性(同口径的分日转化量不应无故跳变),并在模型侧用 robust loss(如 Huber)降低个别错误标签的影响。
把这层接回 12.4:开环下平台的「深度转化出价」实际是 浅层代理 + 深度校正 的结构——出价公式仍用 pCTR × pCVR(浅层、标签充足),再用回传的深度数据周期性校准浅层目标与真实深度目标的映射(「激活成本多少时,付费成本大概率达标」)。这是开环平台能提供「付费出价」产品的真实形态:不是直接预估付费,而是用代理链路逼近它。
第五层:半闭环的折中与优化空间
半闭环(广告主只回传部分事件)是当前 App 下载广告的主流状态,值得单独展开它的 优化空间在哪。设广告主回传「激活」而不回传「付费」。平台能直接优化激活成本,但激活成本与付费成本的相关性因广告主而异——同一激活成本下,素材 A 拉来的用户付费率可能两倍于素材 B。平台手里的杠杆有三个:素材/人群维度的付费率分层估计(用回传激活但后续行为可见的子样本——若平台还能通过其他产品观测到部分后链路——估计「哪类激活更可能付费」)、探索性放量与 bandit 权衡(对付费信号不确定的定向组合,用 E&E 决定继续收割还是探索)、以及 激励回传(对全量回传的广告主给予出价深度的解锁——回传付费事件才开放付费出价,这是平台侧「用产品换数据」的机制设计)。最后一点把半闭环从纯技术问题变成了机制问题:数据回传本身可以被定价与交易,与 12.10 的数据交易视角接壤。
第六层:增量测量:归因的尽头是「有没有用」
归因回答「功劳记给谁」,增量测量回答更根本的问题:这些广告费不花,转化会不会照样发生? 开环场景下归因链路已经千疮百孔,增量测量的地位反而上升。三个层级的手段:实验法(geo 实验/受众 holdout——把流量按地域或人群切分,对照组完全不出广告,直接测增量转化,这是因果上最干净的方案,代价是牺牲对照组的营收);合成控制(用未投放的相似地域/时段合成「反事实基线」,估计投放期的增量);营销组合模型(MMM)(用宏观的时间序列回归把销售量分解到各渠道投入,不依赖用户级数据——隐私时代因此复兴)。工程上要把增量结论接回投放:增量测量得到的 渠道/素材级增量系数,可以修正归因口径的「虚功」,指导预算在渠道间的再分配——这正是「归因管分账、增量管决策」的分工。
Analysis: 把六层串起来看,开环广告的工程哲学是 在确定性缺失的世界里做工程化的近似:回传协议解决「能不能拿到数据」,MMP 解决「拿到的数据可不可信」,SKAN 建模解决「聚合噪声里怎么还原信号」,延迟/偏差建模解决「残缺标签怎么用」,半闭环机制解决「怎么激励数据变得更完整」,增量测量解决「这一切分出来的账到底指向什么决策」。每一层都不是完美解,但叠加起来,开环平台可以在 70%~80% 的精度上支撑完整的投放闭环——而一个开环广告工程师的核心竞争力,就是知道每一层的精度边界与失效模式。
🧠 Mental Model: 修复文物的考古队
闭环广告像有监控的博物馆,每件展品的来龙去脉都在录像里。开环广告像出土现场:文物(转化)散落在域外的土层里,你得先有发掘协议(回传规范)、再请中立的鉴定师(MMP)防止各家都说是自己挖的、还得懂碳十四(SKAN 建模)从聚合残片里断代、用概率模型(延迟反馈建模)推断缺失的部分、并设计激励机制(半闭环)让藏家愿意交出私藏。考古队永远得不到监控录像,但一支装备齐全的考古队,能把历史还原到足够指导今天决策的程度。
12.6.6 Part 12 最终收束:闭环不是目的,可观测性才是
回到本章开头那句话,现在可以把它说完整了。闭环广告之所以「改变一切」,不是因为「闭环」这个词本身有什么魔力,而是因为它意味着 可观测性(Observability) :谁能拿到更完整的转化数据,谁就能把优化做得更深。闭环只是实现可观测性的一种方式——把转化圈进自己的域内。开环场景里,广告主也可以用高质量的回传、MMP 的中立仲裁、第一方数据战略,部分地重建这种可观测性。所以别把「闭环」当目的去追逐,要追逐的是它背后的东西: 数据链路的完整度。
于是可以给整个 Part 12 写下最终的一条乘法总结,在 12.5 的版本上补上最后一项:
机制决定「规则怎么定」,出价决定「预测怎么花」,测量决定「预测准不准」,而数据可观测性决定「预测有没有料可学」。前三者的一切精妙,都建立在一个更底层的前提上——平台手上握着多少真实转化样本。12.1 的生态全景讲透了「流量怎么流动」,8.3 的 EGA 讲透了「机制怎么被学进模型」,而本章补上了它们共同依赖的底座:没有可观测的转化,EGM 也好、oCPM 也好、ESMM 也好,都只是在一份残缺的账本上做算术。
最后的趋势判断,落在三条并行的迁移上。其一, 超级 App 闭环化 :抖音、快手、淘宝把交易、直播、本地生活圈进生态,把「流量 + 观测」的双重护城河越挖越深。其二, 半闭环 的折中:广告主不全量回传,只回传部分事件(如只回传「激活」而不回传「付费」),平台拿一份不完整的标签做部分优化——这是开环与闭环之间的灰色地带,也是当前多数 App 下载广告的真实状态。其三, 隐私政策推动第一方数据战略 :当跨 App 追踪被制度性收紧,企业与平台都转向经营自己与用户直接发生的数据关系。三条迁移指向同一个结论: 未来广告竞争的胜负手,正在从「谁能买到流量」转向「谁能看见转化」——而看懂这条线,你就读懂了 Part 12 的最后一页。
⚠️ Common Mistakes in 12.6
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 以为开环/闭环是广告形式而非数据链路 | 「原生广告就是闭环广告」 | 同样是信息流原生广告,投站内小店是闭环、投 App 下载是开环;判断标准只有「转化是否在平台可观测域内」 | 用「转化发生的位置」这条开关来判断,不看广告形式 |
| 2 | 把归因当客观事实而非分配规则 | 「数据驱动归因算出了真实的功劳」 | 归因模型是「怎么分功劳」的约定;换一个模型,同一条旅程结论截然不同,不存在唯一「真相」 | 把归因模型当业务假设来选,先问链路长度与数据量,再选分配规则 |
| 3 | 忽视回传污染与归因作弊 | 「广告主回传什么就信什么」 | 自归因下各网络重复计数可达真实量 200%~300%;回传本身可能被刷、被污染 | 引入 MMP 中立仲裁,统一口径、校验回传真实性 |
| 4 | 以为 SKAN 是 IDFA 的等价替代 | 「SKAN 接上就能恢复原来的归因精度」 | SKAN 是聚合、随机延迟、群组匿名的隐私框架,用确定性换了隐私,粒度与及时性都回不去了 | 理解 SKAN 的三次回传窗口与群组匿名,按「混合 SKAN + 授权确定性 + 建模」三层重建 |
| 5 | 在开环场景直接套用闭环的深度出价 | 「App 下载广告直接开付费 ROI 出价」 | 付费在域外,平台看不到也收不到足够回传,pDeepCVR 无从训练 | 开环先用浅层目标(激活/表单),深度目标需广告主持续回传 + 数据积累门槛 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 数据可观测性 | 开环 vs 闭环 = 转化是否发生在平台可观测域内;是数据链路差异,不是广告形式差异 | 广告世界的第二根轴,决定平台能做多深的优化 |
| 闭环的价值 | 直接观测转化 → 深度 pCVR 模型 → 深度转化出价(付费/ROI/次留/7 日 ROI)→「越投越准」飞轮 | 行业口径 eCPM 普遍高出约 20%,超级 App 护城河的底层逻辑 |
| 开环的归因 | clickid 下发 → 转化回传 → ip+ua 兜底;六种归因模型是分配规则而非客观事实 | 同一条旅程在不同模型下结论完全不同,选模型先问链路与数据 |
| MMP 的价值 | 中立第三方仲裁,对抗自归因重复计数 | 多网络并跑时各平台报告安装数常达真实量 200%~300% |
| 隐私浪潮 | ATT(opt-in 约 25%)→ SKAN(聚合/随机延迟/群组匿名,SKAN 4.0 三次回传 0-2/3-7/8-35 天)→ Privacy Sandbox | 确定性归因坍缩,只能混合 SKAN + 授权确定性 + 建模估计 |
| 开环工程六层 | 回传协议(clickid/幂等/乱序)→ MMP 仲裁反作弊 → SKAN 落地(Conversion Value 编码)→ 稀疏延迟标签建模(浅层代理+深度校正)→ 半闭环激励回传 → 增量测量 | 把断掉的链路逐层工程化接回,70%~80% 精度支撑完整投放闭环 |
| Part 12 收束 | 广告系统 = 机制(12.3)× 出价(12.4)× 测量(12.5)× 数据可观测性(本章) | 竞争胜负手从「谁能买到流量」转向「谁能看见转化」 |
❓ FAQ
Q1: 闭环广告一定比开环广告好吗?
A: 对平台而言,闭环的数据完整度与优化深度通常更高,但它也有代价:广告主把转化圈进平台,等于把交易数据、客户关系也交给了平台,私域掌控力下降。对广告主而言,开环保留了自由度和第一方数据,代价是测量精度差、深度优化做不了。因此「闭环 vs 开环」不是绝对优劣,而是数据主权与优化深度之间的权衡——半闭环(回传部分事件)正是这条权衡线上的折中态。
Q2: 归因模型选哪个最好?数据驱动归因是不是永远最优?
A: 数据驱动归因在「数据充足」时确实最能反映真实贡献,但它需要大量可观测的转化样本去学——开环且隐私受限的场景下往往喂不饱它。决策链短、即点即买选最后点击;重品牌曝光、周期长选首次点击或位置加权;意图短促选时间衰减。没有放之四海皆准的最优,只有匹配「链路长度 + 数据量」的最合适。
Q3: SKAN 的三次回传窗口意味着什么?广告主该怎么用?
A: SKAN 4.0 把回传拆成约 0–2 天、3–7 天、8–35 天三个窗口,意味着转化数据不是一次性到达,而是随转化进程分波次、且带随机延迟地回流。广告主的正确姿势不是「等一份完整报告」,而是把 SKAN 的聚合回传、opt-in 用户的确定性数据、以及基于两者训练的建模估计三层信号组合使用,接受「模糊但合规」的测量,而不是追求恢复 IDFA 时代的精确。
Q4: 开环场景的延迟反馈建模,三族解法(重要性采样 / 假负样本 / 流式 FTRL)该怎么选?
A: 数据量小、能承受周期性重训选重要性采样——离线对延迟分布建模后加权,实现最简单;在线实时训练(数据按时间流式到达、样本随到随学)选假负样本纠正——转化未到时先当负样本用、回传到达后纠正,配合 FTRL 更新;介于两者之间用「延迟窗口 + 定期回填」的折中。共同前提是样本必须按事件时间组织(见练习 12.6.5),否则三族方法修的都是错误的偏。
🔗 前后关联
- 12.1 (计算广告全景与生态)——本章引入「数据可观测性」这根与「交易结构」正交的第二根轴;12.1 讲流量怎么流动,本章讲转化怎么被看见,二者拼成完整的广告地图。
- 12.4 (智能出价与预算控制)——闭环之所以能做出价栈最深的那层(oCPM/深度转化出价),正是因为它补上了 12.4.1 公式里 pCVR 的训练数据前提;两阶段冷启动在深度目标上再次复现。
- 12.5 (预估偏差与校准)——开环的延迟反馈(回传 + SKAN 随机延迟)放大 12.5.3 的标签晚到问题;开环的稀疏回传标签也加深 12.5.2 的训练/推理空间裂缝。
- 8.3 (端到端生成式广告 EGA)——EGA 把分配与支付端到端学进模型,但同样逃不开「有没有转化标签可学」这一底座;没有可观测转化,EGA 学到的只是一份残缺账本上的算术。
- Part 3 (排序与预估模型)——pCVR/pDeepCVR 模型结构同源,但它们的「能不能训练」由本章的数据可观测性决定;推荐模型进广告场景,先问数据链路是否闭合。
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 12.6.1 — 判断开环还是闭环 🟢 Easy
判断以下场景属于闭环广告、开环广告还是半闭环,并说明判断依据(看「转化是否发生在平台可观测域内」,而不是看广告形式): (a) 抖音信息流里的一条抖音小店商品广告,用户点击后站内下单支付。 (b) 同一条抖音信息流广告,但落地是引导用户去 App Store 下载某款手游。 (c) 该手游广告主只向平台回传「激活」事件,不回传「付费」事件。 (d) Facebook feed 里的品牌广告,点击后跳转到品牌官网完成注册。
💡 Solution (click to reveal)
Approach: 用「转化发生的位置 + 平台能看到多少」这条开关逐项判断。
- (a) 闭环 :下单、支付都在抖音站内(抖音小店),平台直接观测全链路转化。
- (b) 开环 :转化(下载)发生在 App Store,跳出平台域,抖音看不见下载事件。
- (c) 半闭环 :转化仍在域外,但广告主回传了部分事件(激活),平台能拿到不完整的标签做部分优化——这是开环与闭环之间的灰色地带。
- (d) 开环 :转化(注册)发生在品牌官网,Facebook 只能确认点击,注册事件需广告主回传或 MMP 归因。
Key points:
- 判断标准唯一:转化是否在平台可观测域内——与广告形式(信息流、原生)无关。
- 半闭环 = 域外转化 + 部分回传,是当前 App 下载广告的常态。
Problem 12.6.2 — 手算归因模型分配 🟡 Medium
一条用户旅程包含三个触点,按时间顺序:广告 A 曝光(第 0 天)→ 广告 B 点击(第 1 天)→ 广告 C 点击(第 3 天)→ 第 4 天转化下单。 (a) 分别用 最后点击 与 首次点击 模型,写出 A、B、C 各自的功劳分配。 (b) 用 线性 模型写出分配。 (c) 用 位置加权 (U 型:首尾各 40%、中间均分)写出分配。
💡 Solution (click to reveal)
Approach: 按各模型的分配规则逐一映射到三个触点。
- (a) 最后点击:转化前最后一次触点是 C,故 A = 0%、B = 0%、C = 100%。首次点击:第一次触点是 A,故 A = 100%、B = 0%、C = 0%。
- (b) 线性:三人均分, A = B = C = 33.3%。
- (c) 位置加权(U 型):首触点 A = 40%、尾触点 C = 40%、中间 B = 20%,合计 100%。
Key points:
- 同一旅程三种模型给出三种答案:C 是「收口者」、A 是「种草者」、B 是「路人」——归因立场决定答案。
- 最后点击与首次点击是「全有或全无」的极端规则,线性与位置加权是「平滑分配」规则。
Problem 12.6.3 — 时间衰减归因的权重 🟡 Medium
同 12.6.2 的旅程(A 曝光第 0 天 → B 点击第 1 天 → C 点击第 3 天 → 第 4 天转化)。时间衰减模型按「离转化越近权重越大」分配,设每次往回退一个触点,权重减半:C 的基础权重为 1,B 为 1/2,A 为 1/4。 (a) 计算归一化后 A、B、C 各自的功劳百分比。 (b) 对比线性模型,说明时间衰减在「短周期意图驱动」场景下为何更合理。 (c) 若 B 和 C 是同一天发生的两次点击(B 第 3 天、C 第 3 天),时间衰减权重该如何调整?这暴露了该模型什么局限?
💡 Solution (click to reveal)
Approach: 权重先按规则赋值,再归一化到百分比;再讨论时间信息与模型局限。
- (a) 权重总和 。归一化:C ,B ,A 。
- (b) 线性模型无视时间,把「第 0 天的曝光」和「第 3 天、转化前一天的点击」一视同仁。短周期意图驱动(如「最近想买」)下,靠近转化的触点才是真正的临门一脚,时间衰减把功劳向 C 倾斜,更贴合「越近越关键」的直觉。
- (c) B、C 同一天,则它们「离转化等距」,权重应相等:C = B = 1,A = 1/2(若仍按「往回退一个触点减半」)。这暴露了时间衰减的局限:它本质是「按触点序号的衰减」,而非「按真实时间间隔的衰减」——它只用了顺序信息,没用量化的时间差。更精细的实现应直接按时间差(如指数衰减 )赋值。
Key points:
- 归因权重是归一化的:先赋相对权重,再除以总和。
- 时间衰减用「顺序」而非「时间差」,是它的简化所在;需要真实时间信息时应改用指数时间衰减。
Problem 12.6.4 — SKAN 归因坍缩的量化分析 🔴 Hard
某 iOS 手游广告主投放 10,000 次安装。ATT 落地前,确定性归因(IDFA)可覆盖全部安装;ATT 落地后,opt-in 仅约 25%,SKAN 聚合回传覆盖其余部分,但 SKAN 回传受群组匿名与随机延迟影响,仅约 60% 的安装能被 SKAN 及时、可靠地归因到具体广告系列。 (a) 计算确定性覆盖、SKAN 覆盖、以及「完全无法归因」三部分安装数。 (b) 说明这三部分各自对应的测量方式(授权确定性 / 聚合回传 / 建模估计),以及建模估计在其中扮演的角色。 (c) 为什么说「SKAN 不是 IDFA 的等价替代」?从及时性与颗粒度两个维度解释。
💡 Solution (click to reveal)
Approach: 按比例切分三部分,再把每部分映射到三层混合归因策略。
- (a) 确定性覆盖 = 次(opt-in 用户,有 IDFA)。SKAN 覆盖 = 其余 7500 次中的 60%,即 次。无法归因 = 次(约 30% 的安装彻底丢失在噪声里)。
- (b) 2500 次用 授权后的确定性数据 (最精确、样本小);4500 次用 SKAN 聚合回传 (模糊、延迟、带群组匿名);3000 次无直接信号,只能靠 建模估计——用前两者的已知样本训练模型,去外推「那 3000 次大概是什么构成」。建模估计的价值正是把「完全看不见」的缺口,用可观测部分的规律补齐。
- (c) 及时性:SKAN 回传带随机计时器延迟、且按三次窗口(0–2/3–7/8–35 天)分批到达,转化信号要等几天到几周才回齐,远不如 IDFA 的准实时。颗粒度:SKAN 是聚合非用户级、群组匿名,安装量低时信息更少,永远无法定位到「具体是哪个用户、哪条广告」这一 IDFA 级别的确定性。所以它是「用确定性换隐私」的新契约,而非等价替代。
Key points:
- 隐私浪潮后,任何单一信号都不够用,三层混合(SKAN + 授权确定性 + 建模)是标准姿势。
- 建模估计填补的是「结构性缺口」,不是锦上添花——约 30% 的安装靠它才能「拼回」视野。
Problem 12.6.5 — 设计回传去重与乱序处理 🔴 Hard
你是某广告平台的回传系统工程师。广告主的服务器在支付成功后异步回调平台的转化接口,实际线上观察到三类脏数据:(1) 同一次支付因重试机制被回调了 3 次;(2) 一条「激活」回传比对应的「付费」回传晚到了 2 小时(网络重试);(3) 一次回传的时间戳被广告主服务器时钟错误标到了 8 天前。 (a) 设计幂等去重键,说明应取哪些字段、为什么「订单号」单字段不够。 (b) 乱序到达的事件流如何恢复真实顺序?说明为什么离线训练样本必须按真实事件时间而非到达时间组织。 (c) 时钟错误如何检测与兜底?
💡 Solution (click to reveal)
Approach: 回传协议三要素:幂等键、时间戳重排、时钟校验。
- (a) 幂等键 = 设备标识(clickid 或归一化的设备 ID)× 事件类型 × 业务去重键(如订单号)。订单号单字段不够的原因:不同广告主可能使用相同的订单号格式乃至重复的流水号,且同一订单可能对应「支付成功」与「退款」两类不同事件——必须把事件归属(哪台设备、哪个广告的转化)编码进键里,服务端按键做 set 语义去重。
- (b) 以回传体里携带的 事件发生时间戳 (而非接收时间)为准,按 (设备, 事件链) 维度重排。离线训练时若按到达时间组织,延迟的「激活」会排在「付费」之后,构造出「先付费后激活」的负样本泄漏与漏斗倒挂,模型学到的是回传系统的延迟分布而非用户行为。正确做法是等延迟窗口(如 1 小时~1 天)走完再回填样本标签,或用延迟反馈建模(重要性采样/假负样本纠正)修正。
- (c) 检测:与平台接收时间比对,偏差超过阈值(如回传时间戳早于对应点击时间,或晚于接收时间)即标记异常;兜底:用接收时间与事件时间的中位数差对每个广告主做时钟偏移估计,超出置信区间的样本进隔离区人工/规则复核,不直接进训练流。
Key points:
- 幂等去重的维度是「设备 × 事件类型 × 业务键」,缺一不可。
- 训练样本按事件时间组织、按到达时间截断——两者的差就是延迟反馈问题本身。
- 时钟校验是回传协议里最容易被忽视的脏数据来源。
🏆 Problem 12.6.6 — 设计一个闭环深度转化出价方案
你是某超级 App 广告平台的算法工程师,平台已建成完整电商闭环(站内曝光→点击→下单→支付全链路可观测)。请为一个「站内小店商品推广」广告主设计一套深度转化出价方案,要求: (a) 明确出价目标选型:在「付费单出价 / 付费 ROI 出价 / 激活-次留双出价 / 7 日 ROI 出价」中选一个,说明理由与适用广告主画像。 (b) 写出深度出价的核心公式(基于 12.4 的 oCPM 推广到深度目标),并说明 pDeepCVR 与普通 pCVR 的关系。 (c) 给出冷启动与数据积累的过渡方案,以及「累计转化数门槛」如何设定。 (d) 讨论该方案相对「开环 App 下载广告」在数据、出价深度、延迟反馈三个维度的优势。
💡 Solution (click to reveal)
Approach: 把 12.4 的 oCPM 出价栈推广到闭环的后链路目标,再用 12.5 的延迟反馈与冷启动纪律约束方案。
(a) 选型 :若广告主是「长线付费/LTV」导向的商家,选 付费 ROI 出价 或 7 日 ROI 出价——它直接把「每花一元广告费带来的付费额」当优化目标,对齐广告主的终极商业价值。若广告主既想要新客量又想要留存质量,选 激活-次留双出价 (平台同时预估 pCTR、pCVR、pDeepCVR,兼顾浅度成本与深度留存)。本题以「付费 ROI 出价」为例展开。
(b) 核心公式 :深度出价是 12.4.1 oCPM 公式的后链路推广——把「点击→付费」这一整段深度转化概率代入:
其中 是「点击 → 付费」的深度转化概率, 是广告主申报的每次付费的目标价值(付费 ROI 目标下即「目标 ROI × 付费额」折算出的价值锚)。它与普通 pCVR 的关系:普通 pCVR 是「点击 → 下单」,pDeepCVR 是「点击 → 付费」或「点击 → 次留」——后者在转化漏斗的更深处,样本更稀疏、延迟更高,但离「钱」更近。闭环的价值正在于平台能直接观测「付费」这个深度标签,pDeepCVR 得以直接训练。
(c) 冷启动与门槛 :付费事件稀疏且延迟高,新广告没有深度转化统计,pDeepCVR 对它毫无把握。过渡方案沿用 12.4.1 的两阶段:先用浅层目标(如下单出价或 CPC)投放,积累付费样本;待累计付费转化数跨过门槛(例如 30~50 次付费转化,具体由平台的置信度策略定)后,再切换到付费 ROI 出价。门槛的意义是保证 pDeepCVR 模型对这批广告有最小可用的统计置信——过早切换等于让平台闭眼押注后链路。
(d) 相对开环的优势 : 数据——闭环直接观测付费,开环靠广告主回传、且隐私限制下回传稀疏; 出价深度——闭环能做付费/ROI/次留/7 日 ROI 这些后链路目标,开环只能停在激活/表单; 延迟反馈——闭环付费即时可见、标签窗口可控,开环要等回传 + SKAN 随机延迟,标签成熟时间被拉长且不可控。三者叠加,正是 12.6.1「越投越准」飞轮得以转起来的原因。
Key points:
- 深度出价 = oCPM 出价栈向后链路目标(付费/ROI/次留)的推广,核心是平台能否直接观测 pDeepCVR 的标签。
- 闭环不是「免费解锁深度目标」,它只让「攒够深度数据」变得可行;稀疏事件仍需冷启动与门槛约束。
在线分配与流量管理
📝 Before You Continue: 本章需先读 12.1(全景图)——合约广告在生态中的位置与「保量」交易的由来;以及 12.4(智能出价与预算控制)——pacing 乘子与本章的对偶变量是同一思想在两个市场的投影。12.3(竞价机制)帮你看清本章的对照组:竞价市场靠价格出清,合约市场靠算法分配。
12.4 里我们解决的是「钱」的约束:预算有限,怎么花得又慢又准。这一章处理它的孪生兄弟——「量」的约束:品牌广告主签下的是「未来两周、25–35 岁女性用户、100 万次展示」这样的合约,平台必须在流量到来时实时决定每一次展示给谁,最终既不超卖(供给有限)也不欠量(合约要保)。这就是 在线分配(Online Allocation) 问题。它诞生于担保式投送(Guaranteed Delivery, GD)这种看起来有些「古老」的合约广告系统,但它给出的框架——供给/需求二部图 + 带约束优化 + 对偶变量定价——至今仍支撑着品牌合约广告的投放引擎,而它训练出的思维方式(把约束写进优化目标、用对偶价格解释流量价值)正是 12.4 那套智能出价体系的理论源头。
本章沿「问题 → 模型 → 支撑技术 → 求解 → 执行」的路线展开:先把保量问题写成二部图上的带约束优化,再补上流量预测与频次控制两块地基,然后看工程上如何从不可解的直接线性规划走到紧凑的对偶方案(SHALE),最后落到实用启发性算法 HWM 与它的线上执行逻辑。
读完本章,你将能够:
- 把「保量 + 优化收益」表述为供给/需求二部图上的带约束优化问题,写出需求约束、供给约束与目标函数
- 描述流量预测的反向索引方案,解释它为什么是「广告检索的对偶问题」
- 解释频次控制如何打破展示可分解性假设,以及客户端/服务端两种实现方案的取舍
- 说明为什么直接线性规划在大规模合约系统里不可解,紧凑分配方案如何用 级的对偶变量恢复 级的分配率
- 实现 HWM 离线规划与在线 serving 的完整流程,完成 5 道分层练习题
12.7.0 保量广告:一个带约束的决策系统
先区分两种卖法。竞价广告 (12.3 整章)像证券市场:每一次展示当场拍卖,价高者得,流量用价格出清。合约广告 像提前包场:广告主与媒体约定定向人群、时间段与展示量,价格与量都写进合同。合约的最初形态是按广告位包时段售卖的 CPT 广告,这类 排期系统 并不个性化——素材按事先确定的排期直接插入媒体页面,通过 CDN 加速访问,服务器端几乎没有决策压力。工程上唯一值得留意的是混合投放的调度:排期广告走 CDN 前端直投,动态广告走服务端决策;若服务端超时或出错,页面要渲染 CDN 上的 防天窗广告 (兜底素材),保证广告位永远不空白。这套「前端兜底」的思路今天仍是广告位容错的标准答案。
真正的复杂性出现在 展示量合约 :按 CPM 计费、按人群售卖。此时服务器必须实时决策每一次展示给哪份合约,且必须保证每份合约到期能凑够约定量——这样的系统叫 担保式投送(GD)系统。只要所有合约都被满足,收益就是一个常量(量与价都签死了),优化目标随之从「收益最大」变成「在满足所有合约量的前提下,把流量分配得尽量好」。这一转变把一个无约束的排序问题变成了一个 带约束的优化问题 ,而这正是本章全部技术的出发点。
🧠 Mental Model: 包桌的餐厅
把广告系统想成一家餐厅。竞价广告是散客:每晚开门,谁出价高谁坐最好的位子,收入随行就市。合约广告是包桌:客人提前一个月订下「周五晚 8 点、二楼包间、10 桌」。包桌有两条铁律——每桌的菜不能少(合约量要满足),一桌不能同时坐两拨客人(流量不能超卖)。包桌生意难做在哪?周五晚上到底来多少客人(流量),你只能根据过去几个月的客流(历史日志)去猜;猜完还要提前定好「来了 100 位散客时,先安排哪几桌给包桌客人」(分配方案)。在线分配就是把这套「提前订位 + 当晚调度」变成数学。
GD 系统的整体架构并不复杂:在线投放引擎接收用户触发的广告请求,用用户标签与上下文标签匹配可服务的合约,再由 在线分配模块 决定本次展示投给谁;展示与点击日志进入数据高速公路,一面离线整理出合约执行计划(分配算法的参数),一面流式计算反作弊与计费。接下来两节先讲两块支撑技术(流量预测、频次控制),再进入分配算法本体。
12.7.1 二部图:把保量写成带约束优化
在线分配有两个天然难点:一是要在量的约束下优化效果;二是必须对每一次展示实时决策。直接同时优化这两件事非常困难,因此工程上把问题简化为一个 二部图(bipartite graph) 匹配问题:一侧是 供给节点 ,每个节点代表所有标签都相同的一块流量库存,其总量记为 ;另一侧是 需求节点 ,每个节点代表一份广告合约,约定量记为 。若供给节点的受众标签能满足某合约的定向要求,就在两点间连一条边,全体边的集合记为 ,合约 相邻的供给节点集合记为 。
图中的每份合约带着自己的定向条件与约定量,供给节点则按标签组合聚合流量。要注意这个结构做了一个重要近似:同一供给节点与同一需求节点之间的所有展示,收益不再区分(收益 只依赖节点对,不依赖单次展示的 组合)。这不完全准确,却是研究在线分配算法的合理简化;而且供给节点的数目会随定向条件组合呈几何级数上升,这个近似也让问题规模保持在可处理的范围。
在这个二部图上,分配方案就是一组 分配比例 : 表示把供给节点 的多大比例流量分配合约 。整体收益函数假设可加、可分:
约束有两组。第一组是 需求约束(demand constraint)——分配合约 的收益(或量)至少要达到约定值 :
其中 是把供给节点 连接到需求节点 的单位流量惩罚(或收益系数)。实际产品中需求约束常见两类:一类是预算、服务成本等上限要求;另一类是合约量的下限要求——后者 取负值,约束描述的是收益项的下限。第二组是 供给约束(supply constraint)——每个供给节点分出去的量不能超过它的总流量:
再加上 保证分配非负,就得到在线分配的一般优化框架。这个框架不止服务于 GD:后面 12.7.4 的理论分析与 12.4 的预算出价,用的都是它。
两个典型实例值得记住。GD 问题 :按 CPM 售卖的合约市场,所有合约都满足时收益是常量,于是优化目标写成最大化整体分配收益、同时保证每份合约的分得量不低于约定值——本质是「更好地满足所有合约」。AdWords 问题 (也称带预算约束的出价问题):CPC 竞价环境下,给定各广告主的预算 ,最大化整个市场的收入——此时需求约束变成「每个广告主的花费不超过预算」。AdWords 问题的对偶变量正是「流量对预算的边际价值」,这就是 12.4.2 预算 pacing 乘子的理论原型;在自助式投放中广告主常常先设较少预算、花完再追加,所以预算在实践中未必是强约束,但这套思考方式对各类量约束优化问题的框架意义是值得体会的。
12.7.2 两块地基:流量预测与频次控制
分配算法要「提前离线算好方案、在线照此执行」,前提是你对未来的流量心中有数。流量预测(traffic forecasting) 要回答的问题是:给定一组受众标签组合与一个 eCPM 阈值,估算将来某时段内满足这些标签、且市场价在该阈值以下的展示量。eCPM 阈值主要用于竞价场景(了解某出价水平下能拿到多少流量);对展示量合约,这个阈值设为一个很大的常数即可。
工程上的主要挑战在于:标签组合的可能性是天文数字,不可能预先把每个组合的流量都统计好。可行思路是把流量预测变成一个 反向索引 问题——普通广告检索里,索引的「文档」是广告,查询是展示上的标签;流量预测恰好对偶:文档是每次展示上的 标签组合,查询是广告设定的受众条件。具体四步:
- 准备文档 :把历史流量按 上所有标签聚合为供给节点,统计总流量 ,以及这部分流量在 eCPM 上的直方图 ;
- 建立索引 :对每个供给节点建倒排索引,关键词就是它的全部标签,正排表记录 与 ;
- 查询 :对输入的广告 ,用其定向条件作查询,取出所有满足条件的供给节点;
- 估算流量 :遍历每个供给节点,计算广告在该节点的 ,结合直方图折算广告在出价 下能获得的近似流量。
日志规模太大时,在第 1、2 步之间加一层采样即可——流量预测允许误差,索引规模控制住比精确更重要。这套方案今天仍在合约售卖的流量预估、ADX 询价优化等场景中使用;其现代演进在于,深度模型与时间序列方法已用于精细化的流量曲线预估,但「按标签组合聚合 + 反向索引」仍是工程上撑住查询响应的骨架。
第二块地基是 频次控制(frequency capping) :控制组合 在一定时间周期内的展示次数。动机来自经验规律——随着同一用户看到同一创意的频次上升,点击率呈单调下降趋势(传统广告的「三打理论」认为三次曝光最有效,在线环境的效果曲线则随频次单调下降,并不在第三次达到峰值)。在按 CPM 采购时,广告主常要求限制某创意对单一用户的曝光次数,以提高性价比;视频等高曝光强度的产品里尤其显著。
从计算的角度看,频次是破坏「每次展示独立、收益可分」假设的最主要因素——而 12.7.1 的整个框架恰恰建立在可分性之上。把频次作为可控的定向条件引入系统后,问题虽不能被彻底解决,却可大大缓解;在 CPC 竞价广告中,则把频次作为 CTR 预估的特征之一,隐式地控制重复展示的损耗。
实现方案有客户端与服务端两条路。客户端方案 把用户对某创意的频次记录在浏览器 cookie(或移动端 SDK 的本地存储)里,投放决策时传给投放机:简单、服务成本低,在 SDK 控制投放的移动场景是很好的选择;缺点是跨广告追踪多频次时 cookie 会变得很重,影响响应时间。服务端方案 在后台设一个专用的频次缓存,请求到来时查候选广告的频次、实际投放后更新:这要求缓存同时扛住高并发读与高并发写。好在频次存储的规模有天然上限(一个时间周期内的频次变量总数不会超过该周期内的展示总数),且业务上对极小比例的冲突组合允许频控不准——用 MD5 之类的哈希方法生成键即可,还能顺带满足投放过程弱一致的设计原则。因此通用 NoSQL 反而不合适,业界普遍自研轻量级内存键值对缓存,规模大到可以直接放在广告投放机的本机内存里。跨媒体的频次控制(同一用户在不同媒体上合并计频)则依赖统一身份识别——这条线索在 12.6 的开环/闭环与身份基础设施里已经展开。
12.7.3 求解:从直接线性规划到紧凑分配方案
现在进入分配算法本体。假设未来一段时间的合约已知,且流量分布在各周期内近似平稳——那么可以先用历史数据拟合未来流量 ,把在线问题转化成离线问题,直接对 12.7.1 的优化框架求解。这是几乎所有实用工程方法的基本出发点。
第一条路:直接求解。 当目标函数是线性或二次函数时,这是一个标准的线性规划(LP)或二次规划(QP)问题,用优化工具直接求解即可。它适合定向标签少、合约数少的小规模场景。但大型合约广告系统里,供给节点数随定向条件呈几何级数上升,需求节点可达数千个,边数 在百万级以上——变量个数正比于 ,经典算法(内点法为 的多项式级别,单纯形法约 )在小时级更新的节奏下几乎不可能求解;而且解出来的参数本身就是 级的,线上投放机要加载、查询这么庞大的方案表也非常笨重。
第二条路:对偶与紧凑分配方案。 转机来自对偶视角。LP 的每个约束对应一个对偶变量:需求约束的对偶变量记为 (合约级,量级是合同数,成百上千),供给约束的对偶变量记为 (供给级,量级数十万到千万)。直觉上 是「节点 一块流量本身的价值」, 是「合约 的稀缺程度」。既然 远小于 ,能否只保留合约级的对偶变量,在线上再恢复出完整的分配率?答案是肯定的:对偶问题的 KKT 条件给出了一组由 恢复 与 的解析关系。定义每个需求节点的 需求-供给比 :
它衡量合约 能分到的合规流量相对自身需求有多紧张。给定 ,供给侧与分配率可按如下关系恢复(、 已知时一步算出):
由于方案的存储量正比于合约数 而非边数 ,这被称为 紧凑分配方案(compact allocation plan)。它还有第二个关键性质——无状态 :分配策略只依赖预计算好的 (及由它导出的比例),与投放历史无关,多台广告投放机之间不需要为状态同步做任何通信,系统的稳健性和扩展性都因此受益。这与 12.4.2 里 pacing 乘子「一个标量控制全局」的品味一脉相承:约束优化的对偶变量,天然就是把复杂约束压缩成低维控制信号的工具。
SHALE:原始对偶迭代。 紧凑方案还剩一个开销:在大规模历史数据上解对偶问题本身仍然昂贵。SHALE 算法把这一步改成原始对偶方法迭代:交替执行「固定 解 、固定 解 」,每轮迭代都改善对偶解,直到收敛。迭代法不仅省下离线计算时间,还能更好地支持 增量求解——插入一份新合约时从当前解出发继续迭代即可,不必整个重解。
Analysis: 三条路线的取舍可以浓缩成一张表。直接 LP:解质量最优,但变量 、求解时间不可行、方案表庞大;紧凑方案:存储 、无状态、支持增量,代价是要离线解一次对偶问题;HWM(下一节):连对偶问题都不解,纯启发式,工程最简、效果近似。共同点是——三者都把「在线决策」压缩成「离线算参数 + 在线查参数」,这是在「信息不全时做实时决策」这一根本困难下,唯一现实的系统形态。
12.7.4 极限性能:对偶更新与 上限
如果不利用流量预测,在线分配的效率上限在哪里?这一极端情形对实用系统的直接帮助有限,但它揭示了「聪明的分配策略」长什么样,而且结论直接通向现代预算出价的理论。衡量指标是 竞争比(competitive ratio) :若某在线策略在最坏情形下能达到离线全局最优目标函数的 倍(),就称它是 -competitive 的。
把每次展示当作一个 的供给节点,优化框架的拉格朗日对偶给出一个在线算法骨架:为每份合约维护一个对偶变量 (近似「该合约当前还差多少量、差的是好流量还是差流量」);展示到达时,分配给 最大的合约(收益超过机会成本才投,否则交还给其他变现渠道);随后按某种规则更新 。不同更新规则对应不同算法: 贪心 ( = 已分配的前 个高权重展示中的最低权重)、平均加权 (前 个的算术平均)、指数加权 (前 个的指数加权,越接近当前权重越高)——极限性能依次变好,其中指数加权被证明达到 -competitive,且这是所有在线分配算法理论上可达的最优上限。
这段理论在今天的价值不在「背结论」,而在两个思想。其一, 的含义就是 流量的机会成本 :展示投给某合约之前,先问「这块流量在别处值多少钱」——12.4.2 的 pacing 乘子、oCPC 预算约束下的出价缩放,本质都是对这个对偶价格的在线估计。其二,Free Disposal(超投无损失也无收益)的假设符合大多数广告合约的现实,它让「分配少了可以补、多了不用赔」成为算法可以依赖的宽容性。
12.7.5 HWM:工程上活下来的启发式算法
理论方案离线求解对偶仍然复杂。能不能不解优化问题,只靠「合约的紧缺程度 + 一个分配比例」就把方案定出来? 高水位(High Water Mark, HWM)算法 就是这样一种启发式:数学上不完全严谨,但保留了紧凑、无状态的特性,实际效果相当不错,加上工程实现简单,成为合约广告系统里真实在用的方案。
HWM 离线规划分两步。第一步,对每份合约计算紧缺程度 (与紧凑方案里的需求-供给比同一个量),按 降序确定分配优先级——越难满足的合约越先分。第二步,按优先级依次处理各合约:合约 先看其全部候选供给节点的剩余总流量,若不足则全部分给它(),否则分给它所需的比例 ,并把每个候选节点的剩余流量按 折减。
线上执行时,对每次展示:把满足定向条件的候选合约按优先级排序,累加它们的分配比例;若累积比例超过 1,用随机数落在哪个合约的累积区间来决定投给谁(概率与优先级相配合);若所有候选的分配比例之和不足 1,则以 的概率把这次展示交还服务器,转给其他流量变现渠道(如竞价广告)。
下面的 Python 代码实现了 HWM 的离线规划与在线决策两个函数,可以直接运行验证:
import random
def hwm_plan(supplies: dict, demands: dict, links: dict) -> tuple[dict, dict]:
"""离线规划。supplies: {供给节点: 流量}; demands: {合约: 约定量};
links: {合约: [候选供给节点]}。返回 (优先级, 分配比例)。"""
theta = {a: d / sum(supplies[i] for i in links[a]) for a, d in demands.items()}
orders = dict(sorted(theta.items(), key=lambda kv: -kv[1])) # 越紧缺越先分
remains = dict(supplies)
rates = {}
for a in orders:
total = sum(remains[i] for i in links[a])
rate = 1.0 if total < demands[a] else demands[a] / total # ← KEY LINE: 需求/剩余供给
rates[a] = rate
for i in links[a]:
remains[i] *= (1 - rate) # ← KEY LINE: 折减候选节点余量
return orders, rates
def hwm_serve(candidates: list, orders: dict, rates: dict) -> str | None:
"""在线决策。返回选中的合约 id,或 None 表示交还其他渠道。"""
cands = sorted(candidates, key=lambda a: -orders[a]) # 按优先级排序
r, acc = random.random(), 0.0
for a in cands:
acc += rates[a]
if r < acc: # ← KEY LINE: 随机数落累积区间
return a
return None
supplies = {"s1": 300, "s2": 500, "s3": 200}
demands = {"a_men": 250, "a_geo": 300, "a_all": 200}
links = {"a_men": ["s1"], "a_geo": ["s2"], "a_all": ["s1", "s2", "s3"]}
orders, rates = hwm_plan(supplies, demands, links)
print(rates) # {'a_men': 0.83, 'a_geo': 0.6, 'a_all': 0.3} 量级示意
print(hwm_serve(["a_all", "a_geo"], orders, rates))
下面的交互式模拟器把整条链路跑给你看:点击「生成流量预测」看供给节点的余量如何被各合约按优先级逐层折减,然后逐次「投放展示」,观察随机数落区间与合约完成度的变化;把任一合约的约定量调大,你会看到它的 上升、优先级前移,整个分配比例表随之重排。
模拟器中每一次展示的决策只依赖预计算好的优先级与分配比例——没有跨请求的状态,这正是 12.7.3 说的「弱状态 + 多机低耦合」在工程上的模样。
Analysis: HWM 的时间复杂度:离线规划 (排序 + 每条边折减一次),在线决策 ( 为候选数,主要开销在排序)。它放弃了对偶变量对流量价值的精细刻画,换来「一个 dict 就能部署」的工程简单性;在合约结构相对稳定、流量预测足够准的市场里,这个近似是划算的。反过来,当合约之间强耦合、定向标签高度重叠时,HWM 的贪心顺序会让先分配的合约挤占后分配合约的优质流量,此时 SHALE 类方案的对偶定价仍不可替代。
⚠️ Common Mistakes in 12.7
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把在线分配当成「每次展示求全局最优」 | 展示到达时现场解一遍带约束优化 | 分配发生在信息不全的时刻,现场求解既不可行也非最优;正确形态是离线规划 + 在线执行 | 离线用历史流量解参数,线上只做查表与随机决策 |
| 2 | 忘记供给约束或非负约束 | 只写需求约束,得到 的方案 | 一个供给节点的流量分给多份合约,比例总和超过 1 就是超卖;负比例无物理意义 | 恒检查 与 ,恢复公式里的 就是干这个的 |
| 3 | 低估供给节点数的组合爆炸 | 按「性别 × 年龄 × 地域」笛卡尔积建供给节点,每加一个标签维度节点数翻倍 | 供给节点数随定向条件呈几何级数上升,直接 LP 变量数正比于边数,百万级边不可解 | 用紧凑分配方案只存 级参数,或用 HWM 的比例表 |
| 4 | 在频次控制场景下沿用展示独立假设 | 频次已到 5 的用户仍按基础 pCTR 参与分配 | 频次破坏收益可分性,重复展示的边际收益显著衰减,保量合约会被低质展示填满 | 把频次作为定向条件硬控,或在竞价场景作为 CTR 特征隐式控损 |
| 5 | 把 AdWords 预算当强约束、把 HWM 当最优算法 | 按预算卡死投放;宣称 HWM 输出全局最优 | 自助投放中广告主常花完预算再追加,预算是软约束;HWM 数学上不严谨,只是效果良好的启发式 | 预算约束按业务口径确认强弱;HWM 输出与对偶方案冲突时优先怀疑流量预测与合约耦合度 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 在线分配 | 量的约束下优化效果:二部图 + 需求/供给约束 + 可分收益函数;离线规划 + 在线执行 | 广告中所有「带量约束」问题的统一框架,GD 与预算出价共用 |
| 流量预测 | 反向索引方案:文档=标签组合的流量聚合,查询=广告定向条件;eCPM 直方图折算可获流量 | 分配算法的地基,也是合约售卖与询价优化的支撑技术 |
| 频次控制 | 频次上升 CTR 单调下降;客户端 cookie/SDK vs 服务端内存缓存;哈希键 + 弱一致 | 打破展示可分性的主因,也是品牌广告主最常提的硬性要求 |
| 紧凑分配方案 | 只存合约级对偶变量 ,用 KKT 关系恢复 与 ;SHALE 用原始对偶迭代求解并支持增量合约 | 把 级方案压到 级,且无状态、多机零同步 |
| HWM | 按 排优先级,逐层折减供给余量定分配比例;线上按累积比例随机决策 | 工程最简的实用方案,弱状态、易部署,合约市场真实在用 |
❓ FAQ
Q1: 合约广告看起来是「过时」的形态,这套技术今天还有多少在用?
比想象中多。中国品牌广告大盘里合约售卖仍占相当份额,头部媒体的 GD/排期引擎每天都在跑在线分配;程序化交易里的 PD(程序化直采)同样带着保量承诺。更重要的是,这套「约束优化 + 对偶定价」的框架是预算出价(12.4)、ADX 询价优化等实效广告技术的理论底座——学它不是复古,是打底。
Q2: 紧凑方案只保留 ,供给约束会不会被违反?
不会——恢复关系 是从 KKT 条件推导出来的, 恰好取到让供给约束取等的值(当该供给节点的流量被用满时)。工程上若流量预测偏差导致实际超投,Free Disposal 的假设也保证了超投部分无额外损失。
Q3: HWM 与紧凑方案该选哪个?
看合约结构与求解成本预算。合约数多、相互耦合强、标签重叠严重时,HWM 的贪心顺序损耗明显,值得离线跑 SHALE;合约稀疏、流量平稳时,HWM 的效果与优化方案差距很小,部署成本却低一个量级。实践中常见混合形态:核心保量合约走优化方案,长尾合约走 HWM。
🔗 前后关联
- 12.1 (全景与生态):合约广告与竞价广告的市场分界,是本章问题来源的业务背景
- 12.4 (智能出价与预算控制):pacing 乘子与 AdWords 对偶变量是同一约束优化框架在竞价侧的投影,预算约束 = 需求约束的镜像
- 12.6 (开环与闭环广告):跨媒体频次控制依赖的身份识别基础设施,与开放互联网身份退化互为因果
- 12.2 (计费模式与核心指标):流量预测的 eCPM 阈值与直方图,口径完全建立在 12.2 的 eCPM 定义上
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 12.7.1 — 计算 HWM 的分配比例 🟢 Easy
供给节点:(女性用户),(地域 X 用户),(同时满足女性与地域 X)。合约:(女性),(地域 X),(女性 且 地域 X)。按 降序确定优先级,并给出各合约的分配比例。
Sample Input: 供给 ;需求 Sample Output: 优先级 ;比例 (数值容差内)
💡 Solution (click to reveal)
**Approach:** 先算每个合约的候选总供给,再算 ,降序排列后逐个分配、折减余量。- 可满足集合: 总供给 700; 总供给 900; 总供给 300。
- ,,。优先级:。
- 分配合约 3:候选余量 ,; 余量折减为 。
- 分配合约 2:候选余量 ,; 余 , 余 。
- 分配合约 1:候选余量 ,。
对照一下不做折减的朴素比例分配(、、,三者对 的比例之和已超过 1,会超卖):HWM 的折减过程正是它避免超卖的关键——先分配的合约会真实挤占后分配合约的候选余量。 Key points:
- 衡量的是「需求相对全部候选供给」的紧缺度,与候选余量的折减是两个阶段
- 折减发生在每个候选供给节点上,而不是只折减合约自己的量
Problem 12.7.2 — 用对偶关系恢复分配率 🟡 Medium
已知某市场有两个供给节点()与两份合约(),合约 1 只能用节点 1,合约 2 可用两个节点。流量预测无偏。若求解对偶得到 ,且解出的 ,用紧凑方案的恢复公式计算分配率 ,并验证供给约束与需求约束。
Sample Input: , Sample Output: ,,
💡 Solution (click to reveal)
**Approach:** 先算 ,再代 。- ;。
- 。
- ——但合约 1 与节点 2 之间没有边,。
- (无边);。
验证约束:节点 1 分配 ✓;节点 2 分配 ✓。需求端:合约 1 得 ,合约 2 得 ——需求约束未取等,说明给定 并非该问题最优对偶解(最优解应使约束紧张的合约 且需求取等)。本题考察的正是: 恢复公式是纯机械操作,但输入的对偶解必须真的来自优化求解 ,随手编一组数就会违反约束。 Key points:
- 恢复公式 中无边处直接取 0
- 验证解的有效性要同时检查供给约束、需求约束与对偶可行性,缺一不可
Problem 12.7.3 — 实现 SHALE 的一轮原始对偶迭代 🔴 Hard
写出 SHALE 的 toy 版本:给定供给、需求与连接关系,实现 get_beta_from_alpha(alpha) 与 get_alpha_from_beta(beta) 两个交替更新函数,迭代 次,从 出发。用 Problem 12.7.2 的市场数据验证:迭代收敛后需求约束应当取等(分得量 ≈ 约定量)。
Sample Input: ,,, Sample Output: 收敛后 ,,;两份合约分别分得 60 与 80,恰好足量
💡 Solution (click to reveal)
**Approach:** 原始对偶迭代的核心是两个解析更新式的交替(形式与 12.7.3 的紧凑方案一致):固定 时每个供给节点解出 ,固定 时每份合约解出 ,循环直到收敛。def get_theta(s, d, links_a):
# 需求-供给比: theta[a] = d_a / sum(候选供给流量)
return [d[a] / sum(s[i] for i in links_a[a]) for a in range(len(d))]
def beta_from_alpha(alpha, s, d, links_i, theta):
"""固定 alpha 更新 beta_i(供给约束对偶变量)。"""
beta = []
for i in range(len(s)):
t = sum(theta[a] for a in links_i[i]) # 该节点可服务合约的 theta 之和
if abs(t) < 1e-20:
beta.append(0.0); continue
tmp1 = t + sum(theta[a] * alpha[a] for a in links_i[i]) - 1
beta.append(max(0.0, tmp1 / t)) # ← KEY LINE: KKT 解析式
return beta
def alpha_from_beta(beta, s, d, links_a, theta):
"""固定 beta 更新 alpha_a(需求约束对偶变量)。"""
alpha = []
for a in range(len(d)):
t = theta[a] * sum(s[i] for i in links_a[a])
if abs(t) < 1e-20:
alpha.append(0.0); continue
tmp1 = d[a] + theta[a] * sum(s[i] * beta[i] for i in links_a[a]) - t
alpha.append(tmp1 / t) # ← KEY LINE: 令需求约束取等
return alpha
def shale(s, d, links_a, links_i, N=50):
theta = get_theta(s, d, links_a)
alpha = [0.0] * len(d)
for _ in range(N): # ← KEY LINE: 交替迭代
beta = beta_from_alpha(alpha, s, d, links_i, theta)
alpha = alpha_from_beta(beta, s, d, links_a, theta)
x = {(i, a): max(0.0, theta[a] * (1 + alpha[a] - beta[i]))
for i in range(len(s)) for a in links_i[i]}
return alpha, beta, x
s = [100.0, 100.0]; d = [60.0, 80.0]
links_a = [[0], [0, 1]] # 每份合约的候选供给
links_i = [[0, 1], [1]] # 每个供给节点可服务的合约
alpha, beta, x = shale(s, d, links_a, links_i)
# x = {(0,0): 0.6, (0,1): 0.4, (1,1): 0.4},alpha = beta = [0, 0]
Key points:
- SHALE 的本质是 交替更新对偶变量 : 对应合约稀缺度、 对应供给机会成本
- 本例从 出发一轮即收敛到不动点,且需求约束恰好取等——紧张的合约 大,恢复公式自动把比例抬到足量
- 收敛后的信号:约束紧张的合约 、宽松合约 ;生产实现还需处理采样与数值稳定性
Problem 12.7.4 — 供给节点组合爆炸的量化估算 🔴 Hard
某媒体定向维度为:性别 3 档、年龄 7 档、地域 30 档、兴趣 20 类、平台 3 种。若完全按标签笛卡尔积切分供给节点,估算供给节点数;再假设每份合约平均覆盖 1% 的供给节点、合约数 5000,估算二部图边数与直接 LP 的变量规模,并说明这解释了 12.7.3 的哪个论断。
Sample Input: 维度档数 ;覆盖率 1%;合约 5000 Sample Output: 供给节点 ;边数 ;LP 变量同量级
💡 Solution (click to reveal)
**Approach:** 笛卡尔积 ——还只是五维全开;实际系统允许单维及组合定向,标签组合空间按 量级膨胀(每个维度取或不取),以组合数 的子集结构计,可达 量级节点。- 边数:。
- 直接 LP 变量数正比于 :约 个变量,内点法在此规模小时级更新不可行;方案表本身也放不进投放机内存。
这解释了 12.7.3 的论断: 大型合约系统里直接求解不可行的根源是供给节点随定向条件组合爆炸——所以才需要把方案压缩到合约级的紧凑分配方案( = 5000 个参数)或 HWM 比例表。 Key points:
- 供给节点数是「组合数」而非「标签数」,增长是指数级的
- 紧凑方案的参数量只随合约数线性增长,这是它工程上成立的核心原因
Problem 12.7.5 — 设计一个分配方案的线上监控体系 🏆 Challenge
你是某媒体 GD 系统的负责人,上线 HWM 分配方案两周后,运营反馈「部分合约完成率掉到 85%」。请设计一套诊断流程:列出至少 4 个可能根因(分别来自流量预测、分配算法、频次控制、上游链路),说明每个根因对应的可观测指标与验证方法,并给出修复动作。
Sample Input: 合约完成率周报 + 展示/点击日志 + 合约定向配置 Sample Output: 根因 × 指标 × 验证方法 × 修复动作的对照表
💡 Solution (click to reveal)
**Approach:** 按数据流顺序排查:预测 → 规划 → 执行 → 外部。| 可能根因 | 可观测指标 | 验证方法 | 修复动作 |
|---|---|---|---|
| 流量预测偏差(预测高估) | 预测流量 vs 实际流量的分天对比; 分布漂移 | 用上周实际流量重跑规划,离线模拟完成率是否恢复 | 引入更保守的分位数预测(P50→P30);缩短规划更新周期到天级 |
| 频次控制过紧 | 受频次约束过滤的展示占比;合约候选池大小 | 关闭频控的灰度实验对比完成率 | 区分品牌曝光类(保留硬控)与效果类(改为 CTR 特征软控) |
| 合约耦合挤压(HWM 贪心顺序损耗) | 未完成合约的 与其高 邻居的重叠度 | 离线用 SHALE 重解同一市场,对比完成率差距 | 高耦合市场迁移到紧凑分配方案;或调整合约售卖结构减少标签重叠 |
| 上游链路截流 | 请求到达量 vs 媒体侧曝光量;超时率 | 对账媒体侧打点与投放机日志 | 恢复防天窗兜底逻辑、修复超时配置,必要时降低单机负载 |
Key points:
- 完成率下降必须先二分「预测错了」还是「执行错了」——前者看预测-实际对账,后者看单合约分得量 vs 计划量
- 任何修复动作都应先在离线模拟器上用历史流量回放验证,再灰度上线
受众定向技术
📝 Before You Continue: 本章需先读 12.1(全景图)——定向标签在 eCPM 排序体系中的位置;12.2(计费模式与核心指标)——eCPM 这把尺子如何消费 与 上的特征。12.5(偏差与校准)的 AUC 与校准概念将在 12.8.3 的评测环节再次登场;12.7.2 的「反向索引」思想会以对偶形式出现在上下文定向的工程方案里。
12.4 里我们让平台替广告主出价,12.7 里我们让系统按合约分配流量——但两个问题都默认了一件事:你已经知道「这次展示面前站着一个什么样的人」。回答这个问题的技术就是 受众定向(Audience Targeting) :对广告 、用户 、上下文 三个维度提取有意义的特征(业界统称 标签 )的过程。把上下文也视为「即时的用户兴趣」后,受众定向就是展示广告最核心的驱动力,也是计算广告成为大数据典型应用的关键——没有定向,广告只能按广告位粗放售卖;有了定向,同样的流量才能按「人」卖出不同的价钱。
本章沿「分类 → 上下文 → 主题模型 → 行为 → 人口属性」的路线展开:先建立 、、 三类标签的技术分野,再看最轻量的上下文定向(半在线抓取是理解广告系统弱一致需求的绝佳样本),然后进入本章的核心——行为定向的建模、特征生成、决策与评测全链路,最后用一节收尾人口属性预测。主题模型(LSA/PLSI/LDA/word2vec)按「讲清直觉、标注演进」的原则处理。
读完本章,你将能够:
- 按计算框架把定向技术归入 、、 三类,并解释「效果 × 规模」双指标为何是市场充分竞争的前提
- 设计上下文定向的半在线抓取系统,说明它为什么比搜索引擎爬虫轻量得多
- 用一句话讲清 LSA、PLSI、LDA 三代主题模型的演进逻辑与 word2vec 的工程设计
- 完整实现行为定向的特征生成(时间衰减累积)、打分决策( 阈值)与 reach/CTR 评测
- 判断人口属性预测在什么数据条件下值得做,完成 5 道分层练习题
12.8.0 定向的分类:t(c)、t(u) 与 t(a,u)
回顾 12.2 的排序算术:,其中 是点击率预估。定向技术回答的正是 的输入从哪里来——它对 三个维度提取特征的过程,产出就是标签。按计算框架的不同,这些标签分为三类:
- 用户标签 :以用户历史行为数据为依据打上的标签。人口属性定向、行为定向(兴趣定向)属于这一类。
- 上下文标签 :根据用户当前访问行为得到的即时标签。地域定向、频道定向、上下文定向属于这一类。
- 定制化标签 :也是一种用户标签,不同之处在于它是针对某一特定广告主而言的,必须根据广告主的属性或数据来加工。重定向与新客推荐(Look-alike)属于这一类。定制化标签的数量不再是常数,而可能与广告主数目成正比,因此天然适合在程序化交易环境中由需求方直接提供——这条线在 12.10(数据管理平台)与 DSP 技术中展开。
还有一个容易忽略的对偶侧:每个广告 自己也要打上标签 ,才能与 、 匹配。常用做法有二:直接把广告主、广告计划、广告组、关键词等投放层级信息用作标签,或人工归类。
图中三类标签的实现方案差异很大: 在广告请求时即时计算(在线), 离线批量加工历史日志(离线), 则依赖广告主的数据供给——这也是本章只重点展开前两类的原因。
对某种定向技术,需要同时关注 效果 与 规模 两个指标:既要有覆盖率高但精准程度有限的标签,也要有非常精准但量相对较小的标签。这不是工程上的妥协,而是市场设计——只有标签谱系拉开了效果与规模的两端,不同预算与目标的广告主才能各取所需,竞价广告才有充分竞争的基础。
🧠 Mental Model: 图书馆的三张索引卡
把广告系统想成一座图书馆。 是「这本书现在摊开在哪一页」——你进门时手里正翻着菜谱,管理员立刻递上一本烹饪杂志,即时但不深; 是「这位读者过去一年的借阅记录」——离线整理出来的阅读画像,深但要等; 是「出版社指名要找的那批读者」——需求方自带名单,图书馆只负责对接。三种索引各管一段信息,合起来才能在每一次请求的瞬间答出「该把哪本书递给谁」。
12.8.1 上下文定向:即时兴趣的轻量加工
类定向里,有一批根据广告请求参数简单运算即可得到:地域(IP/GPS)、频道、URL、操作系统等。真正需要讨论的是第二类——根据上下文页面的内容特征(关键词、主题、分类)打标签。打标签的方法归纳为五种思路:
- 规则归类 :把页面按域名归入频道或主题分类(如
auto.*.com下归入「汽车」),简单直接; - 关键词提取 :把搜索引擎的关键词匹配技术推广到媒体页面,是上下文定向的基本方法;
- 入链锚文本关键词 :需要全网爬虫支持,已超出一般广告系统的范畴;
- 流量来源搜索词 :分析访问该页面的用户从哪些搜索词跳转而来,需要页面访问日志支持,技术方案上更接近行为定向;
- 主题模型映射 :把页面内容映射到语义空间的一组主题上,目的是泛化广告主需求、提高市场流动性——这是 12.8.2 的主题。
关键词提取是基础技术。信息检索的通用做法是选页面中 TF-IDF 较高的词;更有效的变体是 需求方驱动 :从广告主相关描述中得到商业价值高的关键词表和 IDF,再与页面词频一起计算 TF-IDF。当能拿到丰富广告信息时(如运营搜索文本广告、或拿到广告主 SEM 词表),后一种方法往往更准——因为它筛的是「商业价值高」的词,而非「统计显著」的词。
半在线抓取:广告系统弱一致需求的教科书案例
页面的标签不可能在广告请求发生的几毫秒内实时分析出来。那要不要像搜索引擎那样预先全网抓取?不需要——页面信息对搜索引擎是服务的主体,对广告系统只是锦上添花的补充。据此可以设计一个 半在线抓取系统 :不做任何离线抓取,在线服务时产生实际需求后才尽快抓取。
工作流程用缓存(如 Redis)保存每个 URL 对应的标签:
- 广告请求到来,URL 命中缓存 → 直接返回标签;
- 未命中 → 为不阻塞请求, 当时返回空标签集合 ,同时把 URL 加入后台抓取队列;秒至分钟量级后该页面被抓取、打标、入缓存;
- 设置缓存 TTL(time to live),页面内容更新后标签自动过期重抓。
这个方案的巧妙处在于两点:缓存命中率极高——只有最近真有广告请求的 URL 才会被抓取,爬虫资源不浪费在可能永远用不到的页面上;覆盖率也高——页面在第一次广告请求后很快就有标签。付出的代价是少量请求拿到空标签,而这恰恰是可接受的:某一次展示标签缺失并不致命,广告系统只要保证大多数决策最优,少量次优甚至随机决策都可以容忍。这种 弱一致 的业务需求是设计高效率、低成本广告系统的关键洞察,在 12.7 的频次缓存(哈希键 + 弱一致)里我们已经见过同款思路。
Analysis: 半在线方案的复杂度不在算法而在系统:缓存读路径要求毫秒级响应,抓取队列要求秒级吞吐,两者解耦靠的是「允许暂时返回空」。对比搜索引擎爬虫:全网抓取、全量索引、强一致更新,成本高几个量级。定向标签的在线检索则与 12.7.2 的流量预测构成对偶——那里文档是 标签组合、查询是广告定向条件;这里文档是 URL 标签、查询是广告请求,都靠倒排索引撑住查询延迟。
🔮 2026 现状注解:页面关键词与主题打标今天普遍由 embedding 与 LLM 完成——页面内容过一遍向量模型或大模型即可输出结构化标签,效果与维护成本都优于手工词表 + TF-IDF 的老方案。但「半在线缓存 + TTL + 允许空返回」的骨架完全没变:现代系统的推理结果同样写进这层缓存,按 URL 复用。变的打标手段,不变的系统形态。
12.8.2 文本主题挖掘:从 LSA 到 word2vec
上下文定向的粒度可以细到关键词,也可以粗到页面类型;介于两者之间,可以把页面映射到一组有概括意义的主题上(如把编程博客映射到「IT 技术」)。把页面视为文档,这就是 文本主题模型(topic model) 的研究问题。主题模型分两大类:监督式——预先定义主题集合,把文档映射上去;非监督式——不预定义集合,自动学出主题与映射。用途决定选择:只做广告效果优化的特征提取,两者皆可;若用于向广告主售卖的标签体系,应优先监督式——广告主需要的是预先定义好、可解释的标签,而不是一堆统计意义上的「簇」。
三代非监督模型的演进脉络值得用直觉串起来。设词表大小 ,文档集 以词袋(BoW)表示为矩阵 ( 为词 在文档 中的词频或 TF-IDF 值),目标是对每个文档得到 个主题上的强度。
LSA:几何视角。 对 做奇异值分解,保留最大的 个奇异值、将其余置零:
它去掉了大多数非主要因素的影响,得到语义空间的平滑描述。缺陷在于两个变换矩阵不保证元素非负——直觉上意味着「一篇文档有某主题时,某些词频的期望为负」,这与直觉不符。
PLSI:概率视角。 把同一思想用文档生成过程重新表述:先按分布从文档 选出主题 ,再按 从主题生成词。这就是 概率潜在语义索引(PLSI)——概率化了的 LSA,两个条件分布对应 LSA 的两个变换矩阵,但所有元素为正,直觉上更合理。它还是指数族混合分布的特例,可以直接套 EM 算法与 MapReduce/MPI 迭代解法;而 SVD 的分布式化需要专门技巧。因此海量数据场景下 PLSI 比 LSA 有实用优势。
LDA:贝叶斯视角。 给 PLSI 的主题分布 加上共轭先验 Dirichlet 分布,参数变随机变量——这就是 潜在狄利克雷分配(LDA)。贝叶斯框架的价值在数据噪声大或文档较短时提供有效平滑;求解用变分法近似或更常用的吉布斯采样(Gibbs sampling),后者也更容易分布式实现。
word2vec:表示学习的起点。 主题模型之后, 词嵌入(word embedding) 把词级语义映射成稠密的实数向量:词表维度降到一个 维特征空间,相近的词彼此靠近,词的表示因此具有泛化性。word2vec 常被误认为深度学习模型,其实它层次很浅、隐藏层都被省去了。以「CBOW + 哈夫曼树」为例:输入层用连续词袋(CBOW)——与 n-gram 相似,但基于上下文窗口词预测当前词,上下文词向量平均后直连输出层;输出层若对整个词表做 softmax,计算复杂度是难以承受的 ,word2vec 的特殊设计是把词表编码成一棵哈夫曼树,目标词沿树路径逐层做二元 softmax(逻辑回归),复杂度降到 。这正是它单机训练高效、2013 年开源后迅速流行的工程原因。
词嵌入有语义可加性,短语、句子、文章的语义也可以嵌入表达;又因基于非线性变换、部分考虑了上下文结构,在短文本场景逐渐取代了 LDA。但它与无监督 LDA 有同样的问题:只基于词共现做无监督学习,不能针对具体任务学习语义,特定任务上效果与主题模型差距不大——真正带来跃升的是后面用有监督方式训练任务相关的词表示。
🔮 2026 现状注解:必须坦率地说,主题模型打标在今天的工业界已经边缘化。现代标签加工的主流路线是 embedding 打标:word2vec(无监督共现)→ 双塔/图 embedding(有监督任务对齐,见 Part 3 检索篇)→ LLM 打标(零样本输出结构化标签体系)。那为什么还要保留这一节?两条理由:其一,word2vec 是 embedding 思想的历史源头,「用无监督目标从共现数据里学稠密表示」的范式由此确立,理解它才理解后续所有表示学习;其二,LDA 的「文档—主题—词」三层生成假设至今是可解释标签体系的思维模板。学它们是为了继承直觉,不是为了在生产环境复刻。
Analysis: 四种技术的工程画像:LSA 依赖 SVD,分布式化困难,适合小规模离线分析;PLSI 用 EM,天然可分布式,曾是海量文档打标主力;LDA 加了先验更稳健,Gibbs 采样易并行;word2vec 单机即可训练大词表,是四者中唯一在今天的系统里仍以「变体形态」活跃的技术——它的后代(item2vec、双塔、图 embedding)遍布广告与推荐。若你的场景是「给页面打可售卖标签」,2026 年的正确答案是监督分类或 LLM 打标,而非本节的任何非监督模型。
12.8.3 行为定向:从历史行为到标签得分
现在进入 的核心——行为定向(Behavioral Targeting, BT) :根据用户一段时期内的各种网络行为,把用户映射到某个定向标签上。它是在线广告中数据利用与变现最重要的计算问题之一,我们分建模、特征生成、决策、评测四步走完全程。
建模问题:用泊松分布描述点击
行为定向的目标是找出在某类广告上 eCPM 相对较高的人群。若假设该类广告上点击价值近似一致,问题就转化为找出 点击率较高的人群——于是建模对象取「某用户在某类广告上的点击量」。点击是离散到达的随机变量,最自然的概率描述是泊松分布:
其中 是某用户在某定向类别广告上的点击量(单位有效展示对应的点击数,直接比较单位时间点击量没有意义), 是受众标签, 是控制点击到达频繁性的参数。行为定向模型要做的,就是把用户行为与 联系起来。用线性模型联系(对数链接),得:
其中 枚举行为类型(搜索、网页浏览、购买等),原始行为 先经过 特征选择函数 映射为特征, 是标签 对应的待优化参数。代入泊松分布,就得到行为定向的整体模型。
这是工程上极典型的 广义线性模型(Generalized Linear Model, GLM) 建模思路:面对多自变量回归问题,先按目标值特性选一个指数族分布描述它,再用线性模型把自变量与分布参数联系起来——既利用线性模型更新简单、可解释性强的优点,又对目标变量类型有较强适应性(12.2 的 CTR 预估、12.4 的出价模型都是同一思路的变体)。
两点特别说明。其一, 可以与标签 相关——对不同标签训练不同的线性函数:类别建模更准,但数据不足的类别估计偏差大;此时原始行为也可以经过与标签无关的选择函数,因为类的本质特征已反映在模型参数上。其二,这套方法适用于 有明确需求方意义的标签体系——只有广告 上也有这些标签,才能根据广告上的点击行为来建模。
特征生成:标签化与时间衰减
特征生成有两个环节:特征选择函数 的确定,与训练集的组织方式。样本量大,处理的高效性是主要工程考量。
最常用的特征选择函数,是把一段时间内的原始行为映射到确定的标签体系上,同时计算各行为在对应标签上的累积强度:页面浏览行为用上下文定向的方法把 URL 转成标签、强度置 1;搜索行为按查询词映射标签、强度置 1。模型中的 实际作用就是调节不同行为类型(搜索、浏览、广告点击、购买)的重要程度。各类行为的标签化是整个计算链路中最关键的一环:
| 行为类型 | 标签化方法 |
|---|---|
| 网页浏览、分享等内容相关行为 | 有监督文本主题模型映射到标签体系,或直接提取内容关键词 |
| 广告点击等广告活动相关行为 | 转化为对落地页内容的分析;文字链创意可直接用题目/描述作内容;图片创意需人工标注,工作量大且正确性难评估,只在必要时做 |
| 搜索、搜索点击等查询相关行为 | 查询信息量少,需借助搜索引擎:或把查询送入通用搜索引擎、用返回结果作内容扩展;或用垂直媒体的标签体系——如电商行业把查询送入淘宝搜索引擎,取返回商品分类作标签,分类分散则视为无标签 |
| 转化、预转化等需求方行为 | 往往对应一个单品,用单品分类信息映射标签;站内搜索按一般搜索行为处理 |
第二个环节是行为累积。过于久远的行为对当前兴趣贡献很小,工程上有两种把行为累积控制在一段时间内的方法。滑动窗法 :设定窗长 ,累加窗口内所有属于 的行为强度,窗型是矩形。时间衰减法 :不设窗长,设衰减因子 ,用上一时间片的累积特征与本时间片的行为强度递归得到今天的累积特征(窗型是指数形):
两种方法没有本质区别(窗型都由唯一参数控制),但工程上推荐时间衰减法:只需保存上一个时间片的累积特征与当前时间片的行为强度,空间和时间复杂度都低。实际建模中一律用累积特征 替代单时间片特征 。
训练集组织上,为消除工作日的周期性,训练天数取 7 的整数倍;每个用户累积到前一时间片的特征 与本时间片的该标签广告点击次数 构成一个训练样本,时间片越小对标签时效性反馈越快,但样本数正比于训练集长度、反比于时间片长度,总量可能非常大。高效的样本生成算法复杂度约 :预处理时把每个用户各时间片的 与 按时间排列成事件流,在事件流上向前滑动,依次得到各时间片的累积特征与训练样本。这正是计算广告架构里「用户行为以用户标识为键组织在一起」的原因——数据组织方式决定了训练能不能跑得动。
决策过程:一条递归公式打天下
训练的产出是各标签的权重 ;决策时不需要泊松分布——只需算出线性函数值 ,与预先确定的阈值比较,决定用户是否被打上某标签。当特征累积用时间衰减法时,得分也可以递归地得到:
这条公式揭示了线上实现的关键点:存储各用户标签得分的缓存中,每个新周期只需把旧得分乘 衰减、再把本周期收集到的原始行为加权求和累加上去——比每个周期重新计算所有 、刷新整个缓存轻量得多。当需要对用户短时行为快速反馈时,这种递归式计算非常有效。
评测:reach/CTR 曲线
行为定向模型可以通过调整 的阈值控制标签人群的量:阈值调低、人群扩大,精准性一般随之下降——评测必须把「量」考虑进来。业界通行 reach/CTR 曲线 做半定量评测:reach 是标签接触到的人群规模,reach 与该人群 CTR 构成的曲线是判断定向是否合理、效果如何的重要依据。
读曲线有三个要点。其一,曲线应大体单调下降——小人群更精准(CTR 高),随人群扩大 CTR 走低;若出现非下降趋势或头部偏低(调低规模反而 CTR 下降),说明数据质量或定向建模有问题,需检查流程或判断数据是否根本撑不起该标签。其二,曲线最右端(reach = 100%,全部用户)的 CTR 是固定的,无法靠改善数据和模型提高。其三,曲线斜率越大,定向模型鉴别力越强;实践中阈值往往设得较高以保效果,因此重点关注曲线头部即可。
这套语言与 12.5 完全同构:曲线头部的陡峭程度就是 判别力 (AUC 衡量的排序能力),而全量 CTR 是一个与模型无关的基准点。工程上生成曲线要求数据仅访问一遍——因此离线流程中必须保留每个用户在各标签上的 得分值 ,而不是最终二值的打标结果;有了得分,按分数分桶、逐桶累计 reach 与点击即可一次扫完。
Analysis: 行为定向的时间复杂度集中在两处:离线训练样本生成 (事件流一遍扫描),线上决策 (缓存递归更新)。空间上时间衰减法只需存上一时间片状态,是「在线学习」思想在标签系统里的最早实践之一。它的局限同样明显:每个标签独立训练导致长尾标签数据不足、估计偏差大——这正是现代方法(统一用户表示向量 + 序列模型)要解决的问题。
🔮 2026 现状注解:现代工业界的「行为定向」大多不再按标签独立训练 GLM,而是把用户行为序列编码成统一的用户表示向量(召回侧的 U2I 双塔、精排侧的 DIN/SIM 类序列模型,见 Part 3/Part 4),再由下游任务消费;标签体系退居为特征工程的一部分或 LLM 直接输出。但 GLM + 时间衰减 + 阈值打标这套框架仍是理解一切用户兴趣建模的原型,且在标签售卖型产品(DMP 人群包)里仍在服役。
12.8.4 人口属性预测:当行为泄露身份
年龄、性别、教育程度、收入水平等 人口属性 严格说不是兴趣,而是用户的确定特点。除实名社交网络外,规模化获得人口属性很困难,因此仍需数据驱动的模型、以行为为基础自动预测。直觉很好理解:经常访问军事或汽车网站的用户以男性居多,常浏览娱乐八卦的用户以女性居多。
以性别为例,这是典型的二分类问题:输入是用户原始行为 (或提取后的特征),输出 ,可用最大后验概率框架或 SVM、AdaBoost 等模型求解。建模中有两个关键问题比选模型更重要:
- 拒识门槛 :对行为不够丰富或不够有代表性的用户,必须输出「未知」,而不是让模型硬算一个结果——错打的标签会污染整个定向体系;
- 训练集获取 :算法本身的提升往往不如「更准确、更大规模的训练集」明显。大规模标注通常依赖社交网络——例如把广告系统用户身份与微博用户对应,从微博公开属性获得标注。
性别之外的属性用简单分类模型并不准确。以年龄为例:把标签设为 5 个年龄段时,把第一个年龄段错分到第二段与错分到第三段的代价显然不同,简单多分类忽略了这种 有序错分代价 ,教育程度、收入水平类似。总体上说,从行为预测非性别属性是较难的任务,除非有强相关的数据来源和充分多的准确训练样本,否则不建议硬做。
🔮 2026 现状注解:今天主流的人口属性标签早已不靠问卷或第三方数据包,而是「点击反馈 + 模型预估」:用户在广告上的点击、转化行为作为弱监督信号,配合实名场景(社交登录、支付实名)的合规数据训练预估模型,覆盖率与精度都远超旧方案。同时,隐私合规(个人信息保护相关法规)对人口属性这类「身份数据」的收集与交易提出了远比 2010 年代严格的约束——12.6 开环闭环里讨论的身份基础设施与合规边界,正是这条线今天的延伸。
最后补一句互链:把本章的数据收集与定向功能独立出来做成专门产品,就是 数据管理平台(DMP)——它对接第一方、第二方、第三方数据,按受众标签做灵活的人群划分,再通过用户身份对应与数据传递把标签卖给购买方(如 DSP)。技术架构不过是本章功能的独立化,产品与技术细节见 12.10。
⚠️ Common Mistakes in 12.8
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 模仿搜索引擎做全量离线爬取 | 预先把全网页面抓下来打标签建索引 | 页面标签对广告只是补充信息,全量抓取成本高数个量级,且绝大多数页面永远等不到广告请求 | 半在线抓取:请求驱动 + 缓存 + TTL,允许暂时返回空标签 |
| 2 | 用无监督主题模型直接构建售卖标签体系 | 跑一个 LDA,把聚出的 50 个「簇」当标签卖给广告主 | 无监督簇不可解释、不可控,广告主无法理解也无法采买;售卖标签必须预先定义且可解释 | 售卖标签用监督分类;无监督结果只做效果优化的内部特征 |
| 3 | 用单时间片特征训练行为定向模型 | 只用「今天浏览过汽车页 = 1」作特征 | 单日行为噪声大、周期性强,丢失了兴趣的时间累积结构 | 用滑动窗或时间衰减累积特征 替代单时间片 ,推荐时间衰减法 |
| 4 | 线上每周期重算所有用户的标签得分 | 定时任务全量刷新 λ 缓存 | 用户 × 标签的组合是天文数字,全量重算既慢又贵 | 用递归式 在缓存上原地更新 |
| 5 | 评测标签只看一个人群规模的 CTR | 「reach 5% 时 CTR 0.9%,标签很准」 | 单点无法区分鉴别力与人群规模的影响,也无法发现曲线非单调的建模问题 | 保留得分值生成完整 reach/CTR 曲线,检查单调性与头部斜率 |
| 6 | 人口属性预测无拒识、把低置信结果硬打上 | 行为只有 3 条的用户也被打了「女,25–30 岁」 | 错打的身份数据会污染下游所有定向与频控,且此类错误难以被点击类指标发现 | 设置拒识门槛,行为不足输出「未知」;优先扩充准确训练集而非换模型 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 定向分类 | 用户标签 / 上下文标签 / 定制化标签;广告侧还需 匹配;效果 × 规模双指标 | 三类的计算框架(离线挖掘 / 在线即时 / 需求方供给)完全不同,决定系统架构分工 |
| 上下文定向 | 关键词(TF-IDF,需求方驱动 IDF 更优)+ 主题;半在线抓取:请求驱动、缓存 + TTL、允许空返回 | 广告弱一致需求的教科书案例,与 12.7 频次缓存、流量预测反向索引同一思想族 |
| 主题模型演进 | LSA(SVD,允许负值)→ PLSI(概率化 + EM 可分布式)→ LDA(贝叶斯平滑);word2vec 用哈夫曼树把 softmax 降到 ,是 embedding 思想源头 | 主题模型打标已边缘化,但「生成式直觉」与 embedding 范式从这一节生长出来 |
| 行为定向 | 泊松 GLM:,;时间衰减累积 ;线上递归更新 ;reach/CTR 曲线评测 | 在线广告数据变现最重要的计算问题,所有用户兴趣建模的原型框架 |
| 人口属性预测 | 性别可作二分类;必须有拒识门槛;训练集质量比模型更重要;非性别属性需考虑有序错分代价,预测困难 | 现代做法是点击反馈 + 模型预估替代问卷,且受隐私合规强约束 |
❓ FAQ
Q1: 行为定向为什么用泊松分布,而不是像 CTR 预估那样直接做二分类?
二者针对的问题不同。CTR 预估回答「这次展示被点击的概率」,单次展示、伯努利事件;行为定向回答「这个用户对某类广告的单位有效展示点击量有多大」,点击在时间上是离散到达的计数,泊松分布是计数的自然描述。两者在 12.5 意义下是同一枚硬币的两面:GLM 框架换一个指数族分布,就从一个任务切换到另一个。
Q2: 时间衰减法与滑动窗法效果有差别吗,为什么工程上总推荐前者?
两者对原始行为的过滤窗形不同(矩形 vs 指数),建模效果没有本质区别。差别全在工程:滑动窗要保存窗长 内的全部行为,时间衰减只需保存上一个时间片的累积值和当前行为,空间 ,而且得分 能用同一条递归式在线原地更新——这是它压倒性胜出的原因。
Q3: 主题模型已经被淘汰了,这一节为什么还要花篇幅讲 LSA/PLSI/LDA?
三个理由。第一,word2vec 是 embedding 思想的源头,而 embedding 是今天一切表示学习(双塔、图 embedding、LLM 打标)的直系祖先,讲清源头才能讲清演进;第二,「文档—主题—词」的生成式假设是可解释标签体系的思维模板,监督打标方案的设计仍从中受益;第三,「无监督学不出可售卖标签」这个结论本身,就是从这三种模型的局限里得出的——知道为什么死,才知道该绕开什么。
🔗 前后关联
- 12.2 (计费模式与核心指标):定向标签是 eCPM 算术 中 的输入来源;本章产出特征,12.2 定义消费方式
- 12.5 (偏差与校准):行为定向的 reach/CTR 头部斜率对应判别力(AUC),得分阈值化后进入算术就必须过校准;泊松 GLM 与 CTR 模型同属指数族 GLM 家族
- 12.7 (在线分配与流量管理):流量预测的反向索引与上下文标签检索互为对偶;频次缓存的弱一致设计与半在线抓取同构
- 12.10 (数据管理平台):DMP 是本章数据收集与定向加工能力的独立产品化,受众标签经它进入程序化交易
- 12.3 (竞价机制):定向标签谱系的效果 × 规模两端,是竞价市场充分竞争、价格发现有效的前提
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 12.8.1 — 计算时间衰减累积特征 🟢 Easy
某用户「汽车」标签上的每日行为强度为:4 天前 ,3 天前 ,前天 ,今天 。取衰减因子 ,从 4 天前开始逐步递推(初始累积为 0),计算今天的累积特征 。
Sample Input: 行为序列 (从旧到新); Sample Output:
💡 Solution (click to reveal)
**Approach:** 逐日套用 。- :
- :
- :
- :
def decay(events, alpha):
f = 0.0
for x in events:
f = alpha * f + x # ← KEY LINE: 递归累积
return f
print(decay([1.0, 0.0, 2.0, 1.0], 0.6)) # 2.416
Key points:
- 注意中间值:3 天前只有 0.6,几乎被前天的 2「顶」上去——指数窗对近期行为的响应远快于矩形窗的均匀平均
- 整个过程只需保存一个标量,这正是时间衰减法空间 的含义
Problem 12.8.2 — 需求方驱动的关键词选择 🟡 Medium
某页面共 100 个词,其中「手机」出现 5 次、「凸轮轴」出现 3 次。文档集共 个文档,「手机」出现在 个文档中,「凸轮轴」只出现在 100 个文档中。使用 ,判断上下文定向应选哪个词作为该页面的标签。
Sample Input: 页面词数 100;手机: 5 次, df ,凸轮轴: 3 次, df 100; Sample Output: TF-IDF(手机),TF-IDF(凸轮轴);选「凸轮轴」
💡 Solution (click to reveal)
**Approach:** 分别计算两个词的 TF 与 IDF,再相乘比较。- 「手机」:,,TF-IDF
- 「凸轮轴」:,,TF-IDF
「手机」词频更高但几乎处处出现,区分度低;「凸轮轴」词频略低却高度稀疏,是更能代表页面内容的标签。若再叠加需求方驱动的思路——广告主词表里「汽车零部件」类词商业价值高——「凸轮轴」的优势进一步放大。 Key points:
- IDF 是区分度的度量:常见词的 TF 再高也不该成为定向标签
- 需求方驱动变体的差别在 IDF 的来源:用广告主词表的 IDF 替换通用语料 IDF,筛出的词天然带商业价值
Problem 12.8.3 — 生成 reach/CTR 曲线并诊断 🟡 Medium
某「母婴」标签的测试数据按得分从高到低分 5 桶(每桶展示数, 点击数):。计算从头部起逐桶累计的 reach 与 CTR,验证曲线单调性,并回答:reach = 100% 时的 CTR 由什么决定?该标签建模是否正常?
Sample Input: 5 桶 Sample Output: 累计 reach ,CTR ;单调下降,建模正常
💡 Solution (click to reveal)
**Approach:** 从高分桶向低分桶逐个累计展示与点击,计算累计 CTR。- 总量:展示 ,点击
- reach 4%:;reach 10%:;reach 20%:;reach 40%:;reach 100%:
bins = [(200,6),(300,6),(500,7),(1000,8),(3000,9)]
total = sum(r for r,_ in bins)
acc_r = acc_c = 0
for r, c in bins:
acc_r += r; acc_c += c
print(acc_r/total, acc_c/acc_r) # ← KEY LINE: 逐桶累计
reach = 100% 的 CTR(0.72%)是全体用户的 CTR,由数据本身决定,与模型好坏无关——它是曲线的固定锚点。曲线严格单调下降,说明得分高的用户点击率确实更高,定向建模正常;若某累计点 CTR 反弹上升,则要回头检查得分或数据质量。 Key points:
- 曲线头部斜率(3.0% → 2.4%)体现鉴别力:阈值设在头部即可用最小人群换最高 CTR
- 生成曲线只需按得分排序扫一遍数据——前提是离线流程保留了得分而非二值打标结果
Problem 12.8.4 — 实现行为定向的特征生成与打分决策 🔴 Hard
实现两个函数:bt_features(events, alpha) 按 生成逐日累积特征(events 为按天排列的行为强度矩阵,3 维特征 × 5 天);score(w, feat) 计算 。用下表数据(,,阈值 )判断该用户最终是否被打上标签,并指出打分序列中的异常现象。
| 天 | (浏览汽车) | (搜索汽车) | (浏览母婴) |
|---|---|---|---|
| 1 | 1 | 0 | 0 |
| 2 | 1 | 1 | 0 |
| 3 | 0 | 1 | 2 |
| 4 | 1 | 0 | 1 |
| 5 | 0 | 0 | 1 |
Sample Input: events 如上表;;; Sample Output: 末日累积特征 ;,打上标签; 序列 在第 5 天回落
💡 Solution (click to reveal)
**Approach:** 先逐日递推三维累积特征,再对末日特征加权求和。def bt_features(events, alpha):
cur = [0.0] * len(events[0])
feats = []
for e in events:
cur = [alpha * cur[d] + e[d] for d in range(len(e))] # ← KEY LINE: 递归累积
feats.append(cur[:])
return feats
def score(w, feat):
return sum(w[d] * feat[d] for d in range(len(w)))
events = [[1,0,0],[1,1,0],[0,1,2],[1,0,1],[0,0,1]]
feats = bt_features(events, 0.5)
lams = [round(score([0.8, 0.2, 0.5], f), 4) for f in feats]
print(feats[-1]) # [0.6875, 0.375, 2.0]
print(lams) # [0.8, 1.4, 1.9, 2.25, 1.625]
print(score([0.8, 0.2, 0.5], feats[-1])) # 1.625
末日累积特征(以 为例:):;,打标。异常现象:第 5 天 从 2.25 回落到 1.625——当天汽车行为为零,指数窗让旧兴趣迅速衰减,而新行为集中在权重较低的母婴维度上。这正体现了时间衰减对「兴趣漂移」的快速响应:若用户连续数日行为转向,标签得分会及时回落,无需等窗口滑出。 Key points:
- 累积特征必须递推生成,事件流一遍扫描即得全部训练样本,复杂度
- 线上只需对末日特征算一次 (),或直接在缓存里做 的原地更新
Problem 12.8.5 — 设计一个标签的上线评测与诊断方案 🏆 Challenge
你是广告平台的标签负责人,「家居装修」行为定向标签即将上线。请设计完整方案:(a) 训练阶段如何组织数据(行为类型、时间片、训练集长度);(b) 上线前如何用离线数据评测该标签是否值得上线(给出可量化的上线标准);(c) 上线三个月后发现该标签人群 CTR 接近全量水平,列出至少 3 个可能根因与对应的验证方法。
Sample Input: 点击/展示日志、用户行为事件流、标签得分明细 Sample Output: 数据组织方案 + 量化上线标准 + 根因 × 验证方法对照表
💡 Solution (click to reveal)
**Approach:** 按「训练组织 → 离线评测 → 线上诊断」三段展开。(a) 数据组织:行为类型上覆盖浏览(装修类 URL/频道打标)、搜索(查询词经搜索引擎或家居垂直分类扩展)、广告点击(落地页分析)、购买(家居单品分类);训练集长度取 14 天(7 的整数倍,消除工作日周期性);时间片按标签时效需求定,装修属于决策周期长的低频兴趣,可取天级时间片 + 较大(衰减慢,如 0.9)的累积特征。
(b) 离线上线标准(示例,可按业务调整):reach/CTR 曲线在 reach ≤ 20% 区间单调下降,且头部 CTR ≥ 全量 CTR 的 3 倍;AUC ≥ 0.65;标签人群规模 ≥ 售卖所需最小量(如 1000 万),否则只保留头部。三条同时满足才上线——效果、鉴别力、规模缺一不可。
(c) 人群 CTR ≈ 全量 CTR 意味着标签丧失鉴别力,可能根因:
| 根因 | 验证方法 | 修复动作 |
|---|---|---|
| 阈值设置过低(reach 被拉满) | 检查线上阈值对应的 reach;用保留的得分重画 reach/CTR 曲线看头部表现 | 上调阈值,缩小人群到曲线头部 |
| 特征失效(行为源枯竭或标签化错误) | 统计该标签的累积特征分布是否塌缩;抽查 URL/查询词标签化结果 | 修复标签化链路(如落地页改版后解析失效);补充行为源 |
| 兴趣错位(装修行为多发生在低点击倾向场景) | 对比标签人群与非人群的曝光位置/时段分布 | 若属实,考虑该标签不适用 CTR 类效果售卖,转向品牌合约场景(呼应 12.2 的计费口径) |
Key points:
- 评测方案的前提是离线保留每个用户在各标签上的得分——只存二值打标结果,事后任何曲线都画不出来
- 「标签 CTR 接近全量」是 reach/CTR 框架给出的标准失败信号,诊断顺序:先查阈值(最便宜),再查特征,最后才怀疑建模本身
广告检索与语义召回
📝 Before You Continue: 本章需先读 12.1(全景图)——竞价广告在生态中的位置,以及 12.2(计费模式与核心指标)——eCPM 的定义,因为本章讲的检索正是「eCPM 排序之前的那个环节」:没有候选,排序无从谈起。12.3(竞价机制)帮助你理解检索的下游终点;12.7.2 的流量预测用了「反向索引」,与本章的倒排索引互为对偶,读过后回头再看会更有味道。
12.2 与 12.3 把「候选广告摆上桌之后」的事讲透了:算 eCPM、排序、按 GSP 计价。但桌上的候选是哪来的?在大量中小广告主参与的市场里,每次广告请求背后站着的是 数以亿计 的广告候选——每个都带着自己的一组定向条件,而系统必须在几毫秒内决定「哪些广告有资格参加这一场竞价」。这就是 广告检索(ad retrieval) 要解决的问题:从全部广告中,找出可参与本次竞价的少数。它不追求把每个广告都看一眼——亿级候选逐个求值定向表达式,任何毫秒级预算都会瞬间爆掉——而是靠索引结构与剪枝思想,让绝大多数广告「根本不被看见」。
这一章还会走到检索技术的当代前沿:当定向从「标签的布尔组合」演进到「语义的向量表示」,检索问题就从「布尔表达式匹配」变成了「近似最近邻查找(ANN)」,工具箱也换成了向量索引。有趣的是,这两套技术今天在真实系统里是并存的——多路召回 正是它们的合奏。
读完本章,你将能够:
- 解释广告检索与搜索引擎检索的两个本质差异:布尔表达式文档与超长查询
- 把广告定向条件分解为 DNF → Conjunction → Assignment 三层结构,并描述两层倒排索引与 size 分层剪枝的工作方式
- 描述 WAND 算法如何用「上界 + 堆阈值」在检索阶段完成 Top-K 剪枝
- 说明 DSSM/双塔模型如何把检索问题转化为向量空间中的最近邻查找,以及 LSH、向量量化、图索引三类 ANN 方案的直觉
- 看清检索漏斗全貌:召回 → 粗排 → 精排 → 竞价,完成 5 道分层练习题
12.9.0 检索为什么特殊
先看一个数字对比。搜索引擎面对的文档库是几十亿网页,查询是 1~4 个关键词;广告系统面对的广告库同样是亿级,但每次请求 留给检索的时间只有几毫秒——因为同一毫秒预算里还要装下 CTR 预估、排序、计价、日志等一系列环节。更麻烦的是,广告检索面对的「文档」和「查询」都长得不像搜索引擎的那一套,书里指出了两个本质差异:
差异一:广告文档不是词袋,是布尔表达式。 在受众定向的售卖方式下,一条广告的定向条件形如「(年龄 ∈ {25–35} 且 地域 ∈ {北京})或(地域 ∉ {北京,广东})」——由「与」「或」「非」连接的 布尔表达式 ,而不是一堆关键词的集合。搜索引擎的倒排索引回答「哪些文档包含这些词」,广告检索要回答「哪些广告的定向条件被这组标签满足」,后者的求值结构复杂得多,也留下了针对性的优化空间。
差异二:查询可能非常长。 搜索引擎的查询来自用户输入,天然简短;广告检索的查询却可能由上百个标签组成——上下文定向场景下,网页内容抽出的关键词就有十几个甚至几十个,再加上用户的兴趣标签。试想把 100 个关键词同时输入搜索框:按「与」组合,几乎不会有任何文档同时包含所有词;按「或」组合,又会返回海量相关性很差的候选。这两个极端都不可用,于是催生了 12.9.3 末尾的相关性检索技术。
🧠 Mental Model: 招聘筛简历
把广告检索想成一场大规模招聘。全量广告库是简历池:每份简历上都写着硬性要求——「必须会 Python 且 5 年经验,或者:博士学历且不在北京」——这是布尔表达式。求职者(广告请求)带着自己的标签到来。第一步筛简历绝不能逐份细读,而是用索引快速定位「条件可能被满足的少数简历」(布尔检索);对于描述特别模糊的岗位(超长查询),则按「匹配程度」估个分,先淘汰明显没戏的(WAND 剪枝);还有一种招聘方式压根不写硬性条件,而是把岗位描述和简历都变成向量,「感觉像」就推荐过来(语义召回)。三轮筛完,才进入真正的面试(eCPM 排序与竞价)。
这两个差异决定了广告检索不能照搬搜索引擎的方案,需要在倒排索引这个共同地基上发展出自己的技术体系。下面先花极小的篇幅回顾检索的下游——计价算法,明确「检索为谁服务」,再进入三项核心技术:查询扩展(搜索广告特有)、布尔表达式检索与语义召回(通用基础)。
12.9.1 计价算法回顾:检索为谁服务
竞价广告的完整决策链路是: 检索出候选 → 估算每个候选的 eCPM → 按 eCPM 排序 → 对胜出者计价。后三步在 12.2(eCPM 的定义与分解)和 12.3(GSP 计价与市场保留价)已经讲透,这里只用一句话把它们钉在位置上:对 CPC 竞价,eCPM 按下式分解,排序按 eCPM 降序,计价按下一名的 eCPM 除以自己的点击率(GSP),并以市场保留价(MRP)托底:
其中点击率 是广告、用户、上下文三方的函数,点击价值 在 CPC 场景下就是广告主出价、无需估计(CPS 场景下还需预估点击价值,参见 12.2)。多种计费模式并存时,各算各的 eCPM 再统一排序:CPM 广告的 eCPM 就是出价本身,CPC 是预估点击率乘出价,CPS 是点击率乘点击价值预估。
对本章而言,这条公式链的意义在于划定边界: 计价是检索的下游。检索决定了「哪些广告能站上赛场」,计价与排序决定了「谁赢」。赛场的入场券发得太少,再精巧的拍卖也无人竞标、变现受损;发得太多,排序环节的算力与相关性都会被拖垮。检索技术的全部目标,就是在几毫秒内发出「不多不少、恰有胜出潜力」的那一批入场券。
12.9.2 搜索广告:查询扩展与广告放置
搜索广告是竞价广告中最早也最重要的产品形态,它的检索有个特点: 上下文极强、用户信号受限。用户输入的查询就是决策的全部上下文,而用户标签的作用受到很大限制——搜索广告的检索过程一般不考虑用户 ,离线受众定向也基本可以省略。但查询本身粒度极细,如何把一个简短的查询词扩展成一组可参与竞价的关键词,就成了搜索广告特有的核心技术。
查询扩展(query expansion) 对供需双方都有价值:需求方(广告主)靠它获得更多流量,供给方(平台)靠它变现更多流量、提高竞价激烈程度。它主要用于广泛匹配的情形,书里给出了三条主要思路:
- 基于推荐的方法。 把一个用户会话内的查询视为目的相同的一组活动,在「会话 × 查询」的交互强度矩阵上做协同过滤——某个用户搜过某词,矩阵对应元素就记上交互值。这个矩阵极其稀疏,推荐算法(从基于内存的非参数方法到矩阵降维的参数化方法)的任务就是用已知元素去预测性填充未知元素;平滑之后再比较两个关键词对应向量的相似度,就稳健得多了。一个值得体会的细节: 推荐问题里未观测的交互单元是「未知」,而文档主题模型里未在某文档出现的词是「零」——两种看似相似的问题,对缺失值的语义假设完全不同。
- 基于主题模型的方法。 不用搜索日志,而用一般文档的主题模型:每个词对应一个主题向量,用主题向量的相似度做扩展。它捕捉的是 语义上 的相关,而非 用户意图上 的相关,效果会差一些,适合作为搜索行为数据不足时的补充。
- 基于历史效果的方法。 直接用广告的历史 eCPM 数据挖掘「哪些相关查询变现好」:若历史数据显示某些关键词对某些广告主 eCPM 较高,就把这些查询组记录下来,以后别的广告主也选了其中某个词时,自动扩展出效果好的查询。它与前两种方法的结果经常重合,但因为 直接用优化目标(eCPM)来指导扩展 ,对营收的拉动往往最好,是极重要的补充手段。
查询扩展有明确的收益边界:搜索查询的 过分泛化会对相关性造成较大负面影响——这正是搜索广告不在检索阶段引入短时用户标签的原因;短时信号更适合放在排序阶段,加权那些用户更倾向选择的结果。
广告放置(ad placement) 是搜索广告另一个有个性化空间的决策:确定一次搜索结果页上北区(主结果上方)和东区(右侧)各放几条广告。约束是系统在一段时间内 北区广告的平均条数上限 (用户体验),优化目标是整体营收,形式化为:
其中 是第 次展示的北区条数,、 分别表示北区、东区的第 个位置——注意 里多了位置参数,而排序阶段按 (首位)处理即可。这个问题的巧妙之处在于个性化:不同用户对广告的容忍度差异很大(即使在用户受教育水平较高的北美市场,也至少有三四成用户不能完全分辨搜索结果与广告),于是可以用该用户对北区广告的历史平均点击率与全体用户的平均点击率之比 去调整收入项,在「平均条数相同」的约束下显著提升整体营收。调整北区准入的指标——MRP、相关性、质量度——都隐式地影响这个问题的解。目标函数形式上不可导、可调参数也不多,工程上用下降单纯型法这类直接搜索方法求解即可。
现代注解 北区/东区是 PC 搜索时代的版式概念。移动搜索全面信息流化之后,「北区放几条」演化为「广告密度与原生样式如何混排」的决策——约束优化 + 个性化调整收入的框架没有变,变的是决策变量的形态。
12.9.3 布尔表达式检索:两层索引与 WAND 剪枝
现在进入本章核心。受众定向售卖方式下,一条广告文档是定向条件组成的 析取范式(Disjunctive Normal Form, DNF)——若干个交集(conjunction)的并。理解算法只需三个概念,自顶向下:
| 概念 | 含义 | 例子 |
|---|---|---|
| DNF | 一条广告的完整定向条件:交集的并 | |
| Conjunction(交集) | 若干赋值集的交,命中它则该分支成立 | |
| Assignment(赋值集) | 对一个标签的最小约束:属于或不属于某取值 | 、 |
整个检索算法建立在 两个关键性质 上。其一:当某次请求的标签满足某个 Conjunction 时,一定满足所有包含该 Conjunction 的广告——所以只需对 Conjunction 建倒排索引,再套一层「Conjunction → 广告」的辅助索引,而不必对每条广告的完整 DNF 求值。其二:令 为请求携带的定向标签个数, 为其中含「」的赋值集数目,当 时该 Conjunction 必然不满足——请求连它要求的标签数都凑不齐。这条性质把索引按 size 分层,查询时整层跳过,是最有力的剪枝。
图中把书里那组经典示例完整重建了一遍:7 条广告 – 分解出 7 个 Conjunction(–),第一层索引把 这类赋值集 拆成多个键 (、), 操作符不进键、只放在倒排链表的具体元素上;size=0 的纯 型 Conjunction 挂在一个特殊键 上,保证每个赋值集都至少出现在一个倒排链里。一次请求到来时:按 size 分层逐层查键得到候选 Conjunction 集合,经第二层索引取并集得到 候选广告超集 ,最后只对这个超集逐条做精确布尔判定。候选超集允许「多召」——把明显不满足的 也召进来了——代价只是对少数广告做一次精确求值,换来的是检索阶段绝无遗漏。
Analysis: 两层索引的复杂度账很清楚。设请求含 个标签、命中键的平均倒排链长为 ,候选集规模约为 ,远小于广告总量 ;size 分层把「请求标签不足」的层整层剪掉,实际工程中通常能跳过大部分层。代价是索引体积:每个 Conjunction 按其赋值集拆键存储,空间换取的是查询时间的数量级下降——这是检索系统里最典型的时空交换。
相关性检索与 WAND
布尔索引解决了「定向条件匹配」,但开头说的第二个问题还在:上下文定向时,请求可能带几十上百个关键词。此时布尔逻辑两难——「与」匹配不到结果,「或」召回一堆垃圾。解决思路是换目标:检索阶段不问「词是否出现」,而问「查询与文档的 相似程度 够不够高」,这就是 相关性检索。
做法是在检索阶段就引入一个评价函数,用它的结果决定返回哪些候选。函数设计有两个要求: 合理性 (与最终排序用的评价函数近似)和 高效性 (必须能在检索阶段快速算,否则与直接对每个候选精算没有区别)。研究表明:当评价函数是 线性的 (变量为各标签/关键词)且权重均为正时,可以构造出这样的快速算法。设线性评价函数为:
其中 、 分别是广告文档与上下文中非零特征的集合, 是特征 在查询侧的权重(如 TF-IDF,同一次查询内为常数), 是 在广告 上的贡献值。VSM 的余弦相似度因归一化分母不符合线性要求,但去掉归一化后可作检索阶段的近似预评估。
加速的关键是 两个上界 :其一,关键词 在所有文档上的贡献值上界 (建索引时预计算);其二,把查询中若干关键词的 累加,得到任意文档对该查询得分的上界 。配合一个维护当前 Top- 结果的 小顶堆 (堆顶是第 名的分数,即剪枝阈值),就得到 Broder 等人提出的 WAND(weight AND)算法——上下文定向广告与内容推荐产品中非常实用的快速检索方案。每次迭代两步:
- 将各关键词的倒排链按其当前最小文档 ID 升序排列;
- 依次访问各关键词、累加 到 :若 尚未超过堆顶阈值就已扫完所有链,说明当前文档即使用上界估算也进不了 Top-, 直接跳过 ;若扫到某个位置时 超过堆顶,且首末两个关键词的倒排链指向同一文档,才对该文档做 精确评分 ,分数高于堆顶则入堆。
Analysis: WAND 的威力来自「用上界排除 + 用堆抬高门槛」的正反馈:结果集越好,堆顶阈值越高,能被上界放行的文档越少。它不做全量精算,只对「有可能进 Top-」的文档精确评分,工程实践中常能跳过绝大多数候选。其适用边界也清晰:评价函数必须线性且权重非负——好在排序模型常用广义线性模型建模,这个框架的覆盖面比看起来大。对非线性深度排序模型,同样的「粗略上界 + 精确打分」分治思想在粗排层延续(见 12.9.5)。
12.9.4 语义召回与近似最近邻检索
布尔检索与 WAND 解决的是「标签层面的匹配」,但它们有一个共同的盲区:当一个概念在查询和广告里 用词不同——用户搜「笔记本散热」,某条广告写的是「电脑风扇静音」——关键词匹配就失效了。主题模型(如 LDA)有一定的泛化能力,但无监督训练难以针对性解决具体业务问题。真正的转机是词嵌入带来的: 端到端地从原始数据中监督学习任务相关的语义表示 ,让语义的表达能力和准确程度大幅提升——这是广告检索技术走向当代形态的分水岭。
DSSM:用点击当老师
在广告、搜索、推荐领域,现成的弱监督信号是 点击 :给定上下文 (搜索场景是查询,上下文定向场景以内容为主),若 ( 被点击而 没有),就认为 与 更相关。DSSM(Deep Semantic Similarity Model) 正是在这个信号上训练的深度语义模型,名字里两个词各有含义: 语义——把 和 从各自的原始空间映射到一个共享的隐藏语义空间,相关性在该空间里度量; 深度——这个映射由多层神经网络学出来。其结构分三步:
- 输入层把 和 的词做嵌入,用 BoW(词袋求和、不计词序,复杂度最低)或 CNN/RNN(需要刻画词序与局部特征时)加工成定长向量 ;
- 经多层非线性变换投影到语义空间,得到语义向量 与 ,相关性用余弦相似度度量(乘以调节因子 控制动量程);
- 把信息检索建模成多分类:正例 是被点击的文档,负例是随机采样的未点击文档,最大化给定 下点击 的后验概率(softmax 形式);也有把目标简化为 按对排序 的版本——只取一对正负样例,最大化其相关性得分之差。
训练完模型,每个查询和文档都有了语义向量。检索的最相关文档,就变成向量空间里找最近邻。
双塔的雏形:用户向量化
推荐场景下,DSSM 的思路换个输入就是 双塔模型 的雏形(书里以 YouTube 个性化推荐为例,对受众定向广告同样适用)。区别在输入层:DSSM 的输入是文本,这里的输入是 用户历史行为——把搜索、广告点击等每次行为的稀疏特征都表示成稠密语义向量,不定长的行为序列取平均得到嵌入部分,再拼接性别、年龄、地域等画像特征,组成一个较宽的定长向量,逐层降维后输出与广告向量同维度的用户向量 ,用 softmax 多分类损失训练。两个工程细节影响深远:
- 负样本不能只用「展示未点击」。 线上真实未点击的数据往往与查询有一定相关性,只拿它当负例,模型会学出「相关性不重要」的错误结论,召回质量崩塌。YouTube 用候选采样(candidate sampling)为每条正样本采样负例,并固定每用户的样本数防止分布被高频用户带偏。
- 离线建向量索引,在线查索引。 检索在线执行时,不可能拿用户向量与全部广告向量逐个算距离——这就引出了最近邻检索的工程问题。
ANN:从 LSH 到图索引
先看暴力法为什么不行:语义向量 200 维、候选文档 100 万的数据集,全量遍历计算距离要耗时数十毫秒——高并发的在线广告场景完全不可接受。于是需要 近似最近邻(Approximate Nearest Neighbor, ANN) :对候选做剪枝,接受一点召回率损失,换取毫秒级的检索速度。书里讲了三类典型方案,它们的核心都是「分治」——把大空间切成小区域,只在少数区域内精确搜索:
1. 哈希算法(LSH)。 局部敏感哈希的直觉一句话就能说完: 原始空间里更近的点,哈希后更容易碰撞到同一个桶。以余弦距离对应的随机投影为例:随机生成一个超平面,取投影值的符号 为哈希值;两向量夹角为 时,同桶概率为:
夹角越小同桶概率越高,恰好满足局部敏感的定义。单个超平面太粗糙,实践用 个超平面做「与」操作、拼成 比特签名作为桶号;召回不足时两条路: LSH forest (空间换召回—— 组独立签名取并集,内存 倍增长)与 multi-probe (时间换召回——签名改 位生成新签名二次查询, 时复杂度显著上升且不好控制精度)。
2. 向量量化(VQ)。 把向量整体量化映射到 个离散码字之一,用「压缩」来分治。经典 K 均值就是最简单的向量量化:聚类产出 个质心,查询时找最近质心。两个实用改进: 乘积量化 PQ——把向量切 等份分别做 K 均值,高维下在内存与精度间取得平衡(Facebook 开源的 faiss 库提供高效实现); 层次 K 均值树 HKM——借鉴 KD 树在每个节点做 的聚类递归划分,查询从根走到叶,复杂度从 降到 ,且通过「查兄弟叶节点」平滑扩大召回。
3. 基于图的算法(NSW)。 树结构检索路径固定、只能自顶向下,图结构则灵活得多。可导航小世界(Navigable Small World, NSW) 利用小世界网络的性质:少量长程连接让大多数节点间路径很短。建索引时逐个插入节点、与当前近邻建立连接(早期插入形成的连接自然成为长程连接);查询时从任意节点(可多入口并发)出发,贪心地走向离查询更近的邻居,直到 Top- 收敛。
💡 现代注解:2026 的工程主流长什么样 书中这三类方案按时间线看正是索引技术的演进史,今天的工业实践中:LSH 已基本退出主流,但其「近点更易碰撞」的直觉仍是一切 ANN 的思想原点;图索引 HNSW(NSW 的分层版本,上层稀疏图做快速导航、底层稠密图保精度)凭借高召回 + 高并发的优势成为多数场景的默认选择;IVF-PQ(先用 K 均值粗聚类分桶 IVF,桶内再做乘积量化压缩)在大规模、内存受限的场景与 HNSW 分庭抗礼,faiss 同时提供两者。召回侧则演进为多路召回:语义向量召回、协同/行为召回、热门兜底等多路并行各取 Top-K,合并去重后进入排序——单一索引独扛全局的时代结束了。而 DSSM/YouTube 模型演进成了今天的双塔模型标配训练法:用户塔与物品塔各自独立打向量,batch 内互为负例(in-batch negatives),线上线下解耦部署。
Analysis: 三类 ANN 的取舍可以浓缩为:LSH 实现最简单、内存可控,但召回率天花板低;量化类(PQ/HKM)内存最省、适合超大候选池,但有量化精度损失;图类(NSW/HNSW)召回率与查询延迟表现最好,代价是索引内存较大、建图成本高。共同前提是双塔式的表示学习质量——向量本身不好,任何索引都救不回来;这也解释了为什么语义召回的竞争焦点最终回到了样本与损失函数的设计上。
12.9.5 收束:检索漏斗与系统的全貌
把本章的技术放回系统全景,就是一张 检索漏斗 :亿级候选经过召回、粗排、精排、竞价四层逐级收窄,最终只剩 1~3 条广告被真正展示。
这张图值得停下来读三个细节。第一,每一层都是「缩小候选」与「提高打分精度」的交换 :召回层用索引结构(布尔倒排、ANN 向量索引)做到亿级到万级,代价是打分极粗(只看「能不能匹配」或「向量像不像」);粗排用轻量模型在万级候选上打分,把 WAND 式的「上界粗估 + Top-K 保留」思想工程化;精排才对百级候选上完整 CTR 模型(其精度与校准见 12.5);最后竞价层按 eCPM 排序、GSP 计价。第二,上游永远无法用下游的精度弥补——召回层漏掉的广告,精排再准也看不见,所以工程上宁可多召(图中布尔索引的「候选超集」哲学),也绝不轻易收窄召回面。第三,多路召回是常态 :布尔定向召回与语义向量召回并行各出一路候选,合并去重后统一进入下游——12.9.3 与 12.9.4 的两套技术不是替代关系,而是同一漏斗的两条进水管。
对照推荐系统(本书上篇的主线),你会发现这个漏斗与「召回→粗排→精排→重排」几乎是同构的——广告系统与推荐系统在检索这一层共享了全部工程智慧,差异只在漏斗尽头:推荐优化用户价值,广告还要穿过一层 出价与机制 (12.4 的智能出价决定广告主愿意为什么样的候选付多少钱,12.3 的 GSP 决定收多少钱)。检索为这一切提供入场券。
⚠️ Common Mistakes in 12.9
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 对每条广告逐个求值布尔表达式 | 请求到来时遍历亿级广告、逐条判 DNF | 检索预算只有几毫秒,全量求值必然超时;两层索引正是为此设计 | Conjunction 建倒排 + Conj→AD 辅助索引,只对候选超集精确判定 |
| 2 | 忽略 size 分层剪枝,或把 计入 size | 请求只带 2 个标签却去查 size=2 以上所有层;把 也当索引键 | 时必不满足,整层可跳过; 不进键,只放链表元素上 | size = 含「」的赋值集数目;按 size 分层建索引,查询逐层剪枝 |
| 3 | 把非线性精排函数直接搬到检索阶段剪枝 | 用深度 CTR 模型的打分在检索阶段做 WAND 上界 | WAND 的快速排除依赖「线性 + 权重非负」才能累加上界;非线性函数无法构造可累加的 | 检索/粗排用线性或广义线性近似;深度模型留给精排 |
| 4 | 语义召回上线后对全库暴力算余弦 | 每次请求拿用户向量与 100 万广告向量逐个点积 | 200 维 × 百万级的全量遍历需数十毫秒,高并发下不可接受 | 部署 ANN 索引(HNSW/IVF-PQ),接受近似换毫秒级延迟 |
| 5 | 把 LSH/HKM 当成当代主流方案 | 新系统选型直接上 LSH forest | LSH 召回天花板低、HKM 检索路径固定,工程上已被图索引与 IVF-PQ 取代 | 现代选型优先 HNSW/IVF-PQ;LSH 保留其「近点易碰撞」的直觉价值 |
| 6 | 查询扩展只看语义相似度 | 用主题模型把「笔记本」扩展到「笔记本电脑包」,不顾变现差异 | 语义相关不等于意图相关,更不等于 eCPM 高;过度泛化还会损害搜索广告的相关性 | 三路并用:协同过滤 + 主题模型兜底 + 历史 eCPM 效果数据主导 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 广告检索的特殊性 | 文档是 DNF 布尔表达式而非词袋;查询可由上百个标签组成 | 决定广告检索不能照搬搜索引擎方案,需要专用索引与剪枝 |
| 布尔表达式检索 | DNF → Conjunction → Assignment 三层分解;两层倒排索引 + size 分层剪枝;候选超集 + 精确判定 | 亿级候选毫秒级检索的基石,竞价广告最核心的通用技术之一 |
| WAND | 线性评价函数 + 关键词上界 + 小顶堆阈值,只对可能进 Top-K 的候选精确评分 | 超长查询场景(上下文定向)的实用快速检索;「上界粗估 + 门槛正反馈」思想延续到粗排 |
| 查询扩展 | 协同过滤(会话×查询矩阵)、主题模型(语义补充)、历史 eCPM(直接对准营收)三路并用 | 搜索广告的流量与营收杠杆;泛化过度损害相关性是硬边界 |
| 语义召回 | DSSM/双塔:点击作弱监督,端到端学语义向量,检索变最近邻查找 | 解决关键词匹配的泛化盲区,是当代召回技术的基础形态 |
| ANN 演进 | LSH(直觉原点)→ 向量量化 PQ/HKM → 图索引 NSW/HNSW;现代主流 HNSW/IVF-PQ + 多路召回融合 | 向量检索的工程地基;向量质量比索引选择更根本 |
❓ FAQ
Q1: 布尔检索和语义召回,现代系统到底用哪个?
都用,而且是并行使用。广告主的定向条件必须精确满足(这是合约承诺),布尔倒排索引不可替代;语义召回负责补布尔逻辑覆盖不到的「意图相近」的流量。两者各自产出一路候选,合并去重后统一进入排序——即多路召回。讨论「谁替代谁」是伪问题,工程难点在多路候选的配额与合并策略。
Q2: WAND 里「允许非负权重线性函数」的限制,实际影响大吗?
比直觉小。排序模型长期以广义线性模型(特征 × 权重再套非线性链接)为主流,广义线性打分仍可拆成线性项累加,WAND 框架直接适用。即便是深度模型,也可以在粗排层用线性/轻量近似做 Top-K 筛选——分治思想不依赖具体模型形态。
Q3: ANN 选型记住一条什么原则就够?
向量质量优先于索引选型。HNSW/IVF-PQ 的差距是工程常数级的,而双塔训练的样本与损失函数设计(负采样、in-batch negatives、特征覆盖)决定召回质量的上限。索引选型的实用起点:内存充足选 HNSW,亿级以上且内存受限选 IVF-PQ,其余细节交给基准测试。
🔗 前后关联
- 12.2 (计费模式与核心指标):检索的下游终点是 eCPM 排序,eCPM 的分解口径(pCTR × 点击价值)直接定义了「什么样的候选有入场资格」
- 12.3 (竞价机制):GSP 计价与市场保留价作用于检索漏斗的最后一层;检索质量决定竞价的激烈程度
- 12.4 (智能出价):漏斗尽头的出价决定广告主愿意为何种候选付费;预算消耗状态反过来会收紧上游的检索配额
- 12.5 (偏差与校准):精排层 pCTR 的校准质量影响 eCPM 排序,进而影响「检索该召回多少」的配额决策
- 12.7 (在线分配):流量预测的「反向索引」与本章广告检索的倒排索引互为对偶——文档与查询互换角色,同一索引技术服务两个问题
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 12.9.1 — DNF 分解与命中判定 🟢 Easy
某广告的定向条件为:。请把它分解成 Conjunction 的并,写出每个 Conjunction 的 size(含「」的赋值集数目),并判断以下两个请求是否命中该广告:(1) ;(2) 。
Sample Input: 请求 (1) ;请求 (2) Sample Output: 分解 ,两个 Conjunction 的 size 均为 2;请求 (1) 命中,请求 (2) 不命中
💡 Solution (click to reveal)
**Approach:** 按「∩ 连接的段为一个 Conjunction、∪ 连接的段为不同 Conjunction」拆分,逐赋值集核对请求标签。- 分解:,。各自含 2 个 赋值集,size 均为 2。
- 请求 (1): 需要 ✓ 与 ✓,满足 → 命中(DNF 中只要一个 Conjunction 成立即可)。
- 请求 (2): 需要 ,请求是 ✗; 需要 ,请求是 ✗ → 不命中。
- 顺带验证 size 剪枝:请求 (2) 只有 2 个标签,size=2 的层仍可查(),若广告再增加一个 赋值集使 size 变 3,则整个 Conjunction 无需求值即可排除。
Key points:
- DNF 命中条件:至少一个 Conjunction 的全部赋值集被满足
- size 以「」赋值集计数, 不计入也不进索引键
Problem 12.9.2 — 两层索引查询模拟 🟡 Medium
使用 12.9.3 图中的 7 条广告(–)与其 Conjunction 分解(–,其中 、)。请求为 ,size=3。请写出:(1) 查询各命中键后得到的候选 Conjunction 集合;(2) 经第二层索引取并集后的候选广告超集;(3) 精确判定后的最终命中列表,并说明哪条广告被排除、为什么。
Sample Input: 请求标签 Sample Output: 候选 Conjunction ;候选广告 全部 7 条;最终命中 ,排除
💡 Solution (click to reveal)
**Approach:** 逐层查键 → 第二层取并集 → 精确判定,与图中流程一致。- 第一层查键 (size ≤ 3 的层均可查):size=2 层,、、;size=1 层,。候选 Conjunction 。(size=0)只在特殊键 下,需精确判定。
- 第二层取并集 :、、、、,并集为 ——候选超集覆盖了全部广告。
- 精确判定 :( ✓)、(:age=3 ✓,gender=男 ✓,geo=北京 ∉{广东} ✓)、(:age ∈ {3,4} ✓)、( ✓)、( ✓)、( ✓)。 被排除: 需 gender=女 ✗, 需 geo ∉ {北京,广东} 但 geo=北京 ✗。
Key points:
- size=1 的 也要查——size 剪枝只剪「size 大于标签数」的层,不剪小 size
- 候选超集允许包含最终不命中的广告(如 ),精确求值只发生在超集上,这正是效率来源
Problem 12.9.3 — WAND 剪枝推演 🟡 Medium
某次上下文定向查询含 3 个关键词,其倒排链当前头的文档 ID 依次为:,,。各关键词的贡献上界为 、、。当前小顶堆已装满 个结果,堆顶分数(剪枝阈值)。请推演 WAND 本轮迭代的两个步骤,判断 doc 5 是否会被精确评分,并说明系统下一步的动作。
Sample Input: 倒排链头 ;上界 ;阈值 Sample Output: pivot 停在 (累计上界 ); 的链头(doc 5)与 pivot 链头(doc 9)不一致 → doc 5 不评分;从前面某条链跳到 doc 9,进入下一轮
💡 Solution (click to reveal)
**Approach:** 第一步按链头 docID 升序排列,第二步累加上界找 pivot,再比较首尾链头。- 排序后顺序即 。累加上界:;; → pivot 为 。
- pivot 判定: 与 的链头 docID 分别为 5 与 9, 不一致 → 当前文档(doc 5)即使用满上界也只是在 两条链上,其真实得分上界为 ,不可能进堆 → doc 5 被剪枝,不做精确评分。
- 下一步:从前面的链中选一条(如 )用 skipto 跳到 doc 9,回到第 1 步;此时 链头一致且累计 ,若 链头也到达 9,则 doc 9 值得精确评分。
Key points:
- 累加的是「上界」而非真实得分——上界不够就绝不精算,这是 WAND 省算力的全部来源
- 堆顶阈值随结果集变好而抬高,剪枝越来越狠:正反馈是 WAND 高效的深层原因
Problem 12.9.4 — 随机投影 LSH 的召回账 🔴 Hard
用随机投影做余弦 LSH。两个向量的夹角 。(1) 单个超平面下两向量同桶的概率是多少?(2) 用 个超平面拼 8 比特签名(「与」操作),同桶概率变为多少?(3) 为提升召回改用 LSH forest: 组独立签名取并集,「至少一组同桶即判为近邻」的召回概率是多少?(4) 若改用 multi-probe,二次查询需生成的新签名数在 和 时各是多少?据此说明两种扩召回方案的代价差异。
Sample Input: ,, Sample Output: (1) ;(2) ;(3) ;(4) 时 8 个, 时 28 个
💡 Solution (click to reveal)
**Approach:** 逐层代入公式 、签名概率 、并集召回 、组合数 。- (1) 。
- (2) 8 位签名全部一致才同桶:。「与」操作让桶极小、查询极快,但单签名召回急剧下降。
- (3) 组签名至少一组碰撞:。召回从 3.9% 提升到 32.8%,代价是索引内存 10 倍。
- (4) 修改 位的新签名数为 : 时 ; 时 。multi-probe 不增内存但每次查询要发起多路二次检索, 时查询次数迅速膨胀且精度-召回权衡难以平滑控制。
Key points:
- LSH 的三种扩召回手段本质都是拿别的东西换召回:forest 换内存、multi-probe 换查询时间、增大 换桶精度
- 数值上看清了 LSH 的局限——想要 90%+ 召回需要天文数字的签名组数,这正是图索引取代它的原因之一
Problem 12.9.5 — 实现两层布尔倒排索引 🏆 Challenge
用 Python 实现书中示例的完整检索:给定 7 个 Conjunction(–)与 7 条广告的分解(–),实现 build_index()(按 size 分层的 Conjunction 倒排 + Conj→AD 辅助索引,含 size=0 特殊键 Z)与 retrieve(query)(size 剪枝 + 键查询 + 精确判定),并用四组请求验证输出。
Sample Input: 请求 ,以及 、、
Sample Output: ['a1','a3','a4','a5','a6','a7'];['a4','a5'];['a2','a4','a5','a6'];['a1','a4']
💡 Solution (click to reveal)
**Approach:** 赋值集建模为(属性,取值集合,belong)三元组;size 只数 赋值集; 拆成两个索引键;纯 型挂特殊键 Z 走精确判定。# 每个赋值集: (属性, 取值集合, belong),belong=True 为 ∈,False 为 ∉
CONJUNCTIONS = {
"j1": [("age", {3}, True), ("geo", {"北京"}, True)],
"j2": [("age", {3}, True), ("gender", {"女"}, True)],
"j3": [("age", {3}, True), ("gender", {"男"}, True), ("geo", {"广东"}, False)],
"j4": [("gender", {"男"}, True), ("geo", {"广东"}, True)],
"j5": [("age", {3, 4}, True)], # ← KEY LINE: 一个 ∈ 赋值集,size=1
"j6": [("geo", {"北京", "广东"}, False)], # ← KEY LINE: 纯 ∉ 型,size=0
"j7": [("gender", {"女"}, True), ("geo", {"广东"}, True)],
}
ADS = {
"a1": ["j1", "j4"], "a2": ["j2", "j6"], "a3": ["j3", "j7"],
"a4": ["j5", "j4"], "a5": ["j6", "j5"], "a6": ["j6", "j1", "j7"],
"a7": ["j1", "j7"],
}
def build_index():
by_size, conj2ad = {}, {}
for c, assigns in CONJUNCTIONS.items():
k = sum(1 for _, _, b in assigns if b) # size = ∈ 赋值集数目
for attr, vals, b in assigns:
if b:
for v in vals: # age∈{3,4} 拆成两个键
by_size.setdefault(k, {}).setdefault((attr, v), set()).add(c)
if k == 0: # 纯 ∉ 型挂特殊键 Z
by_size.setdefault(0, {}).setdefault("Z", set()).add(c)
for ad, cs in ADS.items():
if c in cs:
conj2ad.setdefault(c, []).append(ad)
return by_size, conj2ad
def holds(assigns, query):
for attr, vals, b in assigns:
q = query.get(attr)
if b and q not in vals:
return False
if not b and q in vals: # q 不在集合时 ∉ 成立(含缺失)
return False
return True
def retrieve(query, by_size, conj2ad):
conjs = set()
for k, posting in by_size.items():
if k > len(query): # ← KEY LINE: size 剪枝
continue
for key, cs in posting.items():
if not isinstance(key, tuple): # 跳过特殊键 Z
continue
attr, v = key
if query.get(attr) == v:
conjs |= cs
for c in by_size.get(0, {}).get("Z", set()): # size=0 走精确判定
if holds(CONJUNCTIONS[c], query):
conjs.add(c)
return sorted({ad for c in conjs
if holds(CONJUNCTIONS[c], query)
for ad in conj2ad[c]})
idx = build_index()
print(retrieve({"age": 3, "geo": "北京", "gender": "男"}, *idx))
# ['a1', 'a3', 'a4', 'a5', 'a6', 'a7']
print(retrieve({"age": 4, "geo": "北京"}, *idx))
# ['a4', 'a5']
print(retrieve({"age": 3, "geo": "上海", "gender": "女"}, *idx))
# ['a2', 'a4', 'a5', 'a6']
print(retrieve({"gender": "男", "geo": "广东"}, *idx))
# ['a1', 'a4']
注意第三个请求:(geo ∉ {北京,广东},geo=上海 成立)经 Z 键的精确判定进入候选,连带召回 与 中的 分支——这正是 size=0 层不能靠键查询、必须精确判定的原因。第四个请求验证了 的反例: 因 geo=广东 ∈ {广东} 被精确判定排除,虽然它的 、 键都命中了(该请求无 age 标签,j3 靠 gender 键入候选后仍被 ∉ 条件挡下)。 Key points:
- size 剪枝在
k > len(query)处:请求标签不足时整层跳过 - 只存在于链表元素(此处化简为精确判定阶段),永远不进索引键
- 候选超集 → 精确判定是「允许多召、不许漏召」的检索哲学
数据加工与交易
📝 Before You Continue: 本章需先读 12.2(计费模式与核心指标)——数据附加费按 CPM 结算,eCPM 口径必须先建立;以及 12.3(竞价机制)——RTB 询价流程是数据交易得以「搭车」的载体。12.4(智能出价)会让你明白标签最终流向哪里:定向与出价特征。12.6(开环与闭环广告)已讲过身份信号侧的 ATT/SKAN/Privacy Sandbox,本章只处理数据合规与交易侧,两者互为表里。
定向要准、出价要狠,前提都是「你比别人更懂这个用户」。前几章里我们反复使用的 用户标签——兴趣、意图、人群属性——并不是凭空出现的:它们来自对行为数据的收集与加工,而在程序化交易市场中,它们本身还是一种可以定价、可以买卖的商品。这一章把镜头从「怎么投广告」拉回到「广告的燃料从哪来」:哪些数据真正有价值?谁来把原始日志加工成标签?标签如何定价与交割?以及——当你收集和买卖用户数据时,法律与安全的安全边界在哪里?
数据行业最初是为广告服务的,但今天它已经发展成一个相对独立的产业。理解这一章,不只是理解广告的一个配套环节,而是理解「个性化系统如何把行为变成资产」这门通用手艺。
读完本章,你将能够:
- 区分第一方、第二方、第三方数据,判断任意一条数据在广告交易中的归属与用途
- 按价值阶梯为各类用户行为数据排序,并说明两条价值规律背后的逻辑
- 对比第一方 DMP 与第三方 DMP 的职责、商业模式与产品案例
- 描述以 ADX 为中转的数据交易机制:CPM 计价、按实际成交交割,以及「数据价格向流量价格转移」的经济问题
- 掌握隐私保护的基本原则、准标识符与 K 匿名的思想,识别程序化交易中供需两侧的数据安全风险,完成 5 道分层练习题
12.10.0 三方数据:定向与出价的燃料
广告系统的每一个决策——检索哪些候选、预估多少点击率、出多少钱——本质上都是「用数据换判断」。12.3 的竞价机制让流量有了市场价格,而让同一个流量在不同 DSP 眼里价格不同的,正是各自掌握的数据。所以围绕数据的收集、加工与交易,与投放技术本身一样重要。
广告中用到的用户数据,按来源分为三类。第一方数据 来自广告主:自己的 CRM、订单记录、官网访客行为; 第二方数据 来自广告平台:用户在媒体或平台上产生、由平台自己掌握的行为数据; 第三方数据 则来自不直接参与广告交易的其他数据提供方——中小媒体、会员体系、各类数据公司。在广告网络模式下,主要用第二方数据指导投放;而到了实时竞价(12.3)时代,玩法变了:第一方数据可以被激活,第三方的加工与交易也随之发展起来。
三类数据的地位并不对等。第一方数据量一般不大,却是所有数据的 灵魂——它与你的生意直接相关,语义最明确、离转化最近。以第一方数据为基础,用好第二方和第三方数据,是实时竞价时代最重要的方法论。下面的生态图是本章的路线图:数据从三类来源出发,经 DMP 加工成标签,通过 ADX 交易附着到每一次竞价请求上,最终在 DSP 变成定向与出价的弹药,而投放效果又回流为新的数据——闭环至此合上。
🧠 Mental Model: 石油炼化厂
把数据生态想象成石油工业。原始行为日志是原油——埋在地下、不能直接驱动任何东西;DMP 是炼化厂——把原油分馏成汽油、柴油(标准化的用户标签);ADX 是加油站与油表——把成品油按升卖出去(标签按 CPM 附着在流量上);DSP 是发动机——烧油产生动力(定向与出价);最后排出的尾气(转化数据)又被回收提炼——闭环的原料永不枯竭。记住一个反差:自家油田(第一方数据)产量不高,但品质与归属都最好;批发市场(第三方数据)量大管饱,但成色参差。
12.10.1 有价值的数据来源
数据是精准广告市场的核心,但不是所有数据都值得收集与加工。哪些数据对广告业务有直接贡献?我们逐类来看,并给出价值的判断框架。
用户标识。 如何确定哪些行为来自同一个用户,是最容易被低估的问题。稳定的用户身份就像一串 0 前面的那个 1:无论能拿到多少行为数据,如果无法把它们关联到投放系统里的那个人,这些数据就无法发挥作用。浏览器时代的基础方案是 cookie——虽然多浏览器、过期、用户主动清除都会破坏长期一致性,但广告起关键作用的本来就是近期行为,所以 cookie 仍是业界广泛采用的方案;若运营广告的域名同时提供电子邮件、SNS 等永久身份服务,可以用永久身份找回过期的 cookie。移动端则分化:iOS 用广告专用标识符 IDFA,性质与 cookie 类似;Android 没有专门广告 ID,一般用 Android ID 或 IMEI 等设备标识。高质量的用户标识本身就是有价值的资产,可以在市场上交换和售卖——这条线索我们在 12.10.2 的现代注解里会继续展开。
用户行为。 业界公认可广泛采集、对定向有明确作用的在线行为包括:转化、预转化、搜索广告点击、展示广告点击、搜索点击、搜索、分享、页面浏览、广告浏览等。按对效果广告的有效性,它们分成四级:
- 决策行为 :转化与预转化——都发生在广告主的网站内。电商场景里,转化对应最后的下单,预转化对应下单前的搜索、浏览、比价、加购物车等准备工作。这类行为兴趣指向最明确,价值最高,但也最难被供给方或广告平台拿到;用它们做重定向或个性化重定向是最直接的利用方式。量不大,但不能忽视。
- 主动行为 :广告点击、搜索、搜索点击——用户在明确意图支配下主动产生,信息量丰富。广告点击量太小,不足以作为定向的主要来源;而 搜索是能大量获得的最主要主动行为 ,要特别挖掘利用。
- 半主动行为 :分享、页面浏览——产生于目的较弱的内容消费过程,能把握兴趣领域,但内容精准度有限。指导意义有限,数据量却是各类行为中最大的。
- 被动行为 :广告浏览——严格说不能算定向的行为依据,但它的频次与对应类别的广告点击负相关,所以在行为定向建模中仍然可用。
价值判断有两条基本规律:其一, 随着用户主动意图的提升,行为数据价值随之增大 ;其二, 越接近转化的行为,对效果广告的精准指导作用越强。但这里有一个容易被忽视的提醒:广告的根本目的是「低成本地接触 潜在 用户」。靠近转化的行为之所以更精准,是因为这部分人群已经站在决策的最终阶段——换句话说,越发不是「潜在用户」了。只盯着转化 ROI 做定向,覆盖率会塌缩到漏斗最底部。正确的做法是根据广告主的人群接触目标,平衡效果与覆盖率。
人口属性。 常用的定向标签,但来源受限:一般只有能与实名身份绑定的服务才能直接得到。用行为数据预测人口属性是常见做法,但准确率有限,且仍需标定数据来训练。某些特殊信息反而容易给出准确判定——例如语音服务记录的声音信号可以相当准确地区分男女。
地理位置。 用途随精度剧变。IP 映射只能到城市级别,这对很多投放已有价值;移动环境下 GPS 或蜂窝定位可达几百米精度,就能捕捉用户的线下到店兴趣,让餐饮等区域广告主做精确位置定向成为可能。
社交关系。 社交关系隐含着「兴趣相似」的合理推测,可以用来做 用户兴趣的平滑 :当某个用户的行为数据不足、无法精准定向时,可以借鉴其社交网络朋友的行为与兴趣——一个微博好友大多爱足球的人,大概率也爱足球。这样的平滑只适用于长期稳定的兴趣,对短时购买兴趣不适用;因此强关系 SNS 比弱关系 SNS 更有优势。
设备信息。 移动设备能拿到的数据远比 PC 丰富:应用安装列表、机型、陀螺仪乃至电池电量等状态信息,对识别使用场景非常有帮助。移动广告对设备信息的深入加工有特别重要的意义。
Analysis: 六类数据没有一个统一「排行榜」,因为价值取决于用途:效果类投放里决策行为价值碾压一切;品牌曝光类则恰恰要避开转化边缘人群,半主动行为的大数据量反而是覆盖率的朋友。真正普适的判断框架就是那两条规律(主动意图、离转化距离)加上一个反向提醒(离转化太近就不再是潜在用户)。收集与加工之前,先用这个框架过一遍:这条数据服务于谁的什么目标?
12.10.2 数据管理平台 DMP
有了原始数据,谁来把它炼成可用的人群标签?这类把数据整理加工成可直接利用的信息、并支持变现的产品,统称为 数据管理平台(Data Management Platform, DMP)。市场上 DMP 有立足第一方与第三方两种场景:技术环节基本一致,产品方向和商业模式却差别很大。
先明确 12.10.0 遗留的一个技术细节: cookie 映射。当广告业务域名与拥有永久身份的域名不同时,在后者同意的前提下,可以通过映射技术把两边的用户身份对应起来——这是数据对接与交易的基础设施,后面数据交易的星形拓扑正是围绕它优化的。
第一方 DMP:数据托管与加工服务。 对没有技术积累的广告主或媒体来说,专门设团队做数据加工并不划算,于是产生了专门管理这项业务的产品。它有两个核心功能:一是为网站(媒体或广告主网站)提供受众定向功能,既加工通用标签,也能灵活按网站自定义的标签体系加工人群;二是让广告主与广告采买渠道方便地对接数据。后者的价值可以这样理解:广告主要做外部重定向,需要把自己的用户集合通知广告平台——若每个平台都到网站上装跟踪代码,一是页面被压得越来越重,二是访客积累动辄数周、重定向效率低下。由 DMP 统一负责用户积累与划分、再通过数据接口传给广告平台,两个问题同时解决。
第一方 DMP 按数据方(Data Provider, DP)的需求收集、加工数据,向 DP 收取服务费。它是一种 数据托管和加工服务,不以数据变现为目的 :绝对不应该把客户数据当作自己的财产二次变现,也不能把不同 DP 的数据混合使用——这是这类产品商业模式的底线。客户多为大中型媒体和广告主;有实力的广告主也可以自建 DMP。
第三方 DMP:数据交易平台。 它的主要产品功能是聚合各种来源的在线用户行为数据,加工成有价值的用户标签,再通过售卖标签变现,收入按比例分成给数据提供方。它往往也兼具第一方 DMP 的加工能力,但关键差别在于:数据交易平台 按自己的逻辑、而非媒体的需求 来制定标签体系和加工数据——所以它站在第三方数据的角度提供产品,也称第三方 DMP。它的 DP 以中小型媒体和数据所有者为主,这些玩家数据不少,但单独变现并不划算。
Analysis: 两种 DMP 的商业模式对照。第一方 DMP:卖「服务」——客户付托管与加工费,数据归属权在客户,产品讲求灵活对接与定制标签;第三方 DMP:卖「数据」——按自有标签体系加工后向 DSP 售卖,与 DP 分成,产品讲求标签覆盖与类目运营。前者是 to B 服务逻辑,利润稳定但天花板低;后者是商品流通逻辑,想象空间大但要承担数据质量与合规的全部责任。这个分野决定了后面所有产品案例的走向。
产品案例。 国际市场上曾有三个代表。BlueKai 是最典型的第三方 DMP:2008 年建立 Data Exchange 数据库,一边让中小网站提供流量与会员资料,一边加工后卖给广告主;它坚持不提供媒体竞价采购服务,以保持中立、与多家 DSP 对接——这套「独立 DMP」路线一度非常成功,活跃用户超 3 亿,前 20 大广告网络与门户中 80% 使用其数据;2014 年被 Oracle 以 4 亿美元收购。它的标签体系是开放式的:Intent(近期搜索词表现出需求,16 亿以上用户)、B2B(来自 Bizo)、Past Purchase(Addthis、Alliant)、Geo/Demo(融合 Bizo、Datalogix、Expedia 等多家数据源)、Interest/Lifestyle 等,按来源与市场需求不断拓展——像「对宝洁洗发水感兴趣的人」「想去日本旅游的人」这样的精细类目对效果广告主非常有意义,售价也高。AudienceScience 则代表另一条路:最早提出受众定向概念,主要提供第一方 DMP 服务(如帮《纽约时报》加工财经类、体育类用户标签),同时自营一个效果广告网络变现——它不直接卖标签,而是把标签创造的营收与提供数据的媒体分成,因为「数据加工扣除分成后利润空间太小,自营广告网络有更大套利空间」。2017 年 5 月它关闭了,这也反映出单纯数据服务的规模化和盈利能力都比较有限。TalkingData 是中国市场的代表:以应用统计分析工具切入,积累了海量独立设备数据后推出营销云 MarketingCloud,功能包括用户 ID 的映射与管理(打通 CRM、线下门店、线上浏览、公众号等不同 ID 体系的同一用户)、开放的第三方标签库(800 多个细分维度)、地理围栏目标受众、营销过程监测与管理——商业模式上更接近第一方 DMP,是「数据驱动的营销自动化」这一方向的先行者。
💡 现代注解(2026):上面的案例像一部「前智能手机时代」的纪录片。三方 cookie 在 Safari(ITP)与 Firefox 已被封锁,Chrome 也转向用户选择模式——cookie 映射作为行业基建事实上已经终结,12.6 讲的身份信号退化正是它的终局。取代品是一套新的一一方数据基建:CDP(Customer Data Platform,客户数据平台) 把品牌自有触点(官网、App、小程序、CRM)的数据统一为持久客户档案,替代了旧第一方 DMP 的大多数场景;跨域身份则靠 Unified ID 2.0(UID2)——The Trade Desk 主导、以哈希后的邮箱/手机号为根的开放身份框架——以及 Amazon 等巨头基于自家账号体系的 first-party ID。曾经的独立 DMP 们(BlueKai、Liveramp 等)或被并购消化、或转型为身份与数据协作服务商。旧书里的商业模式教训没有过时:数据能力正在向掌握登录态的一方集中,中立第三方数据的生存空间被合规与技术双重挤压。
12.10.3 数据交易的基本过程
标签加工好了,怎么卖? 数据交易一般通过 ADX 或 SSP 作为中转来完成 :DMP 的各种用户标签以批量传输的方式提供给 ADX,作为 ADX 的辅助产品售卖给各 DSP。标签一般按 CPM 计价:DSP 若选择购买某种标签,广告询价时 ADX 就把本次请求的用户标签随请求传给 DSP,最终以 DSP 实际成交的展示量 × CPM 价格 作为购买数据的附加费用。
以广告交易为载体进行数据交易,比 DMP 与 DSP 之间直接交易合理得多,好处有四:
- 传输成本。数据量级可能很大,直连交易的传输成本不可忽略;而在广告请求上附加用户标签几乎不带来额外服务开销——整体传输成本只剩 DMP 到 ADX 的一次。
- 星形拓扑。所有 DSP、数据提供方都只需与 ADX 做 cookie 映射,而 ADX 触达的用户规模远高于单个 DSP 或 DMP——这最大限度地避免了映射造成的数据损失。
- 部分交易。DSP 很少用得上某个 DMP 的全部数据;在交易过程中传数据,DSP 可以自由限定所需范围——只投上海的 DSP 选了上海地区后,就只会收到上海的数据。
- 天然计费。ADX 恰好站在买卖双方之间,顺带完成了数据使用量监测与计费——它本来就是数钱的那一方。
🧠 Mental Model: 自来水与水表
数据交易像供水。DMP 与 DSP 直连交易,相当于每家用户自己挖井铺管——铺 N 条管线、每条都要结算,成本爆炸;通过 ADX 交易,则是自来水公司统一铺管网(批量传输 + 星形映射),水表装在 ADX 上(每次成交展示量 × CPM),按用量付费。更妙的是「部分交易」:你可以只订上海的水(限定标签范围),不必把整座水库买下来。但自来水与矿泉水有个本质区别:同一份数据可以重复卖给很多家,而且大家喝的是同一片地下水——这正是下面要说的麻烦所在。
数据作为信息商品的独特性在于两点:它可以 重复售卖 (这点像软件);但与软件不同,同一份数据的所有使用者面对的是 同一批用户群 ,因此彼此之间存在博弈关系。由此产生两个深层问题。
其一, 数据的重复售卖会引起数据价格向流量价格的转移。看一个例子:某 DMP 知道某用户是高尔夫爱好者,把这一信息卖给了一家 DSP——该 DSP 利用它获得高回报,自然承受得起较高的数据采购价。但如果 DMP 把它卖给了多家 DSP,这些 DSP 定向同一个用户时必然因竞价关系抬升流量成本,靠这条数据获得的回报就摊薄了,间接也压低了数据的变现价格。卖得越多,单份价值越被竞价稀释——利润从「数据红利」转移成了「流量价格」。其二,重复售卖下 无法按竞价方式售卖数据。在线广告市场正是靠竞价模式才带来客户数量和变现能力的大幅提升(12.3),我们自然期望数据也能竞价。方向是 限量售卖 :每条信息在一定时间内只提供给有限几家购买者,才可能发展出竞价模式并保证数据提供方的利益。但具体限几家、竞价机制如何设计,仍是开放问题。
Analysis: 这个机制的设计精髓是「搭车」:把一种新商品(标签)的交易嵌进一个已成熟的市场(RTB),复用其传输通道、身份映射、计费与监测设施,边际成本近乎为零。对照 12.3 的询价流程,数据交易没有新增任何一次往返。局限也来自同一处:数据价值在成交前不可验证(A/B 才知道这标签值不值),定价只能一刀切按 CPM;加上重复售卖的稀释效应,市场最终走向了下一节要讲的合规化形态。
💡 现代注解(2026):明文人群包交易在成熟市场已大幅萎缩,主流合规形态是数据清洁室(Data Clean Room):广告主把第一方数据、平台把行为数据各自导入受控环境,在互不可见明细的前提下做匹配、重叠分析与效果度量——只输出聚合报表(常叠加差分隐私噪声),不出原始人群包。Google Ads Data Hub、Amazon Marketing Cloud、Meta 的先进分析工具以及 LiveRamp 等中立方案都属于这一形态。12.10.4 的差分隐私与 GDPR/PIPL 合规要求,正是 clean room 的技术底座;它与 UID2 一起,构成了 2020 年代数据协作的新范式——数据可用不可见。
12.10.4 隐私保护与数据安全
广告是典型的个性化系统:定向要靠用户行为数据,交易市场又在买卖这些数据。于是有两类安全问题必须一起考虑——用户的隐私 (个人信息是否泄露),以及 数据拥有方的商业数据安全 (广告主的关键数据是否被平台或对手利用)。
隐私问题的真正难点,比「批量泄露」更隐蔽。 除了成批的用户资料泄露,更大的挑战是 针对熟人的隐私窥探 :窥探者已掌握目标的一些背景信息,用这些信息进一步挖掘更多隐私。这类风险可能是人工与机器结合、对成本不敏感,因此危害最大——曾有人在社交媒体上通过分析发帖与照片准确定位到他人住址,就是典型案例。
在这个背景下,工业界形成了一些共识性的隐私保护原则:
- 严格避免使用个人可辨识信息(PII)——身份证号、电话号码、邮箱、家庭住址等能方便地定位到具体人的信息,必须无条件严格保护。当时的通行认知是:cookie、IMEI 这类用户标识不具有方便辨识人的作用,不属于 PII(这一认知在今天的法律环境下需要修正,见现代注解)。
- 用户有权要求停止跟踪。行为定向广告应给出明确提示(如创意右上角的 AdChoices 标识),用户可通过 Opt-Out 操作通知系统停止记录与使用自己的行为数据——把是否接受个性化广告的决定权交给用户。
- 不应长期保留用户行为数据。长期保留对定向价值有限,却放大泄露风险;过期且与业务无直接关系的数据不应再存储。
- 权限严格分配与最小数据访问。调试用采样、匿名化的数据子集;生产环境经特别密钥访问原始数据;连开发者乃至管理层都不应有数据访问权限。
准标识符:去掉 PII 就安全了吗? 看这条记录:「年龄 36;工作地点上海市某大厦;性别男;职位测试工程师;爱好羽毛球;月薪 15000 元」——姓名手机号都隐去了,但他的朋友靠「年龄 + 工作地点 + 职位 + 爱好」的组合仍能一眼认出是谁,从而读到「月薪」这个隐私。这类 单独看无辨识力、组合起来却能定位个人 的信息,叫 准标识符(quasi-identifier)。对策是 泛化 :把「36 岁」泛化为「30~40 岁」、「某大厦」泛化为「上海市」——若泛化后数据集中每组准标识符的实例都能找到 K 条与其相同的,就实现了 K 匿名。K 取得合理时,泄露风险显著下降。
稀疏行为数据:K 匿名救不了个性化系统。 个性化系统对用户的描述包含大量行为数据,而行为数据极为稀疏——任何两个用户的行为几乎不可能相同,K 匿名无从做起。风险有真实案例:著名的 Netflix 百万美元推荐大赛公布了去除 PII 并做过 K 匿名的数据集,但观影记录与打分未做处理——有研究者发现,把这些稀疏行为数据与 IMDb 等公开数据做简单匹配,就能以相当高的准确率重识别用户;此前已有用户从他人的观影记录中(包括一些同性恋题材影片)被认出。这类研究让工业界的隐私认知大大提升,也催生了 差分隐私 的研究:对数据集做一定程度的修改,在尽可能少损失查询准确率的情况下使泄露风险最低(苹果在 iOS 10 中宣称集成了该技术)。坦率地说,稀疏行为数据的风险至今没有成熟解法,它是大规模行为数据利用头上的达摩克利斯之剑——数据交易与披露时要对它保持敬畏。
程序化交易中的数据安全。 RTB 让供需两侧的数据在一次交易中汇合,这把双刃剑的两面都伤人。
供给方数据安全 :ADX 向参与竞价的 DSP 广播每次展示的 URL 和 cookie,理论上存在 DSP 规模化监听媒体用户行为的可能——恶意 DSP 对所有请求都以极低价格参与竞价,目的不是赢流量,而是收集媒体上的用户行为。好在实际危害可控:由于带宽限制,ADX 会做询价优化(只向最可能赢的 DSP 发询价),以收集数据为目的的 DSP 在理想情况下会被挡在大部分询价之外。
需求方数据安全 :更严重的一面。RTB 中引入定制化标签后,广告主的第一方数据也暴露在交易过程中。设想两个英语教育类广告主都通过 DSP 做重定向:各自的访客集合本是广告主最具商业价值的私有数据,但 DSP、ADX、媒体都有可能在 RTB 过程中得到它们。若 DSP 想制造更激烈的竞价环境,可以把两个广告主的访客集合合并、打上「英语教育人群」这样模糊的标签,吸引双方来竞价——实质是在竞争对手之间倒卖访客集合 ,操作还非常隐蔽。竞价越激烈,原本属于广告主的利润就向市场其他环节转移。这个问题决定着广告主是否敢放心用 RTB 采购,而当前市场的重视程度和解决方案都不充分——广告主面对强势广告平台使用第一方数据时,要特别留意数据安全(现代的对策正是 12.10.3 注解中的 clean room:访客匹配在互不可见的环境里完成)。
GDPR:隐私保护的立法标杆。 欧盟议会 2016 年 4 月通过《通用数据保护条例》(GDPR),2018 年 5 月生效,任何收集、传输、保留或处理欧盟成员国个人信息的机构均受约束。要点有三:其一,明确列出敏感数据——种族或民族出身、政治观点、宗教/哲学信仰、工会成员身份、健康/性生活/性取向、基因数据、生物识别数据(后两类是新时代的合理拓展);其二,处理必须以 明确同意 为基础,同意条文中必须说清收集哪些信息、如何存储使用,模糊条文不再被允许;其三,赋予用户四项权利——数据访问权 (了解企业如何使用自己的数据)、被遗忘权 (要求删除已收集的数据)、限制处理权 (禁止用于营销或透露给第三方)、数据携带权 (离开平台时可带走个人数据)。
💡 现代注解(2026):GDPR 罚则的准确上限是「2000 万欧元与全球年营业额 4% 中的较高者」——这才是「史上最严」的实际牙齿,远比「数千万欧元」的模糊表述更有威慑力。本书当年对 GDPR 的批评(执行标准语焉不详、企业自己都说不清深度学习时代数据如何被使用、改造成本有利寡头)至今仍有讨论价值,但历史已经给出了裁决:GDPR 之后全球立法跟进,中国的《个人信息保护法》(PIPL)于 2021 年 11 月施行,确立了知情同意、最小必要、可撤回同意等原则,并同样区分敏感个人信息;cookie 类标识符在多法域已被纳入个人信息范畴——8.4 时代「cookie 不算 PII」的认知已成历史。至于 ATT/SKAN/Privacy Sandbox 这些信号侧的隐私基建如何在投放中适配,12.6 已专门展开,本章不重复;一句话互链:12.6 讲「信号变弱后怎么投」,本章讲「数据在交易与合规上怎么管」。
12.10.5 收束:数据变现闭环
把本章的零件装回一张图(回顾 12.10.0 的生态图):
数据源 → DMP 加工 → 交易 → DSP 应用 → 效果回流。
- 数据源 :第一方(广告主,灵魂)、第二方(广告平台)、第三方(其他数据方),价值由「主动意图 × 距转化距离」排序;
- DMP 加工 :第一方 DMP 做托管与定制加工收服务费;第三方 DMP 按自有逻辑加工标签售卖变现、与数据源分成——现代形态演进为 CDP + UID2/first-party ID 的身份基建;
- 交易 :标签批量接入 ADX,附着在竞价请求上按 CPM 计价,按 DSP 实际成交展示量交割——现代形态演进为 clean room 的「可用不可见」协作;
- DSP 应用 :标签进入定向与出价(12.3 的竞价、12.4 的智能出价),按需限定购买范围;
- 效果回流 :转化数据回流到数据源侧,成为下一轮加工的原料——12.6 的闭环度量正是这条回流的现代化身。
几个工程与商业判断值得带走:数据的价值不在于多,而在于与业务目标的匹配——效果广告要决策行为,品牌触达要覆盖率;数据交易的市场设计远未完成——重复售卖的价格稀释与竞价机制的缺失是教科书级的开放问题;而隐私与数据安全不是合规成本,是这套燃料体系的承压壁—— Netflix 重识别、访客集合倒卖这些案例提醒我们,壁上任何一道裂缝都会让整个生态失去信任。
⚠️ Common Mistakes in 12.10
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 只用靠近转化的行为做定向 | 只拿下单/加购用户做扩量种子 | 这部分人群已在决策末段、不再是「潜在用户」,覆盖率塌缩,违背「低成本接触潜在用户」的根本目的 | 按广告主的接触目标平衡 ROI 与覆盖率:效果类重决策行为,品牌类向半主动行为的量要覆盖 |
| 2 | 把第一方 DMP 当数据变现方 | DMP 私自把客户人群包卖给其他买方、或混合多家客户数据加工新标签 | 第一方 DMP 是数据托管与加工服务,客户数据二次变现直接摧毁商业模式与信任 | 数据归属写进合同;变现只出现在第三方 DMP 的模式里,且须与数据提供方分成 |
| 3 | 认为去掉 PII 就没有隐私风险 | 脱敏后的行为明细直接对外披露 | 准标识符组合可定位个人;稀疏行为数据几乎无法 K 匿名(Netflix 重识别案例) | 输出前做准标识符泛化与聚合;明细数据走 clean room,只出聚合结果并叠加差分隐私 |
| 4 | 数据附加费按询价量而非成交量计费 | DSP 被按收到的所有带标签请求计费 | 数据交易的交割口径是「实际成交的展示量 × CPM」,按询价计费等于让 DSP 为没买到的流量付钱 | 对账时以 ADX 成交日志为口径;部分交易的范围限定(地域/类目)也要核进计费 |
| 5 | 忽视需求方数据安全 | 把重定向人群包直接开放给 DSP 定制化标签,无任何隔离条款 | DSP/ADX 可能合并访客集合转卖给竞争对手,制造竞价推高流量成本,利润向市场转移 | 签署数据使用限制条款;用 clean room 做访客匹配;监控 win rate 与流量成本的异常漂移 |
| 6 | 把 cookie 时代的方案照搬到 2026 | 设计依赖三方 cookie 映射的标签分发,或宣称 cookie 不属于个人信息 | 三方 cookie 在 Safari/Firefox 已死、Chrome 转向用户选择;多法域已把标识符纳入个人信息范畴 | 一方数据走 CDP + UID2/first-party ID;跨方协作走 clean room;合规按 GDPR/PIPL 口径 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 三方数据 | 第一方=广告主(灵魂)、第二方=广告平台、第三方=其他数据方;RTB 时代方法论:以一方为基础用好二三方 | 所有定向与出价差异的源头,数据资产归属判断的基础 |
| 数据价值排序 | 决策 > 主动 > 半主动 > 被动;两条规律:主动意图越强价值越高、越接近转化指导越准;反向提醒:靠近转化即失去「潜在」属性 | 收集与加工数据前的投资判断框架 |
| DMP 两种模式 | 第一方 DMP:托管加工收服务费、绝不二次变现;第三方 DMP(数据交易平台):按自有逻辑加工售卖、与 DP 分成;现代演进:CDP + UID2/first-party ID | 理解数据产品商业模式与 2026 一方数据基建的谱系 |
| 数据交易机制 | 经 ADX 中转:批量传标签、附加在询价请求、按实际成交展示量 × CPM 计附加费;四大好处:传输成本、星形映射、部分交易、天然计费;开放问题:重复售卖致价格向流量转移、竞价模式待探索 | 程序化市场中标签流通的标准形态与经济学局限 |
| 隐私保护 | 四原则(避 PII/Opt-Out/不长期保留/最小访问);准标识符与 K 匿名;稀疏行为数据无成熟解(Netflix 案例);差分隐私 | 个性化系统数据使用的安全底线,clean room 的技术根源 |
| 交易数据安全 | 供给方:恶意低价 DSP 监听,靠询价优化缓解;需求方:访客集合被合并倒卖、利润向市场转移,比供给方更关键 | 决定广告主是否敢把第一方数据接入程序化交易 |
| GDPR / PIPL | GDPR:敏感数据清单、明确同意、四项权利(访问/被遗忘/限制处理/携带),罚则 max(€20M, 全球营收 4%);PIPL 2021 年施行 | 全球数据合规的两大地基,多法域业务绕不开 |
❓ FAQ
Q1: 第三方 DMP 的时代是不是彻底结束了?
明文人群包交易确实萎缩了,但「聚合多方数据、加工成可商用标签」的需求没有消失,而是换了形态:从独立 DMP 转向平台内建的数据市场(以平台自有身份体系为根)、clean room 数据协作,以及 UID2 这类开放身份上的受众解决方案。旧模式死于身份基建崩塌与合规挤压;学到的东西——标签体系设计、数据质量运营、分成机制——在新形态里全部用得上。
Q2: 「数据价格向流量价格转移」对数据买方意味着什么?
意味着「买数据」的红利会随竞争自动摊薄:当多家 DSP 持有同一标签去竞同一批流量,数据优势转化成了更高的成交价,利润从数据方转移到流量方。买方的应对是把数据用在「别人没有的交叉组合」上(独占性越强越好),并且持续用增量实验验证这条数据的边际贡献,而不是按「有没有」付钱。
Q3: 广告主应该自建 DMP/CDP 还是用外部服务?
看数据规模与团队。数据量大、有工程团队、数据是核心竞争力的(大型零售、金融),自建可控性最好;否则用外部第一方 DMP/CDP 服务,但要守住两条底线:合同明确数据归属与用途限制、绝不允许服务方把你的数据与其他客户混合或二次变现。无论哪种,访客类高价值人群对外协作一律走 clean room。
🔗 前后关联
- 12.1 (全景与生态):本章的数据闭环嵌在广告生态全景中,是「定向与出价从哪来」的供给侧答案
- 12.2 (计费模式与核心指标):数据附加费的 CPM 口径与 eCPM 定义完全建立在 12.2 之上
- 12.3 / 12.4 (竞价机制 / 智能出价):标签经 ADX 交易后,最终作为定向条件与出价特征进入这两章的决策引擎
- 12.6 (开环与闭环广告):信号侧的 ATT/SKAN/Privacy Sandbox 在彼处展开,本章负责数据合规与交易侧;效果回流闭环在 12.6 的闭环度量中现代化
- 12.7 (在线分配):流量预测按标签组合聚合流量——标签体系的质量直接决定预测与分配的精度
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 12.10.1 — 行为数据价值分层 🟢 Easy
把下列在线行为按「决策 / 主动 / 半主动 / 被动」四类归类,并指出哪一类是「能大量获得的最主要主动行为」:
电商下单、加入购物车、广告点击、分享、页面浏览、搜索、搜索点击、广告浏览、下单前的比价
Sample Input: 上述 9 种行为 Sample Output: 决策:{电商下单, 加入购物车, 下单前的比价};主动:{广告点击, 搜索, 搜索点击};半主动:{分享, 页面浏览};被动:{广告浏览};量最大的主动行为:搜索
💡 Solution (click to reveal)
**Approach:** 决策行为 = 转化 + 预转化,全部发生在广告主站内;主动行为 = 明确意图支配下的点击与搜索;半主动行为 = 弱目的内容消费;被动行为 = 广告曝光本身。- 电商下单是转化;加入购物车与下单前的比价是典型的预转化——三者都是决策行为。
- 广告点击、搜索、搜索点击都是主动行为;其中广告点击量太小,只有搜索是「能大量获得的最主要主动行为」。
- 分享与页面浏览是半主动行为;广告浏览是被动行为,其频次与同类广告点击负相关,仍可用于建模。
Key points:
- 预转化(比价、加购)属于决策行为——它发生在广告主站内且兴趣指向明确
- 判断标准是「主动意图强度 × 离转化距离」,不是数据量大小
Problem 12.10.2 — 计算数据交易附加费 🟢 Easy
某 DSP 从 ADX 购买「母婴人群」标签,CPM 价格为 ¥2.50。本月它赢得的所有附带该标签的展示为 120,000 次(全部命中标签口径)。
(a) 本月数据附加费是多少? (b) 若这些展示带来 480 次转化,摊到每转化的数据成本是多少? (c) 下月该 DSP 只投放上海地区,按「部分交易」规则只收到命中标签的成交展示 90,000 次,附加费变为多少?这体现了数据交易四大好处中的哪一个?
Sample Input: 标签 CPM ¥2.50;成交展示 {120000, 90000};转化 480 Sample Output: (a) ¥300 (b) ¥0.625/转化 (c) ¥225;部分交易
💡 Solution (click to reveal)
**Approach:** 交割口径 = 实际成交展示量 × CPM 价格。- (a) mille,,附加费 ¥300。
- (b) ,每转化数据成本 ¥0.625。这个数可以直接进 ROI 核算:只有当标签带来的转化增量价值超过 ¥0.625/转化时,购买才划算。
- (c) ,,附加费 ¥225。DSP 只买了上海一个地域范围的数据,只按该范围的成交计费——这正是「部分交易」的好处:DSP 自由限定所需数据范围,不为用不上的数据付费。
Key points:
- 计费基数是「实际成交展示量」,不是询价请求量(对照 Common Mistakes #4)
- 部分交易 + 按成交计费,共同构成数据交易对买方的保护
Problem 12.10.3 — 三方数据归属与 DMP 选型 🟡 Medium
判断下列三个场景中数据的归属方(第一/第二/第三方),并为每个场景选一种最合适的数据产品路线(A:第一方 DMP/CDP 自建或托管;B:接入第三方 DMP/数据交易平台;C:两者结合),说明理由。
- 《纽约时报》:拥有海量自有用户与在线数据,但核心业务不是广告也不是数据加工。
- 某卖服装的小网店:有自己的用户搜索与购买行为,数据量不大,不值得单独分析变现。
- 某大型电商平台:既握有海量平台内行为,又要做外部重定向与站外拉新。
Sample Input: 三个场景描述 Sample Output: 1 → 第二方数据 + 路线 A(AudienceScience 模式);2 → 第三方数据 + 路线 B(BlueKai 模式);3 → 第一/第二方数据 + 路线 C(TalkingData MarketingCloud 模式)
💡 Solution (click to reveal)
**Approach:** 先按「数据在谁手里、谁直接参与交易」定归属,再按「数据规模 × 是否值得自营加工」选路线。- 数据产生在媒体自己的站点上、由媒体直接掌握,对广告平台而言是第二方数据。NYT 不愿自营数据加工 → 托管给第一方 DMP(如 AudienceScience 帮它加工财经类、体育类用户标签),标签回流供自家 BI 与内容运营使用 → 路线 A。
- 小网店的行为数据是它自己的一手数据,但在市场上它以「不直接参与广告交易的数据提供方」身份出现,属于第三方数据。数据量小、不值得自营 → 把数据交给数据交易平台聚合加工、售卖后分成(BlueKai 专门聚合这类中小网站数据)→ 路线 B。
- 平台内行为是第二方数据,CRM/订单是第一方数据。规模大到值得自建,同时又需要外部数据补足站外场景 → 两者结合:自建第一方数据基建(现代形态即 CDP),需要时接入外部标签与身份方案 → 路线 C。
Key points:
- 第一/二/三方是「相对广告交易中的位置」而定的,同一条数据对不同主体归属不同
- 选型的核心变量是数据规模:量小→托管或出售,量大→自营
Problem 12.10.4 — 准标识符泛化与 K 匿名 🔴 Hard
某员工数据集含 5 条记录(准标识符 = 年龄、城市;敏感属性 = 月薪):
| # | 年龄 | 城市 | 月薪 |
|---|---|---|---|
| 1 | 36 | 上海 | 15,000 |
| 2 | 38 | 上海 | 17,000 |
| 3 | 52 | 北京 | 25,000 |
| 4 | 54 | 北京 | 22,000 |
| 5 | 33 | 北京 | 14,000 |
目标是发布数据集且满足 K 匿名(K = 2)。(a) 只把年龄泛化为 10 岁区间([30,40)、[50,60)),K 匿名满足吗?给出等价类。(b) 给出一个满足 K = 2 的最小额外泛化方案,并验证。(c) 若不想进一步泛化,还有什么替代操作?
Sample Input: 上表;K = 2 Sample Output: (a) 不满足,等价类 {[30,40)·上海]={1,2},[50,60)·北京]={3,4},[30,40)·北京]={5}},后者大小 1 < 2;(b) 城市泛化为「一线城市」后等价类大小 {3, 2},K = 2 ✓;(c) 抑制(删除)记录 5
💡 Solution (click to reveal)
**Approach:** K 匿名要求泛化后每个准标识符等价类至少含 K 条记录;逐层尝试泛化,找到满足约束的最小改动。- (a) 年龄分箱后:记录 1、2 → ([30,40), 上海);记录 3、4 → ([50,60), 北京);记录 5 → ([30,40), 北京)。前两类大小 2,但 ([30,40), 北京) 只有 1 条——K 匿名不满足,记录 5 的月薪(14,000)对任何认识他的人仍可指认。
- (b) 把城市泛化为「一线城市」:等价类变为 ([30,40), 一线) = {1, 2, 5}(大小 3)与 ([50,60), 一线) = {3, 4}(大小 2)。两类都 ≥ 2,数据集满足 K = 2。✔
- (c) 替代方案是 抑制 :直接删除记录 5,剩下两个等价类各为 2 条,满足 K = 2——代价是损失一条记录的信息。泛化保留数据但降低精度,抑制保精度但丢数据,工程上按业务对哪段数据的敏感度取舍。
Key points:
- 准标识符的风险来自 组合 :单独看无辨识力的属性,交叉后可唯一指认
- K 匿名的等价类大小要在「最终泛化粒度」上验证,中途满足不算数
- 现实提醒(对照正文):行为数据极稀疏,任何两个用户几乎不重——K 匿名在个性化系统的行为明细上根本做不起来,这正是 clean room + 差分隐私接棒的原因
Problem 12.10.5 — 识别与防御访客集合倒卖 🏆 Challenge
你是某教育品牌的效果投放负责人,通过 DSP 做重定向。近一个月你观察到:重定向流量的平均 CPC 上涨约 40%,win rate 下降,且你从未出价购买、也从未授权外流的「英语教育人群」标签出现在你竞得的流量上。请设计一套诊断 + 防御方案:列出至少 3 个需要排查的假设(区分市场因素与数据安全因素)、每个假设的验证方法,以及数据安全假设成立时的防御措施(至少 3 条)。
Sample Input: CPC 漂移 +40%、win rate 下降、陌生竞品标签出现 Sample Output: 假设 × 验证方法 × 防御措施的对照表
💡 Solution (click to reveal)
**Approach:** 先排除正常市场因素,再验证数据安全因素——不要一看到涨价就指控对手。| 假设 | 验证方法 | 结论路径 |
|---|---|---|
| 行业大盘竞价升温(市场因素) | 拉同期行业 CPM/CPC 指数与你未打标签的普通流量成本对比:若大盘同步上涨,属市场因素 | 大盘同步涨 → 调预算与出价策略,与数据安全无关 |
| 竞品新增投放预算(市场因素) | 监测竞品创意在广告库工具中的投放密度与覆盖时段变化 | 竞品加大投放 → 属正常竞争,优化自身出价与频控 |
| 访客集合被 DSP/ADX 合并倒卖(数据安全) | 检查合同授权范围外是否出现与自家重定向人群高度重叠的人群标签(如「英语教育人群」);对自家人群包与非自家流量做重合度抽样比对;观察涨价是否集中在这些标签命中的流量上 | 重合度高且涨价集中于该标签 → 高度怀疑倒卖 |
数据安全假设成立时的防御措施:
- 合同层 :与 DSP/ADX 签署数据使用限制条款,明确第一方人群包仅可用于本广告主投放、禁止二次加工与转售,并约定审计权。
- 技术层 :访客匹配改走 clean room——人群包以加密/哈希形式进入受控环境,只输出匹配结果,平台侧不可见明细,从根上切断「合并访客集合打新标签」的操作路径。
- 监控层 :建立第一方数据外泄的哨兵指标——win rate 与 CPC 的分标签漂移、自家重定向人群与市售标签的重合度周期抽样、陌生标签命中流量的溢价监控,异常即触发审查。
- 战略层 :重定向等高价值场景优先投给可审计、支持 clean room 的渠道;对强势平台的定制化标签功能,默认最小化开放。
Key points:
- 正文结论:需求方数据安全比供给方更关键——它决定广告主敢不敢把第一方数据接入程序化交易
- 诊断必须先二分「市场因素」与「数据安全因素」,证据是「涨价是否集中在重叠标签命中的流量上」
- 防御的主线与 12.10.3 的现代注解呼应:clean room 让数据「可用不可见」,是倒卖问题的结构性解法
实验框架与反作弊:广告系统的两条底线
📝 Before You Continue: 本章是 Part 12 的收官章,默认你已读过 12.1(全景与生态)——本章的选型实战会整体回扣那张生态图;12.5(偏差与校准)与 12.6(开环与闭环)——这两章的结论都建立在「实验可信」之上,本章解释为什么。12.2(计费模式)帮你看懂反作弊到底在保护什么:计费口径本身。
12.1 到 12.7 我们把广告系统的「发动机」装好了:竞价机制、智能出价、在线分配、校准与归因。但一台发动机要敢踩油门,还差两样东西。第一样是 度量可信 :你改了排序模型、调了出价策略,线下评测和模拟永远反映不了线上各模块之间的真实相互作用——你必须有一套实验框架,从真实流量里切一部分出来验证,而且要能同时容纳尽量多的实验,否则产品的进化速度会被流量本身卡死。第二样是 流量真实 :广告市场里媒体、平台、广告主对手三方都有制造虚假流量或劫持归因的动机,所有建立在曝光、点击、转化上的计费(12.2)与优化(12.4、12.6)都会被作弊流量污染——反作弊就是这台印钞机的防伪验钞模块。
本章也是《计算广告》第 17 章对应内容的收官:我们沿「创意优化 → 实验框架 → 广告监测与广告安全 → 作弊与反作弊 → 产品技术选型实战」的路线走完,最后以三方选型清单收束整个 Part 12。
读完本章,你将能够:
- 说明创意优化与受众定向的本质区别,描述程序化创意与点击热力图的工作方式
- 设计分层实验框架:解释层内互斥、层间正交、按用户切分与发布层灰度,并用 AA 实验校准框架本身
- 描述第三方广告监测的原理与广告安全(品牌安全、可见性、反劫持)的关键技术
- 按主体、原理、手段三个维度对广告作弊分类,并为每类作弊手法匹配统计破绽与对抗思路
- 站在媒体、广告主、数据方三个角色的视角完成广告产品的选型决策,完成 5 道分层练习题
12.11.0 机制跑起来之后:两条底线
先给本章定位。广告系统的所有优化技术——检索、排序、出价、分配——本质上都在回答一个问题:「怎么把广告效果做得更好」。但在真实生产环境中,还有两个问题先于「做得更好」: 「我知道我做得更好了吗」(度量) 和 「我度量的是真的吗」(真实)。
第一个问题催生 实验框架(experimentation framework)。策略、算法、架构的调整,通过线下评测和模拟都很难完全反映线上的变化——12.5 讲过的位置偏差、竞争偏差,12.3 讲过的机制与出价的耦合,都意味着「把新模块单独测好」不等于「放进系统整体更好」。唯一的裁决方式是从实际流量中分出一定比例跑实验。切流量本身不难,难的是同时测试的方案往往很多:如何在一个框架里容纳更多的测试,是提高广告系统进化效率的关键工程问题。
第二个问题催生 反作弊(anti-fraud)。广告是广告主、媒体与平台三方交互的生意,每一方(甚至不在这三方里的对手)都有动机制造虚假流量,或者用技术手段骗过广告监测与归因。由于这是一个「道高一尺、魔高一丈」的动态博弈过程,反作弊并无确定不变的技术和算法,但有一些原则和基础方法可以遵循。与之配套的还有 广告监测——需求方委托独立第三方对展示与转化做核实性度量——以及由此发展出的 广告安全 技术。
🧠 Mental Model: 印钞机、质检仪与验钞机
把广告系统想成一台印钞机:12.3–12.7 装好的竞价与分配机制是印钞的动力系统,12.2 定义的 eCPM 与计费口径是钞票的面值规格。实验框架是质检仪——任何零件升级(新模型、新策略)都要先在一小批「试验钞」上验证没印歪,才能全量投产;分层实验的意义在于同一张纸能同时过好几道质检,而不是每道质检都浪费一整批纸。反作弊是验钞机——市场上永远有人制造假币(刷量)和调包真钞(劫持、归因作弊),验钞机没有一劳永逸的型号,但统计特征(频次分布、点击热力图、转化率)就是假币永远藏不住的水印。
还有一个贯穿本章的视角: 监测、反作弊、实验框架共享同一套底层资产——日志与统计特征。点击热力图在 12.11.1 里是创意优化工具,在 12.11.4 里就成了甄别机器点击的反作弊工具;频次统计在 12.7.2 里是频次控制的依据,在反作弊里就是识破客户端刷量的探针。学完本章你会发现,这两条底线用的不是什么神秘技术,而是把前三节的基础统计用出了「刑侦」的味道。
12.11.1 程序化创意与点击热力图
创意对广告效果的影响巨大,但有一个前提必须先立住: 创意优化不能混同于受众定向的效果。随着创意改变,广告表达的诉求已经变了,点击行为就不再完全可比。书中的例子很直白:一个保险类广告主,把宣传公司品牌与实力的品牌型创意,换成让用户填车险申请的表单式创意——后者点击率会大幅上升,但前者服务的是长期的品牌渗透与利润空间,后者服务的是短期转化。两者诉求根本不同,直接比 CTR 没有意义。因此一般讨论的创意优化,指的是 在基本诉求保持稳定的前提下调整创意以提高效果。
在这个前提下,程序化创意的核心原则来自第 2 章的广告有效性模型: 把向用户推送此广告的关键原因,在创意中明确表达出来。推送原因众多,不可能预先制作全部素材,只能由程序在投放时自动组装——类比程序化交易,这被称为 程序化创意(programmatic creative)。几个经典形态:
- 地域型创意 :同一汽车广告,对北京和上海的受众分别动态加上当地经销商的联系电话。对每个城市做一版独立素材不经济,地域信息应在投放时在线拼装。
- 搜索重定向创意 :把用户曾经的搜索词放进创意下方的搜索框中,明确标示「我就是为你搜的那个东西来的」,更容易唤起注意力。
- 个性化重定向创意 :展示的单品在线决定、创意在线合成,是程序化创意的完整形态。
创意迭代需要工具, 点击热力图(click heatmap) 就是最重要的一个:把创意各位置被点击的密度呈现成热力图,帮助优化者直观发现问题。书中案例:创意中人物的眼神方向变化,会让用户点击的热点发生明显移动——在热力图指导下,创意迭代可以半定量、有目的地进行,而不是靠设计师的感觉。程序化创意给热力图带来一个障碍:创意的部分内容在线修改后,叠加在一起的热力图无法反映细节问题;但对 固定元素 的优化和 动态模块整体 的效果评估,热力图依然很有帮助。
现代注解(2026): 创意的视频化与交互化(激励视频、试玩广告 HTML5 方案)已演化为行业标配,而程序化创意的主流水线进一步升级为「AI 生成创意 + 自动化实验优选」:大模型批量生成素材与文案的组合(素材 × 文案 × 落地页),投放系统用多臂老虎机式的自动实验在线淘汰差组合——书里 CrossInstall「用请求参数划分流量测试泡泡排数」的做法,就是这套闭环最朴素的雏形。创意优化与下一节的实验框架,在这里合流了。
12.11.2 实验框架:分层、正交与按用户切分
现在进入本章第一块核心。设计实验系统的关键,是利用系统模块之间的相对独立性, 用分层的结构来扩展实验容量。
分层实验架构
典型架构把实验参数分置于不同的 实验层(layer) :广告系统通常按 检索、排序、展现 三个模块划分实验层,每一层都可以把流量切成不同的测试子集(域)。关键性质有四条:
- 层内互斥 :同一层内,一个用户(域)只属于一个实验,避免同模块参数相互干扰;
- 层间正交 :不同层上的实验 共享同一份流量——检索层的实验域和排序层的实验域独立切分,一次请求同时落在每层的一个域里。这使同时进行的实验数目从「流量能切几份」变成「各层切分数之和」,实验容量成倍扩展;
- 非重叠测试域 :系统预留一小块不参与分层的流量,专门做需要联合调整各层参数的特殊实验(例如同时改检索触发逻辑与排序模型的联动效果);
- 发布层 :实验通过的参数并不直接全量,而是经由专门的发布层 灰度放量 (如 1% → 5% → 50% → 100%)。
参数的优先级关系是: 实验层参数 > 发布层参数 > 默认参数 ;且同一个参数只能出现在一个实验层和一个发布层中。这样一个兼顾流量实验与灰度发布的框架,能覆盖绝大多数工程需求。
图中每个请求从左边的哈希入口进入,固定落进每层的一个域;三层的域彼此独立,于是同一份流量被「复印」了三次,同时支撑三组互不干扰的实验。
按用户切分,而不是按展示切分
一个容易踩的坑: 按每次展示做随机分配是不合适的。多次广告展示之间存在相关性(同一用户连续请求),按展示随机会让实验组与对照组的「人」混在一起,策略的高阶与长期影响(比如新排序改变了用户行为习惯)无法真实表现。正确的做法是 按用户划分 :每个用户的广告展示请求被固定地送到同一个域中(用 user ID 哈希决定),保证一个用户的完整体验自洽地属于某一个实验组。
AA 实验与离线/在线指标一致性
书里着墨不多、但工业上不可或缺的一环是 AA 实验 :把两组流量按完全相同的配置运行,验证框架本身没有引入系统性偏差。AA 实验的核心指标是「两组差异应在统计噪声范围内」——如果 AA 都能跑出显著差异,说明切分不均匀、日志口径有问题或存在位置/时间相关的混杂因素,此后一切 A/B 结论都不可信。这一点与 12.5 的校准一脉相承:校准解决「模型输出的绝对值可信」,AA 实验解决「度量系统本身可信」,两者共同保证线上指标的绝对值有意义。配套地,实验指标要保持 离线与在线的一致性 :离线训练用的目标(如校准后的 pCTR)与线上实验观察的指标(实际 CTR、eCPM、转化)必须口径对齐,否则实验会出现「离线涨、线上跌」这种无法解读的结果。
Analysis: 分层实验框架不是深奥技术,却是出了名的「容易被低估工程量」的模块:它与投放引擎、数据处理各个环节耦合紧密,又没有直接收益,启动产品时最容易被砍掉。但任何产品研发启动时最重要的两点,一是定义好可衡量的目标函数,二是建立灵活高效的实验框架——有了这两项,产品迭代会大大加速。回头看 Part 12:12.3 的机制设计、12.4 的出价策略、12.5 的校准方案,每一个上线决策都消耗实验容量;实验框架的容量,就是广告系统「进化带宽」的上限。
12.11.3 广告监测与广告安全
实验框架回答的是「改动有没有效」,这一节回答另一个度量问题:「账对不对」。在线广告区别于线下广告的重要特征是可监测性,但交易过程涉及媒体、广告平台、广告主多个环节——除 CPC 外的计费模式下,计费指标总有一方不可见。因此需要独立、公正的 第三方 对展示量或转化效果进行度量,这就是 广告监测。监测的主要需求存在于 CPT/CPM 计费的合约广告中:竞价广告没有约定价格,广告主可以按后续效果调整出价,监测不是强需求。效果监测主要服务品牌广告主,一般占在线品牌广告投放约 1% 的预算。
第三方监测的原理
监测代码指具有客户端信息收集功能的代码:曝光发生时,它把客户端信息拼成参数化 URL,以 HTTP 请求发给第三方,告诉它「谁,在什么时候,看到了来自哪个媒体展示的,哪个广告主的广告」。行业里说的「监测代码」其实指这条监测 URL 本身;URL 参数包含广告、媒体、用户三方标识(如操作系统、设备 ID、IP、UA、时间戳)。第三方解析 URL、形成日志,即记录了一次曝光。宏观链路就是「曝光/点击打点 → 第三方日志 → 与媒体/平台数据对账」,协议细节(参数规范、SDK 采集项)随行业标准演进,理解链路即可。
真正的难点在于 按受众投放的验证。某广告计划要求在男性用户流量上投放 1000 mille 展示,怎么确定结果达标?通行方案是「采样 + 付费」:收集小比例人群上的真实用户属性,验证这部分人群上的属性准确率,再反推整体投放数据。方法简单,但采样集与投放人群分布可能偏差较大, 纠偏 是关键;而且只有人口属性类投放可以这样验证——兴趣标签对同一用户不存在标准答案,监测意义不大。趋势是用人口属性数据更准、规模更大的平台作基准(如尼尔森与 Facebook 合作推出基于其人口属性的监测服务)。
广告安全:品牌安全、可见性与反劫持
在复杂的程序化交易中,广告主已经很难明确管理自己的投放媒体,但存在切实需求: 广告不要出现在特定内容的媒体上 (汽车广告主不希望出现在车祸新闻或低俗网站上)。保证这一诉求的服务称为 广告安全(ad safety) ,两项关键技术:
- 广告投放验证(advertising verification) :重点不是计量,而是 阻止 不恰当展示的发生——发现页面内容不符合品牌安全诉求时,停投广告主创意、改投与品牌无关的创意。工程核心是 iframe 穿透 :交易中媒体可能用多层 iframe 伪装 URL、以次充好(把小网站的流量套上高溢价域名的壳),必须在投放时实时判断页面的顶层 URL。有历史经验积累后,可采用 pre-bid(投放前) 方案:对已确认不安全的 URL 或广告位直接不参与交易,节省服务成本。
- 可视性验证(viewability verification) :品牌广告主关心曝光程度——第二屏广告位的曝光远差于第一屏。技术方案是判断浏览器是否对广告创意 发生了渲染 ,未渲染的展示不算可视。书成稿时可对 95% 以上的浏览器内流量做可视性验证,移动应用内广告当时尚无良方。现代注解(2026): 可见性已由 MRC 等标准统一(如面积与持续时长的双阈值「可见曝光」定义),并成为品牌采买的默认结算口径之一。
- 反劫持 :流量劫持(无权投放处强行投放、篡改创意甚至落地页)是广告安全要面对的灰色地带,我们把它放到 12.11.4 与作弊一起讨论。
归因去重 :按 CPA/CPS/ROI 计费时,转化发生在媒体之外,需要第三方把转化与展示/点击对应起来——即 广告效果归因。归因的模型谱系、归因窗口、ATT/SKAN 等隐私时代方案,12.6 已系统讲过,此处不重复;你只需记住一条与本章的连接: 归因规则(如「点击后 N 天内的下载归给点击渠道」)正是归因作弊的攻击面——下一节马上展开。
12.11.4 作弊与反作弊
本章第二块核心。反作弊要做到知己知彼,必须先搞清三个问题: 谁在作弊、为什么作弊、怎么作弊。
三类作弊主体
广告活动是广告主、媒体与用户三方交互的行为,作弊主要来自三种主体:
- 媒体作弊 :广告网络与媒体多按点击计费,因此 点击作弊 最常见;为满足 CPM 订单量也存在刷展示的情形。
- 广告平台作弊 :广告网络或交易市场有制造虚假点击以获取更多分成的动机;DSP 这类需求方产品则会混入劣质流量、制造虚假点击与 虚假转化 ,以满足广告主的效果考核。
- 广告主竞争对手作弊 :用技术手段大量消耗某广告主的预算,达成压低其广告效果的非正常竞争目的。
三个维度的分类
- 按原理 : 虚假流量作弊 (NHT, non-human traffic)——展示、点击或转化本身就是伪造的,是 CPM/CPC 广告作弊的主流; 归因作弊——把其他渠道的流量或自然流量记在自己名下,CPA/CPS 广告因伪造转化成本高,多用此路。
- 按手段 : 机器作弊 易于规模化,但容易在统计上留下明显特征(AI 与深度学习也正让机器作弊更逼近真人,反作弊难度随之上升); 人工作弊 在 CPA/CPS 类广告中流行——转化总量可控时,真人操作更接近真实效果。
- 按环节 :曝光作弊、点击作弊、转化作弊,对应 12.2 计费口径的三个计量点。
常见作弊手法与对抗矩阵
上图浓缩了书中 17.4 的手法清单,这里展开几个最有「刑侦味」的:
- 刷监测代码(服务器版 / 客户端版) :直接向监测 URL 发请求就能伪造曝光。服务器版简单直接,但 IP 与 cookie 分布不自然——屏蔽 IDC 机房 IP 即可解决大部分,逼作弊者去搞大量代理 IP。客户端版(网页 JS 反复请求监测代码)从用户分布上难找漏洞,但会留下 频次指纹 :某网站用户频次大量聚在 8、16、24、32 这些数字上——每个用户的浏览都被多刷了 7 次;自动发现这类模式可以用 傅里叶变换 在用户频次分布曲线上找 基频。此外,刷量在 点击热力图 上也会露馅:自然点击的分布与创意关键区域相关、形态自然,机器点击要么过于均匀、要么过于集中。
- 频繁更换用户身份 :单一 IP/cookie 的大量展示点击最容易去除(设合理频次上限、超限拉黑),所以作弊者必然频繁变换 IP 与 cookie。DSP 侧的对策简单粗暴而有效: 第一次见到的 cookie 或设备号,干脆不参与竞价。
- 肉鸡与手机 root :被木马感染可远程控制的机器(肉鸡)、拿到 root 权限的手机,都能在后台执行与真实数据无异的浏览、点击和下载,统计上难以分辨——对抗要靠设备环境与行为序列特征,而非流量统计。
- 流量劫持 :只有 DNS、CDN 等网络底层服务提供者有能力实施的「准作弊」,手段包括信道弹窗、创意替换、搜索结果重定向、落地页来源劫持。前三种损害媒体利益(流量本身是真的),第四种(在访问广告主落地页时直接加渠道参数)是彻底的作弊,损害广告主利益。这就是 12.11.3 里 iframe 穿透与顶层 URL 校验要防的对象。
- Cookie 填充(cookie stuffing) :CPS 联盟广告特有的归因作弊——通过隐藏 iframe 等方式在用户不点击的情况下静默打上来源 cookie,用户后续的自然购买就「变成」了该渠道的效果,与点击注入同属「把自然结果变成推广效果」。
- 点击滥用(click spam / click flooding)与点击注入(click injection) :移动下载广告中最泛滥的两种 归因作弊。点击滥用钻的是用户 ID 碰撞归因的空子(12.6 的归因窗口规则):对大量用户伪造点击,这些用户后续的自然下载就归因到渠道头上——而且因为劫持的是自然下载,后续效果甚至优于普通渠道。它在统计上不难发现,有两个铁证:其一,把所有用户都标记点击,CVR 会比正常广告 低一到两个数量级 ;其二,点击到转化的时间分布在归因周期内 近似均匀 ,而正常转化随时间拉长 快速衰减。点击注入则利用 Android 的安装广播:应用 A 一被安装,系统广播让作弊应用 B 的 SDK 立刻补发一条点击,把几秒后的激活抢归因到自己渠道——特征是 CVR 异常高、点击到激活间隔极短;若应用商店与归因监测方配合核验下载时间,此路几乎必被发现。设备农场(device farm) 是归因作弊的现代人肉形态:真人持真机批量完成「浏览—点击—转化」,各维度数据都像真的,只能靠设备聚集度与关联网络识别。
现代注解(2026): 反作弊的主流已经从「规则黑名单」转向机器学习大盘异常检测 + 设备信誉分体系(如 MIPS 一类设备完整性/信誉分),MMAF、Adjust、AppsFlyer 等移动反作弊框架把点击滥用、点击注入、设备农场等模式的识别做成了成熟能力。但底层逻辑与书里完全一致:作弊可以伪装单条记录,无法同时伪装所有统计分布。
对抗思路的三层体系
把上面的手段归纳成方法论,反作弊体系有三层:
- 异常检测 :在频次分布、点击位置分布(热力图)、CVR、点击-转化时间分布等统计特征上设阈值与模型,识别与自然流量的偏离。这是性价比最高的一层。
- 设备指纹与身份图谱 :跨 IP、跨 cookie 追踪同一作弊源,对肉鸡、root、设备农场建立设备级黑名单与信誉分。
- 图分析 :把设备、IP、账号、支付账户连成图,作弊团伙在图上呈现高聚集结构(同批设备共享 IP 段、同批账号共享收款路径),单条记录的伪装在关联网络面前失效。
工程形态上,反作弊判断模型需要 两个版本 :在线实时版本为计费与其他实时反馈模块做过滤;离线精细版本每天处理全量广告日志,产出最终确认的财务结算数据。反作弊特征与模型是广告系统高度保密的模块——保密本身就是对抗的一部分(对应作弊侧的对策 IP 遮盖 :作弊者屏蔽监管人员的 IP 段,让违规场景难以被复现审查)。
12.11.5 收官:产品技术选型实战
全篇最后一节,回到 12.1 那张生态图。从广告与泛广告变现的角度看,互联网市场上有三种资产能变成钱: 数据、流量、品牌属性——后两项是媒体的专属,第一项既可能来自媒体,也可能来自第三方数据拥有者。三类角色各自面对一个核心问题,选型清单如下。
媒体:如何用合适的广告产品更好地变现
媒体变现要兼顾 短期收益与长期品牌价值 :坚持高质量广告变现有利于品牌溢价,但中小媒体往往只能盯即时的单位流量变现能力(RPM)。决策清单(按优先级):
- 原生优先 :内容流、列表等适合原生的形态,优先考虑原生付费内容;流量充分可自营原生广告平台(尤其站内搜索流量够大时),否则与原生平台或行业搜索广告商合作。
- 品牌合约 :具备品牌属性时,强曝光位走 CPT 广告位合约,通用横幅位走 CPM 展示量合约(售卖定向人群标签)——品牌溢价通常带来更高的 RPM。注意合约售卖率不会太高,且后续接竞价广告时要防止对品牌价格体系的冲击。
- 剩余流量竞价 :垂直商业媒体(汽车、房产、电商)适合行业垂直广告网络;综合或非商业垂直媒体可用水平广告网络——质量高或流量大可自建,否则卖给大广告网络更便捷。
- 程序化交易 :对广告主质量有要求走私有交易(PMP/PDB,控制 DSP 准入),无特殊要求走公开交易;SSP 正在与 ADX 同质化。
- 数据支持 :有 CPM 定向合约、自营 ADN 或私有交易时,需要人群标签能力——数据充足且有团队可自建受众定向平台,否则直接采用第三方 DMP。
广告主:选择何种平台与数据完成高效营销
第一分叉是 品牌还是效果 :
- 直接效果 :无第一方数据时,搜索广告是高 ROI 的首选(选词出价复杂,中小广告主多交由 SEM 公司),垂直行业入口(应用市场、联运、团购等本行业主要流量来源)是首要选择之一,展示广告网络作为放大触达的辅助渠道;有第一方数据与技术能力时,加上 效果类 DSP :老客再营销走重定向、新客拓展走新客推荐、大型在线服务商可与 DSP 深度对接做个性化重定向。
- 品牌推广 :阶段性主题活动(如「双十一」)选强曝光位的 CPT;一般性品牌推广结合人群策略选 CPM 定向合约;媒体标签表达不了的策略,用 品牌类 DSP (CPM 计费 + 服务费)在交易平台按自己的人群划分投放。
- 自建门槛 :大中型广告主在 SEM 优化产品(大型电商的 SEM 往往是内部重要产品)与定制化标签投放量很大时(自建 DSP)值得投入,否则不必。
数据提供方:如何把数据变成钱
数据变现之前先做 价值评估 :用户数 × 平均用户价值,其中平均用户价值由 RPM(数据的价值密度)与单个用户被广告有效触及的展示次数(需要扩大媒体接触)决定。变现路径:
- 委托加工(轻参与) :数据量有限不值得自加工的,委托 DMP 加工,标签经数据交易平台在交易过程中售卖——中小服务商的简单易行方案。
- 自营广告产品(深参与) :成功运营广告产品绝不只是搭一套系统,需要技术、产品与商业模式的贯通。选择取决于数据覆盖面: 数据集中在覆盖率有限但价值高的垂直行业 (汽车、医疗)时,SSP/ADN/ADX 都不合适——正确方案是搭 DSP ,只对数据能覆盖到的流量出价; 数据跨行业且覆盖人多 时,可运营 广告网络 变现。
这张三方清单,就是 12.1 生态图在每个角色手里的「操作手册」:媒体握着流量与品牌属性向上游要价,广告主带着预算与第一方数据向下游买效果,数据方在两者之间出售信息差。至此,Part 12 从全景出发,走完计费、机制、出价、校准、归因、分配,最后落回全景——广告系统这幅地图的每个格子,你都已经踩过了。
⚠️ Common Mistakes in 12.11
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 按展示随机切分实验流量 | 每次广告请求独立随机决定进实验组还是对照组 | 同一用户的多次展示高度相关,按展示随机会把「人」拆进两个组,策略的长期与高阶影响无法表现 | 按 user ID 哈希固定落域:一个用户的所有请求永远属于同一个域 |
| 2 | 指望一个实验框架无限容纳实验,或不做 AA 直接开 A/B | 所有实验挤在一层互斥切分,流量早早耗尽;上线新策略前从不验证框架本身 | 单层互斥切分的实验容量 = 流量份数,扩展不动;AA 有显著差异说明切分或口径有偏,之后一切 A/B 结论不可信 | 按模块分层(层间正交)+ 预留非重叠域 + 发布层灰度;定期跑 AA 实验校验框架 |
| 3 | 把创意优化的效果混同于受众定向的效果 | 品牌型创意换成表单型创意后 CTR 大涨,归功于「定向调好了」 | 创意改变意味着诉求改变,点击行为不再可比,CTR 上升可能只是诉求换了 | 评估创意优化时保持基本诉求稳定,或明确区分品牌与效果两类诉求的目标 |
| 4 | 只在离线做反作弊,或只靠单一规则黑名单 | 每天离线跑一次规则过滤 IP 黑名单,线上计费不做过滤 | 虚假流量实时进入计费与优化数据,等离线批次跑完损失已经发生;单一规则对频繁换身份、肉鸡等手法全部失效 | 在线实时模型(计费过滤)+ 离线精细模型(财务结算)双版本,叠加统计异常、设备指纹、图分析 |
| 5 | 监测计量不去除作弊流量,或忽视归因规则被反向利用 | 第三方监测直接按原始打点数与媒体对账;归因窗口设得越长越好 | 一切展示/点击计量必须建立在去作弊的基础上,否则对账本身就是错的;归因窗口宽松等于给点击滥用发奖金 | 计量前先过反作弊过滤;归因窗口按行业转化周期设定,并监控 CVR 与点击-转化时间分布的异常 |
| 6 | 把流量劫持当成普通刷量,或分不清它损害谁 | 把信道弹窗与落地页来源劫持归为同一类问题统一处置 | 信道弹窗、创意替换、搜索重定向损害的是媒体利益(流量本身真实),落地页来源劫持损害广告主利益,责任方与对策完全不同 | 先按「谁受损」分类:媒体侧靠 iframe 穿透与 pre-bid 屏蔽,广告主侧靠来源参数校验与渠道对账 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 程序化创意 | 把推送的关键原因在线拼进创意(地域/搜索词/单品);点击热力图指导半定量迭代 | 创意优化必须与受众定向的效果分开评估;2026 已演化为 AI 生成创意 + 自动化实验闭环 |
| 分层实验框架 | 层内互斥、层间正交共享流量、非重叠域做联合调参、发布层灰度;按用户切分;AA 实验校准框架 | 实验容量 = 系统进化带宽的上限,12.3–12.7 所有策略上线都消耗它 |
| 广告监测 | 第三方用监测 URL 计量「谁何时在哪个媒体看了哪个广告」;定向投放靠采样+纠偏验证 | CPM/CPT 合约结算的事实基础,服务品牌广告主(约 1% 预算) |
| 广告安全 | 投放验证(iframe 穿透、pre-bid)保品牌安全;可视性验证(渲染判断)保曝光质量 | 阻止负面效果的展示发生,而不只是事后计量 |
| 作弊与反作弊 | 三类主体 × 虚假流量/归因作弊两大原理;对抗 = 统计异常检测 + 设备指纹 + 图分析,在线/离线双模型 | 保护 12.2 的计费口径与 12.6 的归因口径不被污染;动态博弈无终极解 |
| 选型实战 | 三种资产(数据/流量/品牌属性)× 三类角色(媒体/广告主/数据方)的决策清单 | Part 12 全篇的落点:生态图在每个角色手里的操作手册 |
❓ FAQ
Q1: 实验框架没有直接收益,中小团队值得投入吗?
最小可用版本并不贵:单层随机域 + 按用户哈希切分 + 一条 AA 校验流程,一个工程师周级别的活。真正贵的工程量在多模块分层与参数冲突管理,可以随业务长大再补。反过来看成本:没有实验框架,12.4 出价策略调一个乘子、12.5 换一版校准方案,效果好坏全靠猜——错一个决策的代价往往就超过自建框架的成本。
Q2: 隐私时代归因越来越受限(ATT/SKAN,见 12.6),归因作弊是不是消失了?
攻击面变了,没有消失。点击注入这类依赖系统广播与精确 ID 碰撞的手法确实被收紧了,但作弊转向了更难识别的形态:设备农场批量真人操作、通过 MMM/增量类度量漏洞混入增量(SKAN 的聚合上报同样存在伪造安装后的后验转化问题)。反作弊的重心随之从「单条记录真伪」转向「大盘分布与群体关联」——这正是现代注解里 ML 异常检测与设备信誉分成为主流的原因。
Q3: 点击热力图同时服务于创意优化和反作弊,同一个工具怎么两头用?
本质是同一份数据(点击位置分布)的两种读法。创意优化看「点击集中在哪、是否落在关键信息区」,是局部诊断;反作弊看「分布形态像不像自然点击」,是整体统计检验——机器刷出的分布要么过于均匀、要么过于集中,与自然形态可区分。工程上反作弊用的是全量流量的分布检验,创意优化用的是单创意的聚合热力图,粒度不同、原理同源。
🔗 前后关联
本章是 Part 12 收官,「前后关联」改为对全篇的回扣:
- 12.1 (全景与生态):12.11.5 的三方选型清单,就是生态图上每个角色(媒体/广告主/数据方)手里的操作手册——三种可变现资产(数据/流量/品牌属性)恰好对应三类角色的资源禀赋
- 12.2 (计费模式与核心指标):反作弊守护的对象就是计费口径本身——CPM 的曝光数、CPC 的点击数、CPA 的转化数,每一个计量点都对应一类作弊(曝光/点击/转化作弊)
- 12.3 与 12.4 (竞价机制、智能出价):机制与出价的每一次迭代都消耗实验容量,分层实验框架的容量就是这两个方向的进化带宽
- 12.5 (偏差与校准):校准保证模型输出的绝对值可信,AA 实验保证度量系统本身可信——两者合起来线上指标才有意义
- 12.6 (开环与闭环广告):归因规则是归因作弊(点击滥用/点击注入/cookie 填充)的攻击面;ATT/SKAN 收紧归因的同时也改变了作弊形态
- 12.7 (在线分配):保量合约的完成率监控与流量预测偏差诊断,同样依赖本章的实验与监控闭环
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 12.11.1 — 从频次分布识破客户端刷量 🟢 Easy
某网站接了一个展示广告,第三方监测数据显示:当日共有 10,000 个独立用户,监测曝光总量 80,000 次,且用户频次分布异常集中在 8、16、24、32 这几个数字上。假设该网站真实人均浏览就是 1 次/日,作弊代码在每次页面浏览时额外多请求 7 次监测 URL。请计算:真实曝光量、作弊曝光量、以及作弊流量占总曝光的比例;并说明用傅里叶变换如何自动发现这类模式。
Sample Input: 独立用户 ;监测曝光 ;人均真实浏览 1 次;每次浏览多刷 7 次 Sample Output: 真实曝光 ;作弊曝光 ;作弊占比
💡 Solution (click to reveal)
**Approach:** 每个真实浏览产生 次监测请求,所以观测频次是 8 的整数倍——这正是频次聚在 8/16/24/32 的原因。- 真实曝光 = 独立用户数 × 真实浏览次数 = 。
- 自查:,与监测总量吻合。
- 作弊曝光 = ;占比 。
傅里叶变换的用法:把「用户频次 → 用户数」的分布曲线看作信号,正常用户行为产生的频次分布是平滑衰减的,而「每次浏览固定多刷 7 次」会在频次 8、16、24、32 处产生等间隔的尖峰——对分布曲线做傅里叶变换, 基频对应 1/8 周期 (即刷量次数 7 + 1),尖峰间隔的倒数直接暴露作弊代码每次的重复请求次数。 Key points:
- 作弊代码的「规律性」必然在统计分布上留下周期性指纹,这是所有统计异常检测的出发点
- 真实流量是平滑的,作弊流量是有节奏的——分布形态检验比逐条记录审查便宜得多
Problem 12.11.2 — 用 AA 实验校准实验框架 🟡 Medium
某实验平台按 user ID 哈希把流量切成两个域做 AA 实验:域 1 与域 2 各 100,000 次展示,域 1 产生 200 次点击(CTR = 0.200%),域 2 产生 212 次点击(CTR = 0.212%)。用两比例 z 检验判断:在 (双尾,临界值 )下,两组差异是否显著?这个结果说明实验框架可不可以放心用于 A/B 实验?
Sample Input: ;, Sample Output: ,差异不显著,AA 通过
💡 Solution (click to reveal)
**Approach:** 两比例 z 检验,合并比例估计方差。import math
n, c1, c2 = 100000, 200, 212
p1, p2 = c1/n, c2/n
pp = (c1 + c2) / (2*n) # ← KEY LINE: 合并比例
se = math.sqrt(pp*(1-pp)*(1/n + 1/n))
z = (p2 - p1) / se
print(z) # 0.592
- 合并点击率 。
- 标准误 。
- 。
,两组差异落在统计噪声范围内,AA 实验通过——切分均匀、日志口径一致,框架可以放心用于 A/B 实验。注意反例的用法:若 AA 跑出显著差异,先查切分哈希是否偏斜、指标口径是否一致、是否存在时段混杂, 修框架之前不要上任何 A/B。 Key points:
- AA 实验是实验框架的「自检」:它应该测不出任何东西,测出来就是框架的问题
- 样本量 100,000 时约 ±0.028 个百分点的 CTR 差异在噪声范围内,别把噪声当信号
Problem 12.11.3 — 分层实验的容量扩展计算 🟡 Medium
某广告系统计划搭建分层实验框架:检索、排序、展现三层,另预留 10% 流量作非重叠测试域。业务要求每个实验域的流量占比不低于 5%(保证检验功效)。计算:单层(不分层、所有实验互斥切分)最多能同时跑多少个实验?分层后呢?容量提升几倍?再说明:若有一个「同时修改检索触发逻辑与排序模型」的实验,应该放在哪里跑?
Sample Input: 三层;非重叠域预留 10%;每实验域 ≥ 5% Sample Output: 单层 18 个;分层 54 个;提升 3 倍;联合调参实验放非重叠测试域
💡 Solution (click to reveal)
**Approach:** 可用流量预算 = ;每个实验最少占 5%。- 单层方案(所有实验互斥切分同一份流量): 个实验。
- 分层方案:每层独立切分同一份流量,每层 个,三层共 个实验同时进行。
- 容量提升 倍——正好等于层数。层间正交的本质是 同一份流量被不同层重复使用 ,实验容量随层数线性增长。
「同时修改检索触发逻辑与排序模型」的实验涉及两个层的参数联合调整:放实验层会导致该实验与两层各自的其他实验产生参数耦合,结论无法归因;正确位置是 非重叠测试域——它不参与分层、独占流量,专门服务这类跨层实验。 Key points:
- 层内互斥保证同模块参数不打架,层间正交保证流量不被重复消耗
- 非重叠域是「花钱买特殊实验能力」,预留比例要小(10% 量级)但必须有
Problem 12.11.4 — 识别移动渠道的点击滥用(click flooding) 🔴 Hard
你是某 App 下载广告的广告主,第三方归因平台给出两个渠道上周的数据(归因窗口 7 天):
| 渠道 | 点击数 | 转化(激活)数 | CVR | 点击→转化时间分布(day0 到 day6) |
|---|---|---|---|---|
| 渠道 X | 1,000,000 | 500 | ? | 10% / 15% / 12% / 11% / 11% / 11% / 10% |
| 渠道 Y | 200,000 | 6,000 | ? | 60% / 20% / 8% / 5% / 3% / 2% / 2% |
计算两渠道的点击→激活 CVR;结合「正常渠道 CVR 约 3%」的行业经验与两渠道的时间分布形态,判断哪个渠道存在点击滥用,并给出至少两条证据。
Sample Input: 见上表 Sample Output: 渠道 X CVR = 0.05%(比正常低约 60 倍),时间分布近似均匀 → 判定点击滥用
💡 Solution (click to reveal)
**Approach:** 点击滥用的手法是对大量用户伪造点击、坐等他们的自然下载归因到自己头上,所以它的统计特征必然是「点击极多、转化极稀、时间分布均匀」。- 渠道 X:,比正常渠道约 倍(接近两个数量级)。
- 渠道 Y:,与正常经验一致。
证据一(CVR):渠道 X 低约 60 倍——把所有用户都标记了点击,分母被灌水。证据二(时间分布):渠道 X 的转化在 7 天归因周期内近似 均匀分布 (10%~15%),这是「坐等自然下载」的形态;渠道 Y 则呈 快速衰减 (60% → 20% → …),符合「点击 → 下载决策」的真实行为链路。结论:渠道 X 存在点击滥用,应扣量或剔除,并通知归因平台加入监测。 Key points:
- 点击滥用的两个铁证:CVR 低 1–2 个数量级 + 点击-转化时间分布均匀(正常转化随时间快速衰减)
- 它劫持的是自然下载,所以「后续效果看着还不错」恰恰不能作为渠道 X 无辜的证据
Problem 12.11.5 — 为一家垂直媒体设计变现与保障方案 🏆 Challenge
你是一家汽车行业垂直媒体(日均 UV 80 万,用户为近期有购车意向的高价值人群)的技术负责人。请给出:(1) 按 12.11.5 的选型清单设计变现路径(产品形态、交易方式、数据支持),并说明每一步的理由;(2) 该媒体最需要警惕哪几类作弊手法(结合其行业与流量特点);(3) 若要上线一个新的线索表单优化策略,如何用实验框架验证它——写出层的选择、切分方式与验证流程。
Sample Input: 媒体画像(垂直行业、高价值人群、日均 UV 80 万) Sample Output: 变现路径清单 + 作弊防御重点 + 实验方案
💡 Solution (click to reveal)
**Approach:** 按三方选型清单的顺序走一遍媒体列,再按主体×手法矩阵筛作弊面,最后套分层实验模板。(1) 变现路径:
- 汽车是典型的垂直商业行业,用户意图明确 → 行业垂直广告网络 + 汽车品牌主合约是主力;首页等强曝光位走 CPT 特型合约,通用位走定向 CPM 展示量合约(售卖「近期购车意向」人群标签——这需要行为数据建模购车意向,或接入第三方 DMP)。
- 高价值垂直流量不宜直接接无差别的公开交易 → 程序化部分走私有交易(PMP),控制 DSP 准入,避免与品牌售卖冲突。
- 理由:垂直媒体的核心资产是「意图明确的高价值流量 + 行业品牌属性」,RPM 最高的变现方式是把它们卖给愿意出溢价的行业广告主,而不是批发给水平网络。
(2) 作弊防御重点:
- 汽车行业线索(CPL/CPA 类考核)价值高 → 转化侧的 归因作弊 与人工作弊(设备农场式刷线索表单)是首要威胁;防御靠线索质量校验(留资电话回拨核验、行为序列完整性)与转化率对账。
- 高 RPM 流量也吸引 流量劫持 与 客户端刷量 :防御靠 iframe 穿透验证自有广告位、监测自身频次分布是否出现周期性指纹。
- 作为媒体还要防「被劫持」与「被冒名」:监控自家域名是否出现在异常广告交易日志中。
(3) 实验方案:
- 新策略是「线索表单优化」,作用于 展现环节 → 放 展现层 ;按 user ID 哈希切 5% 流量进实验域,其余为对照。
- 流程:先跑 1–2 天 AA 验证框架无偏 → A/B 观察核心指标(线索提交率、表单完成率)与护栏指标(页面跳出率、后续到店率,防止表单变简单导致线索质量下降)→ 显著且护栏无损后经发布层灰度(1% → 5% → 50% → 100%)。
- 关键点:线索质量是这行的「效果口径」,实验指标必须包含质量护栏,否则会优化出一个「表单好填但全是水线索」的假赢。 Key points:
- 垂直媒体的选型主线:高价值流量 → 控量溢价售卖(合约 + 私有交易),而非走量
- 作弊防御按「自己最值钱的计量点」布防:垂直媒体最值钱的是线索,所以防人工作弊与归因作弊优先
- 上线任何策略前,AA 通过是 A/B 结论有效的前提
合约广告:产品形态与售卖模式
📝 Before You Continue: 先读 12.1(全景图)——合约广告在生态中的位置;以及 12.7.0(保量广告)——排期系统与防天窗的工程细节已在彼处展开,本章从产品视角切入,不再重复。12.8(受众定向)讲「标签怎么打」,本章讲「标签怎么卖」:两章拼起来才是定向售卖的完整故事。
Part 12 讲到此处,你已经见过竞价市场的全部机关:eCPM 排序、GSP 定价、博弈机制(12.2–12.3)。但在线广告并非生来就是竞价市场。在线广告业务的初始阶段,媒体与广告主的代理商是市场的主要参与者,线下广告的商业逻辑被原样照搬到线上:广告代理公司与媒体签订协议,确保某些广告位在某时间段为指定广告主所占有,费用按整体合同支付。这就是 合约广告——「约定量的展示交付」,量与价都写进合同,而不是交给市场博弈去出清。
理解合约广告不是发思古之幽情。其一,它是整个在线广告产品演进谱系的起点——「先有广告位,后有广告」:最早的商品就是门户网站首页上那几块固定的位置。其二,它至今没有消失:今天头部媒体的品牌专区、开屏合约、CPD 排期,商业逻辑仍是这一套,算法底座就是 12.7 的在线分配。其三,也是最重要的:合约广告演进到「人群售卖」时遭遇的困境,恰恰是竞价广告产生的内在动力——读懂它,你才能真正理解 12.3 那套市场机制为什么长成那个样子。
读完本章,你将能够:
- 区分合约广告的三种售卖形态(CPT 独占、CPD/轮替、CPM 展示量合约)及其各自适配的业务场景
- 解释「从卖位置到卖人群」演进的产品逻辑:数据如何开始直接参与售卖
- 说明为什么卖保量合约之前必须先做流量预测,以及「先分桶聚合再查」的预估思想
- 用保量/保价、排期/实时两对维度对比合约与竞价两种市场的产品逻辑
- 完成 4 道分层练习题
12.12.0 为什么从合约广告讲起:先有广告位,后有广告
把时间拨回互联网广告的蛮荒期。那时的流量还没有被精细刻画的能力——用户是谁、在看什么、想买什么,系统一概不知。能被明码标价的只有两样东西: 位置 (页面上的哪块版面)和 时间 (哪一天、哪个时段)。于是最早的在线广告交易,就是把线下广告的合同照搬过来:某汽车厂商包下门户网站首页的横幅一个月,费用一次性谈定。这就是 CPT 广告位合约,它对技术的依赖性很小,只需要一套简单的 广告排期系统。
随着技术与业务的发展,售卖的标的物沿着一条清晰的路线不断细化:从「位置 × 时段」整买,到按天售卖与轮播拆分,再到「位置 + 人群」的 CPM 展示量合约。每一步细化的驱动力都一样——把流量切得更细,就能卖出更高的总价;而切到「人群」这一步时,数据第一次直接参与售卖,这是在线广告发展史上真正意义上的里程碑。
图里有一条容易被忽略的主线:随着售卖形态演进, 技术复杂度全部压在了供给方(媒体)身上。CPT 时代媒体只需要排期系统照合同自动执行;到了展示量合约,媒体必须预测流量、规划分配、实时决策。而需求方(广告主)在合约广告里几乎没有优化空间——投放的要求都以合约形式交由供给方完成了,量与价都被合同锁死。正是需求方对深入优化效果的进一步需求,催生了按竞价方式售卖的广告系统。这条「供给方技术压力 → 需求方优化诉求 → 交易形态更替」的因果链,是贯穿本章的理解主线。
🧠 Mental Model: 演唱会的两种卖票方式
把广告流量想成一场演唱会的门票。合约广告是包销:主办方提前把一定数量的票按约定价格批发给渠道商,承诺「保证有票」——为此主办方必须提前预估能卖多少票(流量预测),并规划好哪部分看台留给哪个渠道(在线分配)。卖不掉的风险和履约的责任都在主办方。竞价广告是现场售票:开门后价高者得,主办方不用承诺任何人能买到票,价格由供需自动出清。包销模式主办方操心、渠道省心;现场售票主办方省心、买家自担风险。两种模式没有绝对优劣——品牌大客户要确定性,所以至今仍选「包销」;长尾广告主要灵活,所以市场走向「现场售票」。
12.12.1 广告位售卖:CPT、轮替与排期
广告位合约 是最早产生的在线广告售卖方式:媒体和广告主约定在某一时间段内的某些广告位上固定投送该广告主的广告,按 CPT (Cost per Time,典型按天计)结算。它的缺点非常明显——无法按受众投放,也就无法做深入的效果优化。但它在特定场景下至今有可取之处:
- 强曝光位的品牌冲击。在应用开屏、门户首页特型位这类强曝光属性的广告位上,独占式投放能给用户带来有效的品牌冲击;长期独占某些横幅位置,有利于形成「橱窗效应」,持续塑造品牌价值与转化效果。
- 竞品排他的高溢价。独占式售卖可以向广告主提供同页面竞品排他等附加服务,使高溢价的流量变现成为可能——这是竞价市场给不了的确定性。
独占式售卖之外还有一种重要变形: 按广告位轮播售卖。当某个位置的独占库存不够、而广告主又需要确定的展现规则保证时,可以把同一个用户对同一广告位的一系列访问,依次标上一组循环的 轮播顺序号 (如 ),把相同顺序号的展示当作一个 虚拟广告位 卖给广告主。这里有一个精巧的细节:对某个用户而言,第一次展示的顺序号不能固定从 1 开始,而要按相等概率从所有轮播顺序号中随机选取一个,再从此开始累加循环——只有这样,各轮播分到的流量才能一致。这种售卖方式在中国门户网站的品牌广告中被广泛采用。
Analysis: 轮替机制的工程成本极低:服务端(甚至前端脚本)只需维护「用户在该位置已看到的次数」这一计数器,取模定序号即可;唯一的状态是随机起始序号。它的局限也在这里——轮播是按「访问次序」切分流量,不是按「人群」,所以四条轮播创意触达的受众结构完全相同。想要在同一位置对不同人展示不同创意,靠的是受众定向(12.8)的创意差异化,而不是轮替本身。
执行 CPT 售卖的工具是 广告排期系统 :合同确定后自动按排期投放,代表性产品有 DoubleClick 的 DFP、中国市场上好耶(Allyes)的同类产品,以及免费给中小网站使用的百度广告管家。排期系统并不个性化——素材按事先确定的排期直接插入页面,通过 CDN 加速访问,服务端几乎没有决策压力;工程上唯一值得留意的是混合投放调度与 防天窗 兜底逻辑(动态广告超时或出错时渲染兜底素材,保证广告位永不空白),这套细节已在 12.7.0 展开,此处不再重复。随着受众定向与实时竞价普及,这些排期产品也逐渐演进:叠加动态分配与 RTB 能力后,就接近供给方平台(SSP)了。
还有一个值得留意的中间形态:随着受众定向技术发展,即使某个广告位全部投放一个广告主的创意,也并不意味着投同样的素材。某汽车厂商旗下有小型车、紧凑型车、豪华车、SUV 等多个车系,潜在购买人群差异很大——若能对各车系受众分别投送相应创意,效果会好得多;即便受众无法区分,也可以用频次控制向同一用户递进式展示一系列创意。这类「定向加持的独占合约」在系统实现上与非独占式售卖已没有本质区别,它就是后来程序化直投的产品雏形。
12.12.2 从「卖位置」到「卖人群」:受众定向售卖的出现
CPT 的天花板很快显现:一个首页横幅,独占只能卖一家,轮替也只能拆出几条。可售颗粒度要再细一个量级,就需要新的切分维度——这个维度就是 人群。按 CPM 计费的 展示量合约 由此登场:合同约定某种受众条件下的展示总量与单位展示价格,售卖对象从「广告位」进化为「广告位 + 人群」。因为数据被直接应用到售卖中,媒体第一次实现了在流量变现之上叠加 数据变现 ;这也是「担保式投送(GD)」中「担保」二字的由来——担保的就是这个量,实际执行中未能完成投放量时,可能要求媒体承担赔偿。
这里要先划清一条容易混淆的界线:按 CPM 计费不等于合约广告。CPM 广告还包括另一种不约定展示量的售卖方式(如广告交易市场中的售卖),那种 非保量 CPM 属于竞价广告 ,商业逻辑差别很大。判断合约与否的标准是「是否保量」,不是计费单位。
人群怎么切、切出来的货怎么卖?这有一套与打标签(12.8 的任务)不同的 售卖逻辑 :
- 售卖目录要为需求方而设计。当标签作为广告投放的直接标的(广告主可以直接选购的人群),标签体系应采用结构化的层级结构——上层标签是下层的父节点、人群覆盖上是包含关系——Yahoo 担保式投送的标签体系(Finance / Travel / Autos / Entertainment 等一级类目)就是典型。反之,标签若只是投放系统的中间变量(如 CTR 预测的输入),就该完全按效果驱动去挖掘,无需层次约束。前者是本章关心的「售卖目录」,后者是 12.8 关心的「打标技术」。
- 地域是最基础的售卖区域。很多广告主业务有区域特性,地域定向是所有在线广告系统都必须支持的选择手段——它计算简单(查表即可),效果虽有限却不可或缺,也是售卖合同里最常见的定向条款。
- 人群覆盖率与标签数量是两回事。 Yahoo 担保式投送市场的行为标签有数千个,但实际产生过销售合约的不过 100 多个——大量精准标签在合约量的束缚下根本无法售卖。评估一个售卖目录,标签种类多少没有太大意义, 标签的人群规模才有说服力 :人群太小的「货」凑不够保量的最小起投规模,进不了合约目录,只能流向竞价市场。
- 人口属性是品牌合约的硬通货。年龄、性别等人口属性标签效果未必突出,但它们可以被监测(采样加调研即可验证一次投放中受众属性的比例),因此在按 CPM 计费的品牌合约中被广告主接受的程度远高于其他标签。
人群切分带来一个全新的、位置售卖时代不存在的复杂性问题: 人群包之间会交叠。「25–35 岁女性」「女性」「一线城市汽车兴趣人群」——这些可售的货共享同一批底层流量,一份合约的售卖区域与另一份高度重叠时,一次展示可能同时满足多份合约。谁来兑现每一份的承诺量?这就是在线分配问题——它的数学形态与解法(二部图、对偶定价、HWM)是 12.7 整章的主题,本章只需要记住产品侧的结论: 保量承诺 + 人群交叠 = 供给方必须用算法做全局规划 ,这是位置售卖时代从未有过的技术负担。
而展示量合约还有一条常被忽略的边界:它以人群为显式标的,却 并没有摆脱广告位这一标的物。CPM 模式下无法把曝光有效性差别巨大的多个广告位打包成同一售卖标的(否则合理 CPM 无从谈起),实践中展示量合约总是以曝光量很大的广告位为基础再切分人群——视频贴片、门户首页广告位是最典型的载体。这也解释了为什么合约广告的目录总是「宽标签 + 大位置」的组合。
12.12.3 展示合约的流量预估:卖保量之前先算得清账
位置售卖时代不需要预测——位置就摆在那里,卖一天是一天。人群售卖则完全不同:卖出去的是「未来某人群的 次展示」,而人群不是摆在那里的确定库存。于是 流量预测 (traffic forecasting)成为保量售卖的前提性技术:如果流量被严重低估,媒体手里有货不敢卖,资源售卖量不足;如果被严重高估,签出去的合约到期凑不够量,触发赔偿。两头都直接侵蚀收入——售前指导因此成为流量预测在广告产品中的第一个用途。
第二个用途在投放执行侧:各种在线分配算法都要依赖流量预估的结果(12.7 的 里那个供给总量 ,正是流量预测的输出)。第三个用途在竞价侧:广告主出价前想预估「我出这个价能拿到多少流量」,判断出价是否合理。一般的流量预测问题可以表述为对函数 的估计—— 是人群标签组合, 是出价;展示量合约没有竞价环节,相当于 的特例。三个用途对应同一个函数的三个切片,这就是为什么它值得做成一项平台级的基础服务。
工程上的主要困难在于:标签组合的可能性是天文数字,不可能预先统计每一个组合的流量。可行的思路是 先分桶聚合、再按查询组装 :把历史流量按标签组合聚合成供给节点并建立反向索引(文档是标签组合的流量,查询是广告的定向条件),售卖或分配时用查询取出候选节点、汇总得到预估量。这套「反向索引」方案的具体四步与采样技巧,12.7.2 已经完整展开——此处要带走的是它的产品意义: 流量预测是把「人群」变成可标价、可保量的标准品的那道工序。没有它,合约目录上每一行都是空头支票。
与流量预测配套的还有一个主动手段: 流量塑形 (traffic shaping)。与其被动统计流量,不如主动影响流量以利于合约达成。典型场景是门户网站:各子频道流量严重依赖首页关键位置链接的导流——车展期间汽车频道展示广告需求旺盛,首页就该多给汽车频道导流。这个想法实践中被广泛使用,但要做到系统化、高效率,必须把用户产品与广告产品的供需情况打通,在不伤害用户体验的前提下提升变现效率;这条线索与原生广告(用户产品与商业产品的融合)有千丝万缕的联系。
Analysis: 流量预测的难度随售卖颗粒度细化而陡增:标签越丰富,单个供给节点的流量越收缩,小样本预测的方差越大。这解释了合约售卖目录为什么必须「宽」——也埋下了本章最后一节的伏笔:当市场要求售卖颗粒度细到合约体系撑不住时,交易形态本身就要更替了。
12.12.4 合约广告的产品价值与现代形态
把本章与 12.3 的内容放在一起,两种市场的产品逻辑可以压缩成两对维度:
| 维度 | 合约广告 | 竞价广告 |
|---|---|---|
| 核心承诺 | 保量:约定人群 + 展示量,不足可能赔偿 | 保价:不承诺量,价格由市场出清 |
| 决策时点 | 排期制:离线规划,线上照方案执行 | 实时制:每次展示当场拍卖 |
| 价格形成 | 双方谈判签定,人工媒介采买 | 机制设计(GSP 等)自动定价 |
| 供给方负担 | 重:流量预测 + 在线分配,履约责任在媒体 | 轻:只维护拍卖规则,不用兜底 |
| 需求方空间 | 小:量价锁死,优化空间有限 | 大:出价、定向、创意自主调整 |
| 可容纳的客户 | 少:几千个品牌广告主的量级 | 多:数百万级活跃广告主 |
合约广告并没有被竞价全面取代,因为「确定性」本身是一种商品。品牌广告主要的是排他、是强曝光、是可监测的人群达成率——这些合约给得了,拍卖给不了。今天头部媒体的品牌产品线仍是这套逻辑的延续:品牌专区的独占词条、开屏的 CPD 排期、视频贴片的 CPM 保量合约,合同里写的依然是「人群 + 量 + 价」。变化的只是执行层:算法底座从人工排期升级为 12.7 的在线分配(流量预测 → 紧凑分配方案/HWM → 无状态线上执行),售卖目录的管理也迁移到了程序化直采(PD)等混合形态中。
同样值得记住的是合约的边界。展示量合约在人群标签非常丰富和精准时无法有效运作:标签越多,供给节点按指数速度膨胀,每个节点的流量迅速收缩,预测不再准确,保量承诺也就无从谈起。这个产品级的死结,正是竞价广告的原动力之一——竞价去除了量的约束,让调度变得简单明晰,也使细分流量、容纳海量广告客户成为可能。所以本章的收束句应该是: 合约广告定义了「卖什么」(人群 + 量),竞价广告解决了「怎么卖」(机制出清) ;理解了前者,后者的一切设计才显得事出有因。
最后用一张知识地图把本章收进 Part 12 的坐标系:
| 知识点 | 本章讲到 | 深入之处 |
|---|---|---|
| 排期系统与防天窗 | 产品形态与售卖动机 | 12.7.0(CDN 直投、兜底素材) |
| 定向标签怎么打 | 售卖目录视角:结构化层级、人群规模 | 12.8(上下文/行为/人口属性定向技术) |
| 流量预测怎么算 | 三个用途与「分桶聚合再查」的动机 | 12.7.2(反向索引四步、采样) |
| 保量怎么分配 | 人群交叠问题的由来 | 12.7.1–12.7.5(二部图、对偶、HWM) |
| 竞价为什么出现 | 合约的死结是竞价的动力 | 12.3(机制设计)、12.2(计费与指标) |
⚠️ Common Mistakes in 12.12
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把一切 CPM 广告当成合约广告 | 「ADX 里按 CPM 计费,所以是合约广告」 | 合约与否看是否保量:非保量 CPM(交易市场售卖)属于竞价广告,商业逻辑完全不同 | 用「是否约定展示量、是否承担履约责任」判定,而不是计费单位 |
| 2 | 认为展示量合约已摆脱广告位 | 把曝光有效性差异巨大的多个位置打包成一个 CPM 标的 | 不同位置的合理 CPM 差别巨大,打包后价格无从谈起;实践总以大曝光位为基础切人群 | 售卖目录设计遵循「宽标签 + 大曝光位」组合 |
| 3 | 轮播售卖固定从 1 号起始 | 用户每次访问都从序号 1 开始循环 | 各轮播分到的流量系统性不均,序号 4 的合约实质上被欠量 | 首次展示按相等概率随机选起始序号,再累加循环 |
| 4 | 售前流量预测宁高勿低 | 预测 100 万就敢卖 95 万 | 高估导致合约违约赔偿,低估导致库存贱卖,两头都亏;保量合约的售卖量必须以预测为硬约束 | 售卖量取预测的分位数并留安全余量,超卖部分流向竞价渠道 |
| 5 | 用标签数量宣传售卖能力 | 「我们有 5000 个行为标签可供合约选购」 | 合约量的束缚下,人群过小的标签根本无法售卖;Yahoo 数千标签实际产生合约的只有 100 多个 | 考核标签的人群覆盖率与规模,小标签打包或下放竞价 |
| 6 | 以为合约广告中需求方有优化空间 | 建议品牌合约广告主「实时调价优化 ROI」 | 合约的量与价都签死在合同里,需求方没有可调的旋钮;这恰恰是竞价产生的原因 | 需求方的优化诉求应导向竞价产品(12.3–12.4) |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 合约广告 | 约定量的展示交付;量价写进合同,履约责任在供给方 | 在线广告产品演进谱系的起点,品牌确定性需求的现代答案 |
| 广告位售卖 | CPT 独占(品牌冲击/竞品排他)→ CPD/轮替(随机起始序号保证流量均匀)→ 排期系统自动执行 | 先有广告位后有广告;排期 + 防天窗至今是广告位容错的标准答案 |
| 受众定向售卖 | 数据首次直接参与售卖;结构化标签体系作售卖目录;地域是基础售卖区域;人群规模比标签数量重要 | 把流量切细卖高价的关键一步,也是流量可标准化的前提 |
| 流量预测 | 售前指导 / 在线分配 / 出价指导三用途; 函数,合约是 特例;先分桶聚合再查询 | 保量售卖的前提工序,没有它合约目录就是空头支票 |
| 合约 vs 竞价 | 保量 vs 保价、排期 vs 实时;标签过细时合约体系崩溃,正是竞价的动力 | 理解 12.3 机制设计「事出有因」的产品史背景 |
❓ FAQ
Q1: 合约广告既然「非主流」,为什么还要花一章学它?
三个理由。第一,它至今承载着品牌广告的确定性需求,头部媒体的品牌合约产品线每天都在跑这套逻辑。第二,它贡献了在线广告的核心技术地基:受众定向、流量预测、在线分配都诞生于保量售卖的压力之下。第三,它是理解竞价广告的对照组——竞价的机制设计解决的是合约体系解决不了的问题,不知道问题是什么,就看不懂解法为什么长那样。
Q2: 轮替售卖为什么要随机起始序号,而不是每个用户都从 1 开始?
轮播是把访问序列按循环序号切成若干条虚拟流量。如果所有用户都从 1 号开始,那么序号 1 永远覆盖每次访问序列的开头几屏(注意力最强),序号 4 只覆盖长会话的尾部——各条流量的量与质都系统性不均,序号 4 的买方实质被欠量。首次展示按相等概率随机选起始序号,才让各轮播在期望上分到相同的流量。
Q3: 展示量合约为什么不直接把所有广告位打包按 CPM 卖,像交易市场那样?
因为 CPM 合约要事先定死单价,而不同广告位的曝光有效性差别巨大,合理 CPM 相应大幅变动,混装打包后价格无从谈起。交易市场之所以能按 CPM 广泛计费,是因为它不保量、每次展示单独竞价定价,价格由市场实时出清——这正是「保量合约困在大曝光位上」与「非保量 CPM 属于竞价」两条结论的共同根源。
🔗 前后关联
- 12.1 (全景与生态):本章给出合约广告在生态谱系中的起点位置与「先有广告位后有广告」的演进主线
- 12.7 (在线分配与流量管理):本章只讲保量售卖的产品动机;二部图建模、流量预测的反向索引四步、对偶与 HWM 算法全部在 12.7 展开
- 12.8 (受众定向技术):本章从售卖目录视角看标签(结构化层级、人群规模);打标的技术实现(上下文/行为/人口属性)在 12.8
- 12.3 (竞价机制):合约体系在标签精细化时的死结是竞价产生的原动力;机制设计如何接棒,见 12.3
- 12.2 (计费模式与核心指标):CPM/CPT 计费口径与 eCPM 的定义是本章售卖形态讨论的度量基础
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 12.12.1 — 轮替售卖的流量均匀性 🟢 Easy
某广告位按 4 条创意轮替售卖,某用户一天内共访问该位置 7 次。(1) 若固定从序号 1 开始循环,各序号各获得多少次展示?(2) 若首次展示按相等概率随机选取起始序号,各序号获得展示次数的期望是多少?
Sample Input: 轮播数 ;访问次数 Sample Output: 固定起始 ;随机起始期望各 次
💡 Solution (click to reveal)
**Approach:** 固定起始时按循环展开数一数;随机起始时用对称性求期望。- 固定起始:访问序列的序号为 ,计数得序号 1/2/3 各 2 次、序号 4 仅 1 次——最少的比最多的少 50%,序号 4 的买方被系统性欠量。
- 随机起始:起始序号在 上等概率选取,由对称性每个序号的期望展示次数都等于 次。
- 一般结论: 不能整除 时固定分配必然不均,随机起始把不均从「系统性偏差」变成「均值为零的随机波动」。
Key points:
- 轮替均匀性靠的是起始序号的随机化,不是访问次数的整除
- 随机起始同时保护了各条流量的「质」:没有哪条轮播总霸占会话开头的高注意力展示
Problem 12.12.2 — 嵌套人群的售卖可行性 🟡 Medium
某媒体首页横幅日流量 1000k 次展示,人群分布:女性 600k(其中 25–40 岁女性 250k、其他女性 350k),男性 400k。当天已排三份合约:A = 女性、300k;B = 25–40 岁女性、250k;C = 全部用户、300k。(1) 总需求 850k < 总供给 1000k,能否据此断言三份合约一定都能完成?(2) 给出一种可行的分配,并指出分配顺序的关键原则。
Sample Input: 供给:25–40 岁女性 250k、其他女性 350k、男性 400k;需求:A 300k、B 250k、C 300k Sample Output: 不能仅凭总量判断;可行分配 ,,,剩余 150k
💡 Solution (click to reveal)
**Approach:** 逐人群核对供需,注意 的人群是 的子集(嵌套关系),分配顺序决定成败。- (1) 不能。总量够不代表结构够:若 先取走 300k 女性(例如取走全部 250k 的 25–40 岁女性再加 50k 其他女性), 的候选池只剩 0,无法完成 250k 的承诺——这就是 12.7 里「合约间抢占供给节点」的产品语言版本。
- (2) 按「先窄后宽」分配: 取走全部 25–40 岁女性 250k; 从剩余的 350k 其他女性中取 300k; 从剩余流量(50k 其他女性 + 400k 男性 = 450k)中取 300k。三份合约全部足量,剩余 150k 可售给竞价渠道或兜底。
- 原则:嵌套(子集关系)的人群包必须先满足最窄的合约,否则宽合约的分配会挤空窄合约的候选池。12.7 的 HWM 按 排优先级,本质就是把这条直觉自动化。
Key points:
- 保量可行性是结构问题,不是总量问题;人群交叠处的分配顺序是关键
- 售卖目录审核时应显式检查人群包之间的嵌套与交叠关系,并在分配规划中给窄人群更高优先级
Problem 12.12.3 — 流量预测偏差的收入核算 🔴 Hard
某媒体以 CPM 单价 10 元售卖一份 950k 次展示的人群合约。实际到期流量只有 800k,欠量部分按合约价的 20% 赔偿。对照方案:若预测准确,售卖 780k 合约可全部足量交付,剩余 20k 流量以 CPM 6 元在竞价渠道全部售出。计算两种方案的净收入并求差额。
Sample Input: 合约 950k @ ¥10/CPM;实际流量 800k;赔偿率 20%;对照:售 780k @ ¥10/CPM + 剩余 20k @ ¥6/CPM Sample Output: 高估方案净收入 ¥7,700;对照方案 ¥7,920;差额 ¥220
💡 Solution (click to reveal)
**Approach:** CPM 报价按千次展示计费,先把「k 次」换算成「千次单位」再乘单价;两方案分别算毛收入与罚金。- 高估方案:合约按 950k 签单,毛收入 元(计费以实际交付为准: 元);欠量 k,赔偿 元;净收入 元。
- 对照方案: 元,足量交付无赔偿;剩余 元;合计 元。
- 差额 元。高估多签的量不仅没换成收入,反而吃掉赔偿与机会成本——这就是售前指导(12.12.3)说「流量严重高估会直接影响收入」的定量版本。
Key points:
- CPM 计费基数是实际交付量,签约量与交付量的差才是风险敞口
- 预测偏差的代价是非对称的:高估赔违约金,低估浪费库存,售卖量应取预测的分位数并留余量
Problem 12.12.4 — 设计一份合约售卖目录 🏆 Challenge
你是某媒体合约广告的售卖负责人,日均流量 1000k 次展示,合约售卖要求单标签起投量不低于 50k/天。候选标签的日覆盖流量:女性 600k;25–40 岁女性 250k;汽车兴趣 80k;母婴兴趣 40k;北上广地域 220k;「北上广 ∩ 汽车兴趣 ∩ 安卓」11k。(1) 筛选出可进入合约售卖目录的标签。(2) 对未通过筛选的标签,说明它们应流向哪里,并解释这背后「合约广告在标签精细化时无法运作」的逻辑。(3) 指出目录中两处嵌套关系及分配规划时的注意事项。
Sample Input: 覆盖流量:女性 600k、25–40 岁女性 250k、汽车兴趣 80k、母婴兴趣 40k、北上广 220k、「北上广 ∩ 汽车兴趣 ∩ 安卓」11k;起投量 50k Sample Output: 目录收录 4 个标签:女性、25–40 岁女性、汽车兴趣、北上广;母婴兴趣与三重交叉标签落选
💡 Solution (click to reveal)
**Approach:** 按起投量硬筛,再从人群结构与分配可行性两个维度复核。- (1) 筛选:覆盖率 × 日流量 ≥ 50k 的标签为女性(600k)、25–40 岁女性(250k)、汽车兴趣(80k)、北上广(220k),共 4 个进入目录。
- (2) 母婴兴趣(40k)与「北上广 ∩ 汽车兴趣 ∩ 安卓」(11k)低于起投量。去向:打包进更宽的父标签售卖,或直接下放竞价市场按效果变现。背后的逻辑:标签越细,供给节点按指数速度膨胀、单节点流量迅速收缩,流量小到无法可靠预测时,保量承诺无从兑现——所以合约目录必须保持「宽」,精细化的长尾标签天然属于竞价。这也是 Yahoo 担保式投送市场数千个标签只有 100 多个产生过合约的原因。
- (3) 嵌套关系一:25–40 岁女性 ⊂ 女性;嵌套关系二:汽车兴趣 ∩ 北上广同时是汽车兴趣与北上广的子集(两两交叠)。规划时窄人群先分配(参见 Problem 12.12.2),并对共享候选池的合约做联合可行性校验,避免宽合约挤空窄合约。
Key points:
- 售卖目录的准入线是人群规模,不是标签数量;标签体系应结构化分层以便广告主理解与选购
- 目录设计 = 覆盖率筛选 + 嵌套/交叠结构检查,两步缺一不可
- 长尾标签的正确归宿是竞价市场,这是产品分工而非技术缺陷
信息流与原生广告
📝 Before You Continue: 先读 12.1(全景与生态)——本章会直接回扣那里的广告形态演进阶梯,12.1 中「信息流广告:平衡效果与体验的正面典型」一段,本章把它完整展开。再读 12.4(智能出价与预算控制)——oCPC/oCPM 的 eCPM 公式与预算控制在那一章已从算法视角讲透,本章只讲产品侧。12.6(开环与闭环)的转化归因链路是 12.13.4 的上游,12.3(竞价机制)的 GSP/VCG 会短暂出场。
程序化交易把广告做成了独立于内容的生意:流量进交易所、数据进 DMP、决策在 DSP——广告与媒体内容的关系被弱化了。这在 PC 的大屏幕上尚可容忍,到了移动设备上却撞了墙:屏幕小、触屏交互不精准、注意力高度碎片化,一条突兀的横幅足以毁掉整个阅读体验。业界的回应是把商业化内容与非商业化内容 统一生产或混合排序——这就是 原生广告(Native Ads) 的方向,也常被称为「内容即广告(content as ad)」。严格说,从软文、搜索广告到社交网络的信息流广告,都只反映了原生的一个侧面;但其中最典型、最早引发讨论的产品形态,是 信息流广告(Feed Ads)。
本章沿「挑战 → 核心形态 → 形态光谱 → 智能投放 → 程序化合流」的路线展开:先看移动环境为什么催生了原生(9.1 的故事),再拆解信息流广告的定义与混排机制(本章核心),然后遍历开屏、插屏、激励视频等原生家族成员,接着从产品视角讲 oCPX 智能投放如何让小广告主也能玩转竞价,最后讨论原生与程序化交易这两条看似相反的道路如何汇合。
读完本章,你将能够:
- 陈述原生广告兴起的移动时代动因,以及移动广告相对 PC 的两大新机会与核心挑战
- 用两个关键条件准确定义信息流广告,并据此判定一个产品形态是否「信息流」
- 描述信息流广告的混排机制:多位置竞价队列与 / 参数的体验-收益权衡
- 区分表现原生与场景原生两种诉求,说清激励视频为什么是 eCPM 最高的原生形态
- 从产品侧描述 oCPX 转化追踪链路与三种出价表达模式,完成 5 道分层练习题
12.13.0 开篇:原生广告是广告与内容形态的融合
先给原生广告一个尽量诚实的定位。原生广告 没有公认的无懈可击的定义——所有将商业化内容与非商业化内容统一生产或混合排序的产品,都可以认为与原生广告有关系。软文是内容本身为委婉宣传而生产;搜索广告与自然结果出现在同一个流里;社交网络的信息流广告则把广告混进了动态列表。它们各反映了「原生」的一个侧面,而把这一方向推向极致的产品理念是:广告不应该是一种需要用户「忍耐」的东西,而应该是内容消费体验的一部分。
为什么这个方向在移动互联网时代才得到充分重视?因为把广告与内容独立地展示和运营,在小屏幕上遇到了巨大挑战。PC 时代的页面动辄上千米宽的画布,横幅、擎天柱各得其所;移动设备的屏幕只有几英寸,触屏交互又远不如鼠标精准——一条悬浮在页面顶部的横幅,用户滑动内容时它纹丝不动,误点与反感同时发生。业界由此开始探讨用原生广告部分代替一般展示广告,提高移动环境下的变现能力。真正由第三方提供的平台化原生广告产品,也正是在移动互联网时代才出现的。
Analysis: 从产品演进的位置看,原生广告不是对程序化交易的否定,而是它的补全。12.1 的演进阶梯有两股力量:机制演进(从卖位置到卖人群、从 CPM 到 RTB)解决「卖得有效率」,形式演进(内容与广告融合)解决「用户愿意看」。程序化交易时代把前者推到了顶点,后者却成了短板——独立于内容的广告交易,必然会在效果和用户体验方面碰到天花板。原生广告正是在这个意义上被写进演进阶梯的顶端。
12.13.1 移动广告的机遇与挑战
移动广告的交易形态可以视为 PC 互联网广告的自然延伸:展示广告网络、搜索竞价排名都原样移植到了移动环境,前面各章的交易机制与产品形态在移动广告中依然适用。但移动广告有两个鲜明的新机会。其一, 场景广告的可能性 :移动设备与用户形影不离,从地理位置、生活状态到需求意图都可能被深入理解——定向完全可以从场景与意图出发,而不只是根据兴趣推商品。比如通过地理位置判断用户正在上班,就不该向其推送游戏广告。其二, 大量潜在的本地化广告主 :PC 时代即使在线广告也只能定位到城市级别,对一个小区的理发店来说粒度太粗;而移动环境的 GPS、蜂窝、Wi-Fi 多种精确定位手段,让本地化广告第一次变得可行。
但机遇背后的挑战同样具体,集中在两点。第一是 数据割裂 :移动互联网没有形成 PC 时代以 Web 为核心的生态,取而代之的是以应用为主的生态体系——各应用之间相对独立,没有超链接那样的组织体系,数据来源割裂、整合困难。理论上移动环境对用户的了解更深入,实际操作中数据的获取反而更困难;Web 生态下常用的数据交换手段在应用生态里大量失效。第二是 隐私与身份的限制 :移动设备标识、跨应用追踪等能力随着隐私监管(ATT、隐私沙盒)不断收缩,进一步加剧了数据侧的困难。这条线在 12.6 的身份基础设施与 12.10 的数据加工与交易中已经展开,本章不再重复。
挑战的直接后果是:传统横幅广告在移动端的表现出了问题。移动横幅的点击率远高于 PC 横幅,但其中有很大比例是误点击——触屏交互不精准,误点会严重打乱用户的任务,对体验伤害很大;而广告主观察到的转化率却很差,因为大量误点不会产生任何效果。点击率虚高、转化相对较差 ,这个组合说明移动端需要一套新的创意与产品思路,这正是原生化的最大动力。
12.13.2 信息流广告:混排问题与体验-收益平衡
信息流广告最早见于社交网络,后来被各类移动广告产品广泛采用。它的效果之所以好,从形式上看有两点:交互的联动性,以及相对独立于周围内容。基于大量产品实践,可以给出这样一个描述性定义:
信息流广告是这样一种广告形式:首先,广告以与内容联动的方式进行交互;其次,被广告区隔开的各部分内容之间没有直接的关联。
第一个条件「交互联动」说的是:用户上下滑动浏览内容时,嵌入其中的广告也按同样方式被操作——怎么操作内容,就怎么操作广告。这样做有两重好处:操作的便捷性大幅提高、误点概率下降;用户会觉得广告也是内容消费的一部分,从而提高关注程度和广告效果。反例很容易找:传统横幅在内容滚动时悬浮不动,不符合这条定义;插屏广告用角上按钮关闭,不是内容的典型交互方式,也不算——但如果通过滑动消除广告、进入其他内容,则可以归入信息流广告。第二个条件「内容相对独立」说的是:被广告隔开的各内容块各自独立表达一项内容,没有接续或因果关系。如果内容块之间有很强的联系,用户从感知上就会认为广告打断了他当前的阅读任务——这会同时损害广告的关注度与产品体验。所以在一篇文章中间开辟广告位的形式不算信息流广告;而社交网络、新闻客户端的内容块天然联系较弱,非常适合信息流变现。至于「展示样式与内容块一致」「按受众定向精准投放」,实践中虽普遍,但并非根本特征,不必放进定义。
🧠 Mental Model: 拼盘与连载
把信息流想成自助餐拼盘,把长文想成连载小说。在拼盘里,每一格食物之间本来就互不相干——混进几格「赞助菜品」几乎无感,你的取用动作对它们一视同仁。而在连载小说中间插一页广告,读者正读到情节关键处被打断,只会愤怒。信息流广告的两个定义条件说的就是这件事:广告必须用与拼盘同样的取用方式(交互联动),且拼盘的格子之间本就独立(内容无关联)。连载里插广告?那是另一种生意,得另想办法。
多位置竞价与 S/K:混排的产品机制
从产品本质上看,信息流广告与普通展示广告区别不大——可以看成是一个 多位置且广告放置比较自由的竞价广告产品。它的展示与交互形式属于另一个范畴:信息流广告生态里同样存在封闭的 ADN、供给方的 ADX 与 SSP、需求方的 DSP,主体决策流程与展示广告一致。真正特有的是两个产品问题。
图中信息流里插入的若干广告位 构成一个 竞价队列 ,可以按 VCG 或 GSP 扣费;也可以把 视为不同广告位分别竞价,但若要求这几个广告位之间对广告去重,就等价于只有一个竞价队列。第二个问题更微妙——广告在哪里出现。它由两个参数决定:,即首条广告出现在第几条内容之后;,即两条广告之间间隔几条内容。 与 的取值越大,广告获得的用户关注就越少,对用户体验的影响也越小。这与搜索广告的放置问题同构:在 平均广告条数 的约束下,通过调整每个用户的 与 ,优化总体广告的点击率——平均广告条数约束相当于对用户体验的约束,求解关键在于尽可能准确地预估每个用户相对整体用户的点击率水平。
与推荐系统的天然同构:混排
现在把视角拉高一层。信息流里,自然内容按相关性排序、广告按 eCPM 排序,两边来自不同的服务、用不同的准则,再按固定逻辑混合——今天的搜索与信息流大多如此。但「内容即广告」的终极方向是:内容与广告 按同一准则统一排序 ,让每一次位置分配都由统一的分数竞争决定。这正是推荐工程里的 混排(re-ranking / mixing) 问题:广告与自然内容作为同一候选池的两种物品,用可比较的分数(自然内容的体验价值 vs 广告的 eCPM 与体验折损)竞争展示位置。对推荐系统工程师来说,这是广告与推荐在工程上最直接的结合点——你熟悉的多样性、体验建模、多目标融合分数,正是解决混排问题的工具箱。
Analysis: 信息流广告之所以被称为效果与体验平衡的典范,是因为它把「广告离内容近」的形式收益与「竞价保效率」的机制收益同时拿到了手:形式上,交互联动与内容独立让用户自然地关注广告;机制上,多位置竞价队列又保留了 12.3 那套价格出清的效率。代价是两个新约束——素材要适配各种信息流位置(12.13.3 的「表现原生」问题),密度要靠 / 精细权衡。一个值得注意的产品细节:任何一个平台在充分变现自有流量后都会向外拓展站外流量,而站外产品情况复杂,做不到原生展示就会带来填充率严重下降——所以连 Facebook 这类单一大流量平台也逃不开适配问题。
12.13.3 原生广告的形态光谱:从开屏到激励视频
信息流之外,移动广告还衍生出一批与内容深度结合的创意形态。按「原生程度」排开,可以拼出一条光谱。
传统形式的补丁:横幅与插屏。 横幅直接从 PC 传承而来,在移动端有点击率虚高、转化较差的问题(12.13.1 已分析)。插屏广告(interstitial ad) 类似视频中的暂停广告,出现在游戏或应用暂停时,同样点击率虚高、转化相对较差。但由于广告网络、广告交易平台等成熟交易体系的存在,这两种标准化程度高的形式最容易形成规模,至今仍是移动展示广告的主要形式,且以竞价售卖为主。
顺水推舟的形态:开屏与锁屏。 开屏广告 在应用打开的加载页面展示全屏广告。它是移动广告形式中相当好的探索:用户在等待应用打开时还没有明确的任务,因此不会对广告很反感;全屏展示也让品牌价值更高,实际售卖往往以 合约方式 为主。锁屏广告 在设备锁定时展示,特性与开屏相似,对体验影响较小,但一般以激励型为主。
激励型下载类:推荐墙与积分墙。 以应用下载为目标的预算催生了专门形式。推荐墙(offerwall) 直接推送下载类广告,类比站外推荐; 积分墙 则在用户下载并激活应用后给予可兑换虚拟物品的积分。它们与返利网同属激励广告,点击与激活数据好看,但后续活跃较差。不过在特殊场景有独特价值:应用上线冲榜需要短时间大量下载,游戏开服需要玩家快速聚齐社区——都曾依赖积分墙。但苹果明确打击用积分影响榜单的做法,其前景并不乐观。
激励视频:为什么它是效果最好的原生形态
激励视频广告(Rewarded Video) 是原生方向上最有代表性的产品,常见于游戏媒体,流程分四步:
- 游戏场景自然带入——用户游戏受挫或想获取虚拟商品时,提示可观看一段视频换取奖励;
- 用户打开视频,播放一段 15 到 30 秒的广告片,且不能跳过;
- 播放结束,向用户展示下载或其他转化跳转页面;
- 用户回到游戏,获得虚拟商品的奖励。
它的效果优势来自两点。首先,在激励场景下用户不能跳过视频、只能看完,接受了充足的信息后转化效果自然变好;其次,广告附赠的游戏内虚拟商品对非充值用户是稀缺资源,让用户愿意在实际价值较低的情况下认真观看。与积分墙那种激励有本质区别:激励视频 只对观看行为给予奖励,并不刺激下载 ,所以不会出现获取用户质量偏低的问题。也正因此,激励视频广告网络服务的最成功的反而是效果广告主而非品牌——主流激励视频网络都以应用下载广告为主要收入来源。商业成绩也佐证了这一点:以激励视频为核心的公司 Applovin 成立于 2012 年,到 2016 年已实现超过 5 亿美元收入与 9000 万美元净利润。
Analysis: 激励视频是原生逻辑的一个精妙平衡:它需要从游戏场景自然带入、与游戏积分体系无缝对接,媒体要付出设计成本;但其核心部分——视频素材的播放——是高度标准化的过程,非常容易程序化地交易。「深度定制的场景外壳 + 标准化可交易的内核」,这正是原生产品规模化的一道通用配方,也解释了为什么激励视频会成为移动广告的重要发展方向。
原生广告平台:表现原生与场景原生
把视野从创意形态拉回平台层。「原生」其实包含两种不同的诉求:一是把广告的展示风格和样式做得与内容一致,叫 表现原生(expressive native) ;二是把广告的投放决策逻辑与内容生产保持一致、按用户场景触发,叫 场景原生(scene native)。对照之前的例子:社交网络信息流侧重表现原生;搜索广告则在两个方面都是原生——它的投放决策完全按照内容结果的展示原则进行,等于以投放内容的方式匹配广告。由此可以总结出原生广告平台的两条产品原则:表现原生要求 由媒体来控制广告展示形式 (连字体、颜色都要按媒体适配,这是传统「创意」无法承载的要求);场景原生要求 用媒体提供的场景与需求来筛选广告。
理想的原生广告平台把两者结合,并以第三方平台的形式规模化运营。其机制被称为 植入式原生广告 :媒体判断用户场景与意图后,以结构化查询(如「类型=酒店;地点=拉萨」)向广告平台请求 结构化的付费内容——平台返回的不是成形创意,而是可拼装的字段素材,由媒体按自己的风格模板拼装渲染。这比传统上下文定向更进一步:上下文定向是广告平台用粗浅的自然语言处理猜页面主题,而媒体的主动参与让意图提取容易得多。挑战也真实存在:媒体参与让交易多了自由度、运营难度大增,中小媒体的接入需要长期市场培育;而分行业、结构化付费内容库的积累需要时间——即便是大平台,手里成规模的也只是创意而非内容库。
12.13.4 oCPX 智能投放:产品视角
移动广告相对 PC 时代还有一个重要的产品差异: 智能投放(oCPX) 模式被广泛采用。本节只讲产品侧——广告主怎么用、链路怎么串;oCPC/oCPM 的 eCPM 公式、预算约束下的出价缩放等算法细节,12.4 已从算法视角讲透,此处互链不重复。
为什么需要 oCPX:帮小客户拆掉门槛
智能投放的基本问题很清楚:竞价过程中由平台承担更多计算任务,帮助那些数据和信息技术能力有限的中小客户,降低他们对竞价广告的理解门槛与运营优化成本。但这里有个陷阱:如果直接采用彻底的 CPA/CPS/ROI 计费,会有大量有问题的客户涌入蹭流量,形成劣币驱逐良币。主流产品的解法是 计费与出价相分离的 oCPX 模式 :计费仍然走 CPM/CPC 的老路,但广告主向平台表达的目标换成转化成本——平台用「我帮你按转化优化」换取「计费口径不变」。
图中链路从产品视角拆开是四步:广告主设置转化出价(每个转化值多少钱)与预算;平台预估点击率与转化率、按 参与排序竞价(公式的推导与预算控制见 12.4.1 与 12.4.2);用户在媒体上点击、下载、转化;转化事件按归因规则回传给平台(归因口径与 ATT/SKAN 带来的限制见 12.6,反作弊口径见 12.11)。闭环的最后一环是平台跟踪实际转化成本与出价期望的偏离,动态调整真实出价。
转化率预估:为什么移动端做成了
从平台的技术角度看,oCPX 引入的新问题主要是 转化率预估。它的困难远超点击率预估:不同行业的客户转化流程差异很大,无法用统一模型建模;转化数据的量比点击还少很多,数据稀疏更严重。在 PC 时代,这两座大山让转化率预估虽被寄予期望、实践中却难以落地。
转机来自移动端一个并不起眼的事实: 转化流程的一致性大大加强了。移动广告中很多行业的转化都以 App 下载的形式体现——电商、游戏、工具、金融的营销目标往往都要先下载客户的 App。从技术而非商业的视角看,真实的转化出口只有一个:应用市场。所有下载类客户的数据流程一致,理论上可以共同建模,数据稀疏问题被极大缓解。受此启发,如今的平台还在 App 下载以外继续推动转化流程的统一——例如中国主流平台上,非平台电商自建站逐渐淡出,转而采用平台提供的统一建站模板,目的之一就是统一转化流程有利于转化率预估的建模。
出价的三种理解:bid、price 与预算
oCPX 有一个隐蔽而关键的产品问题:广告主给出的转化出价 ,平台应该把它理解成 出价(bid) 还是 期望得到的实际转化成本(price) ?两种理解对应完全不同的市场机制。
若理解为 bid,平台按二价机制处理:用 排序,胜出者按下一位的 eCPM 向下收费。此时虽然计费用 CPM,仍可折算客户的实际 CPA 成本——在预估可靠、预算充分的前提下,这一成本一定小于其出价,整个市场与 CPC 二价市场没有本质区别,实话实说与社会福利最优性质都保留。客户只要大致清楚自己每个转化的价值,忠实报价即可。若理解为 price,市场实质变成一价:由于点击率与转化率预估必有偏差,简单按一价处理并不能保证最终转化成本接近出价,所以平台还要 跟踪实际转化成本,根据其与期望的偏离程度动态调整真实出价 ,通过补偿让转化成本收敛到出价。Facebook 的产品术语精确对应这两种理解:前者接近 出价上限(bid cap) 模式,后者接近 花费上限(cost cap) 或 目标花费(target cost) 模式。
对大多数客户而言,连转化出价都嫌复杂——还有什么概念人人能懂?只有预算。Facebook 首创了 预算表达模式 :客户只说一天想花多少钱,平台将预算尽量均匀地在各时段消耗;过程仍在竞价框架内完成——平台预测每个时段客户所选人群的市场价格水平,倒算出需要出多少价才能按计划消耗。这套「傻瓜式」竞价让客户做好素材、选定人群、定好预算、按下启动键即可,市场活跃客户数量大增。但分时倒算出价在某种意义上违背了二价市场的实话实说原则:当某时段倒算出的 CPA 出价高于客户真实转化价值时,便可能带来亏损——所以 Facebook 又为有能力的客户保留了出价上限模式,客户提供的上限低于系统倒算出价时以前者替代。
Analysis: 三种出价表达构成一个「精细度 vs 理解门槛」的阶梯:bid cap 最精细、保留二价市场的机制性质,但要求客户理解「出价」概念;cost cap / target cost 把承诺变成「实际成本」,教育成本低了,但市场退化为一价、需要平台调价补偿;预算表达门槛最低,但倒算出价偏离客户真实价值时可能亏投。作者的观点值得体会:站在二价表达的基础上逐渐引导市场和客户,可能是比较合理的路径——机制的健康与门槛的降低,长期看需要兼得。
12.13.5 收束:原生广告与程序化交易的合流
最后回答一个看似矛盾的问题:程序化交易的趋势是受众购买、自动化竞价,原生广告却要求媒体深度参与、把广告融进内容——这两条道路是不是背道而驰?合流点在哪里?
先观察一个现象:搜索广告有没有程序化交易的可能?市场上从未见过这种产品场景。但 Facebook 的信息流广告里,却存在按广告主上传人群库投放的方式——这不是程序化交易,但目的类似,而且很容易改造成 RTB。同样作为原生广告的特殊形式,为什么对程序化交易的接受程度如此不同?关键在于: 原生广告的触发是否根据用户意图进行。在明确提供用户意图的原生广告(如搜索)中,完全开放 RTB 很难控制付费结果的相关性——能做到良好相关性的只有少数技术强的大平台,引入大量 DSP 参与竞价就很难保证结果质量,因此由单个技术能力较强的原生广告网络(或自营)更可行。而在社交网络信息流这类用户意图并不明确、也不要求广告依意图触发的原生广告中,完全可以考虑用程序化交易的方式运营——这也是原生广告未来的发展趋势之一。
把这条结论放回 12.1 的演进阶梯,本章的位置就清楚了:阶梯由形式演进(内容与广告融合)与机制演进(交易自动化)两股力量推动,在顶端汇合。原生 RTB 正是这个汇合点——「内容的个性化」(原生让广告以用户愿意接受的方式出现)与「交易的程序化」(RTB 让每一次个性化决策在开放市场中定价)不再是一对矛盾,而是同一个决策系统的两个侧面。12.1 那张演进阶梯图中「信息流广告:开始尝试将内容和广告融合」的一行,到本章才算真正落了地。
⚠️ Common Mistakes in 12.13
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | 把信息流广告理解为「长得像内容就行」 | 在文章段落中间开辟广告位,样式与正文一致,就自称信息流 | 定义的第二条件要求被广告区隔的内容相互独立;长文内容块是接续的,插入广告会打断阅读任务 | 用两个定义条件判定:交互联动 + 内容块无直接关联,缺一不可 |
| 2 | 混淆 oCPX 出价的三种表达模式 | 广告主按 cost cap 出价,却按 bid cap 的二价逻辑预期扣费并投诉平台多扣 | bid cap 下出价是 bid(二价市场),cost cap 下出价是期望成本(一价 + 平台调价补偿),预算模式则连出价都不需要 | 对接客户前先确认模式;解释预期成本口径与调价补偿机制 |
| 3 | 认为广告密度越高效益越好 | 把 、 一路调小,追求单次会话广告收益 | 密度过高带来误点与反感,伤害的是长期流量价值;且信息流是竞价队列,劣质位置拉低整体点击率 | 在平均广告条数约束下按用户分群精细化调整 /,优化整体点击率 |
| 4 | 把激励视频等同于积分墙式激励 | 担心激励视频「奖励带来的用户质量低」 | 激励视频只奖励观看行为、不刺激下载,不存在积分墙那种用户质量偏低问题 | 区分「奖励观看」与「奖励下载」两类激励,评估口径随之不同 |
| 5 | 认为搜索类原生广告可以直接开放 RTB | 把搜索广告位接进公开竞价市场 | 明确用户意图触发的原生广告,开放竞价无法控制付费结果的相关性 | 意图明确的原生走强技术能力的单平台网络或自营;意图模糊的信息流类才适合程序化 |
| 6 | 转化预估模型不准时只怪模型 | pCVR 偏差大就反复调模型,忽视转化追踪链路 | 转化事件依赖回传与归因口径;链路丢数据、归因错配会让模型输入本身就是错的 | 先按 12.6 的归因链路核对回传完整性与口径,再诊断模型 |
本章小结
📌 Key Takeaways
| Concept | Key Points | Why It Matters |
|---|---|---|
| 原生广告的由来 | 移动端屏幕小、交互不精准、横幅误点多转化差;统一生产或混合排序商业化与非商业化内容(内容即广告) | 解释为什么原生化在移动时代成为刚需,而非风格选择 |
| 信息流广告定义 | 两条件:广告与内容交互联动;被广告区隔的内容相互独立 | 判定产品形态归属的唯一标准,样式相似不充分 |
| 混排与放置 | 多广告位构成竞价队列(VCG/GSP);(首条位置)与 (间隔)决定密度;约束平均广告条数、优化整体点击率 | 信息流的产品机制核心,也是推荐系统「混排」问题的工程起点 |
| 原生形态光谱 | 表现原生(媒体控制展示样式)vs 场景原生(按场景/意图触发);激励视频 = 深度定制场景 + 标准化可交易内核,只奖励观看不刺激下载 | 原生不是单一形态,而是按原生程度排列的光谱 |
| oCPX 产品链路 | 计费与出价分离;移动端转化流程统一为应用市场下载,缓解数据稀疏;出价三表达:bid cap(二价)/ cost cap(一价补偿)/ 预算表达(倒算出价) | 让小客户也能参与竞价的产品基础设施,机制性质随表达模式变化 |
| 原生与程序化合流 | 触发是否依赖明确用户意图决定能否开放 RTB;意图模糊的信息流类原生可与程序化交易结合 | 回扣 12.1 演进阶梯:形式演进与机制演进在顶端汇合 |
❓ FAQ
Q1: 信息流广告与普通展示广告到底差在哪?既然本质都是竞价?
决策流程(检索、排序、竞价、计费)确实基本一致,信息流生态里同样有 ADN/ADX/DSP。差别集中在展示与交互层:交互要与内容联动、内容块之间要相互独立,由此派生出素材适配与 / 密度控制两个特有产品问题。一句话:同一个竞价内核,换了一层「原生」的外壳与约束。
Q2: 预算表达模式下平台倒算出价,会不会把我的钱花亏?
可能。当某时段倒算出的 CPA 出价高于你真实的转化价值时,就会出现亏投——这正是预算表达模式违背实话实说原则的代价。有运营能力的客户应当使用出价上限(bid cap)模式:系统倒算出价高于你设定的上限时,按你的上限执行。
Q3: 为什么说激励视频服务效果广告主是「与直觉不同」的?
直觉上,全屏视频、深度植入游戏场景,像品牌广告的阵地。但激励场景的两个特性——必须看完、虚拟商品对非充值用户是稀缺资源——天然利好「看完即转化」的效果链路,所以主流激励视频网络都以应用下载广告为主要收入来源。品牌诉求反而更适合开屏这类合约售卖的全屏形态。
🔗 前后关联
- 12.1 (全景与生态):本章是 12.1 演进阶梯中「信息流/植入式原生」两行的完整展开;原生 RTB 是阶梯顶端「形式演进与机制演进汇合」的具体形态
- 12.4 (智能出价与预算控制):oCPC/oCPM 的 eCPM 公式、预算 pacing 与出价缩放的算法视角在 12.4;本章只讲产品侧的链路与出价表达模式
- 12.6 (开环与闭环广告):oCPX 的转化追踪与回传依赖的归因体系,以及 ATT/SKAN 对移动转化的冲击,均在 12.6 展开
- 12.3 (竞价机制):信息流多广告位竞价队列的 VCG/GSP 扣费、二价实话实说性质的理论基础
- 12.11 (实验框架与反作弊):oCPX 转化数据被归因作弊污染的风险与识别手段在 12.11
Practice Problems
Work through all problems in order — they get progressively harder. Each has a complete solution you can reveal after trying it yourself.
Problem 12.13.1 — 用两个定义条件判定信息流广告 🟢 Easy
依据 12.13.2 的定义(交互联动 + 被广告区隔的内容相互独立),判断以下四种形态是否属于信息流广告,并说明理由:
(a) 社交网络动态列表中插入的卡片广告,随内容一起滑动; (b) 长篇文章段落之间的固定横幅,内容滚动时横幅悬浮不动; (c) 游戏暂停时弹出的插屏广告,通过角上按钮关闭; (d) 某应用内广告通过滑动消除,随后进入其他内容界面。
Sample Input: [(a), (b), (c), (d)]
Sample Output: (a) 是;(b) 否;(c) 否;(d) 是
💡 Solution (click to reveal)
**Approach:** 逐条对照两个定义条件:交互联动(怎么操作内容就怎么操作广告)与内容块相互独立(无接续、因果关系)。- (a) 随内容一起滑动满足交互联动;动态列表的内容块天然相互独立。两个条件都满足,是。
- (b) 横幅悬浮不动,违反交互联动;且同一篇文章的内容块是接续的,违反内容独立。两个条件都不满足,否。
- (c) 角上按钮关闭不是内容的典型交互方式,违反交互联动,否。
- (d) 通过滑动消除广告属于与内容一致的交互方式,可归入信息流广告,是。
Key points:
- 「展示样式与内容一致」「精准定向」是常见特征但不是根本特征,不进入判定
- 判定只看交互与内容结构,不看广告是不是真的长得像内容
Problem 12.13.2 — oCPX 二价市场的 eCPM 排序与实际 CPA 🟢 Easy
某信息流竞价队列中有两个候选广告(移动端下载类):
- 广告 A:(点击率),(转化率),转化出价 元
- 广告 B:,, 元
按 eCPM 排序决定胜者;若采用二价逻辑(按下一位的 eCPM 收费),计算胜者的实际 CPA 成本,并与 A 的出价比较。
Sample Input: ; Sample Output: A 胜出; 元, 元;实际 CPA 元 元
💡 Solution (click to reveal)
**Approach:** 用 12.4.1 的公式 排序;二价收费后按「每千次展示收入 ÷ 每千次展示转化数」折算 CPA。- 元; 元。A 胜出。
- 二价按次高价收费:每千次展示收入 30 元。每千次展示的转化数为 。
- 实际 元 元 = 出价。
这正是 12.13.4 说的二价性质:只要点击率与转化率预估可靠、预算充分,实际 CPA 一定低于出价,市场保留了实话实说性质——客户忠实报告每个转化的价值即可。 Key points:
- oCPX 计费口径仍是 CPM,CPA 是从二价扣费折算出来的实际成本
- 实际 CPA 小于出价不是巧合,而是二价机制的必然(本例 30 < 40)
Problem 12.13.3 — 信息流密度的 S/K 放置 🟡 Medium
某资讯 App 每次刷新加载 30 条内容,产品要求 平均每次刷新不超过 3 条广告。若首条广告固定出现在第 3 条内容之后(),且后续两条广告按相同间隔 顺次插入(位于第 、 条内容之后),求满足约束的最大整数间隔 ,并给出三条广告的具体位置;再验证 再大 1 时是否越界。
Sample Input: 内容总数 30;广告上限 3; Sample Output: ;广告位于第 3、16、29 条内容之后
💡 Solution (click to reveal)
**Approach:** 第三条广告的位置是 ,必须不超过内容总数 30:。- ,最大整数 。
- 三条广告位置:第 3、、 条内容之后,均在 30 条以内。
- 验证 :,第三条广告越界,不可行。
顺带体会 / 的权衡含义:在「最多 3 条」的总量约束下, 取到上限意味着广告被尽量稀释到尾部——广告获得关注更少、体验伤害更小;若想让前半程也参与变现,就要减小 并接受体验折损,12.13.2 说的「按每个用户的点击率水平精细调整」正是在这条边界上做优化。 Key points:
- 约束式是 内容总数, 为广告条数
- 总量约束只限制「平均广告条数」,具体位置(、)才是体验-收益权衡的自由度
Problem 12.13.4 — 横幅与激励视频的 eCPM 对比 🔴 Hard
某游戏媒体有两个可选广告位方案,广告主按 CPA 出价 元不变:
- 方案一(横幅):点击率 ,观看后到转化的比例 ;
- 方案二(激励视频):广告不可跳过、必须看完,点击率 ,看完后到转化的比例 。
计算两方案的 eCPM 并求倍数关系;结合激励视频的两个效果来源(必须看完、虚拟商品激励认真观看),解释为什么主流激励视频网络以效果广告主为主要收入来源。
Sample Input: 元;; Sample Output: 元, 元,60 倍
💡 Solution (click to reveal)
**Approach:** 直接套 ,比较两方案的 (每千次展示转化数)。- 方案一: 元。每千次展示转化数 。
- 方案二: 元。每千次展示转化数 。
- 倍数: 倍,全部来自 从 0.05 提升到 3(60 倍)。
分解来看:点击率提升 30 倍(0.5% → 15%,不可跳过 + 看完才给奖励,用户必然完成观看-点击引导),转化率提升 2 倍(1% → 2%,充足的信息传递提升后端转化)。12.13.3 的两个效果来源正对应这两项:必须看完撑起点击率,认真观看与虚拟商品激励撑起转化率。转化率的大幅确定性提升让效果广告主(应用下载为主)愿意为激励视频支付高 CPA,这就是激励视频网络收入以效果广告主为主的原因。 Key points:
- eCPM 差距可以完全分解到 与 两个因子上,出价不变时倍数关系不变
- 「不可跳过」是激励视频的核心产品杠杆:它同时改变了漏斗的曝光-点击与点击-转化两段
Problem 12.13.5 — CPA 超出出价的诊断设计 🏆 Challenge
你是某移动广告平台 oCPX 产品的负责人。运营反馈:一批采用「花费上限(cost cap)」模式的客户投诉实际转化成本比出价期望高出 30% 以上,且调价补偿迟迟不能收敛。请设计一套诊断流程:列出至少 4 个可能根因(分别来自转化追踪链路、归因口径、模型、机制),说明每个根因对应的可观测指标与验证方法,并给出修复动作。
Sample Input: 客户投诉清单 + 平台展示/点击/转化日志 + 回传数据 + 出价调整记录 Sample Output: 根因 × 指标 × 验证方法 × 修复动作的对照表
💡 Solution (click to reveal)
**Approach:** 沿 oCPX 链路(12.13.4 的 ①→④ 环节)从数据源头到机制末端排查:先确认「成本确实高」还是「数据口径不一致」,再区分「模型估不准」与「机制收敛不了」。| 可能根因 | 可观测指标 | 验证方法 | 修复动作 |
|---|---|---|---|
| 转化追踪链路丢单/迟到 | 回传转化数 vs 应用市场侧实际激活数的分日对账;回传延迟分布 | 抽样设备级比对展示-点击-回传全链路日志 | 修复回传接口重试机制;对迟到转化做延迟归因补偿 |
| 归因口径错配 | 平台归因口径 vs 客户/MMP 归因口径(点击后归因窗口、末次点击 vs 多触点)的差异统计 | 对同一批转化按两种口径分别重算 CPA | 与客户对齐归因窗口与口径(参见 12.6);口径无法一致时在产品上明确展示口径 |
| pCVR 模型偏差 | 预估 CVR vs 实际 CVR 的分行业校准曲线(分桶对比,参见 12.5) | 按行业、人群分桶画校准曲线,观察系统性高估/低估 | 分行业单独建模或引入行业特征;预估偏差进入出价补偿的先验 |
| 机制收敛问题 | 调价补偿的响应速度 vs 成本波动速度;极端时段倒算出价记录 | 回放高波动时段(如大促)的出价调整轨迹,检查是否追不上或超调 | 增加调价步长的自适应;对成本波动大的时段设置出价保护带 |
| 客户侧误解(对照项) | 客户实际选择的模式与预期的差异;预算消耗曲线 | 核对客户配置:是否误用预算表达模式却按 cost cap 预期 | 客户教育:三种出价表达(bid cap / cost cap / 预算)的预期成本口径差异 |
Key points:
- 先二分「数据错了」还是「机制错了」:链路与归因问题会让模型输入本身就错,模型再准也没用
- cost cap 是一价 + 补偿机制,收敛依赖「跟踪实际成本 → 调整真实出价」回路的信噪比;数据侧污染直接拖垮收敛
- 别漏掉对照项:相当比例的「投诉」源于客户对出价表达模式的理解偏差,这本身就是 12.13.4 强调的产品问题
术语表 (Glossary)
本表收录本书出现的核心术语,按中文首字母排序。格式:术语 — 一句话定义,必要时交叉引用相关章节。
基础概念(全篇)
- 候选集 (Candidate Set) — 经过召回阶段筛选后、待排序模型精排的物品集合,规模通常为千级。
- 判别式推荐 (Discriminative Recommendation) — 将推荐定义为「给定用户-物品-场景三元组,预测交互概率」的范式,核心为打分函数 。
- 生成式推荐 (Generative Recommendation) — 让模型根据用户历史与场景直接「创作」推荐序列的范式,核心为生成函数 。
- 召回 (Retrieval / Recall) — 推荐流水线的第一阶段,在毫秒级延迟内从亿级物品库快速筛选千级候选。
- 排序 (Ranking) — 推荐流水线的第二阶段,用复杂模型为每个候选计算精确预测分数。
- 重排 (Re-ranking) — 推荐流水线的第三阶段,在保持相关性的前提下优化整张列表的多样性、新颖性等体验指标。
Part 2 · 快速候选召回
- ItemCF (基于物品的协同过滤) — 通过物品共现余弦相似度、由种子物品扩散候选的协同过滤方法(Ch2.1)。
- UserCF (基于用户的协同过滤) — 通过用户相似度聚合邻居行为来预测目标用户兴趣的协同过滤方法(Ch2.1)。
- Swing — 通过分析用户-物品二部图子结构、以「特异性共现」过滤热门噪声的工业级相似度算法(Ch2.1)。
- 二部图 (Bipartite Graph) — 用户与物品为两类节点、交互为边的图结构,Swing 在其上分析子结构以过滤噪声(Ch2.1)。
- FunkSVD — 矩阵分解基础模型,把评分矩阵分解为用户/物品隐向量并以内积预测评分(Ch2.1)。
- BiasSVD — 在 FunkSVD 基础上引入全局均值 、用户偏置 、物品偏置 的矩阵分解改进模型(Ch2.1)。
- MF(矩阵分解) — 将用户-物品交互分解为低秩隐向量、以向量距离反映偏好的方法家族(Ch2.1)。
- Surprise 算法 — Swing 的衍生算法,从类别/商品/聚类三层面挖掘互补商品(Ch2.1)。
- Word2Vec (Skip-Gram) — 用中心词预测上下文、以负采样高效学稠密词向量的序列建模方法,是 I2I 向量召回的理论基础(Ch2.2)。
- Item2Vec — 把 Word2Vec Skip-Gram 直接迁移到推荐、将用户交互历史当「句子」学物品向量的 I2I 方法(Ch2.2)。
- EGES (Enhanced Graph Embedding with Side Information) — 在随机游走访物品图上融合属性、用商品特定注意力加权聚合以解决冷启动/稀疏的 I2I 向量方法(Ch2.2)。
- 双塔模型 (Two-Tower) — 用户与物品分别由独立塔编码为向量、仅在最终内积交互的 U2I 召回架构(FM/DSSM/YouTubeDNN)(Ch2.3)。
- YouTubeDNN — 把召回定义为「预测用户下一观看」、采用非对称双塔与时序分割的工程化双塔模型(Ch2.3)。
- MIND (Multi-Interest Network with Dynamic Routing) — 用多兴趣胶囊分别代表用户多元兴趣、各胶囊独立检索再合并的序列召回模型(Ch2.4)。
- 动态路由 (Dynamic Routing) — 胶囊网络中确定低层与高层胶囊连接强度的迭代算法,MIND 借其把行为软聚类为兴趣胶囊(Ch2.4)。
- squash 函数 — MIND 把向量模长非线性压缩到 、方向不变、模长表兴趣存在概率的函数(Ch2.4)。
- 标签感知注意力 (Label-Aware Attention) — MIND 训练时用目标物品向量作查询、从多兴趣胶囊中挑最相关者的注意力机制(Ch2.4)。
- SDM (Sequential Deep Matching) — 分别建模短期(LSTM+多头)与长期(特征维度注意力)兴趣、以门控动态融合的序列召回模型(Ch2.4)。
- LSTM(长短期记忆) — SDM 用以处理会话序列时序依赖、抑制随机误点击的循环网络(Ch2.4)。
- 多头自注意力 (Multi-Head Self-Attention) — SDM 在 LSTM 之后并行多路注意力以捕捉序列内多重兴趣的机制(Ch2.4)。
- Trinity — 用层次化 VQ 聚类 + 统计直方图显式保留全量历史兴趣、根治兴趣遗忘的召回框架,含 M/LT/L 三召回器(Ch2.5)。
- 层次化聚类 (Hierarchical Clustering) — Trinity 训练阶段用 VQ 维护两级可学习聚类中心(主 128 / 次 1024)的结构(Ch2.5)。
- 流式向量量化索引 (Streaming VQ) — 让物品实时量化到聚类、中心经 EMA 持续自适应、无需中断重建的索引结构(Ch2.5)。
- Exponential Moving Average (EMA) — 用所属物品 Embedding 加权平均平滑更新聚类中心、使其适应分布变化的机制(Ch2.5)。
- 兴趣遗忘 (Interest Amnesia) — 在线学习框架拟合近期样本、致稀疏长尾兴趣记忆衰退的现象,Trinity 试图解决(Ch2.5)。
- 长期兴趣召回 (Trinity-L) — Trinity 用轻量双塔选种子物品、再基于 Embedding 相似度做 I2I 检索的召回器(Ch2.5)。
- 长尾兴趣召回 (Trinity-LT) — Trinity 用流式频率估计追踪长尾聚类、对长尾主题显著行为增强推送的召回器(Ch2.5)。
- 归并排序服务策略 (Merge-Sort Serving) — Streaming VQ 把 score 拆为「聚类级个性化 + 聚类内流行度」、用最大堆 K 路归并保证每聚类贡献候选(Ch2.5)。
Part 3 · 精准偏好预测
- 记忆(Memorization) — 模型学习并记住历史中频繁共现的特征组合(如"买 A 的人也买 B"),对应 Wide&Deep 中 Wide 部分(Ch3.1)。
- 泛化(Generalization) — 模型学到特征间的深层关系,能处理训练时罕见的组合,对应 Wide&Deep 中 Deep 部分(Ch3.1)。
- 交叉特征(Cross-product Features) — 将多个独立特征人工组合成的新特征,用于 Wide 部分捕捉特定共现模式
AND(a, b)(Ch3.1)。 - 联合训练(Joint Training) — Wide 与 Deep 两部分由同一损失同时更新全部参数,区别于分别训练再集成(Ch3.1)。
- 因子分解机 / FM(Factorization Machine) — 用每个特征的低维隐向量内积建模二阶交叉,把参数量从 降到 并缓解稀疏(Ch3.2)。
- 参数共享(Parameter Sharing) — FM 把交叉权重表示为隐向量内积,使未共现特征也能通过各自隐向量泛化预测(Ch3.2)。
- 共享 Embedding(Shared Embedding) — DeepFM 中 FM 与 DNN 组件共用同一份特征 Embedding,兼顾低阶/高阶交互与训练效率(Ch3.2)。
- Cross Network(DCN) — 每层与原始输入做残差交叉 ,明确产出元素级高阶交叉(Ch3.2)。
- CIN(Compressed Interaction Network, xDeepFM) — 在向量级做哈达玛积并加权压缩,逐层显式产出向量级高阶交叉(Ch3.2)。
- 局部激活(Local Activation, DIN) — 用户兴趣表示随候选广告动态变化,由注意力机制加权历史行为得到(Ch3.3)。
- 辅助损失(Auxiliary Loss, DIEN) — 逼 GRU 隐状态预测下一步行为,使其学到有意义的兴趣表示(Ch3.3)。
- AUGRU(Attention Update Gate GRU, DIEN) — 用注意力得分缩放 GRU 更新门,让相关兴趣顺畅传递、抑制兴趣漂移(Ch3.3)。
- 会话(Session, DSIN) — 一段时间内意图集中的行为单元;DSIN 以会话为基本单元做分层序列建模(Ch3.3)。
- 负迁移 / 跷跷板(Negative Transfer / Seesaw) — 多任务硬共享时,任务梯度冲突导致提升一目标损害另一目标的现象(Ch3.4)。
- MMoE(Multi-gate Mixture-of-Experts) — 每任务配专属门控,对共享专家加权融合,实现梯度软隔离以缓解冲突(Ch3.4)。
- PLE / CGC(Progressive Layered Extraction / Customized Gate Control) — 显式分离共享专家与任务专家,物理切断跨任务梯度干扰路径(Ch3.4)。
- 样本选择偏差(Sample Selection Bias, ESMM) — CVR 模型在点击样本训练、全量曝光预估,导致训练/预估分布不一致(Ch3.4)。
- 全空间建模(Entire Space, ESMM) — 用 在曝光空间联合优化,化解 CVR 的偏差与稀疏(Ch3.4)。
- Uncertainty Weight(UWL) — 按任务不确定性动态调损失权重,不确定小且损失大时降权(Ch3.4)。
- GradNorm — 按梯度量级与相对训练速率动态平衡多任务损失(Ch3.4)。
- 帕累托优化(Pareto Optimization) — 用 KKT 条件把损失权重作为可学习变量,把优化引向帕累托前沿(Ch3.4)。
- 多场景建模(Multi-scenario) — 不同场景/分布下预估同一目标,需兼顾共性与特性(区别于多任务)(Ch3.5)。
- STAR FC(Star Topology FCN) — 每层参数由共享与场景私有参数元素积融合 (Ch3.5)。
- 分区归一化(Partitioned Normalization, PN) — 按场景分别统计 Batch Norm 的均值/方差,避免跨场景分布混淆(Ch3.5)。
- Gate NU(PEPNet) — 轻量门控单元,由先验特征生成动态缩放权重调制共享参数(Ch3.5)。
- EPNet / PPNet(PEPNet) — EPNet 做场景级 Embedding 个性化,PPNet 做样本级任务塔参数个性化(Ch3.5)。
- APG(Adaptive Parameter Generation) — 由样本感知输入动态生成参数矩阵,并用低秩分解控制开销(Ch3.5)。
- M2M(元学习多场景多任务) — 用元学习器根据场景/输入特征动态生成任务模型参数(Ch3.5)。
- STAR FCN(Star Topology FCN) — 每层参数由共享与场景私有参数元素积融合 。
Part 4 · 重排多样性建模
- 列表同质化(List Homogenization) — 精排逐点最优化导致头部物品高度相似的现象,是重排存在的根本动机。
- 最大边际相关(MMR, Maximal Marginal Relevance) — 用 的边际收益公式,以贪心方式在相关性与多样性间权衡(Ch4.1)。
- 滑动窗口 MMR(MMR with Window) — 只用最近 个已选物品计算相似度惩罚的 MMR 变体,用于长列表降成本(Ch4.1)。
- 行列式点过程(DPP, Determinantal Point Process) — 用核矩阵行列式度量集合多样性的概率模型,能精确刻画多物品间的相互排斥(Ch4.1)。
- 核矩阵(Kernel Matrix, ) — DPP 中融合相关性与多样性的半正定矩阵,构造为 (Ch4.1)。
- Cholesky 加速 — 利用 分解,把 DPP 贪心选择简化为每轮取 的高效求解法(Ch4.1)。
- 个性化重排(Personalized Re-ranking) — 把用户个性化信号深度融入列表级优化、由模型端到端学习最优列表的重排范式(Ch4.2)。
- PRM(Personalized Re-Ranking Model) — 用 Transformer 编码列表、融合个性化向量(PV)实现端到端个性化重排的模型(Ch4.2)。
- 个性化向量(PV, Personalization Vector) — PRM 中由预训练 CTR 模型隐藏层激活提取的用户-物品偏好向量,是 PRM 个性化的核心(Ch4.2)。
- 排列变异影响(Permutation-Variant Influence) — 相同物品、不同排列顺序导致用户行为不同的现象,是 PRS 的动机(Ch4.2)。
- PRS(Permutation Retrieve System) — 直接优化排列顺序体验收益的重排模型,采用 PMatch + PRank 两阶段化解 组合爆炸(Ch4.2)。
- FPSA(Fast Permutation Searching Algorithm) — PRS 的 PMatch 阶段算法,用 beam search 结合 CTR/Next 双模型快速生成候选排列(Ch4.2)。
- DPWN(Deep Permutation-Wise Network) — PRS 的 PRank 阶段网络,用 Bi-LSTM 评估候选排列质量,以 List Reward(LR)为指标选最优(Ch4.2)。
- List Reward(LR) — PRS 中排列所有位置预测点击概率之和,用于比较候选排列的整列收益(Ch4.2)。
- 重排(Re-ranking) — 三阶段漏斗最末端,对精排输出的候选列表做列表级优化(多样性、新颖性、业务规则)以最大化整屏体验。
Part 5 · 前沿趋势
- 数据偏差(Data Bias) — 推荐数据在收集阶段就因系统策略、用户习惯等带来的系统性失真(Ch5.1)。
- 选择偏差(Selection Bias) — 显式反馈中用户只评分感兴趣内容,导致观测数据不代表真实态度(MNAR)(Ch5.1)。
- 曝光偏差(Exposure Bias) — 隐式反馈中用户只能看到被推荐的物品,未交互可能源于未曝光而非不感兴趣(Ch5.1)。
- 从众偏差(Conformity Bias) — 用户受群体意见影响而附和给出非独立、非真实的评价(Ch5.1)。
- 位置偏差(Position Bias) — 列表推荐中用户更关注排在前面的物品,使点击受位置而非相关性影响(Ch5.1)。
- 非随机缺失(MNAR, Missing Not At Random) — 观测到的评分并非随机样本,导致统计偏差(Ch5.1)。
- 流行度偏差(Popularity Bias) — 模型过度学习热门物品交互模式,致推荐偏向热门、长尾难被发现(Ch5.1)。
- 反馈闭环(Feedback Loop) — 推荐结果影响用户未来行为,行为又成新训练数据,使偏差被滚雪球放大(Ch5.1)。
- 马太效应(Matthew Effect) — 热门物品因曝光多而交互多、再获更多曝光的「富者愈富」恶性循环(Ch5.1)。
- 逆倾向得分(IPS, Inverse Propensity Score) — 用观测概率的倒数作样本权重,逆转选择/曝光偏差,得到无偏风险估计(Ch5.1)。
- 权重截断(Weight Clipping) — 对 IPS 极端权重做上限截断,在无偏与低方差间折中(Ch5.1)。
- 位置感知学习(PAL, Position-bias Aware Learning) — 把点击概率分解为「看到概率 × 看到后点击概率」,在架构上解耦位置与偏好(Ch5.1)。
- 冷启动(Cold Start) — 新物品或新用户缺乏历史交互,传统协同过滤难以服务的困境(Ch5.2)。
- CB2CF(Content-Based to Collaborative Filtering) — 学习内容特征到协同过滤表示的映射,使新物品直接获得 CF 质量表示(Ch5.2)。
- 映射网络(Mapping Network) — CB2CF 核心,多层全连接,学内容空间到 CF 嵌入空间的非线性映射(Ch5.2)。
- MetaEmbedding — 用元学习优化「可快速适应」的初始 embedding 生成器,改善物品冷启动(Ch5.2)。
- MAML(Model-Agnostic Meta-Learning) — 「学会如何学习」的元学习框架,学良好初始化以少量样本快速适应新任务(Ch5.2)。
- MeLU(Meta-Learned User preference estimator) — 基于 MAML 的用户冷启动方法,把每用户当独立任务快速适应(Ch5.2)。
- POSO(Personalized Cold Start Modules) — 用人群专用子模块 + 个性化门控解决用户冷启动的架构方法(Ch5.2)。
- 生成式召回(Generative Retrieval) — 把推荐重定义为序列生成,自回归预测下一个物品的生成式范式(5.3 生成式范式演进)。
- 事件流(Event Stream) — HSTU 把用户属性、行为、时间戳统一编码成的异构序列表示(5.3 生成式范式演进)。
- 语义 ID(Semantic ID) — TIGER 用 RQ-VAE 把物品内容编码成的结构化 Token 元组,携带语义、支持知识共享与冷启动(5.3 生成式范式演进)。
- RQ-VAE(Residual Quantization VAE) — 残差量化变分自编码器,逐层量化残差生成语义 ID(5.3 生成式范式演进)。
- 端到端统一生成(End-to-end Generative) — 用单一模型完成从召回到排序全流程的生成式形态(5.3 生成式范式演进)。
- 稀疏专家混合(MoE, Mixture-of-Experts) — OneRec 解码器中激活少数专家子网络以增容量不增算力(5.3 生成式范式演进)。
- 迭代偏好对齐(IPA, Iterative Preference Alignment) — OneRec 用奖励模型从多候选中构造选择/拒绝对、以 DPO 对齐偏好的机制(5.3 生成式范式演进)。
- DPO(Direct Preference Optimization) — 直接偏好优化,无需独立 critic 即可用「选择/拒绝」对比对优化策略(5.3 生成式范式演进)。
下篇术语 · 生成式推荐主线
- 结果偏差(Result Bias) — 有偏数据经模型训练后体现在推荐结果中的偏差。
- 不公平性(Unfairness) — 系统对某些用户群体或物品类别产生系统性歧视。
- 倾向得分(Propensity Score) — 用户-物品交互被观测到的概率 ,IPS 加权的分母。
- 朴素估计量(Naive Estimator) — 直接在观测数据上求平均的评估量,选择偏差下是有偏的。
- 半合成实验(Semi-synthetic Experiment) — 用真实数据集补全为 ground truth 再按偏差模型采样,制造「已知答案」以量化纠偏效果。
- ProbSeen 模块 — PAL 中仅输入位置、输出被看到概率的轻量模块。
- pCTR 模块 — PAL 中不含位置信息、建模用户真实偏好的深度模块;推理时单独使用以去偏。
- 个性化淹没(Submergence) — 新用户远少于老用户时,其个性化信号被多数老用户数据主导的训练过程淹没。
- 内容冷启动(Item Cold Start) — 新物品缺用户交互,协同过滤无法计算其相似度。
- 用户冷启动(User Cold Start) — 新用户缺行为历史,只能获得基于流行度的通用推荐。
- 约束优化模块(Constraint Optimization) — CB2CF 中用余弦相似度约束保证映射后与真实 CF 嵌入语义一致。
- 元损失(Meta Loss) — MetaEmbedding 中平衡初始质量与适应后性能的损失,如 。
- 参数分离(Parameter Separation) — MeLU 把共享 embedding 参数 与快速适应用的决策参数 分开。
- 个性化门控(Personalized Gating) — POSO 中按用户特征(如 is_new_user)输出各子模块权重的网络。
- 点向聚合(Pointwise Aggregation) — HSTU 摒弃 softmax 归一化、保留用户偏好强度的注意力聚合机制。
- 生成式排序(Generative Ranking) — 把自回归生成思想引入排序阶段(如 GenRank、MTGR)。
- 动作导向(Action-oriented) — GenRank 预测用户对候选的动作概率而非物品 ID,降低计算开销。
- 用户样本聚合(User Sample Aggregation) — MTGR 把用户全部候选聚为单样本,共享用户特征计算。
- 组层归一化(GLN, Group Layer Normalization) — MTGR 对不同语义空间 token 分别归一化。
- 会话级生成(Session-level Generation) — OneRec 直接生成一组有序推荐列表(一个「会话」)而非单一下一个物品。
Part 6 · 生成式推荐范式基础
- 生成式推荐(Generative Recommendation) — 把推荐重定义为序列生成任务,模型直接学习用户交互序列的生成概率并自回归产出物品序列,而非对候选逐一打分。
- 判别式推荐(Discriminative Recommendation) — 学习条件概率 ,对给定候选物品预测正向交互概率的建模范式。
- 自回归建模(Autoregressive Modeling) — 当前预测依赖之前所有已生成输出的生成方式,使信息在时间维度形成循环流动、天然捕捉序列依赖。
- 原子 ID(Atomic ID) — 传统推荐为每个物品分配的随机唯一数字编号,彼此正交无语义关联,难以泛化到新物品。
- 语义 ID(Semantic ID, SID) — 把物品表示为固定长度的离散 token 序列,每个 token 来自可控大小的语义码本,既编码层次化语义又保留协同信息。
- 物品 Token 化(Item Tokenization) — 将推荐系统中的物品转化为生成式模型可理解、可生成的 token 序列的关键技术,是连接传统推荐数据与生成式模型的桥梁。
- Transformer — 基于自注意力机制的深度架构,擅长并行捕捉长程依赖,是生成式推荐与 LLM 的主流骨干。
- 自注意力(Self-Attention) — 通过 Query/Key/Value 的「查询—匹配—聚合」机制,让序列每个位置动态聚焦任意其他位置信息的注意力计算。
- 多头注意力(Multi-Head Attention) — 并行计算多组独立 Q/K/V、各自学习不同关注模式的注意力机制,类似多个「专家」从不同角度理解序列。
- 位置编码(Positional Encoding) — 为序列各位置注入顺序信息的编码,分绝对(正弦/可学习)与相对(偏置)两类,推荐中常扩展为时间感知编码。
- 相对时间位置编码(Relative Temporal Positional Encoding) — HSTU 等采用的时间编码,以 建模行为间时间间隔,使模型兼顾长短期兴趣。
- Encoder-Decoder 架构 — 双塔生成架构:Encoder 双向理解输入、Decoder 因果自回归生成,并以交叉注意力动态查询输入,适合异构输入输出。
- Decoder-Only 架构 — 统一单塔生成架构:输入与输出拼接为连续序列、仅靠因果自注意力自回归生成,参数高效、MFU 高、兼容 LLM 生态。
- 因果掩码(Causal Masking) — 在注意力矩阵中对未来位置施加 的掩码,保证预测第 个 token 时只能依赖前 个,实现自回归并支持训练并行。
- Diffusion 模型(扩散模型) — 通过前向逐步加噪、反向迭代去噪从噪声恢复数据的生成范式,分数据空间与潜在空间两类,与 Transformer 互补。
- Scaling Law(规模化效应) — 模型性能随参数量、数据量、计算量增长而持续提升的经验规律,支撑生成式模型的参数扩展。
- 涌现能力(Emergent Abilities) — 模型规模与数据达到阈值后突然出现的零样本/少样本等能力。
- 预训练(Pre-training) — LLM 第一阶段,在大规模无标注文本上以因果语言建模(下一 token 预测)学习目标,建立通用语言生成能力。
- 指令微调(Instruction Tuning / SFT) — LLM 第二阶段,用「指令—输入—输出」三元组做条件语言建模,仅对输出算损失,使模型学会遵循指令。
- 偏好对齐(Preference Alignment) — LLM 第三阶段,让输出更符合人类价值观与偏好,方法含 RLHF 与 DPO。
- RLHF(基于人类反馈的强化学习) — 收集人类偏好对训练奖励模型,再以 PPO 强化学习优化生成策略并用 KL 散度约束参考模型。
- DPO(直接偏好优化) — 无需显式奖励模型与强化学习,用策略与参考模型比值隐式表示奖励、以似监督方式优化偏好的对齐方法。
- VQ-VAE(向量量化变分自编码器) — 用可学习码本将连续语义向量离散化为单一码本索引的自编码器,是语义 ID 离散化的奠基技术。
- 码本(Codebook) — VQ/RQ 系列中可学习或聚类的离散向量集合,每个向量(码字)对应一个语义 token。
- 直通估计器(Straight-Through Estimator, STE) — 训练量化模型时,前向执行离散量化、反向把量化近似为恒等映射以传递梯度的技巧。
- RQ-VAE(残差量化 VAE) — 通过多层残差量化把连续向量编码为长度 的 token 序列、容量达 并自然涌现层次化语义的模型。
- RQ-Kmeans — 用 K-means 聚类替代梯度学习来构建码本的残差量化方案,将表示学习与码本构建解耦,新物品可经向量检索分配 SID。
- RQ-OPQ — RQ 处理层次化语义、OPQ(优化乘积量化)处理最后一层残差中独特属性的混合编码方案,兼顾召回与长尾精确区分。
- SID 冲突(SID Collision) — 量化信息损失导致不同物品映射到相同 SID 序列的现象,可通过均匀分配或混合编码消歧缓解。
Part 7 · Scaling 生成式排序
- Scaling Law(缩放定律) — 在合适架构下,模型性能随计算量、数据量、参数量增加呈可预测幂律提升的规律,形式常为 。
- DLRM(Deep Learning Recommendation Model) — 传统深度学习推荐模型,依赖手工特征、异构模块与 item-level 逐候选打分,是 Scaling Law 长期失效的代表。
- Generative Recommender / GR(生成式推荐) — Meta 提出的范式,把推荐视为内容与行为交织的随机过程,用统一序列 + 自回归训练实现 user-level 建模。
- HSTU(Hierarchical Sequential Transduction Unit) — Meta 为推荐场景定制的序列模型,三大创新:Pointwise Aggregation、相对时间偏置、门控前馈,首次验证推荐界 Scaling Law。
- Pointwise Aggregation — HSTU 用 SiLU 逐元素聚合(非 Softmax 归一化)替代标准 attention,保留兴趣的「绝对强度」信息。
- 相对注意力偏置 / RAB(rab) — HSTU 在 attention score 中加入可学习偏置,同时考虑位置差、时间差与 token 类型,建模非均匀时间模式。
- Stochastic Length(随机长度) — HSTU 的训练技巧:以一定概率随机截断超长序列,降 复杂度并起正则化作用,参数 控制激进度。
- M-FALCON — HSTU 的推理算法:Batched Inference → Microbatching → KV Caching 三层优化,把多候选排序推理数百倍加速。
- Action-Oriented Organization(行为导向组织) — GenRank 的序列组织:把行为作主体、物品作属性(),序列长度减半、训练提速约 79%。
- ALiBi(Attention with Linear Biases) — 无参数相对位置偏置:给距离远的 query-key 对施加与距离成正比的惩罚,可直接融入 FlashAttention kernel。
- MTGR(Meituan Generative Recommendation) — 美团的混合范式:用生成式架构(Transformer + user-level 聚合)做判别式排序,保留传统交叉特征。
- Group Layer Normalization / GLN(分组层归一化) — MTGR 按 token 类型(User/Seq/RT/Cand)分组独立归一化,解决异构 token 的语义空间冲突。
- Dynamic Masking(动态掩码) — MTGR 按每样本 token 实际时间戳动态生成 attention mask:静态全可见、动态按因果、候选间独立,防信息泄露。
- MFU(Model FLOPs Utilization,模型浮点利用率) — GPU 上有效矩阵乘法计算占总理论算力的比例;传统 DLRM 约 4–5%,LLM 约 40–60%。
- RankMixer — 阿里的 hardware-aware 架构:用 Token Mixing 替代 Self-Attention、Per-Token FFN 捕捉异质性、Sparse MoE 扩展参数,把 MFU 拉到 45%。
- Token Mixing(令牌混合) — RankMixer 的核心操作:在特征维度(按 head 重组)做信息混合而非 token 对相似度,复杂度从 降到 。
- Per-Token FFN(逐令牌前馈) — RankMixer 为每个 token 配备独立 FFN 参数以捕捉异构特征空间,计算复杂度与共享 FFN 相同但参数更专门化。
- ReLU Routing / DTSI-MoE — RankMixer 的稀疏专家策略:ReLU 路由动态激活不同数量 expert;Dense-Training/Sparse-Inference 用双 router 兼顾充分训练与高效推理。
- OneTrans — 字节的统一架构:单一 Transformer backbone 同时做序列建模与特征交互,打破 encode-then-interaction 的模块碎片化。
- Mixed Parameterization(混合参数化) — OneTrans 的参数组织:S-tokens(序列)共享参数、NS-tokens(非序列)独立参数,解决 token 异质性冲突。
- Pyramid Stack(金字塔堆叠) — OneTrans 的渐进式蒸馏:逐层只保留尾部 query token、KV 用全部 token,把信息蒸馏到尾部并降计算量。
- Cross-Request KV Caching — OneTrans 跨请求复用用户侧 KV 缓存(仅追加新增事件),使每请求序列计算近似 (相对候选数)。
- encode-then-interaction(先编码后交互) — 传统分离式范式:序列模块编码为定长向量后再与静态特征拼接做特征交互,信息流受限且执行碎片化。
Part 8 · 端到端生成式应用
- 多阶段级联架构(Multi-stage Cascading Architecture, MCA) — 传统推荐/搜索/广告系统采用的漏斗式多模块架构(召回→预排序→排序→重排),各阶段独立优化、目标可能冲突。
- 语义 ID(Semantic ID) — 把离散业务对象(物品/商品/广告)编码为由粗到细的多层离散 Token 序列,使生成模型能在可控词表内「说出」该对象。
- RQ-Kmeans(Residual Quantization K-means) — 在残差表示上逐层做 K-means 聚类以构建码本的层次化量化方法;与端到端训练的 RQ-VAE 相对,RQ-Kmeans 直接建码本、非端到端。
- RQ-VAE(Residual Quantized VAE) — 残差量化变分自编码器,端到端训练把连续表示离散化为多层语义 ID,常见于 EGA。
- Encoder-Decoder 生成架构 — 编码器双向融合用户/查询上下文、解码器自回归生成目标语义 ID 序列的统一生成结构。
- Lazy Decoder-Only — OneRec-V2 架构:把上下文预处理为静态键值对(Context Processor),解码器仅对目标 Token 计算损失,将算力集中到产生梯度的目标上。
- Scaling Law(规模律) — 模型损失随参数量幂律衰减的可预测规律;OneRec-V2 在推荐模型上验证了该规律。
- 挤压效应(Squeezing Effect) — 强化学习后模型把概率质量压到当前最优输出,使部分合法 Token 概率被压到与非法 Token 相近,导致难分。
- 格式奖励(Format Reward) — 对合法生成样本设优势、丢弃非法样本,以缓解挤压效应、保证生成序列可映射到真实对象。
- P-Score(Preference Score) — OneRec 用神经网络学习的个性化多目标偏好分数,作为强化学习对齐的奖励信号。
- ECPO(Early Clipped GRPO) — 对负优势样本的策略比率预先裁剪的偏好优化算法,避免 GRPO 的梯度爆炸。
- GBPO(Gradient-Bounded Policy Optimization) — 用 BCE 损失的稳定梯度界定 RL 梯度的策略优化算法,支持完整样本利用与有界梯度稳定化。
- PRE(Prefix2Query Representation Enhancement) — OneSug 的前缀表示增强模块,用共现查询检索增强短前缀语义。
- RWR(Reward-Weighted Ranking) — OneSug 的奖励加权排序策略,用六级交互反馈构造偏好对、把业务价值注入排序。
- KHQE(Keyword-enhanced Hierarchical Quantization Encoding) — OneSearch 的关键词增强分层量化编码:前 3 层 RQ-Kmeans 保语义层次、后 2 层 OPQ 保商品独特性。
- OPQ(Optimized Product Quantization) — 优化乘积量化,把残差切分子向量独立量化,编码商品的独特属性。
- Mu-Seq(Multi-view behavior Sequence injection) — OneSearch 从用户 ID 构造、短期序列、长期序列三视角注入用户行为的策略。
- PARS(Preference-Aware Reward System) — OneSearch 的偏好感知奖励系统,含多阶段 SFT 与自适应奖励模型,并把相关性权重放大 10 倍。
- 激励相容(Incentive Compatibility, IC) — 机制设计性质:广告主如实出价是最优策略。
- 个体理性(Individual Rationality, IR) — 机制设计性质:广告主支付不超过其申报竞价()。
- 位置外部性(Position Externality) — 广告的 CTR 受其所在序列其他广告与位置影响,而非相互独立。
- EGA(End-to-end Generative Advertising) — 把竞价机制与生成模型统一、通过 Token 级竞价与 POI 级支付实现 IC/IR 的端到端生成式广告系统。
- POI(Point of Interest) — 兴趣点,如餐厅、健身房等商户实体,是广告生成中的内容主体。
- Token 级竞价(Token-level Bidding) — 用最大值聚合把广告竞价投影到语义 Token,引导生成概率的分配机制。
- POI 级支付网络(POI-level Payment Network) — 独立神经网络,学习满足 IC 约束的支付函数,与分配解耦。
- Ex-post Regret — 广告主通过谎报竞价所能获得的最大额外效用;为 0 时机制满足 IC。
- Lagrangian 优化 — 用对偶乘子把「最大化收益 + regret 约束」转化为可交替优化的损失。
- GPR(Generative Pre-trained Recommender) — 用「预训练 + 微调」范式、统一多场景超长序列的端到端生成式广告系统。
- 四类 Token(U/O/E/I-Token) — GPR 的统一输入表示:User(用户)、Organic(有机内容)、Environment(环境)、Item(广告)。
- RQ-Kmeans+ — 结合 RQ-Kmeans 高质量初始化与 RQ-VAE 端到端优化,缓解码本坍塌(codebook collapse)。
- HHD(Heterogeneous Hierarchical Decoder) — GPR 的三层异构层次化解码器:HSD 意图理解、PTD 推理生成、HTE 价值评估。
- MoR(Mixture-of-Recursions) — 同层递归调用自身多次以增加推理深度、不增参数的机制。
- 价值引导 Trie Beam Search(Value-Guided Trie-based Beam Search) — 依约束构建 Trie 前缀树、用 HTE 价值动态调整束宽与剪枝的解码算法。
- HEPO(Hierarchy Enhanced Policy Optimization) — 同时在 Token 级与 Item 级做层次化策略梯度的强化学习算法。
Part 9 · 推荐中的思考与推理
- 协同语义 (Collaborative Semantics) — 推荐系统通过用户行为共现学习到的物品表示含义,编码在离散 ID 中,本身不携带文本语义(9.1)。
- 语言语义 (Language Semantics) — 大语言模型(LLM)通过预训练在文本上习得的词汇/句法关联含义(9.1)。
- 语义鸿沟 (Semantic Gap) — 协同语义(离散 ID)与语言语义(自然语言)之间无法直接对齐的隔阂(9.1)。
- 语义索引 / 语义 ID (Semantic Index) — 用层次化量化把物品编码为离散 token 序列(如
<A37><B12><C5><D8>),同时可被 LLM 理解并承载协同语义(9.1)。 - 均匀语义映射 (Uniform Semantic Mapping) — LC-Rec 在最后一层量化引入均匀分布约束、以最优传输(Sinkhorn-Knopp)缓解索引冲突的机制(9.1)。
- 多模态嵌入拼接 (Multimodal Embedding Concatenation) — PLUM 将文本/视觉/音频/协同四类嵌入拼接,融合异构信号构建语义 ID(9.1)。
- 多分辨率码本 (Multi-Resolution Codebook) — PLUM 在不同量化层使用不同大小码本(128/256/512/1024),契合从粗到细的信息论原理(9.1)。
- 显式推理 (Explicit Reasoning) — 模型在输出推荐前先生成结构化、可审查的推理链,区别于隐式黑箱打分(9.2)。
- 推理脚手架 (Reasoning Scaffolding) — OneRec-Think 用渐进 prompt 模板与任务引导模型「学会思考」的机制(9.2)。
- 多有效性 (Multi-Validity) — 推荐场景中同一用户常存在多个合理推荐,不存在唯一正确答案的特性(9.2)。
- 推荐特定奖励 (Recommendation-Specific Reward) — 综合协同相似度、内容相关性、推理连贯性、用户反馈的多维奖励函数(9.2)。
- GRPO (Group Relative Policy Optimization) — 对同一样本采样多条 rollout,按相对奖励(而非绝对标准)更新策略的强化学习方法(9.2)。
- Think-Ahead 架构 — 把密集推理从在线关键路径剥离、改为用户行为更新时异步预计算的部署策略(9.2)。
- 自主推理 (Autonomous Reasoning) — 模型在无人工模板、无教师示范下,仅凭任务反馈自主演化推理策略(9.3)。
- 模仿学习 (Imitation Learning) — OneRec-Think 等依赖人工模板/教师知识的推理学习范式(9.3)。
- 探索学习 (Exploratory Learning) — RecZero 依赖强化学习试错与反馈、自主摸索策略的学习范式(9.3)。
- Think-before-Recommendation 模板 — RecZero 只定义「分析用户/分析物品/匹配/评分」四步框架、内容留给模型探索的提示(9.3)。
- 冷启动监督微调 (Cold-start SFT) — RecOne 用少量高质量(含纠偏)推理样本初始化推理能力(9.3)。
- 混合范式 (Hybrid Paradigm) — 监督提供「语言」、强化提供「智慧」,先框架后精进的推理学习思路(9.3)。
Part 10 · 扩散模型推荐
- 扩散模型 (Diffusion Model) — 通过前向逐步加噪、反向学习去噪来建模数据分布的生成模型(10.1)。
- 数据空间扩散 (Pixel-Space Diffusion) — 直接在原始数据空间(像素/交互向量)加噪去噪,代表为 DDPM;计算昂贵(10.1)。
- 潜在空间扩散 (Latent Diffusion, LDM) — 先编码到低维潜在空间再扩散、最后解码,代表为 Stable Diffusion;推荐中更常用(10.1)。
- 前向扩散 (Forward Diffusion) — 按马尔可夫链逐步向数据加高斯噪声,使 x_T 趋近标准高斯(10.1)。
- 反向去噪 (Reverse Denoising) — 训练去噪网络从 x_T 逐步恢复 x_0(10.1)。
- 重参数化技巧 (Reparameterization Trick) — 用 x_t = √ᾱₜ·x₀ + √(1−ᾱₜ)·ε 直接从 x₀ 采样任意 t 的加噪数据(10.1)。
- ε-prediction — 去噪网络预测所加噪声;DDPM 标准参数化(10.1)。
- x₀-prediction — 去噪网络直接预测原始数据;推荐场景更合适(10.1)。
- 分类器引导 (Classifier-Guided) — 用预训练分类器梯度把生成推向目标类别(10.1)。
- 无分类器引导 (Classifier-Free Guidance) — 训练时随机丢弃条件,推理时线性组合条件/无条件预测(10.1)。
- v-prediction — 预测「速度」v = αₜε − σₜx₀ 的参数化,训练更稳定(10.3)。
- 序列增强 (Sequential Augmentation) — 为短序列用户生成「前序」交互以扩充历史;DiffuASR 为代表(10.2)。
- Sequential U-Net (SU-Net) — DiffuASR 把嵌入序列当多通道「图像」处理的 U-Net 变体(10.2)。
- 舍入 (Rounding) — 把去噪后的连续嵌入映射回最近离散物品 ID(10.2)。
- 跨场景增强 (Multi-Scenario Augmentation) — 从数据丰富场景借知识增强冷启动场景;Diff-MSR 为代表(10.2)。
- 分段噪声策略 (Segmented Noise) — Diff-MSR 前期小 β 保留结构、后期线性增长以收敛到高斯(10.2)。
- 不对称扩散 (Asymmetric Diffusion) — 前向在原始特征空间用离散 dropout、反向在潜在空间去噪;AsymDiffRec 为代表(10.3)。
- 特征 dropout — AsymDiffRec 前向用随机丢弃特征模拟真实缺失,比高斯噪声更贴合推荐(10.3)。
- 步长嵌入 (Step Embedding) — 标记哪些特征缺失的二值向量,引导潜在空间补全(10.3)。
- Slate — 一组需整体消费的物品集合(如歌单、套装),需协调性与多样性(10.3)。
- DMSG — 用条件扩散从文本 prompt 生成多样化 slate 的模型,采用 v-prediction(10.3)。
- DDIM 加速 — 把推理步数从上千减到数十的确定性采样加速(10.3)。
Part 11 · 生成式推荐系统实战
- 离线系统(Offline System) — 负责「生产」的子系统:处理全量历史数据、训练模型、计算物品向量与相似度,追求质量而非延迟,产出模型文件与特征索引。
- 在线系统(Online System) — 负责「服务」的子系统:接收实时请求、调用模型、组装推荐结果,目标百毫秒级延迟,依赖离线产出的模型与特征。
- 漏斗式架构(Funnel Architecture) — 工业推荐的经典结构:召回用轻模型快速筛候选、排序用重模型精打分、重排优化体验,逐级缩小候选规模。
- Snake Merge(蛇形合并) — 多路召回融合策略:从各路召回中轮流取候选(A→B→C→C→B→A…),确保每路都有代表进入排序,提升多样性与覆盖。
- 冷启动(Cold Start) — 新用户/新物品缺乏行为数据,传统协同过滤与向量召回失效的现象;本项目用独立冷启动流程(UCB/偏好/热门)应对。
- UCB(Upper Confidence Bound,置信上界) — 平衡探索与利用的算法:分数 = 历史平均奖励 + 探索奖励,未充分推荐的类型获得更高探索机会,避免信息茧房。
- 探索与利用(Exploration vs Exploitation) — 推荐中的基本权衡:利用是推荐已知高质量内容,探索是尝试新类型以发现潜在兴趣;UCB 用单一公式统一两者。
- 困难负样本(Hard Negatives) — 用户曝光过但未正向交互的物品,区分难度大,用于提升模型辨别力。
- 随机负样本(Random Negatives) — 从用户未交互物品中随机采样,扩充负样本数量;本项目与困难负样本按 1:2 混合成 1:3 正负比。
- 滑动窗口样本(Sliding Window Samples) — YoutubeDNN 训练样本的构建方式:给定用户前 次观影,预测第 次,模拟「预测下一个观看」。
- 左填充(Left Padding) — 把变长行为序列在左侧补零到固定长度,使最近行为落在序列右侧,符合时间顺序,适配 RNN/Transformer。
- 物品向量预计算(Item Vector Pre-computation) — 离线用物品塔批量算出全量物品向量并归一化,供在线毫秒级向量检索;双塔可规模化的关键。
- 版本指针(Version Pointer,active.json) — 部署目录中的指针文件,记录当前应加载的模型版本路径;更新时先部署新版本再翻指针,实现无感知热更新与回滚。
- 连续打散(Consecutive Dispersion) — 多样性重排策略:不允许超过 个相同属性(类型/年代)连续出现,在保序前提下提升列表多样性。
- 保序性(Order Preservation) — 重排算法在满足约束下尽量保持原排序,高分仍靠前、仅微调位置,兼顾相关性与多样性。
- Pinia — Vue 官方推荐的状态管理库,以 Store 集中管理跨组件共享状态(如用户认证),状态变化驱动依赖组件自动重渲染。
- 防抖(Debounce) — 前端控制请求频率的技术:用户停止输入一段时间(本项目 300ms)后才真正发起请求,避免实时搜索刷爆 API。
- 单例模式(Singleton) — 在线资源加载的设计:进程级唯一实例,配合惰性加载,模型与词表只加载一次、被所有请求共享,避免重复加载与内存膨胀。
- 优雅降级(Graceful Degradation) — 模型不可用时退化为次优策略(如排序失败用召回分排序),保证服务高可用而非直接报错。
- 数据闭环(Data Loop) — 用户行为经前端采集回写后端与存储,更新特征后影响下一次推荐,使系统持续改进;前端是闭环的采集端。
- Docker Compose — 声明式多容器编排工具,用单个 YAML 描述所有服务及其依赖、网络与卷,一条命令启动完整系统。
- 多阶段构建(Multi-stage Build) — Dockerfile 技巧:先用构建镜像(如 Node)生成产物,再把产物拷入轻量运行镜像(如 Nginx),最终镜像不含开发依赖。
- 命名卷(Named Volume) — Docker 持久化机制:把容器数据存于宿主机具名卷,容器删除后数据不丢;有状态服务(PG/Redis/ES)必须挂载。
- 健康检查(Healthcheck) — 容器定期执行探测命令(如
redis-cli ping),连续失败才判不健康,供依赖服务等待其就绪,保障启动顺序。 - 服务名 DNS(Service-name DNS) — Docker 网络内用服务名(如
postgres)解析到容器 IP,是容器间通信的正确方式(不用localhost)。
Part 12 · 计算广告
12.1
- 计算广告(Computational Advertising) — 以最大化 ROI 为目标,对用户、上下文、广告三元进行匹配优化的技术与商业体系。
- OpenRTB — IAB 制定的实时竞价通信规范:标准化 Bid Request(询价,携带广告位/上下文/用户标识/底价)与 Bid Response(出价/素材引用/监测 URL)两类消息;出价与素材解耦是关键工程约束。
- 出资人(Sponsor) — 广告定义三要素之一,为广告投放付费、有明确商业诉求的广告主。
- 媒介(Publisher) — 广告定义三要素之一,承载广告、掌握用户注意力的媒体或产品。
- 受众(Audience) — 广告定义三要素之一,广告信息触达的目标用户群体。
- 品牌广告(Brand Awareness) — 注重长期影响与认知建立的广告类型,典型度量是曝光与认知度。
- 效果广告(Direct Response) — 以短期转化行为(点击、注册、下单)为诉求的广告类型。
- 广告有效性模型 — 描述广告产生效果的六阶段漏斗:曝光→关注→理解→接受→保持→决策,归入选择、解释、态度三个阶段。
- ROI(Return on Investment,投资回报率) — 广告投放的回报与投入之比,计算广告优化的核心目标。
- eCPM(effective Cost Per Mille) — 千次展示期望收益,由点击率与点击价值相乘得到,广告排序与流量价值评估的统一口径。
- CPM 市场 — 按展示付费的市场形态,点击率与点击价值的决策(与风险)全部交给广告主。
- CPC 市场 — 按点击付费的市场形态,点击价值由广告主出价判断,点击率由平台动态预估。
- CPA/CPS 市场 — 按行为/销售付费的市场形态,决策与风险全部归于平台,适合广告主转化流程高度一致的市场。
- 广告系统价值公式 — 广告系统价值 = 转化效率 × 计价机制 × 资源量 × 投放效率,理解广告技术演进的总纲。
- 广告网络(Ad Network) — 2.0 投放模式下聚合多媒体流量、卖人群不卖广告位的封闭中介系统,以 CPC 为主要计价方式。
- 程序化交易(Programmatic Trade) — 3.0 投放模式下经 DSP-ADX-SSP 完成的自动化、单次展示粒度的广告交易。
- 广告交易平台(Ad Exchange, ADX) — 用实时竞价方式连接广告与(上下文、用户)、按展示粒度竞价结算的交易中枢。
- 需求方平台(Demand-Side Platform, DSP) — 服务广告主的需求侧技术平台,提供定制化用户划分、跨媒体流量采购与 RTB 出价。
- 供应方平台(Supply-Side Platform, SSP) — 服务媒体的供给侧技术平台,核心功能是收益管理,统一优化多种变现方式。
- 数据管理平台(Data Management Platform, DMP) — 为网站提供数据加工与对外交易能力的平台,以定制化用户划分和统一数据接口为特征。
- 广告购买平台(Trading Desk) — 面向需求方、允许广告商跨广告网络采买与 ROI 优化的工具,常由代理公司孵化。
- 实时竞价(Real-Time Bidding, RTB) — 每次广告展示实时向多家 DSP 询价、价高者得的程序化交易机制。
- Cookie Mapping(用户身份匹配) — RTB 前置阶段,由 DSP 发起建立媒体 Cookie 与 DSP 用户 ID 对照表,Mapping 表存于需求方端。
- Ad Call(广告请求) — RTB 竞价阶段:ADX 广播询价请求,DSP 返回出价,最高者赢得展示。
- 担保式投送(Guaranteed Delivery) — 基于合约、约定展示量未完成需补偿的优先销售交易形态,以 CPM 结算、量优先于质。
- 优选(Preferred Deal) — 广告主按约定价格优先挑选流量、无需公开竞价的一对一议价交易方式。
- 网络优化(Network Optimization) — 媒体将流量交给广告网络整体变现的交易方式,属组合优化。
- 定向(Targeting) — 从广大受众中找到广告目标受众的技术,是受众与广告匹配度的专业叫法。
- 上下文定向 — 根据页面内容与场景信息匹配广告的定向技术,工程上以 Near-line 上下文系统实现。
- 行为定向 — 基于用户行为日志的定向技术,行为按信息强度排序且越靠近需求、越主动的行为越有效。
- 重定向(Retargeting) — 广告主提供受众信息、系统从供应方流量中找回这些已触达用户的系统定向技术。
- 个性化重定向(Personalized Retargeting) — 重定向的纵向延伸:对老用户推送商品粒度的个性化广告,相当于站外推荐引擎。
- 搜索重定向(Search Retargeting) — 重定向的横向延伸:把搜索过特定关键词的用户定向到广告主网站。
- 新客推荐(Look-alike) — 广告主提供种子用户,DSP 通过行为相似性在供应方受众中寻找潜在新用户的定向技术。
- 种子用户(Seed Audience) — 新客推荐中广告主提供的高价值目标人群样本。
- 信息流广告(Feed Ads) — 混排在用户阅读信息流中、形态与内容相似的广告形式,平衡广告效果与用户体验的正面典型。
- 植入式原生广告(Native Ads) — 融入产品内容与服务形态、与内容深度结合的广告形式。
- 点击价值(Click Value) — 一次点击带来的期望收益,与点击率共同构成 eCPM。
- 竞价行情预估(Bid Landscape Prediction) — DSP 预测流量竞价分布以决定采买策略的核心问题,其拿到的流量是出价的函数。
- 收益管理(Yield Optimizer) — SSP 的核心功能,统一优化优先销售、网络与 RTB 流量以最大化媒体收益。
12.2
- 广告主(Advertiser) — 出资购买广告并按最终效果反推单次广告价值的一方,是需求侧的决策主体。
- 媒体/供应方(Supply Side) — 拥有广告位与流量的内容或应用方,关心单位广告资源能产生多少收入。
- 效果广告(Direct Response) — 以短期转化行为为诉求的广告形态,供应方根据广告效果计算广告量,按效果计费、竞价交易。
- 品牌广告(Brand Awareness) — 注重长期品牌影响的广告形态,根据展示量计费,以合约方式交易,常见于核心 banner 等优质位置。
- CPT(Cost Per Time,包时段付费) — 按广告位占用时长(包月、包周)收费的模式,省心但计量粗糙,无法保障客户利益。
- CPD(Cost Per Day,包天付费) — 按天买断广告位的计费模式,多见于合约的品牌广告;对合作条件要求低,但长期不如 CPS 实时有效。
- CPM(Cost Per Mille,千次展示付费) — 按每千次展示收费的计费模式,公式为消耗/展现×1000,常见于 RTB,风险主要由广告主承担。
- CPC(Cost Per Click,每点击付费) — 按每次点击收费的计费模式,公式为消耗/点击,是广告主与平台风险的折中点,常见于关键词广告与 RTB。
- CPA(Cost Per Action,按行为付费) — 按注册、下单等用户行为收费的计费模式,点击率与价值皆动态,决策与风险归于平台。
- CPS(Cost Per Sales,按销售付费) — 按实际销售提成换算广告金额的计费模式,广告主规避费用风险,常见于网络联盟。
- dCPM(dynamic CPM,动态千次展示付费) — DSP 普遍采用的结算体系,每次 impression 的出价依据投放效果实时计算,对广告主按效果优化、与媒体仍按展示结算。
- flat CPM(固定千次展示付费) — 与 dCPM 相对,千次展示价格固定不变的传统 CPM。
- 消耗(Spend) — 广告主投放广告的花费,是 CPM、CPC、ROI 等公式的分子口径。
- CTR(Click-Through Rate,点击率) — 点击量与展现量之比,衡量一个广告在多次展现中用户的平均点击次数。
- CVR(Conversion Rate,转化率) — 下单量与点击量之比,衡量用户点击与最终下单之间的关系。
- ROI(Return On Investment,投资回报率) — 下单金额与消耗金额之比,衡量广告花费与带来成交额的回报关系。
- eCPM(effective/expected CPM,千次展示期望收益) — 每千次展示的期望收益;CPC 计费下等于 pCTR×bid×1000,CPM 计费下等于出价,是跨计费模式的统一排序度量衡。
- 担保式投送(Guaranteed Delivery, GD) — 基于合约的广告投送机制:约定展示量未完成需补偿、量优先于质、按 CPM 结算、由服务端决策。
- 在线分配(Online Allocation) — 把广告与 (Context, User) 流量的匹配建模为 Ad→(Context,User) 二部图优化,在满足各合约量的约束下分配展示,经典解法是构造对偶问题。
- 流量预测(Traffic Forecasting) — 对未来各定向流量规模的估计,可视为以广告为 Query、对 (u,c) 空间的反向检索问题,需对 u、c 分别处理。
- 独占要求(Exclusivity) — 合约销售中品牌广告主对曝光的排他性要求(如竞品排斥),进一步收紧在线分配的可行空间。
- 广告层级结构(creative/solution/campaign/advertiser) — 从创意、投放单元、广告计划到广告主的层级组织,用于新广告 CTR 的 back-off 先验估计。
- back-off(回退估计) — 统计缺失时逐级上退到更粗层级借用统计量的估计策略,用于新广告冷启动的 CTR 估计。
- 动态特征(Dynamic Features) — 在标签组合维度上聚合的点击反馈统计特征,响应快、对新组合 back-off 强,但在线存储与更新代价高。
- 在线学习(Online Learning) — 让模型随新数据流式更新以捕捉动态特性的方案,与动态特征构成「调模型 vs 调特征」的权衡。
- E&E(Exploration & Exploitation,探索与利用) — 为长尾 (a,u,c) 组合创造展示机会以累积统计量、从而更准确估计 CTR 的框架,需严格控制探索的量与有效性。
- ε-greedy — 以 ε 比例流量随机探索、其余利用当前最优的多臂老虎机策略。
- UCB(Upper Confidence Bound,上置信界) — 为每个候选计算期望收益的上置信界并选最大者的策略,选择次数越多上界越逼近真实期望。
- Contextual Bandit(上下文老虎机) — 用 arm 的特征矢量代替 arm 本身做决策从而降维的 E&E 方法,适合候选空间巨大的广告场景。
- GSP(Generalized Second Pricing,广义第二高价) — 胜者按下一名折算价格支付的竞价机制,简单易行、被在线广告系统广泛采用,但整体市场并非 truth-telling(详见 12.3)。
- 个体理性(Individual Rationality, IR) — 广告主支付不超过其出价的基本参与约束,如 GSP 支付价 ≤ 胜者 bid。
12.3
- 竞价机制(Auction Mechanism) — 规定广告坑位如何分配与计费的制度设计,由分配规则与定价规则两部分构成。
- 位置拍卖(Position Auction) — 多个广告主竞争多个仅有点击率差异的坑位的拍卖模型,期望价值 。
- 估值(Valuation) — 广告主对一次点击的真实价值判断,是其私人信息,平台不可见。
- 出价(Bid) — 广告主向平台申报的每次点击愿意支付的价格(CPC 口径)。
- 位置点击率(Position CTR) — 坑位 的点击率 ,位置越靠前越大,是坑位间唯一差异。
- 分配规则(Allocation Rule) — 机制中「谁赢哪个坑」的规则,竞价广告中通常为按出价(乘质量分)降序分配。
- 定价规则(Pricing Rule) — 机制中「赢家付多少」的规则,决定广告主是否愿意如实出价。
- 广义第一高价(Generalized First Price, GFP) — 按出价排序分配坑位、每人按自己出价支付的机制,无纯策略纳什均衡、市场震荡,已被淘汰。
- 纳什均衡(Nash Equilibrium) — 任何一方单独改变策略都无法获益的策略组合。
- 纯策略纳什均衡(Pure-Strategy Nash Equilibrium) — 每个参与者选定一个确定性策略构成的纳什均衡;GFP 不存在。
- 二价拍卖(Second-Price Auction / Vickrey Auction) — 最高出价者赢、按第二高出价支付的单坑位拍卖,如实出价是占优策略。
- 占优策略(Dominant Strategy) — 无论对手如何行动都最优的策略;二价拍卖中说真话即占优策略。
- 广义第二高价(Generalized Second Price, GSP) — 第 位广告主按下一名 eCPM 折算支付 、末位付保留价的机制,被在线广告系统广泛采用。
- 保留价(Reserve Price) — 平台设置的最低成交价,末位广告主或无竞争者时按其支付。
- 激励兼容(Incentive Compatibility, IC) — 如实报告估值是占优策略的性质:谎报不能提高效用。
- 个体理性(Individual Rationality, IR) — 参与拍卖不会使参与者效用为负,即支付不超过申报价值 。
- Truth-telling(如实出价) — 广告主按真实估值出价 的行为;VCG 整体市场满足,GSP 不满足。
- 对称纳什均衡(Symmetric Nash Equilibrium, SNE) — GSP 存在的稳定均衡,满足无妒忌性质。
- 无妒忌(Envy-free) — 均衡中没有人想与他人互换位置的分配性质:顶到他人位置需付他人价格,效用不增。
- VCG 机制(Vickrey-Clarke-Groves Mechanism) — 按参与者给其他人造成的外部性损害收费的机制,整体市场 truth-telling,单坑位退化为二价。
- 外部性(Externality) — 一个参与者的在场给其他所有参与者造成的福利损失,即「你不在场,其他人本可多赚多少」。
- 赢家诅咒(Winner's Curse) — 以虚高出价赢下超过自身估值的坑位而招致负效用的情形,一价拍卖下常见。
- 一价拍卖(First-Price Auction) — 赢家按自己出价支付的拍卖;2019 年前后被头部 ADX 在程序化公开竞价中重新采用。
- 头部竞价(Header Bidding) — 媒体在主拍卖前把流量同时发给多家需求方预竞价的技术,其普及是多级转售链路与一价回归的推手。
- 出价遮蔽(Bid Shading) — 一价拍卖下 DSP 基于赢得概率分布把出价压向「能赢的最低价」的出价策略,是一价时代的核心竞争力。
- 智能出价(Smart Bidding) — 平台代广告主出价(如 OCPC 按目标转化成本),把出价换算进排序模型的竞价产品形态。
12.4
- 智能出价(Smart Bidding) — 平台代广告主管理每次展示出价的产品形态:广告主只报目标(target CPA/ROI),出价由平台的价值估计、预算控制与机制适配模块联合决定。
- 转化出价(oCPC / oCPM) — 按转化目标出价的产品:出价公式为 ,oCPC 按点击计费、oCPM 按展示计费。
- 目标转化成本(Target CPA) — 广告主愿意为一次转化支付的目标成本,是出价栈中唯一由广告主直接输入的价值锚点。
- 价值出价(Value Bid) — 用 pCTR × pCVR × targetCPA 把转化目标折算成的单次展示期望价值,是下游 shading 与 pacing 的输入。
- 两阶段投放(Two-Stage Delivery) — oCPC/oCPM 的冷启动惯例:第一阶段沿用 CPC 出价积累转化数据,模型置信后切换到转化出价。
- 深度转化出价(Deep Conversion Bidding) — 把优化目标从激活推到激活后关键行为(次留/7 日付费/复购/绑卡)的出价形态;难点是标签滞后成熟带来的延迟反馈问题。
- LTV 出价(LTV Bidding) — 以用户生命周期价值替代单次转化价值作为出价锚点的形态: 通常拆成「留存概率 × 每期价值」两段建模再相乘,应对重尾稀疏分布。
- 预算平滑消耗(Budget Pacing) — 把日预算按时间进度均匀花完的控制问题,避免前置消耗错过晚高峰优质流量。
- 参照轨迹(Reference Trajectory) — pacing 的控制目标 ,即「消耗进度与时间进度同步」的直线。
- 概率节流(Probabilistic Throttling) — pacing 的一种实现:以概率 决定是否参与每次竞价,是 0/1 的硬门控(LinkedIn,KDD 2014)。
- 出价缩放(Bid Scaling) — pacing 的另一种实现:用乘子 缩放出价 ,保留参与度、牺牲单次竞争力。
- Pacing 乘子(Pacing Multiplier) — 预算控制器的操作量,经 sigmoid 压缩到 ,直接乘在出价上。
- PID 控制(PID Control) — 比例–积分–微分反馈控制器:P 即时响应误差,I 消除稳态偏差,D 超前抑制;广告 pacing 中 D 项因放大离散请求噪声被普遍砍掉,只留 PI。
- 对数比误差(Log-Ratio Error) — 误差形式 ,把偏离归一化为相对值,使不同预算规模的计划可共用同一套控制增益。
- 前馈补偿(Feedforward Compensation) — 在反馈控制之外,用可预测的扰动(如流量日内规律)提前调整操作量,Verizon DSP 的积分控制即配有前馈。
- 期望剩余(Expected Surplus) — 一价拍卖下出价 的期望利润 ,bid shading 的优化目标。
- 最低赢价(Minimum Winning Price) — 刚好能赢下一次拍卖的价格,其分布(CDF)决定赢率 。
- 赢价分布(Bid Landscape / Win-Price Distribution) — 最低赢价随流量变化的概率分布,bid shading 的核心估计对象;log-normal 对其长尾拟合最好。
- 删失数据(Censored Data) — 只观测到部分信息的样本:封闭拍卖中输掉的拍卖看不到真实赢价,需用生存分析处理。
- 生存分析(Survival Analysis) — 处理删失观测的统计方法,DDN 用它从「是否赢 + 赢时最低价」的不完全数据中估计赢价分布。
- 黄金分割搜索(Golden Section Search) — 无需梯度的区间极值搜索,每次迭代保留 0.618 区间;DDN 用它在毫秒级求出 surplus 峰值出价 。
- DDN(Deep Distribution Network) — Verizon Media 的分布估计网络(Zhou et al., KDD 2021):网络输出赢价分布参数,线上 surplus 提升 14.3%,日服务数千亿次请求。
- 分布鲁棒出价(Distributionally Robust Bidding) — 当估值与赢价分布估计噪声大时,用 KL 散度不确定性集做 max-min 优化的出价鲁棒化方法。
- 误差传导链(Error Propagation Chain) — 出价栈各模块串行耦合,上游预测(pCTR/pCVR)的偏差无损传导到最终出价的性质,是 12.5 校准问题的动机。
12.5
- 校准(Calibration) — 预测值与真实概率的一致性:,即打 分的样本约 为正。
- 判别力(Discrimination) — 模型把正例排在负例前面的能力,由 AUC 等指标度量,对分数的单调变换不变。
- 绝对精度(size-accuracy) — 预测值绝对大小的准确度,对精确出价、竞价稳定与混投公平性至关重要。
- 过度自信(Overconfidence) — 深度模型预测值系统性高于真实概率的普遍倾向(Guo et al., 2017)。
- 位置偏差(Position Bias) — 位置靠前带来的点击优势被误记为广告自身质量的偏差。
- 检验假设(Examination Hypothesis) — 点击 = 被看到 × 值得点击的分解假设:。
- 逆倾向加权(Inverse Propensity Weighting, IPW) — 按倾向分倒数对样本加权以还原无偏分布的去偏方法。
- 倾向分(Propensity Score) — 样本被分配到某位置/被选中的概率,IPW 的权重来源,常需随机流量估计。
- PAL(Position-bias-aware Learning) — 华为提出的结构化去偏框架:bCTR = ProbSeen(position) × pCTR(user, ad, context),训练联合、线上只用 pCTR 塔(Guo et al., RecSys 2019)。
- 级联模型(Cascade Model) — 假设用户从前往后顺序浏览、点击即停止、会话至多一次点击的位置建模方式,查看概率与前位内容相关。
- 样本选择偏差(Sample Selection Bias, SSB) — CVR 在点击子空间训练却在全曝光空间推理导致的分布不一致。
- 数据稀疏(Data Sparsity, DS) — 转化样本远少于点击样本(点击仅占曝光约 4%)造成的训练信号不足。
- ESMM(Entire Space Multi-task Model) — 阿里提出的全空间多任务模型:以 pCTCVR = pCTR × pCVR 在全部曝光样本上联合训练,同时解决 SSB 与 DS(Ma et al., SIGIR 2018)。
- pCTCVR — 曝光到转化的概率,等于 pCTR × pCVR,定义在全曝光空间、可直接监督。
- 隐式学习(Implicit Learning) — ESMM 中 CVR 塔无直接损失项、仅由 L_ctcvr 经乘积梯度更新的学习方式。
- 胜出偏差(Winner's Bias) — 竞价日志只记录赢家表现、输家无标签造成的选择偏差,需探索流量供给无偏信号。
- 探索流量(Exploration Traffic) — 刻意让本会输的广告偶尔赢以产生无偏反馈的流量分配策略。
- 延迟反馈(Delayed Feedback) — 转化标签在点击后数小时/数天才回流的标签晚到现象。
- 标签窗口(Label Window) — 校准取数的观察期口径(如 1 天点击、7 天转化),未成熟即取数必有偏。
- 可靠性图(Reliability Diagram) — 预测概率分桶 vs 桶内真实正例率的诊断图,落在对角线即校准完美。
- 期望校准误差(Expected Calibration Error, ECE) — 分桶后实际正例率与平均预测值之差的样本量加权平均。
- Platt scaling — 对模型分数拟合 logistic 变换(两个参数)的校准方法,适合小样本。
- 保序回归(Isotonic Regression) — 拟合自由形单调阶梯函数的校准方法,适合大样本、稀疏区易过拟合。
- PAVA(Pool Adjacent Violators Algorithm) — 保序回归的经典求解算法:反复合并违反单调性的相邻块并取均值。
- 先验修正(Prior Correction) — 负采样后用闭式公式 恢复真实基率的校准方法(Facebook ADKDD'14)。
- 负采样(Negative Sampling) — 训练时下采样负例以加速/平衡样本的技术,会抬高训练基率、需修正后使用。
- 分布漂移(Distribution Drift) — 流量结构、广告库与用户行为变化导致历史校准失准的现象。
- PCOC(Predicted-over-Posterior Click rate) — 预估 CTR 与后验 CTR 之比,越接近 1 越好。
- Cal-N — 多簇 PCOC 聚合得到的整体校准偏差度量。
- GC-N — 分维度加权的校准评估指标。
- SIR(Smoothed Isotonic Regression) — 阿里妈妈校准体系的起点:分桶 + 保序回归 + 线性缩放。
- Bayes-SIR — 在 SIR 上引入贝叶斯先验以解决冷启动与稀疏分桶不稳定的校准算法。
- RTW-BSIR — 在 Bayes-SIR 上叠加实时波动修正、对抗分布漂移的校准算法。
- PCCEM — 利用点击后短期信号预测长期转化、应对延迟反馈的校准算法,阿里妈妈 2018 年起线上部署。
- AdaCalib — 字段级(field-level)细粒度校准框架:保序函数族 + 后验统计自适应引导(Wei et al., SIGIR 2022)。
- observed-vs-predicted 护栏 — 线上持续监控「实际正例率 ÷ 预估正例率」、偏离 1 超阈值即告警重拟合的运维机制。
12.6
- 数据可观测性(Data Observability) — 广告平台能否直接观测到用户转化行为的程度,是决定平台优化深度的第二根轴。
- 闭环广告(Closed-loop Advertising) — 曝光、点击、下单、支付全链路都发生在平台域内、数据不离开平台生态的广告,也称内循环。
- 开环广告(Open-loop Advertising) — 转化发生在平台域外(App Store、品牌官网、线下门店)、平台须依赖回传才能获知转化的广告,也称外循环。
- 内循环 / 外循环 — 闭环/开环广告在业界(抖音、快手、Facebook)的通行别称。
- 半闭环 — 广告主只回传部分事件(如只回传激活、不回传付费)的折中形态,平台拿到不完整标签做部分优化。
- 深度转化出价 — 以付费、ROI、次留、7 日 ROI 等后链路行为为优化目标的出价,只有平台能观测这些行为时才可行。
- 浅层目标 / 深层目标 — 前链路(曝光、点击、激活、表单、注册)与后链路(付费、ROI、次留、7 日 ROI)两组优化目标,分别对应开环与闭环的能力边界。
- pDeepCVR — 「点击 → 付费/次留」的深度转化概率,位于转化漏斗更深处,样本更稀疏、延迟更高。
- 归因(Attribution) — 在广告行为链路中识别关键行为由哪个广告/渠道带来的过程。
- 归因模型(Attribution Model) — 决定转化功劳如何分配给各触点的分配规则,是约定而非客观事实。
- 最后点击(Last-click) — 把 100% 功劳给转化前最后一次触点的归因模型,移动端默认。
- 首次点击(First-click) — 把 100% 功劳给第一次触点的归因模型,用于度量漏斗顶部发现。
- 线性归因(Linear Attribution) — 所有触点均分功劳的归因模型。
- 时间衰减(Time-decay) — 越接近转化的触点分得越多功劳的归因模型,适合短周期意图驱动。
- 位置加权(Position-based) — 首尾触点多分、中间少分(U 型)的归因模型,兼顾发现与收口。
- 数据驱动归因(Data-driven Attribution) — 算法基于观测到的贡献自动分配功劳的归因模型,需大量转化数据。
- clickid — 媒体在广告触点(曝光/点击)时下发的唯一标识,用于后续转化回传时把转化绑定到具体广告。
- 转化回传 — 广告主通过 SDK/API 把设备 ID、clickid、时间戳回传给媒体、告知「该用户已转化」的过程。
- 兜底归因 — 拿不到设备 ID 时退而用 ip + ua 做模糊匹配的归因方式,精度较低。
- 自归因(Self-attribution) — 平台/媒体自行完成归因、宣称转化由自己带来的方式,多网络并跑时易重复计数。
- 非自归因 — 广告主自行匹配用户与媒体信息、独立完成归因的方式。
- 移动归因伙伴(Mobile Measurement Partner, MMP) — 中立第三方归因/分析平台(AppsFlyer、Adjust、Branch、Singular、Kochava),作为广告主与各广告网络之间的仲裁者。
- ATT(App Tracking Transparency) — 苹果 iOS 14.5 起的授权框架,App 访问 IDFA 须弹窗授权,opt-in 比例仅约 25%。
- IDFA(Identifier for Advertisers) — 苹果设备级的广告标识符,ATT 后大面积坍缩,是确定性归因赖以为生的唯一用户 ID。
- SKAdNetwork(SKAN) — 苹果的隐私保护安装归因框架,以聚合、随机延迟、群组匿名的方式回传转化数据。
- 群组匿名(Crowd Anonymity) — SKAN 的隐私机制,安装量低时回传更少信息,防止单个用户被反向定位。
- conversion value — SKAN 中 App 通过 updateConversionValue 上报的用户互动转化值,SKAN 4.0 引入粗/细两种。
- 三次回传窗口 — SKAN 4.0 的回传节奏:约 0–2 天、3–7 天、8–35 天,转化数据分批、带随机延迟回流。
- 层级 source identifier — SKAN 4.0 的 4 位分层来源标识(前 2 位活动、第 3 位位置、第 4 位屏位),随群组匿名级别升高返回更多位。
- Android Privacy Sandbox — Google 的无 cookie 归因方案,含 Attribution Reporting API 与 Topics API。
- Attribution Reporting API — Privacy Sandbox 中提供事件级与聚合归因报告、聚合报告带差分隐私噪声的组件。
- 差分隐私(Differential Privacy) — 向聚合统计注入校准噪声以保护个体隐私的技术,Privacy Sandbox 归因报告使用。
- 确定性归因 / 概率性归因 — 依赖设备级唯一标识的精确归因 vs 依赖聚合/模糊信号的统计归因,隐私浪潮推动前者向后者坍缩。
- 第一方数据(First-party Data) — 企业与用户直接发生、合法合规收集的数据,是跨 App 追踪受限后的战略方向。
- 建模估计(Modeling-based Estimation) — 用可观测部分(SKAN + 授权确定性)训练模型、外推填补「无法归因」缺口的估计方法。
- 归因窗口(Attribution Window) — 触点后多久内的转化才记功的协议参数,点击窗口常见 7 天、曝光窗口常见 1 天,窗口越长该渠道抢功机会越多。
- 幂等去重(Idempotent Deduplication) — 回传接收端按「设备 × 事件类型 × 去重键」做集合语义去重,防止网络重试导致的重复转化。
- 事件时间 vs 到达时间(Event Time vs Arrival Time) — 前者是转化真实发生的时刻(回传体携带),后者是平台收到的时刻;两者的差即延迟反馈问题本身,训练样本须按前者组织。
- Click Flooding(点击洪泛) — 大量伪造/低质点击抬高「被归因概率」的归因作弊,特征是点击密度异常、点击到安装间隔过短。
- Conversion Value 编码 — SKAN 下把想观测的漏斗进度压进 64 个 fine 值与三档 coarse 的信息压缩问题,如 fine 编码留存标志、coarse 编码付费金额分档。
- SKAN 侧建模管线 — 用同期 opt-in 确定性数据训练「聚合分布 → 真实漏斗」映射模型,把带噪延迟的 SKAN 回传还原成可优化信号的技术栈。
- 延迟反馈三族解法 — 重要性采样(Zhang CIKM 2016)、假负样本校正(Chen 2020)、流式 FTRL 数据纠错;选型取决于延迟分布形状与训练实时性。
- 浅层代理 + 深度校正 — 开环平台深度出价的真实形态:出价公式用浅层目标(pCTR × pCVR),再用回传深度数据周期性校准浅层目标与真实深度目标的映射。
- 倾向得分加权(Propensity Score Weighting) — 对「是否回传」这一选择行为建模并加权,缓解开环训练样本只来自回传广告主的选择偏差。
- 激励回传(Incentivized Postback) — 平台「用产品换数据」的机制设计:回传付费事件才解锁付费出价等深度出价能力。
- 增量测量(Incrementality Measurement) — 回答「不投广告转化是否照样发生」的因果测量,与归因(分账)互补,管预算决策。
- Geo 实验(Geo Experiment) — 按地域切分实验/对照、对照组完全不出广告、直接测增量转化的实验法,因果上最干净。
- 合成控制(Synthetic Control) — 用未投放的相似地域/时段合成反事实基线、估计投放期增量的准实验方法。
- 营销组合模型(Marketing Mix Modeling, MMM) — 用宏观时间序列回归把销售分解到各渠道投入的测量方法,不依赖用户级数据,隐私时代复兴。
- 「归因管分账、增量管决策」 — 归因用于渠道间结算分账,增量测量用于预算再分配决策的分工原则。
12.7
- 在线分配(Online Allocation) — 在满足量的约束的前提下,对每次广告展示实时决策,以优化产品整体收益的算法框架;离线规划 + 在线执行是其标准形态。
- 担保式投送(Guaranteed Delivery, GD) — 展示量合约对应的投放系统:合约约定定向人群与展示量,系统须保证到期足量交付,核心计算问题是带约束的在线分配。
- 排期系统(Scheduling System) — 管理 CPT 广告位合约的非个性化系统:素材按排期经 CDN 前端直投,无需服务端实时决策。
- 防天窗广告(House Ad / 兜底广告) — 动态广告服务超时或出错时,由 CDN 渲染的默认素材,保证广告位不空白。
- 二部图(Bipartite Graph) — 在线分配的问题建模:供给节点(标签相同的流量库)与需求节点(合约)之间的匹配结构 。
- 供给节点(Supply Node) — 二部图一侧的节点,代表所有标签都相同的一块流量库存,总量记为 ;节点数随定向条件组合呈几何级数上升。
- 需求节点(Demand Node) — 二部图另一侧的节点,代表一份广告合约,约定量记为 。
- 需求约束(Demand Constraint) — 分配合约的收益(或量)不低于约定值的约束 。
- 供给约束(Supply Constraint) — 每个供给节点分配出去的比例之和不超过 1 的约束 ,违反即超卖。
- 分配比例(Allocation Ratio) — 决策变量 :把供给节点 的多大比例流量分配合约 。
- AdWords 问题(带预算约束的出价) — CPC 竞价下给定各广告主预算、最大化市场收入的在线分配实例;其对偶变量是「流量对预算的边际价值」,是 pacing 乘子的理论原型。
- 流量预测(Traffic Forecasting) — 给定受众标签组合与 eCPM 阈值,估算未来时段可获展示量的技术;工程上用「反向索引」方案(文档=标签聚合的流量,查询=定向条件)。
- 频次控制(Frequency Capping) — 控制组合 在周期内的展示次数;客户端 cookie/SDK 与服务端内存缓存两种实现,是破坏展示可分性假设的主要因素。
- 对偶变量(Dual Variable) — LP 对偶问题中对应约束的变量:(合约稀缺度)与 (供给机会成本),其量级分别正比于合约数与供给节点数。
- 紧凑分配方案(Compact Allocation Plan) — 只保留合约级对偶变量 ( 级),经 KKT 条件恢复 与 的分配方案;无状态、多机零同步。
- 需求-供给比(θ, Demand-Supply Ratio) — ,衡量合约相对其全部候选流量的紧缺程度,同时出现在紧凑方案与 HWM 中。
- SHALE — 在线分配的原始对偶迭代算法:交替更新 与 求解对偶问题,支持增量插入新合约。
- 高水位算法(High Water Mark, HWM) — 工程启发性分配方案:按 降序确定合约优先级,逐层折减候选供给余量得到分配比例;线上按累积比例随机决策。
- 竞争比(Competitive Ratio) — 在线策略在最坏情形下能达到离线全局最优目标函数的 倍,则称其为 -competitive;在线分配的最优上限为 。
- Free Disposal — 超投无收益也无损失的假设,符合多数广告合约现实,是在线分配算法宽容性的来源。
12.8
- 受众定向(Audience Targeting) — 对广告 、用户 、上下文 三个维度提取有意义的特征(标签)的过程,是展示广告最核心的驱动力之一。
- 上下文定向(Contextual Targeting) — 类定向:根据用户当前访问的页面或请求参数(地域、频道、URL、关键词、主题)即时打标签。
- 行为定向(Behavioral Targeting, BT) — 类定向:根据用户一段时期内的网络行为历史,将用户映射到某个定向标签上。
- 定制化标签() — 针对特定广告主加工的用户标签(如重定向、新客推荐),标签数与广告主数成正比,适合由需求方在程序化交易中直接提供。
- 标签体系(Taxonomy) — 向广告主售卖的、预先定义且可解释的标签集合;效果与规模双指标要求它同时覆盖「泛而大」与「准而小」的两端。
- 半在线抓取系统(Semi-online Crawler) — 上下文定向的页面抓取方案:不做离线抓取,广告请求触发后才抓取打标,用缓存 + TTL 管理,允许暂时返回空标签。
- 弱一致(Weak Consistency) — 广告系统的业务特性:只要大多数决策最优,少量次优甚至随机决策可接受,是低成本系统设计的依据。
- 需求方驱动关键词(Demand-driven Keywords) — 从广告主描述中得到商业价值高的词表与 IDF,再与页面 TF 一起计算 TF-IDF 选取关键词的方法。
- 潜在语义分析(Latent Semantic Analysis, LSA) — 对文档-词矩阵做 SVD、保留主要奇异值的主题模型;两个变换矩阵不保证非负,直觉欠合理。
- 概率潜在语义索引(PLSI) — LSA 的概率化:以「文档选主题、主题生成词」的生成过程建模,可用 EM 分布式求解。
- 潜在狄利克雷分配(Latent Dirichlet Allocation, LDA) — 给 PLSI 的主题分布加 Dirichlet 先验的贝叶斯版本,噪声大或短文档下更稳健,常用吉布斯采样求解。
- 词嵌入(word2vec / Word Embedding) — 把词映射为稠密实数向量的表示学习方法;CBOW + 哈夫曼树(层次 softmax)把输出复杂度从 降到 ,是 embedding 思想的源头。
- embedding 打标 — 2026 年主流的标签加工路线:用表示模型(双塔/图 embedding)或 LLM 把内容映射为向量或结构化标签,已取代主题模型打标。
- 时间衰减法(Time Decay) — 行为累积方法 ,指数窗过滤原始行为,只需保存上一时间片状态,工程上优于滑动窗法。
- 滑动窗法(Sliding Window) — 设定窗长 、累加窗口内行为强度的累积方法,窗型为矩形,需保存窗内全部行为。
- 特征选择函数() — 把原始行为 映射到标签 上并给出强度的函数,是行为定向特征生成最关键的环节。
- 用户标签得分() — 行为定向 GLM 的线性打分 ,控制点击到达频繁性;线上按 递归更新。
- 人口属性预测(Demographic Prediction) — 以行为为输入预测性别、年龄等用户确定特点的分类任务;必须有拒识门槛,训练集质量比模型更重要。
- reach/CTR 曲线 — 行为定向的半定量评测工具:标签人群规模(reach)与该人群 CTR 构成的曲线,应单调下降,头部斜率体现鉴别力,最右端 CTR 固定为全量水平。
- AUC(见 12.5) — 衡量模型判别力(相对序)的指标;reach/CTR 曲线头部的陡峭程度是它在定向评测中的投影,进入算术的得分还需过校准。
12.9
- 广告检索(Ad Retrieval) — 从亿级广告候选中,在毫秒级约束下找出可参与本次竞价的少数广告的计算环节;是 eCPM 排序(12.2)之前的入场资格赛。
- 析取范式(Disjunctive Normal Form, DNF) — 广告定向条件的标准表示:若干个交集(Conjunction)的并,命中任一交集即命中该广告。
- Conjunction(交集) — DNF 中由「与」连接的一组赋值集;检索算法以它(而非整条广告)为单位建倒排索引。
- Assignment(赋值集) — 对单个标签的最小约束(属于或不属于某取值集合),如 age ∈ {3};size 只统计含「∈」的赋值集数目。
- 布尔表达式检索(Boolean Retrieval) — 在倒排索引上求值定向条件的检索方式:两层索引(Conjunction 倒排 + Conj→AD 辅助索引)加 size 分层剪枝,先取候选超集再做精确判定;纯「∉」型 Conjunction 挂在特殊键 Z 上兜底。
- 倒排索引(Inverted Index) — 从「键(标签/关键词)」指向「包含该键的文档列表」的数据结构;广告检索把它扩展为按 size 分层的 Conjunction 索引。
- size 分层剪枝 — 按 Conjunction 中「∈」赋值集数目分层建索引;请求标签数小于某层 size 时该层整体跳过,是布尔检索最有力的剪枝。
- 精确匹配(Exact Match) — 搜索广告关键词匹配的最严格档位:查询与竞价关键词完全一致才触发;与之相对的是短语匹配与广泛匹配(触发查询扩展)。
- 查询扩展(Query Expansion) — 搜索广告中把简短查询拓展为一组可竞价关键词的技术;三条思路为协同过滤、主题模型与历史 eCPM 效果挖掘,泛化过度会损害相关性。
- 广告放置(Ad Placement) — 搜索广告中确定北区/东区广告条数的决策:平均条数约束下的营收优化,可用用户点击率比值做个性化调整。
- 相关性检索(Relevance Retrieval) — 超长查询场景下以「查询-文档相似度」而非布尔匹配为目标的检索;要求评价函数线性且权重非负以支持快速上界剪枝。
- WAND 算法(weight AND) — Top-K 剪枝检索算法:预计算关键词贡献上界,累加超过堆阈值才精确评分,配合小顶堆维护当前最优 K 个结果;其「上界粗估 + 门槛正反馈」思想延续到粗排层。
- 语义召回(Semantic Recall) — 用 DNN 把查询/用户与广告映射到同一语义向量空间,以最近邻查找代替关键词匹配的召回方式;解决用词不同导致的匹配盲区。
- DSSM(Deep Semantic Similarity Model) — 以点击为弱监督、端到端学习查询与文档语义向量的深度模型:词嵌入 → 多层网络投影语义空间 → 余弦相似度 + softmax/按对排序损失。
- 双塔模型(Two-Tower Model) — 用户塔与物品塔各自独立编码为向量、在线只做向量内积的召回架构;DSSM/YouTube 模型的现代形态,标配 in-batch negatives 训练。
- 近似最近邻(Approximate Nearest Neighbor, ANN) — 接受一定召回率损失、换取毫秒级向量检索速度的最近邻查找技术总称,分哈希(LSH)、向量量化(PQ/HKM)、图(NSW/HNSW)三类。
- 局部敏感哈希(Locality-Sensitive Hashing, LSH) — 「原始空间越近、哈希越易同桶」的分治式 ANN:随机投影下同桶概率为 1−θ/π;扩召回用 LSH forest(换内存)或 multi-probe(换查询时间),工程上已被图索引取代但直觉仍是 ANN 的思想原点。
- HNSW(分层可导航小世界) — NSW 的分层版本:上层稀疏图快速导航、底层稠密图保精度;当前工业界最常用的 ANN 图索引,faiss/hnswlib 均有实现。
- IVF-PQ — 先用 K 均值粗聚类分桶(IVF)、桶内再做乘积量化压缩(PQ)的 ANN 索引;内存效率高,适合亿级以上候选池。
- 检索漏斗(Retrieval Funnel) — 候选量级逐级收窄的系统全貌:召回(10⁴~10⁵)→ 粗排(10²~10³)→ 精排(10¹~10²)→ 竞价(1~3 条展示),每一层在「缩小候选」与「提高打分精度」间交换;现代召回形态是 多路召回——布尔定向、语义向量、协同/行为、热门兜底并行各取 Top-K,合并去重后统一进入排序。
12.10
- 第一方数据(First-party Data) — 广告主自有渠道产生的数据(CRM、订单、官网访客行为),量小而语义最明确,是所有数据的「灵魂」。
- 第二方数据(Second-party Data) — 用户在媒体/广告平台上产生、由平台自己掌握的行为与投放数据,广告网络模式下指导投放的主力。
- 第三方数据(Third-party Data) — 不直接参与广告交易的数据提供方(中小媒体、数据公司等)拥有并提供流通的数据,量大数据质量参差。
- 用户标识(User Identifier) — 关联「哪些行为来自同一个用户」的基础,如 cookie、IDFA、Android ID/IMEI;身份是一串 0 前面的那个 1。
- 决策行为(Decision Behavior) — 转化与预转化(搜索、浏览、比价、加购等下单前动作),发生在广告主站内,兴趣指向最明确、价值最高。
- 半主动行为(Semi-active Behavior) — 分享、页面浏览等弱目的内容消费行为,把握兴趣领域但精度有限,数据量在各类行为中最大。
- Cookie 映射(Cookie Mapping) — 在一方同意的前提下,把不同域名体系下同一用户的 cookie 身份对应起来的技术;三方 cookie 退场后已成历史基建。
- 数据管理平台(DMP) — 把原始数据整理加工成可直接利用的用户标签并支持变现的产品;分第一方(托管加工收服务费)与第三方(加工售卖变现)两种模式。
- 客户数据平台(CDP) — 统一品牌自有触点(官网、App、CRM)数据为持久客户档案的一方数据基建,现代形态下取代了旧第一方 DMP 的大部分场景。
- 人群包(Audience Segment) — 按标签圈出的一组用户集合,是数据交易与受众定向的标准「商品单元」。
- 数据交易平台(第三方 DMP) — 聚合多方原始行为数据、按自有逻辑加工成标签后售卖变现并与数据提供方分成的产品,代表案例 BlueKai。
- Unified ID 2.0(UID2) — The Trade Desk 主导的开放身份框架,以哈希后的邮箱/手机号为根,替代三方 cookie 的跨域身份方案。
- 数据交易(Data Trading) — 标签经 ADX 中转、附加在竞价请求上按 CPM 计价、按 DSP 实际成交展示量交割的市场机制。
- 数据清洁室(Data Clean Room) — 互不可见明细的前提下做多方数据匹配与分析、只输出聚合结果(常叠加差分隐私)的合规协作环境,2020 年代数据协作的主流形态。
- 准标识符(Quasi-identifier) — 单独看无辨识力、组合起来却能定位到具体人的属性集合(如年龄+城市+职位),即使不含 PII 也有高泄露风险。
- K 匿名(K-Anonymity) — 通过准标识符泛化,使数据集中每组准标识符实例都能找到 K 条与其相同的;对极稀疏的行为数据不适用。
- 差分隐私(Differential Privacy) — 对数据集做适度修改,在尽量少损失查询准确率的前提下使隐私泄露风险最低的技术。
- 需求方数据安全(Demand-side Data Security) — 广告主第一方数据(如访客集合)在 RTB 中被平台或对手获取利用的风险,典型手法是合并访客集合打模糊标签倒卖。
- GDPR — 欧盟《通用数据保护条例》(2018 生效):敏感数据清单、明确同意、访问/被遗忘/限制处理/携带四项权利,罚则上限为 2000 万欧元与全球年营业额 4% 中的较高者。
- PIPL — 中国《个人信息保护法》(2021 年 11 月施行):确立知情同意、最小必要、可撤回同意等原则,并区分敏感个人信息。
12.11
- 程序化创意(Programmatic Creative) — 在投放时由程序把推送广告的关键原因(地域、搜索词、单品等)在线拼装进创意的优化方式,前提是广告基本诉求保持稳定。
- 点击热力图(Click Heatmap) — 把创意各位置被点击的密度可视化的工具,既用于半定量地指导创意迭代,也可通过分布形态(过于均匀/集中)甄别机器刷量。
- A/B 测试(A/B Testing) — 从真实流量中切出对照与实验两组分别运行原方案与新方案、以线上指标裁决优劣的实验方法。
- 实验框架(Experimentation Framework) — 支撑 A/B 测试的线上系统,负责流量切分、参数下发与指标收集,是广告系统进化速度的基础设施。
- 实验层(Layer)与域(Domain) — 按系统模块(检索/排序/展现)划分的实验参数容器为层,层内按 user ID 哈希切出的流量子集为域;一个用户的所有请求固定落在同一域中(层内互斥)。
- 分层实验(Layered Experimentation) — 利用模块间相对独立性扩展实验容量的框架:层内互斥、层间正交、预留非重叠域做跨层联合调参、配套发布层灰度放量。
- 正交(Orthogonality) — 不同实验层的流量切分彼此独立,同一份流量可被多层重复使用,实验容量随层数线性增长。
- AA 实验(AA Test) — 两组按完全相同配置运行的对照实验,用于验证切分均匀与日志口径一致;AA 跑出显著差异说明实验框架本身有偏。
- 广告监测(Ad Monitoring) — 需求方委托独立第三方对展示、点击或转化做核实性度量的服务(约占品牌投放预算 1%);核心载体是拼装广告/媒体/用户三方信息的 监测 URL。
- 品牌安全(Brand Safety) — 保证广告不出现在损害品牌形象的内容上的诉求,由 广告投放验证 (发现不安全内容即停投换创意,工程核心是 iframe 穿透取顶层 URL)实现。
- 可见性(Viewability) — 广告展示实际被用户看到(发生渲染)的程度验证;现代由 MRC 等标准的面积/时长双阈值定义,是品牌结算口径之一。
- 虚假流量作弊(Non-Human Traffic, NHT) — 展示、点击或转化本身被伪造的作弊类型,是 CPM/CPC 广告作弊的主流,按手段又分机器作弊与人工作弊。
- 归因作弊(Attribution Fraud) — 把其他渠道的流量或自然流量记在自己名下的作弊类型,常见于伪造转化成本高的 CPA/CPS 广告。
- 点击滥用(Click Spam / Click Flooding) — 对大量用户伪造点击、坐等其自然下载被归因到自己渠道的手法;铁证是 CVR 低 1–2 个数量级、点击-转化时间分布近似均匀。
- 点击注入(Click Injection) — 利用 Android 安装广播在应用安装瞬间补发点击、抢归因后续激活的手法;特征是 CVR 异常高、点击到激活间隔极短。
- Cookie 填充(Cookie Stuffing) — CPS 联盟广告中通过隐藏请求在用户不点击的情况下静默打上来源 cookie、劫持自然转化的归因作弊。
- 流量劫持(Traffic Hijacking) — 网络底层服务提供者在无权投放处强行投放或篡改创意/落地页的准作弊(信道弹窗、创意替换、搜索重定向、落地页来源劫持);前三种损媒体,来源劫持损广告主。
- 设备农场(Device Farm) — 真人持真机批量伪造浏览-点击-转化的人工作弊形态,各维度数据接近真实,需靠设备聚集度与关联网络识别。
- 设备指纹(Device Fingerprint) — 由硬件与环境特征拼出的设备唯一标识,用于跨 IP/cookie 追踪作弊源与建立设备信誉分。
- 图分析反作弊(Graph-based Fraud Detection) — 把设备、IP、账号、支付路径连成关联网络,利用作弊团伙的高聚集结构识别单条记录无法伪装的群体特征。
12.12
- 合约广告(Agreement Advertising) — 以合同约定量的展示交付的广告交易形态:人群、展示量与单价写进合同,履约责任在供给方;与按市场博弈出清的竞价广告相对。
- 广告位合约(Position Contract) — 最早的在线广告售卖方式:约定某时间段内某些广告位固定投送指定广告主的广告,无法按受众投放,强曝光位上仍有品牌冲击与竞品排他的溢价价值。
- CPT(Cost per Time) — 按时长计费的广告位合约计费模式,典型按时段整买;供需双方技术成分都低,靠代理公司人工媒介采买。
- CPD(Cost per Day) — 按天计费的广告位售卖形态,今天开屏等品牌资源的排期合约仍沿用这一口径。
- 轮替售卖(Rotation) — 把同一广告位的连续访问依次标上循环的轮播顺序号(如 {1, 2, 3, 4}),相同序号的展示作为虚拟广告位售出;用于独占库存不足但广告主要求确定展现规则时。
- 轮播顺序号随机起始 — 轮替售卖的关键细节:某用户第一次展示的顺序号按相等概率从所有序号中随机选取再累加循环,以保证各轮播分到的流量一致。
- 广告排期系统(Scheduling System) — 合同确定后自动按排期执行投放的非个性化工具(如 DFP、好耶、百度广告管家),叠加动态分配与 RTB 后接近供给方平台。
- 防天窗广告(兜底素材) — 动态广告服务超时或出错时由 CDN 渲染的默认素材,保证广告位不空白;工程细节见 12.7.0。
- 展示量合约(Inventory Contract / GD 合约) — 按约定受众条件售卖展示总量并按约定单价计费的合约,即担保式投送;未足量交付可能触发媒体赔偿。
- 担保式投送(Guaranteed Delivery, GD) — 展示量合约对应的投放系统与售卖市场的统称,「担保」即量的约定;算法核心是在线分配(见 12.7)。
- 受众定向售卖(Audience-based Selling) — 以人群标签为标的拆分广告位流量售卖的模式:数据首次直接参与售卖,催生结构化层级标签体系作售卖目录。
- 人群包(Audience Package) — 由标签组合圈定的可售人群流量单元;人群包之间普遍交叠,是保量分配复杂性的来源。
- 售卖区域(Selling Geo) — 合约中约定的地域定向条款;地域是最基础、所有广告系统都必须支持的售卖维度。
- 起投量(Minimum Commit) — 合约售卖目录准入的最小人群日流量门槛;人群规模低于它的标签无法保量售卖,应打包或下放竞价。
- 流量预测(Traffic Forecasting) — 对函数 (人群标签组合 × 出价)的估计,支撑售前指导、在线分配与出价指导三个用途;工程方案见 12.7.2。
- 流量塑形(Traffic Shaping) — 通过调整用户产品导流(如首页链接)主动影响各人群流量分布,以利于合约达成的产品策略。
- 橱窗效应(Showcase Effect) — 长期独占优质广告位对品牌价值与转化效果的持续塑造作用,是独占式售卖的核心卖点之一。
- 竞品排他(Category Exclusivity) — 合约向广告主承诺同页面不出现竞品广告的附加服务,是位置售卖高溢价的来源。
12.13
- 原生广告(Native Ads) — 将商业化内容与非商业化内容统一生产或混合排序的产品方向,也称「内容即广告」;软文、搜索广告、信息流广告各反映其一个侧面。
- 信息流广告(Feed Ads) — 满足两个条件的广告形式:广告与内容以联动方式交互;被广告区隔开的各部分内容之间没有直接关联。产品本质上可视为多位置、放置自由的竞价广告。
- 内容即广告(content as ad) — 原生广告的产品理念表述:广告不再独立于内容,而是作为内容生产与排序的一部分。
- 开屏广告(Splash Ad) — 应用打开加载时展示的全屏广告;用户等待时无明确任务因而反感度低,品牌价值高,多以合约方式售卖。
- 插屏广告(Interstitial Ad) — 出现在应用暂停时、类似视频暂停广告的形式;与移动横幅一样点击率虚高、转化相对较差。
- 推荐墙(Offerwall) — 面向应用下载推广的直接推送类广告形式,可类比站外推荐。
- 积分墙 — 用户下载并激活应用后获得可兑换虚拟物品积分的激励广告;点击与激活数据好但后续活跃差,曾用于应用冲榜与游戏开服。
- 激励视频(Rewarded Video) — 用户观看一段不可跳过的 15–30 秒视频后获得虚拟奖励的原生广告;只奖励观看行为、不刺激下载,因而是用户质量不受损且 eCPM 最高的原生形态。
- 表现原生(Expressive Native) — 将广告的展示风格与样式做得与内容一致的诉求,要求由媒体控制广告展示形式(含字体、颜色等适配)。
- 场景原生(Scene Native) — 将广告投放决策逻辑与内容生产保持一致、按用户场景与意图触发的诉求;搜索广告在表现与场景两方面都原生。
- 植入式原生广告 — 媒体以结构化查询(如「类型=酒店;地点=拉萨」)向广告平台请求结构化付费内容、并按模板拼装渲染的原生广告平台机制。
- 结构化付费内容 — 原生广告平台广告库存的形态:不是成形创意,而是分行业的结构化字段素材,供媒体拼装成与内容无缝融合的创意。
- oCPX — 计费与出价相分离的智能投放模式:计费仍按 CPM/CPC,广告主向平台表达转化出价,由平台承担预估与竞价换算,降低中小客户的投放门槛。
- 转化追踪(Conversion Tracking) — 从展示、点击到转化事件的记录与回传链路;移动端各行业转化统一收敛为应用市场下载,使转化率预估可跨行业共同建模。
- 混排(Mixing) — 自然内容与广告作为统一候选池、按可比较分数竞争展示位置的决策问题;信息流广告按同一准则统一排序的演进方向即混排问题的起点。
- 信息流密度(S/K) — 控制广告位置的两个参数:S 为首条广告出现的位置,K 为两条广告的间隔;在平均广告条数约束下调整 S/K 以优化整体点击率。
- 原生 RTB(Native RTB) — 原生广告与程序化交易的结合形态;适用于用户意图不明确、不要求按意图触发的原生场景(如社交信息流),而意图明确的搜索类原生不宜开放 RTB。
- 预算表达模式 — 广告主只设定每日预算、由平台将其均匀消耗并倒算出价的「傻瓜式」竞价模式;偏离实话实说原则,倒算出价高于真实转化价值时可能亏投。 术语表覆盖上篇(Part 1–5)、下篇(Part 6–11)与专题(Part 12 计算广告)全书内容。_
Word2Vec 专题附录
📝 为何独立成篇: 2.2 向量召回 (I2I) 的 2.2.1 只讲清了 Skip-Gram 的直觉与它在推荐里的迁移。本附录补全被略去的部分——CBOW 架构、中心词/上下文双向量表的结构细节、负采样的精确数学形式、以及词向量运算(类比)性质——让你在使用 Item2Vec / EGES / Airbnb 之前,先吃透底层引擎。
Word2Vec 的目标很朴素:用 大量无标注文本 ,给每个词学一个 低维稠密向量 ,使得:
- 语义相近的词,向量在空间中也相近;
- 词与词之间的关系可以通过 向量运算 反映出来。
这套表示可以直接喂给文本分类、机器翻译、信息检索等下游任务——而在推荐里,它被「结构同构」地迁移成了 Item2Vec。
1. 动机:从 one-hot 到稠密向量
早期最直接的做法是用 one-hot 编码 表示词:词表大小为 ,第 个词就是一个第 位为 1、其余为 0 的 维向量。它直观,却有三个致命问题:
| 问题 | 说明 |
|---|---|
| 维度灾难 | 常达百万级,向量又高又稀疏 |
| 无法表达语义 | 任意两个不同词的 one-hot 内积都为 0,「猫」和「狗」被当成毫不相干 |
| 无法表达语法 | 单复数、时态等关系完全丢失 |
我们需要一种 既低维、又能承载语义/语法信息 的表示——这正是 Word2Vec 要解决的。
2. 分布假说与上下文窗口
Word2Vec 的理论根基是语言学的 分布假说 (Firth, 1957):
「You shall know a word by the company it keeps.」 一个词的意义,由它常伴随出现的词决定。
模型遍历语料中的每个词,通过调整词向量,使「预测的上下文」尽量逼近「语料中真实的上下文」。具体来说,若中心词 在位置 ,其上下文为窗口 内的词 。
3. 两种架构:Skip-gram 与 CBOW
Word2Vec 包含两个镜像对称的模型。在 2.2.1 里我们只用了 Skip-Gram,这里把 CBOW 也补上。
3.1 Skip-gram:用中心词预测上下文
给定一个中心词,模型预测其上下文词出现的概率。对窗口内上下文词 ,条件概率为
其中 是词 的向量表示, 是词表大小。遍历整个语料,似然函数为
3.2 CBOW:用上下文预测中心词
CBOW(Continuous Bag of Words)方向相反:把上下文词 平均 后,预测中心词。
💡 该用哪个? 推荐场景几乎都用 Skip-gram。原因有二:① 它对低频/长尾词更友好(每个上下文Pair都提供独立监督信号);② 它天然适配「用户行为序列」这种变长、稀疏的输入,可直接做序列建模。CBOW 因对上下文取平均,在推荐里会抹掉序列顺序信息。
4. 模型结构与双向量表
上面的条件概率公式里藏着一个 极易误解的细节 :中心词向量 与上下文词向量 并不在同一个向量空间里。
以 Skip-gram 为例,设向量维度为 ,则存在 两张 向量表:
- 中心词向量表
- 上下文词向量表
前向计算流程:
- 输入中心词的 one-hot 表示 ;
- 查表得到中心词向量 ;
- 与上下文向量表第 行相乘,得到 Softmax 的输入;
- 经 Softmax 输出上下文词概率。
⚠️ Common Mistakes in Word2Vec 把 (来自 )和 (来自 )当成同一空间里的向量直接比距离。它们来自两张不同的表,只有训练完成后通常把两张表相加/平均得到的「最终词向量」才可用于相似度计算。
5. 负采样:让 Softmax 变得可计算
直接算第 3/4 节的 Softmax 分母,需要遍历整个词表 (百万级),代价不可接受。Word2Vec 用 负采样(Negative Sampling) 把多分类问题拆成多个二分类问题。
以 Skip-gram 为例,原目标被替换为:
其中 是 sigmoid, 为负样本数量, 是负采样分布。原论文取
💡 直觉: 第一项希望「真实上下文词对」的相似度越来越高(抬高正样本);第二项希望「随机采样的负样本词对」的相似度越来越低(压低负样本)。由 sigmoid 单调性可知,这与最大化原始似然 的目标一致,却避免了对整个词表求和——复杂度从 降到 。
⚠️ Common Mistakes in Word2Vec 以为负采样只是「提速技巧」、不影响语义。事实上,负样本分布 的 次方刻意上抬低频词成为负样本的概率,让模型对罕见词也能学到区分性向量——这对推荐里的长尾物品尤为关键。
6. 词向量运算:类比性质
Word2Vec 最迷人的发现是:训练出的向量空间里, 语义关系可以用向量加减表达。最经典的例子:
这意味着「王 − 男 + 女 ≈ 后」这种类比关系被编码进了几何结构。在推荐里,类似性质表现为「物品 A 与物品 B 的差别,约等于物品 C 与某物品 D 的差别」——这正是后续语义 ID、向量检索能做「可计算类比」的理论底气。
7. 从 Word2Vec 到推荐:Item2Vec 的桥接
把 Word2Vec 迁移到推荐,只需做一次 结构同构替换 (详见 2.2.1):
| 文本世界 | 推荐世界 |
|---|---|
| 词语 | 物品 |
| 句子 | 用户交互序列 |
| 词语共现 | 物品被同一用户交互 |
替换后:
- Skip-gram + 负采样 → 直接成为 Item2Vec 的训练原型;
- 学到的物品向量 → 近邻检索即可实现 I2I 召回;
- 第 4–5 节的双向量表、负采样分布等机制,原封不动地支撑起 EGES、Airbnb 等工业级变体。
💡 一句话收口: Word2Vec 的引擎(Skip-gram + 双向量表 + 负采样)是 I2I 向量召回的方法论基石;推荐领域的所有改进,都只是在「如何构造序列」和「如何定义正负样本」上做文章。
本章小结
- Word2Vec 用 分布假说 把「共现」学成「稠密语义向量」,解决了 one-hot 高维、稀疏、无语义的三大缺陷。
- 两大架构 Skip-gram (中心→上下文)与 CBOW (上下文→中心),推荐中几乎总用 Skip-gram。
- 结构上有 两张向量表 (中心)与 (上下文),分属不同空间,最终向量需合并后使用。
- 负采样 用 个二分类近似全词表 Softmax,并通过 上抬低频词,是工业可行性的关键。
- 词向量具备 类比运算 性质,为语义 ID 与向量检索提供理论支撑。
- 通过「词→物品、句子→行为序列」的同构替换,Word2Vec 直接成为 Item2Vec 与后续 I2I 方法的引擎。
🔗 前后关联
- 前置: 2.2 向量召回 (I2I) 的 2.2.1 把本附录作为「序列建模理论基础」简要引用;读完本附录再回看,会更清楚 Item2Vec / EGES / Airbnb 为何那样设计。
- 后继: 2.3 双塔模型 (U2I) 用「用户塔 + 物品塔」的稠密向量做召回,与这里的「物品稠密向量」思路一脉相承;6.4 Codebook 量化与语义 ID 则是把「离散词 → 连续向量」反过来做成「连续向量 → 离散语义 ID」,可对照理解。
Practice Problems
Problem A.1 — 双向量表误区 🟢 Easy
有人说:「Word2Vec 里中心词 和上下文词 的向量都在同一个 维空间,直接算余弦相似度就行。」这句话哪里错了?
Approach: 回看第 4 节—— 来自 , 来自 。
答: 错在认为两者同空间。实际上中心词向量表 与上下文向量表 是两张独立参数表,对应的向量分属不同空间;直接比距离是无效的。训练后通常把两表相加/平均得到最终词向量,才能用于相似度计算。
Problem A.2 — 负采样缩放 🟡 Medium
负采样分布用 而非直接用词频。若某词出现 16 次、另一词出现 81 次,分别计算它们在 次方后的相对权重比(即 ),并说明这个设计对低频词的影响。
Approach: ;。
答: 相对权重比 。注意词频比是 ,经过 次方后差距被 压缩 (5.06→3.375),等于 上抬了低频词 成为负样本的概率——让模型对罕见词也学到区分性向量,缓解长尾问题。
Problem A.3 — 同构迁移 🔴 Hard
把 Word2Vec 迁移到推荐做 Item2Vec 时,为什么「用户交互序列 = 句子」这个映射是结构同构、而非简单类比?请从训练目标(Skip-gram + 负采样)的角度说明,并指出一个原书 2.2.1 提到的、Item2Vec 相对原版 Word2Vec 的 关键简化。
Approach: 同构指「输入单元 + 共现结构 + 训练目标」三者一一对应;关键简化在 Item2Vec 把用户历史当 无序集合 而非序列。
答: 同构体现在:词→物品、句子→用户行为序列、词共现→同用户交互,且 Skip-gram 的 + 负采样目标函数 形式完全不变 ,只是把文本语料换成行为序列语料。关键简化:原书指出 Item2Vec 默认把每个用户的交互历史当成 无序集合 (忽略时间顺序),而原版 Word2Vec 严格依赖滑动窗口内的有序上下文——这是它和文本版最核心的差异。