动手学深度学习(十六)——数值稳定性和模型初始化(公式说明)

文章目录

    • 一、数值稳定性——梯度消失和梯度爆炸
    • 二、多层感知机器(MLP)中说明梯度爆炸和梯度消失
      • 2.1 梯度爆炸
        • 梯度爆炸的问题
      • 2.2 梯度消失
        • 梯度消失的问题
      • 2.3总结
    • 如何让训练更加稳定?
    • 三、模型初始化和激活函数
      • 3.1 权重初始化
      • 3.2 让每一层的方差都是一个常数
        • Xavier初始化:以多层感知机为例
        • 假设线性的激活函数
      • 3.3 总结

一、数值稳定性——梯度消失和梯度爆炸

考虑一个具有 L L L层、输入 x \mathbf{x} x和输出 o \mathbf{o} o的深层网络。每一层 l l l由变换 f l f_l fl定义,该变换的参数为权重 W ( l ) \mathbf{W}^{(l)} W(l),其隐藏变量是 h ( l ) \mathbf{h}^{(l)} h(l)(令 h ( 0 ) = x \mathbf{h}^{(0)} = \mathbf{x} h(0)=x)。

考虑有L层的网络可以表示为:

h ( l ) = f l ( h ( l − 1 ) )  因此  o = l o s s ∗ f L ∗ … ∗ f 1 ( x ) . \mathbf{h}^{(l)} = f_l (\mathbf{h}^{(l-1)}) \text{ 因此 } \mathbf{o} = loss * f_L * \ldots * f_1(\mathbf{x}). h(l)=fl(h(l1)) 因此 o=lossfLf1(x).

计算损失loss关于任何一组参数 W ( l ) \mathbf{W}^{(l)} W(l)的梯度写为下式:

∂ l o s s ∂ w l = ∂ l o s s ∂ h L ∂ h L ∂ h L − 1 . . . ∂ h l + 1 ∂ h l ∂ h l ∂ w l \frac{\partial loss}{\partial w^l} = \frac{\partial loss}{\partial h^L} \frac{\partial h^L}{\partial h^{L-1}} ... \frac{\partial h_{l+1}}{\partial h^l} \frac{\partial h^l}{\partial w^l} wlloss=hLlosshL1hL...hlhl+1wlhl

换言之,该梯度是 L − l L-l Ll个矩阵 M ( L ) ⋅ … ⋅ M ( l + 1 ) \mathbf{M}^{(L)} \cdot \ldots \cdot \mathbf{M}^{(l+1)} M(L)M(l+1)与梯度向量 v ( l ) \mathbf{v}^{(l)} v(l)的乘积。因此,我们容易受到数值下溢问题的影响,当将太多的概率乘在一起时,这些问题经常会出现。在处理概率时,一个常见的技巧是切换到对数空间,即将数值表示的压力从尾数转移到指数。不幸的是,我们上面的问题更为严重:最初,矩阵 M ( l ) \mathbf{M}^{(l)} M(l) 可能具有各种各样的特征值。他们可能很小,也可能很大,他们的乘积可能非常大,也可能非常小

不稳定梯度带来的风险不止在于数值表示。不稳定梯度也威胁到我们优化算法的稳定性。我们可能面临一些问题:

  1. 要么是 梯度爆炸(gradient exploding)问题:参数更新过大,破坏了模型的稳定收敛;
  2. 要么是 梯度消失(gradient vanishing)问题:参数更新过小,在每次更新时几乎不会移动,导致无法学习。

二、多层感知机器(MLP)中说明梯度爆炸和梯度消失

f l ( h l − 1 ) = σ ( W l h l − 1 ) (1) f_l(h^{l-1}) = \sigma(W^lh^{l-1}) \tag{1} fl(hl1)=σ(Wlhl1)(1) σ \sigma σ 是激活函数

∂ h l ∂ h l − 1 = d i a g ( σ ′ ( W l h l − 1 ) ) ( W l ) T (2) \frac{\partial h^l}{\partial h^{l-1}} = diag(\sigma '(W^lh^{l-1}))(W^l)^T \tag{2} hl1hl=diag(σ(Wlhl1))(Wl)T(2)

∏ i = l L − 1 ∂ h i + 1 ∂ h i = ∏ i = l L − 1 d i a g ( σ ′ ( W l h l − 1 ) ) ( W l ) T (3) \prod_{i=l}^{L-1}\frac{\partial h^{i+1}}{\partial h^{i}} = \prod_{i=l}^{L-1}diag(\sigma '(W^lh^{l-1}))(W^l)^T \tag{3} i=lL1hihi+1=i=lL1diag(σ(Wlhl1))(Wl)T(3)

2.1 梯度爆炸

使用relu作为激活函数
σ ( x ) = m a x ( 0 , x ) a n d σ ′ ( x ) = { 1 , x > 0 0 , o t h e r w i s e (4) \sigma(x) = max(0,x) \quad and \quad \sigma '(x) = \begin{cases} 1,\quad x>0\\ 0, \quad otherwise \end{cases} \tag{4} σ(x)=max(0,x)andσ(x)={1,x>00,otherwise(4)

  • ∏ i = l L − 1 ∂ h i + 1 ∂ h i = ∏ i = l L − 1 d i a g ( σ ′ ( W l h l − 1 ) ) ( W l ) T \prod_{i=l}^{L-1}\frac{\partial h^{i+1}}{\partial h^{i}} = \prod_{i=l}^{L-1}diag(\sigma '(W^lh^{l-1}))(W^l)^T i=lL1hihi+1=i=lL1diag(σ(Wlhl1))(Wl)T  的一些元素来自  ∏ i = l L − 1 ( W i ) T \prod_{i=l}^{L-1}(W^i)^T i=lL1(Wi)T   如果L-l很大,最终得到的梯度的值非常大
M = torch.normal(0, 1, size=(4, 4))
print('一个矩阵 \n', M)
for i in range(100):
    M = torch.mm(M, torch.normal(0, 1, size=(4, 4)))

print('乘以100个矩阵后\n', M)

动手学深度学习(十六)——数值稳定性和模型初始化(公式说明)_第1张图片

梯度爆炸的问题

  1. 超出值域(infinity):对于16位浮点数尤其严重(数值区间为:6e5 - -6e4)
  2. 对学习率非常敏感
    • 学习了太大 -> 大参数值 ->更大的梯度
    • 学习率太小 -> 训练无进展
    • 需要在训练的过程中不断调整学习率

2.2 梯度消失

使用sigmoid作为激活函数:
σ ( x ) = 1 1 − e x (5) \sigma (x) = \frac{1}{1-e^x} \tag{5} σ(x)=1ex1(5)
sigmoid激活函数的导数为:
σ ′ ( x ) = σ ( x ) ( 1 − σ ( x ) ) (6) \sigma '(x) = \sigma (x)(1-\sigma(x)) \tag{6} σ(x)=σ(x)(1σ(x))(6)

∏ i = l L − 1 ∂ h i + 1 ∂ h i = ∏ i = l L − 1 d i a g ( σ ′ ( W l h l − 1 ) ) ( W l ) T \prod_{i=l}^{L-1}\frac{\partial h^{i+1}}{\partial h^{i}} = \prod_{i=l}^{L-1}diag(\sigma '(W^lh^{l-1}))(W^l)^T i=lL1hihi+1=i=lL1diag(σ(Wlhl1))(Wl)T   的元素是L-l个小数值进行乘 0. 8 100 ≈ 2 × 1 0 − 10 0.8^{100} \approx 2 \times 10^{-10} 0.81002×1010

# 下面这是sigmoid激活函数的图像和其导数图像,可以看到sigmoid函数的导数在输入较大的时候输出接近于0
%matplotlib inline
import torch
from d2l import torch as d2l

x = torch.arange(-8.0, 8.0, 0.1, requires_grad=True)
y = torch.sigmoid(x)
y.backward(torch.ones_like(x))

d2l.plot(x.detach().numpy(), [y.detach().numpy(), x.grad.numpy()],
         legend=['sigmoid', 'gradient'], figsize=(4.5, 2.5))

动手学深度学习(十六)——数值稳定性和模型初始化(公式说明)_第2张图片

梯度消失的问题

  1. 梯度值变为0(对16位浮点数非严重)
  2. 训练没有进展(无论怎么选择学习率都是没有用的)
  3. 对于底层影响巨大
    • 一个模型可能仅仅只有顶层训练得较好
    • 限制了网络的深度

2.3总结

  1. 当数值过大或者过小的时候都会导致数值问题
  2. 常发生在深度模型之中,因为其会对n个数进行累乘

如何让训练更加稳定?

  1. 让梯度值在合理的范围之内(限制)
  2. 将乘法变为加法(梯度计算就会由连乘变为累加):ResNet,LSTM
  3. 归一化(梯度归一化、梯度裁减)
  4. 合理的权重初始化和激活函数

三、模型初始化和激活函数

目前为止,模型的参数都是根据某种预先指定的分布设计的,我们认为是理所当然的,却忽略了如何作出这些选择的细节。

但是,初始化方案的选择在神经网络学习中起着非常重要的作用,其对保持数值稳定性至关重要。

初始化方案的选择和非线性激活函数的选择相结合,决定了优化算收敛的速度有多块,糟糕的选择会导致我们在训练时遇到梯度爆炸或者梯度消失。

3.1 权重初始化

在合理值的区间随机初始化参数
在训练开始的时候更容易有数值不稳定

  • 远离最优解的地方损失函数表面可能很复杂
  • 最优解附近比表面会比较平

使用 N ( 0 , 0.01 ) N(0,0.01) N(0,0.01)初始化小网络没有问题,但是不能保证深度神经网络

3.2 让每一层的方差都是一个常数

  1. 将每层的输出和梯度都看作随机变量
  2. 让它们的均值和方差都保持一致

正向
E [ h i l ] = 0 V a r [ h i l ] = a (3.1) E[h_{i}^{l}] = 0 \quad Var[h_{i}^{l}] = a \tag{3.1} E[hil]=0Var[hil]=a(3.1)
反向
E [ ∂ L o s s h i l ] = 0 V a r [ ∂ L o s s h i l ] = b (3.2) E[\frac{\partial{Loss}}{h_{i}^{l}}] = 0 \quad Var[\frac{\partial{Loss}}{h_{i}^{l}}] = b \tag{3.2} E[hilLoss]=0Var[hilLoss]=b(3.2)

Xavier初始化:以多层感知机为例

如果不加上非线性全连接层:该层 n i n n_\mathrm{in} nin输入 x j x_j xj及其相关权重 w i j w_{ij} wij,输出由下式给出

o i = ∑ j = 1 n i n w i j x j (3.3) o_{i} = \sum_{j=1}^{n_\mathrm{in}} w_{ij} x_j \tag{3.3} oi=j=1ninwijxj(3.3)

权重 w i j w_{ij} wij都是从同一分布中独立抽取的。此外,让我们假设该分布具有零均值和方差 σ 2 \sigma^2 σ2。请注意,这并不意味着分布必须是高斯的,只是均值和方差需要存在。现在,让我们假设层 x j x_j xj的输入也具有零均值和方差 γ 2 \gamma^2 γ2,并且它们独立于 w i j w_{ij} wij并且彼此独立。在这种情况下,我们可以按如下方式计算 o i o_i oi的平均值和方差:

E [ o i ] = ∑ j = 1 n i n E [ w i j x j ] = ∑ j = 1 n i n E [ w i j ] E [ x j ] = 0 , V a r [ o i ] = E [ o i 2 ] − ( E [ o i ] ) 2 = ∑ j = 1 n i n E [ w i j 2 x j 2 ] − 0 = ∑ j = 1 n i n E [ w i j 2 ] E [ x j 2 ] = n i n σ 2 γ 2 . (3.4) \begin{aligned} E[o_i] & = \sum_{j=1}^{n_\mathrm{in}} E[w_{ij} x_j] \\&= \sum_{j=1}^{n_\mathrm{in}} E[w_{ij}] E[x_j] \\&= 0,\tag{3.4} \\ \mathrm{Var}[o_i] & = E[o_i^2] - (E[o_i])^2 \\ & = \sum_{j=1}^{n_\mathrm{in}} E[w^2_{ij} x^2_j] - 0 \\ & = \sum_{j=1}^{n_\mathrm{in}} E[w^2_{ij}] E[x^2_j] \\ & = n_\mathrm{in} \sigma^2 \gamma^2. \end{aligned} E[oi]Var[oi]=j=1ninE[wijxj]=j=1ninE[wij]E[xj]=0,=E[oi2](E[oi])2=j=1ninE[wij2xj2]0=j=1ninE[wij2]E[xj2]=ninσ2γ2.(3.4)

保持方差不变的一种方法是设置 n i n σ 2 = 1 n_\mathrm{in} \sigma^2 = 1 ninσ2=1。现在考虑反向传播过程,我们面临着类似的问题,尽管梯度是从更靠近输出的层传播的。使用与正向传播相同的推理,我们可以看到,除非 n o u t σ 2 = 1 n_\mathrm{out} \sigma^2 = 1 noutσ2=1,否则梯度的方差可能会增大,其中 n o u t n_\mathrm{out} nout是该层的输出的数量。这使我们进退两难:我们不可能同时满足这两个条件。相反,我们只需满足:

1 2 ( n i n + n o u t ) σ 2 = 1  或等价于  σ = 2 n i n + n o u t . (3.5) \begin{aligned} \frac{1}{2} (n_\mathrm{in} + n_\mathrm{out}) \sigma^2 = 1 \text{ 或等价于 } \sigma = \sqrt{\frac{2}{n_\mathrm{in} + n_\mathrm{out}}}. \end{aligned} \tag{3.5} 21(nin+nout)σ2=1 或等价于 σ=nin+nout2 .(3.5)

这就是现在标准且实用的Xavier初始化的基础,它以其提出者Glorot.Bengio.2010 第一作者的名字命名。通常,Xavier初始化从均值为零,方差 σ 2 = 2 n i n + n o u t \sigma^2 = \frac{2}{n_\mathrm{in} + n_\mathrm{out}} σ2=nin+nout2的高斯分布中采样权重。我们也可以利用Xavier的直觉来选择从均匀分布中抽取权重时的方差。注意均匀分布 U ( − a , a ) U(-a, a) U(a,a)的方差为 a 2 3 \frac{a^2}{3} 3a2。将 a 2 3 \frac{a^2}{3} 3a2代入到 σ 2 \sigma^2 σ2的条件中,将得到初始化的建议:

U ( − 6 n i n + n o u t , 6 n i n + n o u t ) (3.6) U\left(-\sqrt{\frac{6}{n_\mathrm{in} + n_\mathrm{out}}}, \sqrt{\frac{6}{n_\mathrm{in} + n_\mathrm{out}}}\right) \tag{3.6} U(nin+nout6 ,nin+nout6 )(3.6)

尽管上述数学推理中,不存在非线性的假设在神经网络中很容易被违反,但Xavier初始化方法在实践中被证明是有效的。

假设线性的激活函数

假设 σ ( x ) = α x + β (3.7) \sigma(x) = \alpha x + \beta \tag{3.7} σ(x)=αx+β(3.7)
h ′ = W l h l − 1 a n d h l = σ ( h ′ ) (3.8) h' = W^lh^{l-1} \quad and \quad h^l = \sigma(h') \tag{3.8} h=Wlhl1andhl=σ(h)(3.8)

那么此层输出的均值和方差可以表示为:
E [ h i l ] = E [ α h i ′ + β ] = β (3.9) E[h_{i}^{l}] = E[\alpha h_i'+\beta] = \beta \tag{3.9} E[hil]=E[αhi+β]=β(3.9)

V a r [ h i l ] = E [ ( h i l ) 2 ] − E [ ( h i l ) ] 2 = E [ ( α h i ′ + β ) 2 ] − β 2 = E [ α 2 ( h i ′ ) 2 + 2 α β h i ′ + β 2 ] − β 2 = α 2 V a r [ h i ′ ] (3.10) \begin{aligned} Var[h_{i}^{l}] &= E[(h_{i}^{l})^2] - E[(h_{i}^{l})]^2\\ & = E[(\alpha h_i' +\beta)^2] - \beta ^2\\ & = E[\alpha ^2(h_i')^2 + 2\alpha \beta h_i' + \beta^2] - \beta^2\\ & = \alpha^2Var[h_i'] \end{aligned} \tag{3.10} Var[hil]=E[(hil)2]E[(hil)]2=E[(αhi+β)2]β2=E[α2(hi2+2αβhi+β2]β2=α2Var[hi](3.10)

如果说要让激活函数不改变均值和方差,那么: β = 0 α = 1 \beta = 0 \quad \alpha = 1 β=0α=1
那么激活函数就等于本身了

反向一下看看
假设 σ ( x ) = α x + β (3.7) \sigma(x) = \alpha x + \beta \tag{3.7} σ(x)=αx+β(3.7)
h ′ = W l h l − 1 a n d h l = σ ( h ′ ) (3.8) h' = W^lh^{l-1} \quad and \quad h^l = \sigma(h') \tag{3.8} h=Wlhl1andhl=σ(h)(3.8)

∂ l o s s ∂ h ′ = ∂ l o s s ∂ h l ( W l ) T a n d ∂ l o s s ∂ h l − 1 = α ∂ l o s s ∂ h ′ (3.11) \frac{\partial loss}{\partial{h'}} = \frac{\partial loss}{\partial{h^l}}(W^l)^T \quad and \quad \frac{\partial loss}{\partial{h^{l-1}}} = \alpha \frac{\partial loss}{\partial{h'}} \tag{3.11} hloss=hlloss(Wl)Tandhl1loss=αhloss(3.11)

E [ ∂ l o s s ∂ h i l − 1 ] = 0 (3.12) E[\frac{\partial{loss}}{\partial h_i^{l-1}}] = 0 \tag{3.12} E[hil1loss]=0(3.12)
V a r [ ∂ l o s s ∂ h i l − 1 ] = α 2 V a r [ ∂ l o s s ∂ h j ′ ] (3.13) Var[\frac{\partial{loss}}{\partial h_i^{l-1}}] = \alpha^2Var[\frac{\partial loss}{\partial h_j'}] \tag{3.13} Var[hil1loss]=α2Var[hjloss](3.13)

那么 β = 0 α = 1 \beta = 0 \quad \alpha = 1 β=0α=1

3.3 总结

  1. 合理的权重初始值和激活函数的选择可以提升数值的稳定性

你可能感兴趣的:(动手学深度学习:pytorch)