数值稳定:梯度爆炸/消失、初始化、BN 与残差
连乘的威力、Sigmoid 饱和、Kaiming 初始化、BatchNorm 算例、ResNet 残差。
对应课件:1-2 模型评估和数值稳定
本章对应课件:《1-2 模型评估和数值稳定》。核心内容:梯度爆炸/消失、Sigmoid 饱和、权重初始化、BatchNorm、残差连接 ResNet。
4.1 梯度爆炸与梯度消失
先懂直觉
反向传播是「连乘」:每层梯度乘在一起。如果每层乘的数略小于 1,100 层后趋近 0(消失);略大于 1,100 层后爆炸。深层网络训练难,根子就在这个连乘。
假设深层网络反向传播:
如果每层的局部梯度大约是 1.5:
如果每层大约乘 0.8:
拖动「每层梯度系数」滑块,用对数刻度柱状图观察 100 层后的数值。切换 0.8 和 1.5 两个预设,直观感受指数衰减与指数爆炸。
后果:
| 问题 | 后果 |
|---|---|
| 梯度爆炸 | 参数突然变成极大值,甚至 NaN,训练崩溃 |
| 梯度消失 | 前面层基本学不动,网络只有最后几层在更新 |
课件用 和 来直观说明这个问题。
工程里怎么用(梯度裁剪)
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
optimizer.step()
梯度裁剪把梯度总范数限制在 max_norm 内,是训练 Transformer/RNN 的标准操作,主要防爆炸。梯度消失则靠结构(残差、门控、归一化)解决。
4.2 为什么 Sigmoid 特别容易梯度消失
先懂直觉
Sigmoid 的导数最大只有 0.25,而且两端趋近 0。每过一层至少打 2.5 折,20 层后就是万分之几了。
因为:
最大值只有:
如果连续 20 层都乘 0.25:
很快趋近 0。所以早期深层网络训练很困难。
Sigmoid 导数在 稍大时就急剧饱和:
| x | σ'(x) |
|---|---|
| 0 | 0.25 |
| ±2 | 约 0.105 |
| ±4 | 约 0.0177 |
| ±6 | 约 0.0025 |
而且 Sigmoid 输出非零中心(恒正),还会导致梯度更新方向 zigzag。这就是现代网络改用 ReLU/GELU/SiLU 的原因。
这也是为什么 ReLU、残差连接、Normalization 等技术如此重要。
4.3 权重初始化
先懂直觉
初始权重太大 → 信号和梯度爆炸;太小 → 逐层衰减到 0。好的初始化让每层输出的方差保持稳定,前向反向都「不放大也不缩小」。
如果初始权重特别大,容易梯度爆炸;太小,容易信号和梯度迅速衰减。
课件提到 ReLU 常见 Kaiming / He initialization:
思想是让每层输出的方差不要随着网络深度不断放大或缩小。
前向:。若 、 独立、方差分别为 、,则:
要让它等于 (方差不变),需要:
这就是 Xavier 初始化。对 ReLU,约一半神经元被置零,方差减半,所以补偿为 ——即 Kaiming 初始化。
4.4 Batch Normalization
先懂直觉
每一层的输入分布会随前面层的参数更新而漂移,训练因此变得不稳定。BN 把每个 batch 的激活强行拉回均值 0、方差 1,让每层都在「熟悉的分布」上工作。
BN 的目标:让每层输入保持比较稳定的统计分布。
对一个 batch 的输入 :
均值:
方差:
标准化:
再缩放平移:
输入 batch(单特征):
- ,
- 标准化:
- 若 γ=2, β=1:
γ、β 让模型自己决定「要多少方差、什么均值」。
为什么后面还要 ?
因为如果永远强迫均值 = 0、方差 = 1,反而限制模型表达能力。所以让模型自己学 来调整尺度和偏移。
训练 vs 推理:
- 训练时用当前 batch 的统计量;
- 推理时用训练期间累计的移动平均统计量(否则单条样本无法计算 batch 统计)。
BN 依赖 batch 统计,对变长序列、小 batch、单样本推理都不友好。Transformer 用 LayerNorm / RMSNorm(对每个 token 的 hidden 维归一化,不依赖 batch)。所以 BN 是 CNN 时代的标配,Transformer 时代让位于 LN。
4.5 残差连接 ResNet
先懂直觉
让网络学「在输入基础上加多少修正」,而不是「从头生成输出」。如果不需要修正,直接让 F(x)=0,信息原样通过——至少不会更差。而且反向传播时梯度有一条直通通道。
普通深层网络:
Residual:
非常重要。 如果 学不到什么,,那 ,至少信息可以直接通过。
反向传播:
其中的 1 就是一条非常宝贵的梯度通道——它保证梯度至少能以常数 1 传回去,不会因为连乘而消失。
深网络理论上不应该比浅网络差(多出来的层学恒等映射即可),但实验发现普通深层网络退化严重。残差让「学恒等」变得很容易:把 F 的权重推向 0 即可。所以深度不再是负担。
Transformer 里的:
Attention → Add & Norm → FFN → Add & Norm
其中 Add 就是残差。课件第 14~15 页专门用 解释了这一点。
回到第 7 章的交互结构图,点击「残差相加 ⊕」节点,看它在 Attention 和 FFN 之后如何加回输入。
Q1:梯度消失和梯度爆炸的本质原因是什么?
查看答案
反向传播是链式连乘:∂L/∂W₁ = ∂L/∂hₙ · Π(∂hᵢ/∂hᵢ₋₁)。每层的局部雅可比(含权重矩阵和激活导数)连乘,若谱半径 < 1 则指数衰减(消失),> 1 则指数增长(爆炸)。深度/序列长度越大越严重。
Q2:分别有哪些解决方案?
查看答案
梯度消失:ReLU/GELU 等非饱和激活、残差连接(恒等通道)、归一化(BN/LN/RMSNorm)、LSTM 门控、合适的初始化(Kaiming/Xavier)。梯度爆炸:梯度裁剪(clip_grad_norm)、更小的学习率、warmup、BF16 替代 FP16。
Q3:为什么残差连接对 Transformer 是必需的?
查看答案
Transformer 每一层包含 Attention 和 FFN 两次复杂变换,如果没有残差,梯度必须穿过所有层的雅可比连乘,12 层以上几乎无法训练。残差提供 ∂y/∂x = 1 + ∂F/∂x 中的常数 1 通道,保证梯度可直接回传。
| 技术 | 解决的问题 | 核心机制 |
|---|---|---|
| ReLU | Sigmoid 饱和导致梯度消失 | 正区间导数恒为 1 |
| Kaiming 初始化 | 信号方差随深度漂移 | (ReLU) |
| BatchNorm | 各层输入分布不稳定 | 标准化 + 可学习 γ、β(跨 batch) |
| LayerNorm | 同上,但适配 NLP | 跨 hidden 维归一化(第 7 章) |
| Residual | 深层网络梯度消失 | ,梯度含常数 1 通道 |
显示答案与解析
正确答案:B
σ'(x) = σ(x)(1−σ(x)) 最大值 0.25,且 |x| 增大时迅速趋近 0。深层反向传播连乘会指数衰减。ReLU 正区间导数为 1,避免了这个问题。显示答案与解析
正确答案:B
那个常数 1 保证梯度至少能无损回传一层,是深层网络(ResNet、Transformer)可训练的关键。同时网络只需学「修正量」,学恒等映射变得容易。显示答案与解析
正确答案:B
推理时可能只有单条样本,无法计算 batch 统计,所以使用训练期间累积的 running mean/var。这也是 model.eval() 要切换的原因。显示答案与解析
正确答案:B
ReLU 把负半轴置 0,输出方差约为原来一半,所以初始化方差放大 2 倍(σ² = 2/n_in)才能让每层方差保持稳定。