16  数值稳定性和模型初始化

16.1 数值稳定性

数值稳定性是深度学习中比较重要的点,特别是当神经网络变得很深的时候,数值通常很容易变得不稳定。

例 16.1 (神经网络的梯度)  

  • 考虑如下有 \(d\) 层的神经网络 \[\mathbf {h}^t=f_t\left(\mathbf {h}^{t-1}\right)\quad\text{and}\quad y = \ell\circ f_d\circ \cdots\circ f_1(\mathbf {x})\]

  • 计算损失 \(\ell\) 关于参数 \(\mathbf {W}_t\) 的梯度 (Gradient)
    \[\frac{\partial \ell}{\partial \mathbf{W}^t} = \frac{\partial \ell}{\partial \mathbf{h}^{d}} \underbrace{\frac{\mathbf{h}^{d}}{\mathbf{h}^{d-1}}\cdots\frac{\mathbf{h}^{t+1}}{\mathbf{h}^{t}}}_{d-t~\text{次矩阵乘法}} \frac{\mathbf{h}^{t}}{\mathbf{W}^{t}}\]

16.1.1 数值稳定性的常见两个问题

梯度爆炸

  • 假设梯度都是一些比1大的数比如1.5,做100次乘积之后得到 \(4\times 10^{17}\),这个数字很容易带来一些浮点数上限的问题(需了解更多请参考计算机系统-计算机中浮点数的存储方式)。
  • 问题
    • 值超出值域(infinity)
      • 对于16位浮点数尤为严重(数值区间 [6e-5 , 6e4]),GPU用16位浮点数更快
    • 对学习率敏感
      • 如果学习率太大→大参数值→更大的梯度,如此循环几次,容易导致梯度爆炸
      • 如果学习率太小→训练无进展
      • 我们可能需要在训练过程中不断调整学习率

梯度消失

  • 现象描述: 假设梯度都是一些比1小的数比如0.8,做100次乘积之后得到 \(2\times 10^{-10}\),也可能会带来浮点数下溢的问题。
  • 问题
    • 梯度值变为0
      • 对16位浮点数尤为严重
    • 训练没有进展
      • 不管如何选择学习率,由于梯度已经为0了,学习率x梯度=0
    • 对于底部层尤为严重
      • 仅仅顶部层训练得较好。第t层导数包含d-t个矩阵乘积,越往底层走,t越小,乘得越多,梯度消失越严重,所以底部层效果更差。
      • 无法让神经网络更深。只能把顶部层训练得比较好,底部层跑不动,这和给一个浅的神经网络没有什么区别。

16.1.2 代码实践

源代码

16.2 模型初始化与激活函数

16.2.1 让训练更加稳定

我们的一个核心目标是如何让训练更稳定,梯度值不要太大也不要太小

  • 目标:让梯度值在合理的范围内
    • 例如 [1e-6, 1e3]
  • 常用方法:
    • 将乘法变加法:
      • ResNet(跳跃连接,如果很多层,加入加法进去)
      • LSTM(引入记忆细胞,更新门,遗忘门,通过门权重求和,控制下一步是否更新)
    • 归一化:
      • 梯度归一化(归一化均值,方差)
      • 梯度裁剪 (Clipping) :比如大于/小于一个固定的阈值,就让梯度等于这个阈值,将梯度限制在一个范围中。(可以缓解梯度爆炸)
    • 合理的权重初始和激活函数:本节课讲述重点

16.2.2 基本假设:让每层的均值/方差是一个常数

  • 将每层的输出和梯度都看做随机变量

    比如第i层有100维,就将输出和梯度分别看成100个随机变量

  • 让它们的均值和方差都保持一致

    我们的目标,这样不管神经网络多深,最后一层总与第一层差不多,从而不会梯度爆炸和消失需要控制 被激活函数映射之后的隐藏层值

ReLU 和 tanh 对此都表现良好, 然而, 对于 Sigmoid 做泰勒展开发现, \[\operatorname{Sigmoid}(x)=\frac{1}{2} + \frac{x}{4} - \frac{x^3}{48} + o(x)\] 为了防止梯度爆炸, 可以Sigmoid 做 Scaling 调整后为 \[4\times \operatorname{Sigmoid}(x) -2\]

16.2.3 总结

  • 当数值过大或者过小时,会导致数值问题。

  • 常发生在深度模型中,因为其会对n个数累乘。

  • 合理的权重初始值(如Xavier) 和 激活函数的选取(如relu, tanh, 调整后的sigmoid)可以提升数值稳定性。