梯度爆炸#
由于反向传播时,梯度的计算涉及多次矩阵乘法,则累积多次之后,梯度可能变得过大,甚至大于浮点数表示极限(成为 inf 或者 NaN)。这会导致训练过程对学习率极度敏感,过大会导致模型容易发散,过小会导致学习没有进展,总之难以收敛。这导致我们可能需要动态地调整学习率。
梯度消失#
与梯度爆炸类似,只是换成了梯度趋于 0. 在使用 sigmoid 作为激活函数时尤为明显,并且对深层网络的底部尤为明显,导致靠近输入的层得不到更新。
GPT Q&A#
梯度消失的影响
问:具有多层的深度神经网络,在训练的时候,会不会因为反向传播算法本身的问题,导致模型更倾向于改变离输出层更近的权重,而保守离输入层更近的权重?这样对训练是不是有副作用(比如让模型短视、遗忘已学习的特征)?有什么方式可以减轻这种效应吗
GPT:
你的直觉 完全正确,而且你问到的是深度学习理论中一个非常核心的现象:
深层网络中,越靠近输入的层,其梯度越弱,参数更新幅度越小;越靠近输出的层更新越大。
这不仅是真实存在的现象,而且确实会带来副作用(训练困难、短视、遗忘、特征不稳定)。
下面我会从机理、后果和解决方法三个层面讲清楚。
🧠 1. 为什么靠近输入的层梯度更小?#
因为反向传播在每一层都会乘上一个雅可比矩阵(或其标量/向量形式)。
在深度网络中:
∂W1∂L(k=2∏LJk)∂hL∂L每过一层 → 乘上一组梯度因子。
特别是对于激活函数 f(sigmoid, tanh 等)其导数:
- sigmoid 最大导数约 0.25
- tanh 最大导数约 1
- ReLU 的导数要么 0 要么 1
如果每一层的导数绝对值 < 1(sigmoid最典型),连续相乘会导致:
∥∂h1∂L∥→0这就是梯度消失(vanishing gradient)。
❗ 这导致的问题#
(1) 前层训练速度极慢(因为梯度太小)#
它们的权重几乎不变。
(2) 后层训练速度快(梯度大)#
因此经过几次训练后:
这是你说的 “短视”、“遗忘前面学过的特征”。
确实存在,而且研究中有明确说明。
🧨 2. 是否会导致模型短视?(会)#
后层容易 过拟合:
- 因为它们的梯度大、更新大
- 它们倾向于把前层输出视为固定特征
- 于是只能从“短期误差”中学习
- 从而忽略长程依赖
比如在 MLP 中,靠近输入的 embedding 层更新可能非常小,而靠近输出的层不断重写自己 → 出现 catastrophic forgetting(灾难性遗忘)。
🧨 3. 是否会导致遗忘已学习特征?(会)#
如果浅层梯度一直很小,它们学到的表示(比如边缘、纹理)会因后层变化而失效,但自身却无法及时调整。
这造成了一种“特征漂移”(feature drift)问题。
网络前面的层 “来不及” 跟随数值分布的变化。
🛠 4. 如何减轻这个效应?(深度学习的许多技巧都是为此而生!)#
下面按效果从最强到弱排序:
✅(1)使用 ReLU 或其他不饱和激活函数(最关键)#
- ❌ sigmoid/tanh 的梯度 < 1,因此多层乘积 → 灭掉梯度
- ✅ ReLU 的导数要么 0 要么 1,不会持续缩小
- ✅ GELU / Swish / ReLU6 也比 sigmoid 好得多
没有 ReLU,就没有深度学习革命。
✅(2)使用更好的权重初始化(Xavier/He initialization)#
初始化方法(特别是 He)让梯度在多层中传播更稳定:
- Xavier 适合 tanh
- He 适合 ReLU
能显著减轻梯度爆炸/消失。
✅(3)使用 BatchNorm / LayerNorm / GroupNorm#
Norm 层有三个重要作用:
- 让梯度在多层中更平稳
因为每层的输入分布被归一化,Jaccobian 更接近单位矩阵。
- 减少“短视行为”
后层不再需要频繁适应前层的分布变化。
- 加速训练(巨大效果)
深层网络几乎都靠它。
✅(4)残差连接(ResNet)——专门为解决这个问题而发明#
ResNet 的核心:
hl+1=hl+f(hl)梯度传播变成:
∂hl∂L∂hl+1∂L(I+Jf)中间多了一个恒等映射 I.
这意味着:
- 即使 J_f 导数很小(梯度快没了)
- 单位矩阵项保证梯度仍可回传
这直接解决了梯度消失!
因此 ResNet 能训练上百甚至上千层的网络。
🚀(5)使用优化器 Adam、Adagrad、RMSProp#
这些优化器基于历史梯度累积,能给前层(梯度小)更多更新幅度,使训练更稳定。
Transformer 的 self-attention 层有残差和 LayerNorm,本质上也是为了让深度模型在反向传播中保持梯度健康。
🎯 终极总结#
✔ 深度网络确实倾向于:#
- 更新靠近输出的层更多
- 更新靠近输入的层更少
- 出现短视行为
- 出现特征漂移、遗忘
✔ 这种现象由链式规则导致,是深度网络本质缺陷#
✔ 解决办法#
- ReLU / GELU 激活
- 更好的初始化(Xavier/He)
- BatchNorm / LayerNorm
- 残差网络(ResNet)
- 使用 Adam 等自适应优化器
- 更先进的架构(如 Transformer)
如果你需要,我还可以进一步说明:
- 为什么 ResNet 可以让梯度几乎无衰减穿越 1000 层?
- 为什么 BatchNorm 实际相当于引入了“平坦化的 Jacobian”?
- 为什么 Adam 自带“隐式层级补偿”?
你想继续深入哪个方向?
解决办法#
目标:让训练变得更稳定,即控制梯度合理的范围内,如 [1e-6, 1e3]
- 将乘法变成加法
- 归一化
- 合理的权重初始化和激活函数
合理的权重初始化与合理的激活函数#
合理的权重初始化#
- 在合理值区间里随机初始化参数
- 训练开始的时候更容易出现数值不稳定
- 远离最优解的地方损失函数表面可能很复杂
- 最优解附近表面会比较平
- 使用 N(0,0.01) 来初始化,可能对小网络没问题,但不能保证深度神经网络
以 MLP 为例进行推导#
如果将每一层的输出和梯度都看作随机变量,我们希望它们的期望都为 0,方差在所有层之间都相同。
符号化地,设:
- 第 t 层的权重矩阵为 w,其中的一个元素为 wi,jt
- 第 t 层的输出向量,同时也是第 t+1 层的输入向量为 ht,其中的一个元素为 hit
那么我们的要求可以描述为:
正向(输出)E[hit]Var[hit]=0=a反向(梯度)E[∂hit∂ℓ]=0Var[∂hit∂ℓ]=b∀i,t
为了推导方便,我们做一些假设:
- wi,jt 是独立同分布随机变量,那么 E[wi,jt]=0,Var[wi,jt]=γt
- hkt−1 独立于 wi,jt
同时假设没有激活函数,则:
ht=wtht−1,这里 wt∈Rnt×nt−1
则正向的输出符合:
E[hit]=E[j∑wi,jthjt−1]=j∑E[wi,jt]E[hjt−1]=0
Var[hit]=E[(hit)2]−0E[(hit)]2=E(j∑wi,jthjt−1)2=Ej∑(wi,jt)2(hjt−1)2+期望为零j=k∑wi,jtwi,kthjt−1hkt−1=j∑E[(wi,jt)2]E[(hjt−1)2]=j∑由 E[(wi,jt)]=E[(hjt−1)]=0 得Var[wi,jt]Var[hjt−1]=nt−1γtVar[hjt−1]
因此,若想要 Var[hit] 在不同层 t 之间保持相同,就需要: nt−1γt=1
对反向的梯度也可以做类似推导,得到的要求是:ntγt=1
这不炸了吗
没法同时满足要求。但我们可以做一个权衡:Xavier初始
Xavier 初始#
理念:不能同时满足,但可以折衷。
Xavier 使得 γt(nt−1+nt)/2=1⇒γt=2/(nt−1+nt)
- 正态分布 N(0,2/(nt−1+nt))
- 均匀分布 U(−6/(nt−1+nt),6/(nt−1+nt))
- 分布 U(−a,a) 的方差是 a2/3
- 初值适配权重矩阵的形状,特别是 nt
合理的激活函数#
书接上回,如果考虑激活函数的影响,如何继续保持层输出和梯度在层间相同呢?
继续以 MLP 为例进行推导#
假设激活函数是线性函数:σ(x)=αx+β ,则:
h′=wtht−1 且 ht=σ(h′);
∂h′∂ℓ=∂ht∂ℓ(wt)T 且 ∂ht−1∂ℓ=α∂h′∂ℓ.
推导:
E[hit]Var[hit]=E[αhi′+β]=β=E[(hit)2]−E[hit]2=E[(αhi′+β)2]−β2=E[α2(hi′)2+2αβhi′+β2]−β2=α2Var[hi′]
得到 α=1,β=0
E[∂hit−1∂ℓ]Var[∂hit−1∂ℓ]=0=α2Var[∂hj′∂ℓ]
得到 α=1,β=0
也就是说,我们永远需要 y=x 这个激活函数。
这似乎解释了,为什么 ReLU、tanh 作为激活函数要比 sigmoid 好——tanh 在原点附近近似是 y=x,而 ReLU 更是在 x≥0 时直接等于 y=x,从而能更好避免梯度消失的问题,提高数值稳定性。
同时,如果尝试把 sigmoid 拉伸平移一下,使得其过原点且在原点处斜率为 1,那么其效果也将变得不错。