CoderXL's Blog

Back

数值稳定性——模型初始化和激活函数Blur image

概念#

梯度爆炸#

由于反向传播时,梯度的计算涉及多次矩阵乘法,则累积多次之后,梯度可能变得过大,甚至大于浮点数表示极限(成为 inf\inf 或者 NaN\text{NaN})。这会导致训练过程对学习率极度敏感,过大会导致模型容易发散,过小会导致学习没有进展,总之难以收敛。这导致我们可能需要动态地调整学习率。

梯度消失#

与梯度爆炸类似,只是换成了梯度趋于 00. 在使用 sigmoid 作为激活函数时尤为明显,并且对深层网络的底部尤为明显,导致靠近输入的层得不到更新。

GPT Q&A#

梯度消失的影响

问:具有多层的深度神经网络,在训练的时候,会不会因为反向传播算法本身的问题,导致模型更倾向于改变离输出层更近的权重,而保守离输入层更近的权重?这样对训练是不是有副作用(比如让模型短视、遗忘已学习的特征)?有什么方式可以减轻这种效应吗

GPT: 你的直觉 完全正确,而且你问到的是深度学习理论中一个非常核心的现象: 深层网络中,越靠近输入的层,其梯度越弱,参数更新幅度越小;越靠近输出的层更新越大。

这不仅是真实存在的现象,而且确实会带来副作用(训练困难、短视、遗忘、特征不稳定)。

下面我会从机理、后果和解决方法三个层面讲清楚。


🧠 1. 为什么靠近输入的层梯度更小?#

因为反向传播在每一层都会乘上一个雅可比矩阵(或其标量/向量形式)。

在深度网络中:

LW1(k=2LJk)LhL\frac{\partial L}{\partial W_1} \left(\prod_{k=2}^L J_k \right) \frac{\partial L}{\partial h_L}

每过一层 → 乘上一组梯度因子。

特别是对于激活函数 f(sigmoid, tanh 等)其导数:

  • sigmoid 最大导数约 0.25
  • tanh 最大导数约 1
  • ReLU 的导数要么 0 要么 1

如果每一层的导数绝对值 < 1(sigmoid最典型),连续相乘会导致:

Lh10\|\frac{\partial L}{\partial h_1}\| \to 0

这就是梯度消失(vanishing gradient)。


❗ 这导致的问题#
(1) 前层训练速度极慢(因为梯度太小)#

它们的权重几乎不变。

(2) 后层训练速度快(梯度大)#

因此经过几次训练后:

  • 前层不会学习新特征
  • 后层疯狂拟合当前 batch

这是你说的 “短视”、“遗忘前面学过的特征”。

确实存在,而且研究中有明确说明。


🧨 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 层有三个重要作用:

  1. 让梯度在多层中更平稳

因为每层的输入分布被归一化,Jaccobian 更接近单位矩阵。

  1. 减少“短视行为”

后层不再需要频繁适应前层的分布变化。

  1. 加速训练(巨大效果)

深层网络几乎都靠它。

✅(4)残差连接(ResNet)——专门为解决这个问题而发明#

ResNet 的核心:

hl+1=hl+f(hl)h_{l+1} = h_l + f(h_l)

梯度传播变成:

LhlLhl+1(I+Jf)\frac{\partial L}{\partial h_l} \frac{\partial L}{\partial h_{l+1}}(I + J_f)

中间多了一个恒等映射 II.

这意味着:

  • 即使 J_f 导数很小(梯度快没了)
  • 单位矩阵项保证梯度仍可回传

这直接解决了梯度消失!

因此 ResNet 能训练上百甚至上千层的网络。

🚀(5)使用优化器 Adam、Adagrad、RMSProp#

这些优化器基于历史梯度累积,能给前层(梯度小)更多更新幅度,使训练更稳定。

🚀(6)更巧妙的架构设计(Transformer)#

Transformer 的 self-attention 层有残差和 LayerNorm,本质上也是为了让深度模型在反向传播中保持梯度健康。


🎯 终极总结#
✔ 深度网络确实倾向于:#
  • 更新靠近输出的层更多
  • 更新靠近输入的层更少
  • 出现短视行为
  • 出现特征漂移、遗忘
✔ 这种现象由链式规则导致,是深度网络本质缺陷#
✔ 解决办法#
  • ReLU / GELU 激活
  • 更好的初始化(Xavier/He)
  • BatchNorm / LayerNorm
  • 残差网络(ResNet)
  • 使用 Adam 等自适应优化器
  • 更先进的架构(如 Transformer)

如果你需要,我还可以进一步说明:

  • 为什么 ResNet 可以让梯度几乎无衰减穿越 1000 层?
  • 为什么 BatchNorm 实际相当于引入了“平坦化的 Jacobian”?
  • 为什么 Adam 自带“隐式层级补偿”?

你想继续深入哪个方向?

解决办法#

目标:让训练变得更稳定,即控制梯度合理的范围内,如 [1e-6, 1e3]

  • 将乘法变成加法
    • ResNet
    • LSTM
  • 归一化
    • 梯度归一化
    • 梯度裁剪
  • 合理的权重初始化和激活函数

合理的权重初始化与合理的激活函数#

合理的权重初始化#

  • 在合理值区间里随机初始化参数
  • 训练开始的时候更容易出现数值不稳定
    • 远离最优解的地方损失函数表面可能很复杂
    • 最优解附近表面会比较平
  • 使用 N(0,0.01)\mathscr{N}(0,0.01) 来初始化,可能对小网络没问题,但不能保证深度神经网络
以 MLP 为例进行推导#

如果将每一层的输出和梯度都看作随机变量,我们希望它们的期望都为 00,方差在所有层之间都相同。

符号化地,设:

  • tt 层的权重矩阵为 w\boldsymbol{w},其中的一个元素为 wi,jtw^t_{i,j}
  • tt 层的输出向量,同时也是第 t+1t+1 层的输入向量为 ht\boldsymbol{h}^t,其中的一个元素为 hith^t_i

那么我们的要求可以描述为:

正向(输出)反向(梯度)E[hit]=0Var[hit]=aE[hit]=0Var[hit]=bi,t\begin{array}{c} &\text{正向(输出)} &\qquad& \text{反向(梯度)} \\ & \begin{aligned} \mathbb{E}[h^t_i]&=0\\ \operatorname{Var}[h^t_i]&=a \end{aligned} &&\begin{array}{} \mathbb{E}\left[\displaystyle{\partial \ell \over \partial h^t_i}\right]=0& \operatorname{Var}\left[\displaystyle{\partial \ell \over \partial h^t_i}\right]=b \end{array} & \qquad \forall i,t \end{array}

为了推导方便,我们做一些假设:

  • wi,jtw^t_{i,j} 是独立同分布随机变量,那么 E[wi,jt]=0\mathbb{E}[w^t_{i,j}]=0Var[wi,jt]=γt\operatorname{Var}[w^t_{i,j}]=\gamma_t
  • hkt1h^{t-1}_k 独立于 wi,jtw^t_{i,j}

同时假设没有激活函数,则:
ht=wtht1\boldsymbol{h}^t=\boldsymbol{w}^t\boldsymbol{h}^{t-1},这里 wtRnt×nt1\boldsymbol{w}^t \in \mathbb{R}^{n_t \times n_{t-1}}

则正向的输出符合:

E[hit]=E[jwi,jthjt1]=jE[wi,jt]E[hjt1]=0\mathbb{E}[h^t_i] = \mathbb{E}\left[\sum_j w^t_{i,j}h^{t-1}_j\right] = \sum_j \mathbb{E}[w^t_{i,j}]\mathbb{E}[h^{t-1}_j] = 0 Var[hit]=E[(hit)2]E[(hit)]20=E[(jwi,jthjt1)2]=E[j(wi,jt)2(hjt1)2+jkwi,jtwi,kthjt1hkt1期望为零]=jE[(wi,jt)2]E[(hjt1)2]=jVar[wi,jt]Var[hjt1]由 E[(wi,jt)]=E[(hjt1)]=0 得=nt1γtVar[hjt1]\begin{aligned} \operatorname{Var}[h^t_i] &=\mathbb{E}[(h^t_i)^2]-\underbrace{\mathbb{E}[(h^t_i)]^2}_{0} =\mathbb{E}\left[\left(\sum_j w^t_{i,j} h^{t-1}_j\right)^2\right]\\ &=\mathbb{E}\left[\sum_j \left(w^t_{i,j}\right)^2\left(h^{t-1}_j\right)^2+\underbrace{\sum_{j\ne k} w^t_{i,j}w^t_{i,k}h^{t-1}_j h^{t-1}_k}_{\text{期望为零}}\right]\\ &=\sum_j \mathbb{E}\left[\left(w^t_{i,j}\right)^2\right]\mathbb{E}\left[\left(h^{t-1}_j\right)^2\right]\\ &=\sum_j \underbrace{\operatorname{Var}[w^t_{i,j}]\operatorname{Var}[h^{t-1}_j]}_{\text{由 } \mathbb{E}[(w^t_{i,j})]=\mathbb{E}[(h^{t-1}_j)]=0 \text{ 得}}\\ &=\boxed{n_{t-1}\gamma_t\operatorname{Var}[h^{t-1}_j]} \end{aligned}

因此,若想要 Var[hit]\operatorname{Var}[h^t_i] 在不同层 tt 之间保持相同,就需要: nt1γt=1\boxed{n_{t-1}\gamma_t=1}

对反向的梯度也可以做类似推导,得到的要求是:ntγt=1\boxed{n_t\gamma_t=1}

这不炸了吗

没法同时满足要求。但我们可以做一个权衡:Xavier初始

Xavier 初始#

理念:不能同时满足,但可以折衷。

Xavier 使得 γt(nt1+nt)/2=1γt=2/(nt1+nt)\gamma_t(n_{t-1}+n_t)/2=1 \quad \Rightarrow \quad \gamma_t=2/(n_{t-1}+n_t)

  • 正态分布 N(0,2/(nt1+nt))\mathscr{N}\left(0,\sqrt{2/(n_{t-1}+n_t)}\right)
  • 均匀分布 U(6/(nt1+nt),6/(nt1+nt))\mathscr{U}\left(-\sqrt{6/(n_{t-1}+n_t)},\sqrt{6/(n_{t-1}+n_t)}\right)
    • 分布 U(a,a)\mathscr{U}(-a,a) 的方差是 a2/3a^2/3
  • 初值适配权重矩阵的形状,特别是 ntn_t

合理的激活函数#

书接上回,如果考虑激活函数的影响,如何继续保持层输出和梯度在层间相同呢?

继续以 MLP 为例进行推导#

假设激活函数是线性函数:σ(x)=αx+β\sigma(x)=\alpha x+ \beta ,则:
h=wtht1\boldsymbol{h}'=\boldsymbol{w}^t\boldsymbol{h}^{t-1}ht=σ(h)\boldsymbol{h}^t=\sigma(\boldsymbol{h}')h=ht(wt)T\displaystyle{{\partial \ell \over \partial \boldsymbol{h}'} = {\partial \ell \over \partial \boldsymbol{h}^t}(\boldsymbol{w}^t)^T}ht1=αh\displaystyle{{\partial \ell \over \partial \boldsymbol{h}^{t-1}} = \alpha{\partial \ell \over \partial \boldsymbol{h}'}}.

推导:

  • 正向
E[hit]=E[αhi+β]=βVar[hit]=E[(hit)2]E[hit]2=E[(αhi+β)2]β2=E[α2(hi)2+2αβhi+β2]β2=α2Var[hi]\begin{aligned} \mathbb{E}\left[h_{i}^{t}\right] & =\mathbb{E}\left[\alpha h_{i}^{\prime}+\beta\right]=\beta \\ \operatorname{Var}\left[h_{i}^{t}\right] & =\mathbb{E}\left[\left(h_{i}^{t}\right)^{2}\right]-\mathbb{E}\left[h_{i}^{t}\right]^{2} \\ & =\mathbb{E}\left[\left(\alpha h_{i}^{\prime}+\beta\right)^{2}\right]-\beta^{2} \\ & =\mathbb{E}\left[\alpha^{2}\left(h_{i}^{\prime}\right)^{2}+2 \alpha \beta h_{i}^{\prime}+\beta^{2}\right] - \beta^2 \\ & =\alpha^{2} \operatorname{Var}\left[h_{i}^{\prime}\right] \end{aligned}

得到 α=1\alpha=1β=0\beta=0

  • 反向
E[hit1]=0Var[hit1]=α2Var[hj]\begin{aligned} \mathbb{E}\left[\frac{\partial \ell}{\partial h_{i}^{t-1}}\right] & =0 \\ \operatorname{Var}\left[\frac{\partial \ell}{\partial h_{i}^{t-1}}\right] & =\alpha^{2} \operatorname{Var}\left[\frac{\partial \ell}{\partial h_{j}^{\prime}}\right] \end{aligned}

得到 α=1\alpha=1β=0\beta=0

也就是说,我们永远需要 y=xy=x 这个激活函数。

这似乎解释了,为什么 ReLU、tanh 作为激活函数要比 sigmoid 好——tanh 在原点附近近似是 y=xy=x,而 ReLU 更是在 x0x\ge 0 时直接等于 y=xy=x,从而能更好避免梯度消失的问题,提高数值稳定性。
同时,如果尝试把 sigmoid 拉伸平移一下,使得其过原点且在原点处斜率为 11,那么其效果也将变得不错。

数值稳定性——模型初始化和激活函数
https://blog.leosrealms.top/blog/2025-11-18-numerical-stability---initialization-and-activation-functions
Author CoderXL
Published at 2025年11月18日
Comment seems to stuck. Try to refresh?✨