概述
Deep Crossing 模型。这个模型在推荐系统史上具有里程碑意义,因为它第一次将“Embedding + MLP”这一范式确立为工业级推荐精排模型的标配。
一句话概括:Deep Crossing 是微软于2016年提出的用于搜索广告的深度学习模型。
它最大的贡献是证明了深度神经网络可以自动完成特征交叉,从而让工程师从繁重的手工特征工程(如交叉组合性别+年龄)中解放出来。
核心创新点:
- 端到端自动特征交叉:不用人工构造组合特征,深度网络自己学。
- 残差网络(ResNet)引入推荐:首次将残差连接引入推荐系统,解决深层网络的梯度消失和模型退化问题。
- 高维稀疏特征降维:通过Embedding加长尾共享ID策略,解决了广告计划(CampaignID)等百万级枚举值的存储和训练难题。
Deep Crossing 网络结构五层详解
从下到上依次为:Feature层 → Embedding层 → Stacking层 → Multiple Residual Units层 → Scoring层。
| 层名称 | 核心作用 | 输入 | 输出 |
|---|---|---|---|
| Feature层(输入) | 接收原始特征(类别型One-hot、数值型标量) | 用户、广告、上下文原始数据 | 高维稀疏向量 / 数值标量 |
| Embedding层 | 降维:把高维One-hot映射为低维稠密向量;长尾共享:对频次低的ID统一编号,压缩模型体积 | 稀疏ID(如搜索词、广告ID) | 低维稠密向量(如维度256) |
| Stacking层 | 拼接:将所有Embedding向量和原始数值特征拼成一个长向量 | 多个Embedding + 数值特征 | 一维长向量([v1, v2, ..., vn]) |
| Multiple Residual Units层 | 特征自动交叉:通过多层全连接网络,让所有特征维度两两交互;残差连接:解决梯度弥散 | Stacking输出向量 | 高阶交叉后的特征向量 |
| Scoring层 | 输出概率:将最后一层特征映射为点击概率(Sigmoid) | 残差网络输出 | 0~1之间的概率值 |
完整业务场景与数据推导
场景设定
平台: Bing 搜索广告。
用户行为: 用户在搜索框输入“冬季男士跑鞋”。
目标: 预测用户是否会点击候选广告“Adidas Ultraboost 冬季款”。
真实标签(y):假设用户最终点击了(y=1)。
特征体系(总共选取 4 个特征)
| 特征字段 | 特征类型 | 原始值 | One-hot维度 | 备注 (高基数处理策略) |
|---|---|---|---|---|
| 搜索词 (Query) | 类别型 (ID) | “冬季男士跑鞋” | 词表大小 = 100 | 直接 Embedding |
| 广告关键词 (Ad Keyword) | 类别型 (ID) | “跑鞋” | 词表大小 = 50 | 直接 Embedding |
| 广告计划ID (CampaignID) | 类别型 (ID) | 9527 | 原始100万 → 截断为1001 |
取Top1000高频ID,剩余统一为1000号 (长尾共享) |
| 历史点击率 (CTR) | 数值型 | 0.05 (5%) | 无 (标量) | 不做Embedding,直接输入Stacking层 |
降维设定:为了手算方便,我们统一设置 Embedding维度 d = 4
假设训练好的 Embedding 表(特征 -> 4维向量)
| 特征名称 | 原始ID | Embedding向量 (4维) |
|---|---|---|
| 搜索词:“冬季男士跑鞋” | ID_25 | [0.1, 0.4, 0.7, 0.2] |
| 广告关键词:“跑鞋” | ID_8 | [0.9, 0.3, 0.5, 0.8] |
| 广告计划ID:9527 | ID_887 (截断后) | [0.2, 0.1, 0.6, 0.3] |
| (数值特征) 历史CTR | — | 标量: 0.05 |
补充说明:原论文中,CampaignID 从百万级通过截断(只留TOP 1000)降为1001维,再配合每个ID对应的历史CTR统计特征一起输入,极大地压缩了参数量。
这里是结合了ID Embedding + 统计特征两种信息。
第一层:Feature层(输入层)
接收四个原始特征:
- 搜索词:One-hot 向量(100维,仅ID_25处为1)
- 广告关键词:One-hot 向量(50维,仅ID_8处为1)
- 广告计划ID:One-hot 向量(1001维,仅ID_887处为1)
- CTR:标量
0.05
输入层不进行计算,只是作为数据入口。
第二层:Embedding层(降维与稠密化)
将三个稀疏ID特征查表映射为稠密向量,数值型特征保持标量跳过Embedding。
- equery=[0.1,0.4,0.7,0.2]e_{query} = [0.1, 0.4, 0.7, 0.2]equery=[0.1,0.4,0.7,0.2]
- ekeyword=[0.9,0.3,0.5,0.8]e_{keyword} = [0.9, 0.3, 0.5, 0.8]ekeyword=[0.9,0.3,0.5,0.8]
- ecampaign=[0.2,0.1,0.6,0.3]e_{campaign} = [0.2, 0.1, 0.6, 0.3]ecampaign=[0.2,0.1,0.6,0.3]
- vctr=0.05v_{ctr} = 0.05vctr=0.05 (标量,不经过矩阵变换)
输出维度:4 + 4 + 4 + 1 = 13 维原始表征。
第三层:Stacking层(向量拼接)
核心操作: 将上述所有向量首尾相连,合并成一个长向量 XXX。
X=[equery∥ekeyword∥ecampaign∥vctr] X = [e_{query} \parallel e_{keyword} \parallel e_{campaign} \parallel v_{ctr}] X=[equery∥ekeyword∥ecampaign∥vctr]
此时 XXX 的维度 D=13D = 13D=13
第四层:Multiple Residual Units层(特征自动交叉 + 残差连接)
这是Deep Crossing的灵魂。我们堆叠 2个残差单元(Residual Unit) 进行演示。
残差单元的结构公式
一个残差单元的数学定义如下(去掉了卷积)
Xout=ReLU(X+F(X)) X_{out} = \text{ReLU}(X +\mathcal{F}(X)) Xout=ReLU(X+F(X))
其中:
- F(X)\mathcal{F}(X)F(X) 代表两层全连接 + ReLU 的变换(拟合残差)
- 外层的
+ X就是残差连接(Skip Connection)
为什么需要计算两个(或多个)残差单元?
Deep Crossing 堆叠多个残差单元,根本原因在于特征交叉的“阶数(Degree)”:
- 一阶特征(原始特征):就是 XX 本身,比如“搜索词=跑鞋”和“广告ID=9527”是相互独立的。
- 二阶特征交叉(Residual Unit 1):经过第一层残差单元,网络开始将两两特征进行组合(比如“搜索词”ד广告关键词”的联合作用)。
- 三阶及以上特征交叉(Residual Unit 2):将 Xout1Xout_{1}Xout1(已含二阶信息)再次输入新的残差单元,网络就能捕获更复杂的组合(比如“搜索词”ד广告关键词”ד历史CTR”的三元交互)。
单层全连接(或单个残差块)只能模拟到特征的线性加权和浅层二阶交互。
现实中的点击率预估,往往依赖于“品牌+类目+价格”这种三元以上的高阶组合。
残差网络的堆叠特性,使得 Deep Crossing 可以自动构建任意高阶的特征组合,且残差连接(Skip Connection)保证了网络即使堆叠很深,梯度也不会消失(因为恒等映射 +X+X+X 给反向传播提供了一条“梯度高速公路”)。
残差单元1(Residual Unit 1)的具体手算推导
为简化手算,我们假设第一层全连接权重 W1W_{1}W1 将 13 维压缩到 8 维,第二层 W2W_{2}W2 再将 8 维还原回 13 维。
这里为了展示数学逻辑,我们假设矩阵运算已经完成,重点演示残差连接的效果。
假设经过两层全连接 + ReLU 后,计算出的残差F(X)F(X)F(X) 为(这是一个抽象的中间结果):
F(X)=[0.2,−0.1,0.3,0.0,0.4,−0.2,0.1,0.5,−0.3,0.2,0.1,−0.4,0.2] \mathcal{F}(X) = [0.2, -0.1, 0.3, 0.0, 0.4, -0.2, 0.1, 0.5, -0.3, 0.2, 0.1, -0.4, 0.2] F(X)=[0.2,−0.1,0.3,0.0,0.4,−0.2,0.1,0.5,−0.3,0.2,0.1,−0.4,0.2]
进行残差相加(对应位置相加):
X+F(X)=[0.1+0.20.4−0.10.7+0.30.2+0.00.9+0.40.3−0.20.5+0.10.8+0.50.2−0.30.1+0.20.6+0.10.3−0.40.05+0.2]=[0.30.31.00.21.30.10.61.3−0.10.30.7−0.10.25] X + \mathcal{F}(X) = \begin{bmatrix} 0.1 + 0.2 \\ 0.4 - 0.1 \\ 0.7 + 0.3 \\ 0.2 + 0.0 \\ 0.9 + 0.4 \\ 0.3 - 0.2 \\ 0.5 + 0.1 \\ 0.8 + 0.5 \\ 0.2 - 0.3 \\ 0.1 + 0.2 \\ 0.6 + 0.1 \\ 0.3 - 0.4 \\ 0.05 + 0.2 \end{bmatrix} = \begin{bmatrix} 0.3 \\ 0.3 \\ 1.0 \\ 0.2 \\ 1.3 \\ 0.1 \\ 0.6 \\ 1.3 \\ -0.1 \\ 0.3 \\ 0.7 \\ -0.1 \\ 0.25 \end{bmatrix} X+F(X)=
0.1+0.20.4−0.10.7+0.30.2+0.00.9+0.40.3−0.20.5+0.10.8+0.50.2−0.30.1+0.20.6+0.10.3−0.40.05+0.2
=
0.30.31.00.21.30.10.61.3−0.10.30.7−0.10.25
最后经过外层 ReLU 激活(负数置0):
Xout1=ReLU(X+F(X))=[0.3,0.3,1.0,0.2,1.3,0.1,0.6,1.3,0,0.3,0.7,0,0.25] X_{out1} = \text{ReLU}(X + \mathcal{F}(X)) = [0.3, 0.3, 1.0, 0.2, 1.3, 0.1, 0.6, 1.3, 0, 0.3, 0.7, 0, 0.25] Xout1=ReLU(X+F(X))=[0.3,0.3,1.0,0.2,1.3,0.1,0.6,1.3,0,0.3,0.7,0,0.25]
关键点:由于残差连接 + X 的存在,即使 W1,W2W_{1},W_{2}W1,W2 全为0,Xout1=ReLU(X)Xout1=ReLU(X)Xout1=ReLU(X),信息依然能无损传递。
这在反向传播时,梯度可以直接绕过 FFF 回传,极大缓解了深层网络的梯度消失问题。
ReLU 计算过程
针对向量中的每一个数值 xix_{i}xi,执行 max(0,xi)max(0,x_{i})max(0,xi) 运算。
| 元素索引 | 输入值 xix_ixi (来自残差相加) | ReLU 计算过程 (max(0,xi)\max(0, x_i)max(0,xi)) | 输出值 ReLU(xi)\text{ReLU}(x_i)ReLU(xi) |
|---|---|---|---|
| 1 | 0.3 | max(0,0.3)\max(0, 0.3)max(0,0.3) | 0.3 (保留) |
| 2 | 0.3 | max(0,0.3)\max(0, 0.3)max(0,0.3) | 0.3 (保留) |
| 3 | 1.0 | max(0,1.0)\max(0, 1.0)max(0,1.0) | 1.0 (保留) |
| 4 | 0.2 | max(0,0.2)\max(0, 0.2)max(0,0.2) | 0.2 (保留) |
| 5 | 1.3 | max(0,1.3)\max(0, 1.3)max(0,1.3) | 1.3 (保留) |
| 6 | 0.1 | max(0,0.1)\max(0, 0.1)max(0,0.1) | 0.1 (保留) |
| 7 | 0.6 | max(0,0.6)\max(0, 0.6)max(0,0.6) | 0.6 (保留) |
| 8 | 1.3 | max(0,1.3)\max(0, 1.3)max(0,1.3) | 1.3 (保留) |
| 9 | -0.1 | max(0,−0.1)\max(0, -0.1)max(0,−0.1) | 0 (负数被截断) |
| 10 | 0.3 | max(0,0.3)\max(0, 0.3)max(0,0.3) | 0.3 (保留) |
| 11 | 0.7 | max(0,0.7)\max(0, 0.7)max(0,0.7) | 0.7 (保留) |
| 12 | -0.1 | max(0,−0.1)\max(0, -0.1)max(0,−0.1) | 0 (负数被截断) |
| 13 | 0.25 | max(0,0.25)\max(0, 0.25)max(0,0.25) | 0.25 (保留) |
残差单元2(Residual Unit 2)
经过 Residual Unit 1 得到了:
Xout1=[0.3,0.3,1.0,0.2,1.3,0.1,0.6,1.3,0,0.3,0.7,0,0.25] X_{out1} = [0.3, 0.3, 1.0, 0.2, 1.3, 0.1, 0.6, 1.3, 0, 0.3, 0.7, 0, 0.25] Xout1=[0.3,0.3,1.0,0.2,1.3,0.1,0.6,1.3,0,0.3,0.7,0,0.25]
现在,将 KaTeX parse error: Expected '}', got 'EOF' at end of input: X_{out1| 作为输入,送入 Residual Unit 2。
假设残差单元 2 内部的 两层全连接 + 内部 ReLU 变换后,计算出的残差为 F2(Xout1)F_{2}(X_{out1})F2(Xout1):
F2(Xout1)=[0.1,−0.2,0.4,0.1,0.2,−0.1,0.3,0.4,0.1,−0.1,0.2,0.1,0.15] \mathcal{F}_2(X_{out1}) = [0.1, -0.2, 0.4, 0.1, 0.2, -0.1, 0.3, 0.4, 0.1, -0.1, 0.2, 0.1, 0.15] F2(Xout1)=[0.1,−0.2,0.4,0.1,0.2,−0.1,0.3,0.4,0.1,−0.1,0.2,0.1,0.15]
步骤 1:残差相加(对应位置相加)
将输入 Xout1X_{out1}Xout1 与残差分支 F2F2F2 逐元素相加:
Xout1+F2(Xout1)=[0.3+0.10.3+(−0.2)1.0+0.40.2+0.11.3+0.20.1+(−0.1)0.6+0.31.3+0.40+0.10.3+(−0.1)0.7+0.20+0.10.25+0.15]=[0.40.11.40.31.50.00.91.70.10.20.90.10.40] X_{out1} + \mathcal{F}_2(X_{out1}) = \begin{bmatrix} 0.3 + 0.1 \\ 0.3 + (-0.2) \\ 1.0 + 0.4 \\ 0.2 + 0.1 \\ 1.3 + 0.2 \\ 0.1 + (-0.1) \\ 0.6 + 0.3 \\ 1.3 + 0.4 \\ 0 + 0.1 \\ 0.3 + (-0.1) \\ 0.7 + 0.2 \\ 0 + 0.1 \\ 0.25 + 0.15 \end{bmatrix} = \begin{bmatrix} 0.4 \\ 0.1 \\ 1.4 \\ 0.3 \\ 1.5 \\ 0.0 \\ 0.9 \\ 1.7 \\ 0.1 \\ 0.2 \\ 0.9 \\ 0.1 \\ 0.40 \end{bmatrix} Xout1+F2(Xout1)=
0.3+0.10.3+(−0.2)1.0+0.40.2+0.11.3+0.20.1+(−0.1)0.6+0.31.3+0.40+0.10.3+(−0.1)0.7+0.20+0.10.25+0.15
=
0.40.11.40.31.50.00.91.70.10.20.90.10.40
步骤 2:外层 ReLU 激活(截断负数)
将相加后的向量逐元素输入 ReLU(x)=max(0,x)ReLU(x)=max(0,x)ReLU(x)=max(0,x):
| 元素索引 | 相加后的值 | ReLU 计算 | 输出 Xout2X_{out2}Xout2 |
|---|---|---|---|
| 1 | 0.4 | max(0,0.4)\max(0, 0.4)max(0,0.4) | 0.4 |
| 2 | 0.1 | max(0,0.1)\max(0, 0.1)max(0,0.1) | 0.1 |
| 3 | 1.4 | max(0,1.4)\max(0, 1.4)max(0,1.4) | 1.4 |
| 4 | 0.3 | max(0,0.3)\max(0, 0.3)max(0,0.3) | 0.3 |
| 5 | 1.5 | max(0,1.5)\max(0, 1.5)max(0,1.5) | 1.5 |
| 6 | 0.0 | max(0,0.0)\max(0, 0.0)max(0,0.0) | 0.0 |
| 7 | 0.9 | max(0,0.9)\max(0, 0.9)max(0,0.9) | 0.9 |
| 8 | 1.7 | max(0,1.7)\max(0, 1.7)max(0,1.7) | 1.7 |
| 9 | 0.1 | max(0,0.1)\max(0, 0.1)max(0,0.1) | 0.1 |
| 10 | 0.2 | max(0,0.2)\max(0, 0.2)max(0,0.2) | 0.2 |
| 11 | 0.9 | max(0,0.9)\max(0, 0.9)max(0,0.9) | 0.9 |
| 12 | 0.1 | max(0,0.1)\max(0, 0.1)max(0,0.1) | 0.1 |
| 13 | 0.40 | max(0,0.40)\max(0, 0.40)max(0,0.40) | 0.40 |
因此,第二个残差单元的最终输出为:
Xout2=[0.4,0.1,1.4,0.3,1.5,0.0,0.9,1.7,0.1,0.2,0.9,0.1,0.40] X_{out2} = [0.4, 0.1, 1.4, 0.3, 1.5, 0.0, 0.9, 1.7, 0.1, 0.2, 0.9, 0.1, 0.40] Xout2=[0.4,0.1,1.4,0.3,1.5,0.0,0.9,1.7,0.1,0.2,0.9,0.1,0.40]
注意:这里的 F2F2F2 是我为演示数学流程而构造的抽象向量。在真实的模型训练中,它是通过 ReLU(W2⋅ReLU(W1⋅Xout1+b1)+b2)ReLU(W_{2}⋅ReLU(W_{1}⋅X_{out1}+b_{1})+b_{2})ReLU(W2⋅ReLU(W1⋅Xout1+b1)+b2)
实实在在算出来的,而 W1,W2W_{1},W_{2}W1,W2 是通过反向传播从海量数据中学习得到的。
小结
| 阶段 | 输入 | 核心特征交叉阶数 | 示例交叉组合 |
|---|---|---|---|
| Stacking (起始) | XXX | 一阶 (原始特征) | 单独的 搜索词、广告ID |
| Residual Unit 1 | X→Xout1X \rightarrow X_{out1}X→Xout1 | 二阶交叉 | 搜索词 ×\times× 广告关键词 |
| Residual Unit 2 | Xout1→Xout2X_{out1} \rightarrow X_{out2}Xout1→Xout2 | 三阶交叉 | 搜索词 ×\times× 广告关键词 ×\times× 历史CTR |
在现实推荐系统中,微软论文的实验表明:堆叠 6~10 层残差单元时,模型能捕获足够高阶的特征交互,且由于残差连接的存在,训练依然稳定。
在刚才的案例中,虽然我们只堆叠了 2 层,但完全相同的数学逻辑可以无限延伸:
Xout3=ReLU(Xout2+F3(Xout2)),Xout4=ReLU(Xout3+F4(Xout3)),… X_{out3} = \text{ReLU}(X_{out2} + \mathcal{F}_3(X_{out2})), \quad X_{out4} = \text{ReLU}(X_{out3} + \mathcal{F}_4(X_{out3})), \dots Xout3=ReLU(Xout2+F3(Xout2)),Xout4=ReLU(Xout3+F4(Xout3)),…
第五层:Scoring层(输出点击概率)
残差网络的最终输出 Xout2X_{out2}Xout2仍为 13 维向量。
将其输入一个输出维度为 1 的全连接层(带 Sigmoid 激活函数)。
假设输出层权重 WscoreW_{score}Wscore(13维转1维)点积加偏置 bbb 后,得到了 logit = 1.8。
计算点击概率 ppp:
p=σ(logit)=11+e−1.8≈11+0.1653≈0.858 p = \sigma(\text{logit}) = \frac{1}{1 + e^{-1.8}} \approx \frac{1}{1 + 0.1653} \approx 0.858 p=σ(logit)=1+e−1.81≈1+0.16531≈0.858
模型预测结果:用户点击该广告的概率为 85.8%。
由于真实标签 y=1y=1y=1(用户实际点击了),我们使用 LogLoss(交叉熵) 计算损失:
L=−log(p)=−log(0.858)≈0.153 L = -\log(p) = -\log(0.858) \approx 0.153 L=−log(p)=−log(0.858)≈0.153
这个较小的损失值表明当前模型对该样本的预测较为准确。
在反向传播时,这个 0.153 的标量会驱动所有层的参数(包括底层 Embedding 表)进行梯度下降更新。
反向传播
第一步:前向传播损失计算(起点)
根据案例,前向传播的最终结果:
最终 logit(Scoring 层线性输出):z=1.8z=1.8z=1.8预测点击概率(Sigmoid 输出):p=σ(z)=0.858p=σ(z)=0.858p=σ(z)=0.858真实标签:y=1y=1y=1损失值(交叉熵 Loss):
L=−[ylogp+(1−y)log(1−p)]=−log(0.858)≈0.153 L = -[y \log p + (1 - y) \log(1 - p)] = -\log(0.858) \approx 0.153 L=−[ylogp+(1−y)log(1−p)]=−log(0.858)≈0.153
第二步:求损失对输出 logit 的导数(整个反向传播的“发动机”)
对于二分类交叉熵损失 + Sigmoid 激活函数,其梯度有一个极其简洁的公式:
∂L∂z=p−y \frac{\partial L}{\partial z} = p - y ∂z∂L=p−y
代入具体数值:
δout=∂L∂z=0.858−1=−0.142 \delta_{out} = \frac{\partial L}{\partial z} = 0.858 - 1 = -0.142 δout=∂z∂L=0.858−1=−0.142
关键含义:这个
-0.142是全部反向传播的源头。
负号表示“预测值(0.858)高于真实值(1),需要把 logit 往小了调”。
第三步:Scoring 层参数的梯度计算(更新 WscoreW_{score}Wscore和 bbb)
Scoring 层的表达式为:z=Wscore⋅Xout2+bz = W_{score} \cdot X_{out2} + bz=Wscore⋅Xout2+b
根据链式法则:
1. 对偏置 b 的梯度
∂L∂b=δout=−0.142 \frac{\partial L}{\partial b} = \delta_{out} = -0.142 ∂b∂L=δout=−0.142
2. 对权重向量 W_{score} 的梯度(逐维度)
公式:∂L∂Wi=δout⋅xi\frac{\partial L}{\partial W_i} = \delta_{out} \cdot x_i∂Wi∂L=δout⋅xi
其中 xix_{i}xi 是 Xout2X_{out2}Xout2 中第 i 个元素。
Xout2=[0.4,0.1,1.4,0.3,1.5,0.0,0.9,1.7,0.1,0.2,0.9,0.1,0.40] X_{out2} = [0.4, 0.1, 1.4, 0.3, 1.5, 0.0, 0.9, 1.7, 0.1, 0.2, 0.9, 0.1, 0.40] Xout2=[0.4,0.1,1.4,0.3,1.5,0.0,0.9,1.7,0.1,0.2,0.9,0.1,0.40]
逐项手算(保留 4 位小数):
| 维度 iii | Xout2X_{out2}Xout2 值 | 梯度 ∂L/∂Wi=−0.142×xi\partial L/\partial W_i = -0.142 \times x_i∂L/∂Wi=−0.142×xi | 含义 |
|---|---|---|---|
| 1 | 0.4 | -0.0568 | |
| 2 | 0.1 | -0.0142 | |
| 3 | 1.4 | -0.1988 | |
| 4 | 0.3 | -0.0426 | |
| 5 | 1.5 | -0.2130 | |
| 6 | 0.0 | 0 | 因为该维度输出为0,此处权重不更新 |
| 7 | 0.9 | -0.1278 | |
| 8 | 1.7 | -0.2414 | |
| 9 | 0.1 | -0.0142 | |
| 10 | 0.2 | -0.0284 | |
| 11 | 0.9 | -0.1278 | |
| 12 | 0.1 | -0.0142 | |
| 13 | 0.40 | -0.0568 |
3. 参数如何更新(假设学习率 η=0.1)
以第 3 个权重为例:
W3new=W3old−η⋅∂L∂W3=W3old−0.1×(−0.1988)=W3old+0.01988 W_3^{new} = W_3^{old} - \eta \cdot \frac{\partial L}{\partial W_3} = W_3^{old} - 0.1 \times (-0.1988) = W_3^{old} + 0.01988 W3new=W3old−η⋅∂W3∂L=W3old−0.1×(−0.1988)=W3old+0.01988
因为梯度是负的,这次更新会让 W3W_{3}W3 增大,从而轻微降低最终的 logit(使预测概率 0.858 更接近 1)。
第四步:求损失对 Scoring 层输入 Xout2X_{out2}Xout2 的梯度(误差传回残差网络)
这个梯度是反向传播进入残差网络的“钥匙”:
∂L∂Xout2=WscoreT⋅δout \frac{\partial L}{\partial X_{out2}} = W_{score}^T \cdot \delta_{out} ∂Xout2∂L=WscoreT⋅δout
由于我们假设 WscoreW_{score}Wscore 是全1向量,所以:
∂L∂Xout2_i=1×(−0.142)=−0.142(对每个维度i) \frac{\partial L}{\partial X_{out2\_i}} = 1 \times (-0.142) = -0.142 \quad (对每个维度 i) ∂Xout2_i∂L=1×(−0.142)=−0.142(对每个维度i)
这意味着:残差网络输出的 13 个维度,每个维度都收到一个大小为
-0.142的梯度信号。
第五步:误差穿过残差单元 2(残差网络的核心反向传播)
现在,误差信号 ∇Xout2=[−0.142,−0.142,...,−0.142]∇X_{out2}=[−0.142,−0.142,...,−0.142]∇Xout2=[−0.142,−0.142,...,−0.142] 到达了 Residual Unit 2 的输出端。
残差单元 2 的数学结构是:
Xout2=ReLU(Xout1+F2(Xout1)) X_{out2} = \text{ReLU}(X_{out1} + \mathcal{F}_2(X_{out1})) Xout2=ReLU(Xout1+F2(Xout1))
为了求 ∂L∂Xout1\frac{\partial L}{\partial X_{out1}}∂Xout1∂L ,我们需要分两步走:
1. 通过外层 ReLU 激活函数**
在前向传播中,我们计算了 S=Xout1+F2(Xout1)=[0.4,0.1,1.4,0.3,1.5,0.0,0.9,1.7,0.1,0.2,0.9,0.1,0.40]S = X_{out1} + \mathcal{F}_2(X_{out1}) = [0.4,0.1,1.4,0.3,1.5,0.0,0.9,1.7,0.1,0.2,0.9,0.1,0.40]S=Xout1+F2(Xout1)=[0.4,0.1,1.4,0.3,1.5,0.0,0.9,1.7,0.1,0.2,0.9,0.1,0.40]
ReLU 的导数为:
ReLU′(x)={
1,x>00,x≤0 \text{ReLU}'(x) = \begin{cases} 1, & x > 0 \\ 0, & x \le 0 \end{cases} ReLU′(x)={
1,0,x>0x≤0
因为 S 中第 6 个元素恰好为 0,其余均 > 0。
所以,误差信号通过 ReLU 后,第 6 个维度的梯度被截断为 0,其余保持不变:
∂L∂S=[−0.142,−0.142,−0.142,−0.142,−0.142,0,−0.142,−0.142,−0.142,−0.142,−0.142,−0.142,−0.142] \frac{\partial L}{\partial S} = [−0.142,−0.142,−0.142,−0.142,−0.142,0,−0.142,−0.142,−0.142,−0.142,−0.142,−0.142,−0.142] ∂S∂L=[−0.142,−0.142,−0.142,−0.142,−0.142,0,−0.142,−0.142,−0.142,−0.142,−0.142,−0.142,−0.142]
2. 通过加法门(+ 操作)**
在残差单元中,S=Xout1+F2(Xout1)S=X_{out1}+F_{2}(X_{out1})S=Xout1+F2(Xout1)。加法门在反向传播时,会将上游梯度原封不动地复制一份分别传给两个分支:
传给恒等映射(残差连接)的梯度:
∂L∂Xout1+=∂L∂S \frac{\partial L}{\partial X_{out1}} += \frac{\partial L}{\partial S} ∂Xout1∂L+=∂S∂L
传给残差分支 F2F2F2 的梯度:
∂L∂F2=∂L∂S \frac{\partial L}{\partial \mathcal{F}_2} = \frac{\partial L}{\partial S} ∂F2∂L=∂S∂L
关键结论:由于残差连接 + X 的存在,即使 F2F_{2}F2 分支内部的权重梯度消失(变得极小),Xout1X_{out1}Xout1 依然能接收到一个大小为 -0.142(第6维为0)的实打实的梯度。
这就是残差网络能训练深层模型的数学本质——“梯度高速公路”。
第六步:误差继续回传至 Stacking 层和 Embedding 层
误差信号继续向下流动,到达 Residual Unit 1,再传到 Stacking 层。
1. Stacking 层的反向传播(梯度切分)
Stacking 层在前向时是把 3 个 4 维 Embedding 和 1 个标量拼接而成。
在反向传播时,它按原位置把 13 维梯度切分:
- 第 1~4 维(来自
e_query):收到梯度[-0.142, -0.142, -0.142, -0.142] - 第 5~8 维(来自
e_keyword):收到梯度[-0.142, -0.142, -0.142, -0.142] - 第 9~12 维(来自
e_campaign):收到梯度[-0.142, -0.142, -0.142, -0.142] - 第 13 维(来自
v_ctr标量):收到梯度[-0.142]
2. Embedding 表的更新(以 e_query 为例)
e_query = [0.1, 0.4, 0.7, 0.2],其更新公式(梯度下降)为:
Embnew=Embold−η⋅ablaEmb \text{Emb}_{new} = \text{Emb}_{old} - \eta \cdot abla\text{Emb} Embnew=Embold−η⋅ablaEmb
取第一个维度(学习率 η=0.1η=0.1η=0.1):
0.1new=0.1−0.1×(−0.142)=0.1+0.0142=0.1142 0.1^{new} = 0.1 - 0.1 \times (-0.142) = 0.1 + 0.0142 = 0.1142 0.1new=0.1−0.1×(−0.142)=0.1+0.0142=0.1142
同理,其余维度更新为:
- 0.4→0.4+0.0142=0.4142
- 0.7→0.7+0.0142=0.7142
- 0.2→0.2+0.0142=0.2142
这意味着:搜索词“冬季男士跑鞋”的 Embedding 向量在本次更新中被整体拉升(所有维度数值增大),因为它的预测概率还差一点(0.858)
模型需要让它与“点击”这个正标签更紧密地绑定。
小结: 反向传播数值流动全表
| 传播层级 | 传递的梯度数值 (示例) | 数学作用 |
|---|---|---|
| 损失层 → Logit | δout=p−y=−0.142\delta_{out} = p - y = -0.142δout=p−y=−0.142 | 启动反向传播,指明“需要降低 logit” |
| Logit → Scoring 偏置 bbb | ∇b=−0.142\nabla b = -0.142∇b=−0.142 | 全局分数偏移量微调 |
| Logit → Scoring 权重 WWW | ∇Wi=δ⋅xi\nabla W_i = \delta \cdot x_i∇Wi=δ⋅xi (如 -0.1988, -0.2414) | 控制每个特征维度对最终分数的贡献度增减 |
| Scoring → 残差输出 Xout2X_{out2}Xout2 | ∇Xout2=WT⋅δ=−0.142\nabla X_{out2} = W^T \cdot \delta = -0.142∇Xout2=WT⋅δ=−0.142 (全1权重) | 将误差完整地传回给残差网络 |
| 残差单元 2 (ReLU) | 第 6 维梯度变为 0,其余保持 -0.142 | 稀疏化梯度,被 ReLU 截断的神经元不更新 |
| 残差单元 2 (加法门) | ∇Xout1+=−0.142\nabla X_{out1} += -0.142∇Xout1+=−0.142 (恒等映射直接复制) | 核心优势:底层梯度不衰减,缓解梯度弥散 |
| Stacking 层 (切分) | 切分为 4+4+4+1 维,各为 -0.142 | 将梯度分发回各自的 Embedding 表 |
| Embedding 层 | ΔEmb=−0.1×(−0.142)=+0.0142\Delta \text{Emb} = -0.1 \times (-0.142) = +0.0142ΔEmb=−0.1×(−0.142)=+0.0142 | 对“冬季男士跑鞋”等稀疏 ID 的向量做正向微调 |
通过这一整套数值流动,Deep Crossing 完成了端到端的自动特征交叉学习——即使你不知道特征之间如何组合
梯度下降算法也会通过上述数学链条,自动帮助你去调整最底层的 Embedding 和中间层权重,让预测越来越准。
Deep Crossing 完整数据推导链路总结表
| 层级 | 操作 | 输入维度 | 输出维度 | 手算示例输出 |
|---|---|---|---|---|
| Feature层 | 原始One-hot / 标量 | 可变 | 高维稀疏 | Query ID_25, CTR=0.05 |
| Embedding层 | 查表映射 (降维) | 100万 → 4 | 4维/个 | e_query = [0.1, 0.4, 0.7, 0.2] |
| Stacking层 | 向量拼接 (Concat) | 4+4+4+1 | 13维 | X = [0.1, ..., 0.05] |
| 残差单元1 | ReLU(X + F(X)) | 13维 | 13维 | X_out1 = [0.3, 0.3, ..., 0.25] |
| 残差单元2 | 同上 (高阶交叉) | 13维 | 13维 | X_out2 = [...] (含三阶交叉信息) |
| Scoring层 | 全连接 + Sigmoid | 13维 | 1维 | 概率 p = 0.858 |
| 损失层 | 交叉熵 (LogLoss) | 预测值 p + 真实值 y | 标量 | Loss = 0.153 |
总结:Deep Crossing 为什么是经典?
开创性:它是第一个在工业级推荐中验证“深度学习自动交叉特征”可行的模型,奠定了 Embedding + MLP(含残差) 的标准范式。
工程落地细节:针对高基数特征(如 CampaignID),给出了 TopK截断 + 统计特征(历史CTR) 的具体解决方案,至今仍在业界广泛使用。
残差网络的引入:不仅解决了梯度消失,更重要的是证明了推荐系统可以像CV一样搭建深层网络(实验中甚至尝试了数十层),大幅提升了模型的表达上限。
虽然如今已有更复杂的模型(如 DIN、DIEN、Transformer),但Deep Crossing作为“地基”,其设计思想(Embedding降维、Stacking拼接、全连接自动交叉)依然是现代推荐精排模型(如 YouTube DNN、Google Ranking)的核心组成部分。