想象你经营着一家开了二十年的街角书店。店里两位店员性格完全不同:老店员记性惊人,张先生每周三来,她脱口而出“老规矩,科幻加军事两本”,从不解释为什么——这是“记忆”;年轻店员不爱背搭配,却爱观察,她发现张先生喜欢硬核设定、中国作者,于是斗胆推荐一本他从没买过的《遗落的南境》——这是“泛化”。 但两人单独干活都有毛病:老店员遇到新顾客就哑火,年轻店员面对“周三+雨天+老主顾”这种具体场景又容易跑偏。聪明的店主让两人坐进同一间办公室:老店员先报“老规矩”,年轻店员再补一句“试试新品”,最后由店主综合意见拍板。 这就是 Google 在 2016 年提出的 Wide&Deep 模型——把记忆与泛化焊在一起的深度推荐架构。它先在 Google Play 应用商店大获成功(在线安装量提升 3.9%),随后成为 DeepFM、DCN 等一系列深度推荐模型的范式基础。如今,几乎所有主流推荐系统里,都能看到这对“老店员与新店员”搭档的影子。

岗位关联

理解 Wide&Deep 是踏入深度推荐系统的“第一块积木”:你将真正看懂记忆与泛化如何分工协作,并以此为起点读懂 DeepFM、DCN 等后续模型的演化脉络。

目录
  1. 可视化演示
  2. 模型背景与动机
  3. Wide宽模型与记忆
  4. Deep深模型与泛化
  5. 联合训练架构
  6. 特征工程与输入
  7. 训练与优化
  8. 业界影响与演进
  9. 应用场景与实战
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。

本节配有交互动效(进入视口后自动加载,约 3KB)。

系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T

模型背景与动机

回到那家书店:老店员的死记硬背让她在熟客面前百发百中,可新顾客进门时她只能干瞪眼;年轻店员善于观察规律,但面对“这位顾客三个月没来、上次买的是童书”这种具体场景,又常常猜错。两个人单独干活,都撑不起一家书店。

推荐系统面对的是同样的困境。在应用商店里,系统要预测“用户会不会下载某个 App”,输入大多是稀疏的 0/1 特征,比如“是否安装过《地铁跑酷》”“是否安装过《部落冲突》”。这些特征组合起来数量惊人——用户装过几百个 App 的可能组合是指数级的,稀疏得可怕。如果只靠死记硬背,没见过的新组合就束手无策;如果只靠泛化,那些“装了 A 又装 B”的强规律又容易被忽略。

Google 团队在 2016 年提出了 Wide&Deep 模型,并部署到 Google Play 应用商店:Wide 部分负责记忆高频共现,Deep 部分负责泛化学习,两者联合训练。实验结果令人振奋——在线安装量提升了 3.9%。这个数字背后,是“记忆+泛化”这一对看似矛盾的能力第一次被优雅地焊在了一起。

这个模型的短板很明显:它只会“独立地”看待每个特征,不会自动组合“装了 A 又装 B”这种共现信号。于是,Wide 部分要登场了——它要给这位线性模型装上“交叉记忆”的翅膀。

P(Y=1∣x)=11+e−(w⊤x+b)\displaystyle P(Y=1|\mathbf{x}) = \frac{1}{1 + e^{-(\mathbf{w}^{\top}\mathbf{x} + b)}}
这是推荐系统最基础的逻辑回归模型——Wide 部分的“前身”。它把每个特征当成独立信号,加权求和后压成一个 0 到 1 的概率。
  1. 特征向量每个维度表示一个特征是否出现,比如“是否安装过某款 App”。
    x=(x1,x2,…,xd)⊤\mathbf{x} = (x_1, x_2, \ldots, x_d)^{\top}
  2. 权重向量表示每个特征对最终下载概率的影响强度,可正可负。
    w=(w1,w2,…,wd)⊤\mathbf{w} = (w_1, w_2, \ldots, w_d)^{\top}
  3. 线性加总把所有特征贡献累加,得到原始得分——对应老店员“记得每本书的权重”。
    w⊤x+b=∑i=1dwixi+b\mathbf{w}^{\top}\mathbf{x} + b = \sum_{i=1}^{d} w_i x_i + b
  4. 逻辑压缩把任意实数得分压到 0~1 区间,作为“会下载”的概率。
    σ(z)=11+e−z\sigma(z) = \frac{1}{1 + e^{-z}}

Wide宽模型与记忆

老店员最强的能力,是把“张先生+科幻+军事”这样的固定搭配直接刻进脑子里。她不需要理解为什么,只需要在张先生进门时准确报出那两本书。Wide 模型做的就是这件事:用线性模型直接记住“哪些特征组合经常一起出现”。

Wide 部分本质上是一个线性模型,但它有一个关键设计——人工构造的交叉特征。所谓交叉特征,就是把两个或多个原始特征“乘”在一起:只有这些特征同时为 1 时,交叉特征才为 1。比如“装了《地铁跑酷》× 装了《天天酷跑》”这个交叉特征为 1,就代表用户同时装过这两款跑酷游戏。模型会给这个组合学一个独立权重,相当于老店员记下“这两款游戏经常被一起安装”。

这种设计让 Wide 部分拥有了“记忆共现模式”的能力:它对稀疏的高频组合非常敏感,训练快、可解释性强。但硬币的另一面是,它永远无法回答“没见过的组合”——如果某个用户只装了 A 没装 B,而模型只记住了“A×B“这个交叉特征,那它对这位用户就束手无策。这正是”记忆”的代价:记住的越具体,泛化就越差。

老店员靠着一本二十年积累的“熟客账本”打天下,Wide 部分靠的则是这份人工设计的“交叉特征账本”。账本越精,记忆越准——但账本上没写的组合,它永远答不上来。

ywide=wwide⊤ [x, ϕ(x)]+b其中ϕk(x)=∏i=1dxicki, cki∈{0,1}\displaystyle y_{\text{wide}} = \mathbf{w}_{\text{wide}}^{\top}\,[\mathbf{x},\ \boldsymbol{\phi}(\mathbf{x})] + b\quad\text{其中}\quad\phi_k(\mathbf{x}) = \prod_{i=1}^{d} x_i^{c_{ki}},\ c_{ki}\in\{0,1\}
宽模型的输出 = 原始特征与交叉特征拼接后的线性加权。交叉特征 φ 只有当组合内所有特征都出现时才为 1,这正是“老规矩”的数学表达。
  1. 拼接向量把原始特征与手工构造的交叉特征拼成一个长向量。
    [x, ϕ(x)]=(x1,…,xd,ϕ1,…,ϕm)[\mathbf{x},\ \boldsymbol{\phi}(\mathbf{x})] = (x_1,\ldots,x_d,\phi_1,\ldots,\phi_m)
  2. 交叉特征对一组特征求乘积——所有特征都为 1 时结果才为 1,像老店员记“同时满足几个条件的熟客组合”。
    ϕk(x)=∏i=1dxicki,cki∈{0,1}\phi_k(\mathbf{x}) = \prod_{i=1}^{d} x_i^{c_{ki}},\quad c_{ki}\in\{0,1\}
  3. 独立权重每个交叉组合学一个专有权重,强化共现记忆。
    wwide(k)=模型为第 k 个交叉特征学到的权重w_{\text{wide}}^{(k)} = \text{模型为第 }k\text{ 个交叉特征学到的权重}
  4. 线性输出线性模型把这些加权贡献相加,得到 Wide 分支的原始分数。
    ywide=∑iwixi+∑kwkϕk+by_{\text{wide}} = \sum_{i} w_i x_i + \sum_{k} w_k \phi_k + b

Deep深模型与泛化

年轻店员则完全不同。她从不背账本,而是站在门口观察每一位顾客:穿着、谈吐、在科普区停留的时间、拿起又放下的书……她把这些零散线索综合起来,形成对一个人口味的“感觉”。这种感觉让她敢推荐一本顾客从没买过的书——这就是泛化。

Deep 部分的运作方式异曲同工。它先把稀疏的 0/1 特征映射成稠密的向量——这叫 Embedding。比如“装了《地铁跑酷》”不再是一个孤零零的 1,而是一个 32 维的向量,向量中每个数字都蕴含“这款游戏是什么风格、哪些用户喜欢”的信息。然后这些稠密向量被送入多层全连接网络,每一层都在做特征组合:第一层组合出“跑酷+塔防”这类低阶模式,第二层在低阶模式之上再组合出更抽象的兴趣,层数越深,交互阶数越高。

这种设计让 Deep 部分能自动学习高阶特征交互,泛化到从未见过的特征组合。但它也有代价:需要大量数据才能训练出靠谱的稠密表示,而且对于“只出现过几百次”的稀有共现模式,它往往不如 Wide 记得清楚。就像年轻店员的直觉需要大量观察来培养,遇到奇怪的冷门搭配时,她远不如老店员笃定。

年轻店员的“直觉”来自神经网络一层层抽象出来的高阶交互,她擅长举一反三,但对冷门怪癖的记性不好。店主很快意识到:让两人各自为政,不如让她们并肩作战。

a(l+1)=ReLU(W(l)a(l)+b(l))\displaystyle \mathbf{a}^{(l+1)} = \mathrm{ReLU}\left(\mathbf{W}^{(l)}\mathbf{a}^{(l)} + \mathbf{b}^{(l)}\right)
深度部分的核心公式:第 l+1 层的输出,是对第 l 层输出做加权变换后再通过 ReLU 非线性激活。每经过一层,特征组合的阶数就更高。
  1. 输入表示第一层输入是特征 Embedding 拼接而成的稠密向量。
    a(0)=[emb(x1), emb(x2), …, emb(xd)]\mathbf{a}^{(0)} = [\mathrm{emb}(x_1),\ \mathrm{emb}(x_2),\ \ldots,\ \mathrm{emb}(x_d)]
  2. 权重矩阵第 l 层的连接权重,决定上一层哪些信号被放大、哪些被抑制。
    W(l)∈Rnl+1×nl\mathbf{W}^{(l)} \in \mathbb{R}^{n_{l+1} \times n_l}
  3. 线性变换上一层信号加权求和并加偏置,得到当前层的原始得分。
    z(l+1)=W(l)a(l)+b(l)\mathbf{z}^{(l+1)} = \mathbf{W}^{(l)}\mathbf{a}^{(l)} + \mathbf{b}^{(l)}
  4. ReLU 激活把负值截断为 0,引入非线性,让网络能表达复杂的特征组合。
    ReLU(z)=max⁡(0,z)\mathrm{ReLU}(z) = \max(0, z)
  5. 多层堆叠层层递进,从低阶组合到高阶抽象。
    a(l+1)=ReLU(z(l+1))\mathbf{a}^{(l+1)} = \mathrm{ReLU}(\mathbf{z}^{(l+1)})

联合训练架构

店主最终的办法是:让两位店员坐进同一间办公室。老店员先报“我根据老规矩打 7 分”,年轻店员再说“我根据我的观察打 6 分”,两人各带权重,店主把分数加权求和后拍板。关键在于,两位店员是一起复盘、一起改进的——同一批顾客的反馈同时修正她们俩的判断方式。

Wide&Deep 的联合预测正是如此:Wide 分支的输出与 Deep 分支的输出直接相加,再经过 sigmoid 得到最终概率。这里的相加不是简单的“平均”,而是让两个分支在同一个损失函数下联合优化——梯度会同时回传到 Wide 的线性权重和 Deep 的神经网络参数上。谁在这次预测中贡献更大,谁就会获得更强的学习信号。

正因为两个分支各有所长,联合训练还带来了“分工互补”的效果:Wide 用 FTRL 优化器(擅长处理稀疏特征,保持权重稀疏),Deep 用 AdaGrad 优化器(擅长神经网络的稠密参数更新)。两个优化器各管各的兵,但目标一致——共同最小化同一个预测损失。这就是论文标题里那个“&“的全部含义:不是”或者“,而是”并且”。

两位店员从此不再单干,而是一起看账本、一起观察、一起复盘。但要让这套“双人搭档”真正运转起来,还得先把顾客的信息登记得清清楚楚——这就轮到特征工程上场了。

P(Y=1∣x)=σ(wwide⊤[x,ϕ(x)]+wdeep⊤a(lf)+b)\displaystyle P(Y{=}1|\mathbf{x}) = \sigma\left(\mathbf{w}_{\text{wide}}^{\top}[\mathbf{x},\boldsymbol{\phi}(\mathbf{x})] + \mathbf{w}_{\text{deep}}^{\top}\mathbf{a}^{(l_f)} + b\right)
最终预测 = Wide 分支分数 + Deep 分支分数,一起通过 sigmoid 压缩成概率。两个分支在同一个损失下联合训练,像两位店员对着同一本复盘笔记共同进步。
  1. Wide 分支输出老店员依据“老规矩”(交叉特征)给出的分数。
    wwide⊤[x,ϕ(x)]\mathbf{w}_{\text{wide}}^{\top}[\mathbf{x},\boldsymbol{\phi}(\mathbf{x})]
  2. Deep 分支输出年轻店员依据“观察”(多层网络最后一层)给出的分数。
    wdeep⊤a(lf)\mathbf{w}_{\text{deep}}^{\top}\mathbf{a}^{(l_f)}
  3. 分数相加两人意见直接加总,谁的分量大谁影响力更强。
    z=zwide+zdeep+bz = z_{\text{wide}} + z_{\text{deep}} + b
  4. 概率压缩总分数通过 sigmoid 变成“会下载”的概率。
    p=σ(z)=11+e−zp = \sigma(z) = \frac{1}{1+e^{-z}}
  5. 联合更新同一个交叉熵损失同时驱动两个分支的梯度更新,彼此配合而非各自为政。

特征工程与输入

开店最重要的是什么?是登记簿。每一位顾客的年龄、职业、常逛区域、买过的书,都要分门别类记好。Wide&Deep 的特征工程,就是在为两位店员准备这本登记簿——只不过这本簿子的质量,直接决定她们的上限。

登记簿上有两类信息:一类是“连续特征”,比如用户最近 30 天的活跃天数、平均会话时长,这类数值差异可能很大——有人每天打开 App 一百次,有人一周才打开一次。如果不做处理,数值大的特征会压过数值小的特征,让训练不稳定。所以要先做归一化:减去均值再除以标准差,把不同量纲拉齐到同一起跑线。另一类是“类别特征”,比如用户所在的设备型号、国家代码。这类特征要先映射成整数 ID,再查一张 Embedding 表变成稠密向量,供 Deep 部分使用。

而 Wide 部分要吃的“交叉特征”,则需要人工精心挑选。不是所有组合都要做交叉——全量组合会维度爆炸,而且绝大多数毫无意义。经验法则是:挑选业务上有强共现逻辑、出现频率又足够高的组合,比如“跑酷类 App × 塔防类 App”“母婴用品 × 育儿社区”。设计师就像老店员精心整理账本一样,只记录那些真的会发生“老规矩”的搭配。

登记簿准备好后,Wide 分支拿到的是“稀疏原始特征+交叉特征”,Deep 分支拿到的是“稠密 Embedding 向量”。两位店员各取所需,但能不能配合好,还得看日常训练是否严谨——这是下一节的事。

x^=x−μσ\displaystyle \hat{x} = \frac{x - \mu}{\sigma}
连续特征归一化公式:把原始数值减去全体均值、再除以标准差,让特征分布变得平稳可控,Deep 网络训练起来才不容易“偏科”。
  1. 原始值某用户 30 天内打开 App 的次数,比如 120 次。
    x=120x = 120
  2. 均值全体用户的平均打开次数,衡量“一般水平”。
    μ=15\mu = 15
  3. 标准差用户之间的差异程度,差异越大 σ 越大。
    σ=8\sigma = 8
  4. 归一化结果把 120 转成约 13.1,消除量纲差异,让不同特征可比。
    x^=120−158=13.125\hat{x} = \frac{120 - 15}{8} = 13.125

训练与优化

书店每天打烊后,店主会带着两位店员复盘:今天哪些推荐顾客接受了?哪些被拒绝了?误差有多大?慢慢地,两人根据这些反馈微调自己的判断。模型的“复盘”方式,就是训练与优化。

Wide&Deep 采用小批量随机梯度下降:每次随机抽一批样本,计算预测与真实标签之间的差距——这个差距用交叉熵损失来衡量。交叉熵惩罚“自信地犯大错”:比如模型 99% 确信用户会下载,结果用户没下载,这个误差会被放大。与此同时,为了防止模型“死记硬背过头”(权重过大、只顾训练集上的巧合),还要加上 L2 正则化——相当于在复盘时提醒两人“别把偶然当成规律”。

训练完成后,用什么指标衡量两位店员的配合效果?推荐系统里最常用的是 AUC(ROC 曲线下面积),它衡量模型把正样本排到负样本前面的能力。在实际业务中还会用 GAUC——按用户分组计算 AUC 再加权平均,因为推荐系统更关心“对同一个用户,好东西是否排在前面”。Wide 部分的 FTRL 优化器还会额外保证权重稀疏,让线上推理时只计算少数非零权重,节约延迟。

两位店员在严格的复盘机制下越配合越好。这套“老店员+新店员”的组合拳打出了名堂,其他店主纷纷登门取经——Wide&Deep 的范式开始深刻影响整个推荐系统行业。

L=−1N∑i=1N[yilog⁡pi+(1−yi)log⁡(1−pi)]+λ∥w∥22\displaystyle \mathcal{L} = -\frac{1}{N}\sum_{i=1}^{N}\big[y_i\log p_i + (1-y_i)\log(1-p_i)\big] + \lambda\|\mathbf{w}\|_2^2
损失 = 交叉熵(衡量预测与真实差距)+ L2 正则(惩罚过大权重)。前者要求两位店员把推荐做准,后者防止她们“背答案背得太死”。
  1. 单样本损失当真实标签 y 为 1 时,损失为 -log p;y 为 0 时损失为 -log(1-p)。
    ℓi=−yilog⁡pi−(1−yi)log⁡(1−pi)\ell_i = -y_i\log p_i - (1-y_i)\log(1-p_i)
  2. 批量平均对一个批次 N 个样本的损失取平均,得到稳定的梯度方向。
    1N∑i=1Nℓi\frac{1}{N}\sum_{i=1}^{N}\ell_i
  3. L2 正则所有权重平方和乘以系数 λ,让权重趋向小值,防止过拟合。
    λ∥w∥22=λ∑jwj2\lambda\|\mathbf{w}\|_2^2 = \lambda\sum_j w_j^2
  4. 联合优化梯度同时更新 Wide 与 Deep 的参数,同时最小化损失。

业界影响与演进

老书店的成功配方传开后,各家店主开始改良。有人觉得“老店员的手写账本”(人工交叉特征)太费人力,于是发明了 DeepFM:用因子分解机(FM)自动学习二阶交叉特征,替代人工构建的 Wide 部分。FM 本质上是一台“自动记账机”,它不需要人去指定“哪些特征组合值得记”,而是通过潜向量自动捕捉所有二阶组合的权重。

还有人觉得 Deep 部分的隐式交叉不够“显式、可控”,于是提出了 DCN(Deep & Cross Network):在传统深度网络之外,额外增加一个“交叉网络”层,每一层都显式地计算特征与初始特征的交叉。这相当于给年轻店员配了一个“结构化推理本”,让她能系统性地推演高阶组合,而不是完全依赖黑箱直觉。

但无论怎么改良,几乎所有后续模型都继承了 Wide&Deep 最核心的思想:记忆与泛化分工并行。DeepFM 保留了“浅层自动交叉+深层高阶交互”的双通道;DCN 保留了“显式交叉+隐式交互”的双通道。从 YouTube 的视频推荐到淘宝的商品排序,这个“双店员”范式已成为现代推荐系统的标配骨架。

从 Google Play 到全网推荐系统,“老店员+新店员”的搭档模式成为行业标配。那么,这套组合到底在哪些真实战场上大显身手?让我们看看它的实战足迹。

y^DeepFM=y^FM+y^DNN\displaystyle \hat{y}_{\text{DeepFM}} = \hat{y}_{\text{FM}} + \hat{y}_{\text{DNN}}
DeepFM 的结构公式:FM 部分负责自动二阶交叉,DNN 部分负责高阶交互,两者相加——本质上是把 Wide&Deep 中“人工交叉”升级为“自动交叉”的进化版。
  1. FM 组件因子分解机自动建模所有二阶特征组合,替代人工交叉工程。
    y^FM=b+∑iwixi+∑i<j⟨vi,vj⟩xixj\hat{y}_{\text{FM}} = b + \sum_i w_i x_i + \sum_{i<j} \langle \mathbf{v}_i, \mathbf{v}_j \rangle x_i x_j
  2. DNN 组件多层神经网络继续学习高阶非线性交互。
    y^DNN=MLP([emb(x1),…,emb(xd)])\hat{y}_{\text{DNN}} = \mathrm{MLP}\big([\mathrm{emb}(x_1),\ldots,\mathrm{emb}(x_d)]\big)
  3. 相加输出两者共享输入、联合训练,延续 Wide 与 Deep 的分工互补哲学。
    y^=y^FM+y^DNN\hat{y} = \hat{y}_{\text{FM}} + \hat{y}_{\text{DNN}}

应用场景与实战

从街角书店到全球连锁,这套“双店员”模式正在无数数字世界里无声工作着。凡是同时存在“强共现模式”与“高阶语义”的场景,都是 Wide&Deep 的主场。

最经典的案例是 Google Play 应用商店。Wide 部分的交叉特征记住“装过《地铁跑酷》的用户也常装《天天酷跑》”这类共现规律;Deep 部分则从用户的下载历史、搜索行为、App 描述文本中学习更深层的兴趣偏好。结果是安装量提升 3.9%,这个数字在亿级流量的平台上意味着巨大的商业价值。

第二个主战场是广告点击率(CTR)预估。广告系统的候选集动辄百万级,特征极度稀疏:用户 ID、广告 ID、时段、地点……Wide 部分记忆“母婴用户 × 奶粉广告 × 晚上八点”这类高频共现,Deep 部分泛化“新手妈妈可能对哪些品类感兴趣”。两者加起来,让广告系统在几十毫秒内完成一次精准打分。视频推荐同样如此:Wide 记住“看完 A 立刻看 B”的连播模式,Deep 从观看时长、点赞、评论中学习泛化兴趣,新视频上线几分钟内就能被推给合适的人。

工程落地时还要注意几个要点:Embedding 表通常很大(几亿个 ID 对应几十维向量),需要分片存储;Wide 的交叉特征要关注时效性,热点组合可能一周就变;在线推理必须控制 Deep 的层数和宽度,保证延迟达标。这些细节,决定了这套组合在生产环境中是“利器”还是“累赘”。

老店员与年轻店员的组合,从一家街角书店出发,如今已在应用商店、广告系统、视频平台乃至风控等领域遍地开花。理解了这个“记忆+泛化”的范式,你就拿到了阅读一切深度推荐模型论文的入场券。

CTR=clicksimpressions\displaystyle \mathrm{CTR} = \frac{\mathrm{clicks}}{\mathrm{impressions}}
CTR(点击率)= 点击数 ÷ 曝光数,是推荐与广告系统最核心的业务指标。Wide&Deep 直接优化的是用户的点击概率,本质上就是在优化 CTR。
  1. 曝光数推荐结果展示给用户的次数,是 CTR 的分母。
    impressions\mathrm{impressions}
  2. 点击数用户实际点击的次数,是 CTR 的分子。
    clicks\mathrm{clicks}
  3. 比值含义CTR 越高,说明推荐越精准,模型把“对的物品”排到了“对的人”面前。
    CTR=clicksimpressions\mathrm{CTR} = \frac{\mathrm{clicks}}{\mathrm{impressions}}

AI 应用场景

应用商店 App 推荐

阶段:模型设计 / 训练

解决的问题:传统协同过滤只能记忆“用户-物品”共现,无法理解用户深层偏好。Wide&Deep 让记忆与泛化并行:Wide 记住“装了跑酷又装塔防”的共现规律,Deep 从用户画像和 App 描述中学习兴趣,两者联合打分。

具体案例:Google Play 商店中,输入“用户已安装 App 集合 + 候选 App 特征”,Wide 部分用交叉特征记忆共现,Deep 部分用多层网络挖掘兴趣,联合训练后在线安装量提升 3.9%。

广告点击率预估

阶段:在线推理 / 排序

解决的问题:广告系统候选集大、特征稀疏,需要同时捕捉“强共现”(如母婴用户常点奶粉广告)与高阶语义(如用户长期兴趣变迁)。单一模型难以两全。

具体案例:信息流广告系统中,Wide 部分记忆“广告主-用户-时段”的高频组合,Deep 部分理解用户长期兴趣与内容语义,两者在百毫秒内完成打分,精确预估每次曝光的点击概率。

视频内容推荐

阶段:召回 / 排序

解决的问题:视频推荐既要记住“看完 A 接着看 B”的连续观看共现,又要能泛化到刚上传的新视频——新视频没有历史共现数据,只能靠 Deep 的泛化能力。

具体案例:短视频平台采用 Wide&Deep 结构:Wide 记忆连续观看模式(如“看完做饭视频马上下一条也是做饭”),Deep 从观看时长、点赞、完播率学习泛化兴趣,让新视频上线几分钟内就能触达合适的用户。

Python 演示

python70 行
# -*- coding: utf-8 -*-"""简化版 Wide&Deep:手工实现宽线性部分与深网络部分,并在合成数据上训练"""import numpy as np  class SimpleWideDeep:    def __init__(self, n_feat, hidden_dim=8, lr=0.1):        # Wide 参数:原始特征 n_feat 个 + 交叉特征 2 个        self.w_wide = np.zeros(n_feat + 2)        # Deep 参数:一层隐层        self.W_deep_1 = np.random.randn(n_feat, hidden_dim) * 0.2        self.b_deep_1 = np.zeros(hidden_dim)        self.W_deep_2 = np.random.randn(hidden_dim, 1) * 0.2        self.b_deep_2 = 0.0        self.lr = lr     def build_cross(self, X):        # 交叉特征:特征0与特征1共现、特征2与特征3共现        c1 = X[:, 0] * X[:, 1]        c2 = X[:, 2] * X[:, 3]        return np.hstack([X, c1.reshape(-1, 1), c2.reshape(-1, 1)])     def deep_forward(self, X):        # Deep 前向:ReLU(X W1 + b1) W2 + b2        self.hidden = np.maximum(X.dot(self.W_deep_1) + self.b_deep_1, 0)        return self.hidden.dot(self.W_deep_2) + self.b_deep_2     def predict_proba(self, X):        wide_score = self.build_cross(X).dot(self.w_wide)        deep_score = self.deep_forward(X).ravel()        logit = wide_score + deep_score        return 1.0 / (1.0 + np.exp(-logit))     def train(self, X, y, epochs=500):        Xc = self.build_cross(X)        for _ in range(epochs):            p = self.predict_proba(X)            diff = p - y            # Wide 梯度下降            self.w_wide -= self.lr * Xc.T.dot(diff) / len(y)            # Deep 梯度下降            dz = diff.reshape(-1, 1)            grad_w2 = self.hidden.T.dot(dz) / len(y)            grad_b2 = dz.mean()            grad_h = dz.dot(self.W_deep_2.T)            grad_h[self.hidden <= 0] = 0  # ReLU 导数            grad_w1 = X.T.dot(grad_h) / len(y)            grad_b1 = grad_h.mean(axis=0)            self.W_deep_2 -= self.lr * grad_w2            self.b_deep_2 -= self.lr * grad_b2            self.W_deep_1 -= self.lr * grad_w1            self.b_deep_1 -= self.lr * grad_b1  if __name__ == "__main__":    rng = np.random.RandomState(42)    N = 2000    X = rng.randint(0, 2, size=(N, 4)).astype(float)    # 合成标签:特征0与特征1共现带来正样本,特征2与特征3共现带来负样本    logit = 2.0 * X[:, 0] * X[:, 1] - 1.5 * X[:, 2] * X[:, 3] + 0.3 * X[:, 0] * X[:, 2]    prob = 1.0 / (1.0 + np.exp(-logit))    y = (rng.rand(N) < prob).astype(float)     model = SimpleWideDeep(n_feat=4, hidden_dim=8, lr=0.1)    model.train(X, y, epochs=500)    pred = model.predict_proba(X)    acc = ((pred > 0.5) == y).mean()    print("准确率:", round(acc, 4))    print("Wide 学到的交叉权重:", model.w_wide[-2:].round(3))    print("Deep 隐层形状:", model.W_deep_1.shape)
目的:用 NumPy 从零实现一个极简 Wide&Deep——Wide 部分用线性层加交叉特征,Deep 部分用一层隐层,在合成数据上联合训练,直观展示“记忆+泛化”的协作。
  1. self.w_wide = np.zeros(n_feat + 2)Wide 部分只有一组线性权重,初始全零表示“什么都不确定”,留给梯度去学
  2. c1 = X[:, 0] * X[:, 1]手工构造交叉特征:当两个特征同时为 1 时结果才为 1,模拟老店员的“共现账本”
  3. wide_score + deep_score两路分数直接相加,对应联合预测公式中的 z_wide + z_deep
  4. np.maximum(X.dot(self.W_deep_1) + self.b_deep_1, 0)ReLU 激活函数,让 Deep 具备非线性组合能力
  5. self.w_wide -= self.lr * Xc.T.dot(diff) / len(y)Wide 分支的梯度下降更新,diff 是预测与真实标签的误差
  6. grad_h[self.hidden <= 0] = 0ReLU 的导数:输入为负时梯度为 0,让网络学会“关掉”无关信号

常见误区

误区我以为 Wide 部分就是把所有原始特征塞进一个线性层,Deep 负责学习一切,交叉特征可有可无。

正解Wide 部分的灵魂恰恰是人工交叉特征。如果没有“装了 A 且装了 B”这类乘积特征,线性模型只能独立看待每个特征,完全丧失记忆共现的能力。就像老店员如果不记“张先生总买科幻+军事”这个组合,她就没法说出“老规矩”三个字。线性层本身不神奇,神奇的是喂给它的交叉特征。

为何常见:很多教程把重点放在 Deep 的神经网络上,让人误以为 Wide 只是“凑数”的线性层,忽视了交叉特征工程的价值。

误区深度网络能学高阶交互,泛化能力全面碾压 Wide,Deep 应该能自动记住共现模式。

正解Deep 靠 Embedding 和网络结构来泛化,但面对“仅出现几百次”的稀有共现组合,它很难精确记忆——梯度被多数样本稀释,网络没有足够的信号记住这种小众模式。Wide 的直连权重却能精确地记住它们。就像年轻店员的直觉再强,也记不住某些冷门老主顾的怪癖,还得靠老店员的死记硬背兜底。

为何常见:深度学习的成功让新人容易高估泛化能力、低估长尾记忆的重要性。

误区我以为先训练一个 Wide 模型,再训练一个 Deep 模型,最后把两者的概率加权平均。

正解Wide&Deep 是联合训练(joint training),两个分支共享输入、在同一个损失函数下同时更新。区别在于 Wide 用 FTRL 优化器保持稀疏、Deep 用 AdaGrad 优化稠密参数。它和集成学习(bagging/boosting)有本质区别——集成是“各自训练、投票融合”,Wide&Deep 是“一起复盘、同步改进”。

为何常见:模型融合的思想太深入人心,看到“两个模型组合”就误以为是 ensemble,忽略了“联合训练”这个关键词。

误区既然交叉特征有用,那就把所有两两特征都做成交叉,越多越好。

正解全量交叉的维度是特征数的平方级,绝大多数组合既无业务含义又出现频率极低,只会让模型过拟合噪声。Wide 部分只保留少量精心设计的高频共现组合,比如“跑酷类×塔防类”,而不是“用户 ID 第 3 位 × App 图标颜色”。老店员也不会记所有顾客的所有排列组合,只记那些真正会反复出现的搭配。

为何常见:看到 φ(x) = ∏ x_i^{c} 的数学形式,容易误以为要对所有幂组合做枚举,忽略了“人工挑选”这个前提。

误区这个模型是 Google 在应用商店场景提出的,应该只适合 App 推荐吧?

正解“记忆+泛化”的分工范式是通用的。CTR 预估、搜索排序、风控反欺诈、营销人群圈选……只要任务同时存在“强共现模式”(如欺诈交易中的固定设备组合)和“高阶语义”(如用户行为序列中的深层意图),Wide&Deep 的架构都能迁移。场景不同,特征不同,但“一位老店员配一位新店员”的配方不变。

为何常见:原论文以应用商店推荐为案例,场景太具象,容易让初学者把应用场景当成模型的适用边界。

面试题

Q1. Wide&Deep 中 Wide 部分的核心能力是什么?

单选题 · easy

  • A.记忆高频共现组合模式← 正确答案
  • B.用多层神经元做特征抽象
  • C.自动挖掘全部特征交叉
  • D.对输入特征做归一化处理

答案:A。Wide 部分通过人工交叉特征直接记忆高频共现模式,就像老店员记住“张先生总买科幻+军事”。B 是 Deep 的能力,C 是 DeepFM 的改进而非 Wide,D 属于特征工程而非 Wide 模型的能力。

Q2. Wide&Deep 首次大规模落地于哪个场景?

单选题 · easy

  • A.Google Play 应用商店← 正确答案
  • B.淘宝商品搜索排序
  • C.抖音短视频推荐
  • D.美团外卖商家排序

答案:A。2016 年 Google 团队在 Google Play 应用商店首次部署 Wide&Deep,在线安装量提升 3.9%。其他平台虽然也大量使用该架构,但并非论文的首个落地场景。

Q3. Deep 部分使用什么结构来提取高阶特征?

单选题 · easy

  • A.多层全连接神经网络← 正确答案
  • B.单层线性回归模型
  • C.决策树集成模型
  • D.k 近邻聚类算法

答案:A。Deep 部分由 Embedding 层加多层全连接网络构成,每一层通过 ReLU 激活做非线性变换,逐步组合出高阶特征。线性回归、决策树、KNN 都不是 Deep 部分的组成结构。

Q4. Wide 部分的交叉特征 φ_k(x)=∏x_i^{c_ki},当 c 全为 1 时表示什么?

单选题 · mid

  • A.所有特征都出现时结果才为 1← 正确答案
  • B.任一特征出现结果即为 1
  • C.特征值做连续缩放变换
  • D.对特征取对数后进行加和

答案:A。乘积运算的规则是“全部为 1 才等于 1,否则为 0”。这正是交叉特征记忆共现的原理:只有组合内所有特征都出现(比如既装了 A 又装了 B),这个交叉信号才被激活。B 描述的是“或”逻辑,C 是归一化,D 是对数变换,都不符合乘积定义。

Q5. Wide&Deep 联合训练时,Wide 部分常用的优化器是?

单选题 · mid

  • A.FTRL← 正确答案
  • B.Adam
  • C.SGD with Momentum
  • D.RMSProp

答案:A。Wide 部分处理的是海量稀疏特征,FTRL 在稀疏场景下能有效控制权重稀疏性,减少线上计算量。Adam、Momentum、RMSProp 更适合稠密参数的神经网络训练,通常用在 Deep 部分。

Q6. Wide&Deep 的联合预测中,两个分支如何汇合?

单选题 · mid

  • A.输出层直接相加再经 Sigmoid← 正确答案
  • B.两个模型独立输出后投票
  • C.Wide 输出作为 Deep 的输入
  • D.Deep 输出作为 Wide 的权重

答案:A。联合预测公式为 P = σ(z_wide + z_deep + b),两个分支的分数在输出层直接相加后经 sigmoid 压缩成概率。B 是集成学习的投票思路,C 和 D 把两个分支描述成了串联或权重关系,都与 Wide&Deep 的并行相加结构不符。

Q7. 为什么 Wide 部分需要人工挑选交叉特征而不是全部枚举?

单选题 · mid

  • A.全量交叉维度爆炸且多无意义← 正确答案
  • B.人工特征可以完全避免过拟合
  • C.全量交叉会降低 Deep 训练速度
  • D.人工特征能确保模型完全可解释

答案:A。特征两两组合的数量是平方级,大部分组合业务含义弱、出现频率低,只会引入噪声。人工挑选高频、有业务逻辑的组合是 Wide 特征工程的核心。B 过于绝对,人工特征不能完全避免过拟合;C 是副作用而非主因;D 中“完全可解释”不现实。

Q8. Deep 部分相比 Wide 部分的优势有哪些?

多选题 · mid

  • A.泛化到从未见过的特征组合← 正确答案
  • B.通过 Embedding 处理稀疏特征← 正确答案
  • C.对稀有共现模式记忆更精确
  • D.逐层自动学习高阶交互特征← 正确答案

答案:ABD。Deep 的 Embedding 将稀疏特征映射为稠密向量,多层网络逐层组合出高阶交互,因此能泛化到未见过的组合。C 恰好相反——对稀有共现模式记忆更精确的是 Wide 的直连权重,这是 Wide 的优势而非 Deep 的。

Q9. 下列哪些属于 Wide&Deep 对后续模型的影响?

多选题 · hard

  • A.启发 DeepFM 用 FM 替代人工交叉← 正确答案
  • B.DCN 提出显式交叉网络层← 正确答案
  • C.Transformer 取代全部 Embedding
  • D.确立记忆泛化分工的范式基础← 正确答案

答案:ABD。DeepFM 把 Wide 的人工交叉升级为 FM 自动二阶交叉;DCN 在 Deep 之外引入显式交叉网络;两者都延续了“记忆+泛化双通道”的范式。C 错误,Transformer 取代的是序列建模结构,并非 Wide&Deep 直接衍生出的改进方向。

Q10. 关于 Wide&Deep 的联合训练,下列说法正确的有?

多选题 · extreme

  • A.两分支在同一损失下同步更新← 正确答案
  • B.Wide 用 FTRL 保持权重稀疏← 正确答案
  • C.两分支分别调参后加权融合
  • D.Deep 用 AdaGrad 优化参数← 正确答案

答案:ABD。联合训练意味着两个分支共享同一个损失函数,梯度同时回传更新;Wide 用 FTRL 维持稀疏性,Deep 用 AdaGrad 处理稠密神经网络参数。C 是集成学习的思路,与联合训练的本质相悖——Wide&Deep 不是先各自训练再融合,而是一起训练、共同进步。