deep_learning_7.数值稳定性和模型初始化

到目前为止,我们实现的每个模型都是根据某个预先指定的分布来初始化模型的参数。这样比较容易忽略模型初始值对训练的影响。

选择哪个函数以及如何初始化参数可以决定优化算法收敛的速度有多快。 糟糕选择可能会导致我们在训练时遇到梯度爆炸或梯度消失。

梯度消失和梯度爆炸

当初始值选取的点不一样时,就会造成梯度消失或者是梯度爆炸的情况

所谓梯度消失是指,梯度的值在很小的范围内变化,导数接近于平滑的直线。

梯度爆炸是指,导数斜率很大导致w更新的时候超出了浮点数所能表示的范围

1.梯度消失

曾经sigmoid函数1/(1+exp⁡(−x))很流行, 因为它类似于阈值函数。 由于早期的人工神经网络受到生物神经网络的启发, 神经元要么完全激活要么完全不激活(就像生物神经元)的想法很有吸引力。 然而,它却是导致梯度消失问题的一个常见的原因, 让我们仔细看看sigmoid函数为什么会导致梯度消失。

1
2
3
4
5
6
7
8
9
10
%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))

![](https://raw.githubusercontent.com/YUTING0907/PicGo/main/img截屏2022-10-06 下午11.41.35.png)

当sigmoid函数的输入很大或是很小时,它的梯度都会消失。 此外,当反向传播通过许多层时,除非我们在刚刚好的地方, 这些地方sigmoid函数的输入接近于零,否则整个乘积的梯度可能会消失。 当我们的网络有很多层时,除非我们很小心,否则在某一层可能会切断梯度。 事实上,这个问题曾经困扰着深度网络的训练。 因此,更稳定的ReLU系列函数已经成为从业者的默认选择(虽然在神经科学的角度看起来不太合理)。

2.梯度爆炸

梯度爆炸可能同样令人烦恼。 为了更好地说明这一点,我们生成100个高斯随机矩阵,并将它们与某个初始矩阵相乘。 对于我们选择的尺度(方差σ2=1),矩阵乘积发生爆炸。 当这种情况是由于深度网络的初始化所导致时,我们没有机会让梯度下降优化器收敛。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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)


一个矩阵
tensor([[ 0.4382, -0.7687, 0.2731, -0.2587],
[-0.1789, -0.2395, 1.4915, 0.2634],
[-0.5272, 0.2403, 2.4397, -0.7587],
[ 0.9805, 0.4166, -0.1906, -0.2581]])
乘以100个矩阵后
tensor([[ 7.6616e+22, 4.2587e+22, -5.8065e+22, 1.2980e+23],
[-2.3790e+21, -1.3224e+21, 1.8030e+21, -4.0304e+21],
[-1.3796e+23, -7.6687e+22, 1.0456e+23, -2.3373e+23],
[ 8.5987e+20, 4.7795e+20, -6.5167e+20, 1.4567e+21]])

解决数值不稳定

目标:让梯度值在合理的范围内,例如【1e-6,1e3】

1.合理的权重初始化和激活函数

合理化的权重是要把权重的在均值和方差保持在一个范围

Xavier初始化方法

一般采用Xavier初始化方法来进行初始化,意味着说激活函数应该近似是y=x

常用激活函数

sigmoid(X) = 1/2 + x/4 - x^3 /48 + O(x^5)

tanh(x) = 0+x-x^3/3 + O(x^5)

Relu(x) = 0 + x

调整sigmoid:

4*sigmoid(x) - 2

注:Relu:max(0,x)

2.将乘法变加法

ResNet、LSTM

3.归一化

梯度归一化,梯度裁剪

Q&A

1.nan和inf是怎么产生的?

nan是➗0导致的,inf是值太大了炸掉了。可以把学习率减少,合理的初始化权重,激活函数不要选错,简单的做法是lr调小,直到不出现nan或者inf为止,还有就是初始化权重的时候,可以方差取小一点,均值为0,方差可以取小点

2.训练过程中,如果网络层的输出的中间层特征元素的值突然变成nanle,是发生了梯度爆炸了嘛?

一般是梯度爆炸造成的

3.遇到复杂的数学公式,看文字描述也没什么感觉,怎么突破?

上数学课hhh,线形代数学一学概率论学一学呗,虽然深度学习没有用到太多的数学知识,但是你如果要去看别的模型,数学不好你可能就看不懂,也就玩不了别的模型

4.梯度消失可以说是因为使用了sigmoid激活函数引起的吗?所以我们可以用ReLU替换sigmoid解决梯度消失的问题?

sigmoid确实是会造成梯度消失,但不能说是梯度消失就是sigmoid造成的,还可能有其他原因。用ReLU可以代替sigmoid有可能解决这个问题,但是不能保证一定能解决

5.梯度爆炸是由什么激活函数引起的?

激活函数相对都是比较平滑的曲线,它的梯度一般不会有太大的问题。梯度爆炸的产生是每层输出的值太大,n个很大的数相乘会导致梯度爆炸

6.山地图可以可视化出来吗?我们可以把损失函数可视化出来来指导训练吗?

没有特别好的方法,但是有一些研究正在做

7.强制似的每一层的输出特征均值为0,方差为1,是不是损失了网络的表达能力?会降低学到的模型的准确率?

其实没有损失网络的表达能力,只是把它们拉到一个合理数值区间,只是让硬件更好处理和计算,从数学上来讲无论拉到什么区间都不会影响模型的可表达性

8.为什么4*sigmoid(x)-2可以提高稳定性?

其实是sigmoid做这样的处理后,它在0点附近的区间近视与y=x

9.激活函数选择有什么建议吗?

用ReLU

10.一般权重是在每个epoch结束后更新的吧?

权重更新是在每个data_iter每个batch,每个epoch结束后是已经更新过很多次了


觉得不错的话,给点打赏吧 ୧(๑•̀⌄•́๑)૭



wechat pay



alipay

deep_learning_7.数值稳定性和模型初始化
http://yuting0907.github.io/2022/08/14/deep-learning-7-数值稳定性和模型初始化/
作者
Echo Yu
发布于
2022年8月14日
许可协议