pytorch-数值稳定性和模型初始化
神经网络的梯度
考虑⼀个具有\(t\)层(注意这里的t表示的是层)、输入\(x\)和输出\(y\)的深层网络。每⼀层\(t\)由变换\(f_t\)定义,该变换的参数为权重\(W^{(t)}\),其隐藏变量是\(h^{(t)}\)(令\(h^{(0)} = x\))。我们的网络可以表示为:
计算损失ℓ关于参数\(W_t\)的梯度


这里做了太多的矩阵乘法,所以很容易造成梯度爆炸或者梯度消失。
梯度爆炸和梯度消失

其中diag()是一个对角矩阵
梯度爆炸
- 使用ReLU作为激活函数


- 梯度爆炸的问题

梯度消失
使用sigmoid作为激活函数

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

梯度消失的问题
- 梯度值变成0
·对16位浮点数尤为严重 - 训练没有进展
·不管如何选择学习率 - 对于底部层尤为严重
·仅仅顶部层训练的较好
·无法让神经网络更深
当你的梯度变为0了之后,无论你的学习率多大就没用,因为你的权重就是你的学习率乘梯度。那么你的训练就不会有进展。因此,更稳定的ReLU系列函数已经成为从业者的默认选择。
模型初始化
其实我们就是想让训练更加稳定
- 目标:让梯度值在合理的范围内
例如[1e-6, 1e3] - 将乘法变为加法
ResNet,LSTM - 归一化
梯度归一化,梯度裁剪 - 合理的权重初始和激活函数
我们可以让每一层的输入、输出方差都是一个常数,就是让每一层的均值和方差都保持一致。
比如我们让正向传播的时候它的均值为0,方差为a,反向传播的时候均值为0,方差为b。这样我们不管我们的网络做多深,就可以让数值在一定的范围之内。

权重初始化

我们之前使用N(0,0.01)均值为0,方差为0.01来初始化这个网络,对小网络没问题,但不能保证深度神经网络。
我们看一下,要想使得这个网络满足N(0,0.01)均值为0,方差为0.01,需要什么条件,激活函数需要满足什么条件:




假设线性的激活函数,我们方便计算,但是现实一定不能是线性的:


我们发现加上激活函数之后就是要让他的函数值等于本身,即\(f(x)=x\)。
我们检查一下我们常用的激活函数:

我们用泰勒展开看一下:然后对于tanh(x)和relu(x)来说在0点附近基本上是\(f(x)=x\),实际中也是我们的值都在0点附近。对于sigmoid来说我们调整一下变成\(4*sigmoid(x)-2\)之后也是可以近似为\(f(x)=x\)。

所以常用的是Relu。

浙公网安备 33010602011771号