pytorch-数值稳定性和模型初始化

神经网络的梯度

考虑⼀个具有\(t\)层(注意这里的t表示的是层)、输入\(x\)和输出\(y\)的深层网络。每⼀层\(t\)由变换\(f_t\)定义,该变换的参数为权重\(W^{(t)}\),其隐藏变量是\(h^{(t)}\)(令\(h^{(0)} = x\))。我们的网络可以表示为:

\[h^t=f_t(h^{t−1})\ \ \ and\ \ \ y = ℓ∘f_d∘ … ∘ f_1(x) \]

计算损失ℓ关于参数\(W_t\)的梯度
image
image
这里做了太多的矩阵乘法,所以很容易造成梯度爆炸或者梯度消失。

梯度爆炸和梯度消失

image
其中diag()是一个对角矩阵

梯度爆炸

  • 使用ReLU作为激活函数
    image
    image
  • 梯度爆炸的问题
    image

梯度消失

使用sigmoid作为激活函数

\[\sigma(x)=\frac{1}{1+e^{-x}}\ 导数为\sigma^{'}(x)=\sigma(x)(1-\sigma(x)) \]

image
我们可以发现当他的输入很大的时候他的梯度很小,接近于0。
image
梯度消失的问题

  • 梯度值变成0
          ·对16位浮点数尤为严重
  • 训练没有进展
          ·不管如何选择学习率
  • 对于底部层尤为严重
          ·仅仅顶部层训练的较好
          ·无法让神经网络更深

当你的梯度变为0了之后,无论你的学习率多大就没用,因为你的权重就是你的学习率乘梯度。那么你的训练就不会有进展。因此,更稳定的ReLU系列函数已经成为从业者的默认选择。

模型初始化

其实我们就是想让训练更加稳定

  • 目标:让梯度值在合理的范围内
        例如[1e-6, 1e3]
  • 将乘法变为加法
        ResNet,LSTM
  • 归一化
        梯度归一化,梯度裁剪
  • 合理的权重初始和激活函数

我们可以让每一层的输入、输出方差都是一个常数,就是让每一层的均值和方差都保持一致。
比如我们让正向传播的时候它的均值为0,方差为a,反向传播的时候均值为0,方差为b。这样我们不管我们的网络做多深,就可以让数值在一定的范围之内。
image

权重初始化

image
我们之前使用N(0,0.01)均值为0,方差为0.01来初始化这个网络,对小网络没问题,但不能保证深度神经网络。

我们看一下,要想使得这个网络满足N(0,0.01)均值为0,方差为0.01,需要什么条件,激活函数需要满足什么条件:
image
image
image
image
假设线性的激活函数,我们方便计算,但是现实一定不能是线性的:
image
image
我们发现加上激活函数之后就是要让他的函数值等于本身,即\(f(x)=x\)
我们检查一下我们常用的激活函数:
image
我们用泰勒展开看一下:然后对于tanh(x)和relu(x)来说在0点附近基本上是\(f(x)=x\),实际中也是我们的值都在0点附近。对于sigmoid来说我们调整一下变成\(4*sigmoid(x)-2\)之后也是可以近似为\(f(x)=x\)
image
所以常用的是Relu。

posted @ 2023-08-10 10:01  lipu123  阅读(76)  评论(0)    收藏  举报