Pytorch 4.8 梯度爆炸和梯度消失以及解决的办法
梯度爆炸/消失
梯度消失 : 参数更新过小,在每次更新时几乎不会移动,导致模型无法学习。
%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","Grad"],figsize=(4.5,2.5))
梯度爆炸 : 参数更新过大,破坏了模型的稳定收敛。
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)
[out]:一个矩阵
tensor([[ 0.7392, -0.7381, 0.1063, 0.5866],
[-0.0302, -1.4010, 0.2725, -0.3175],
[-1.9900, -1.1248, 1.7442, 1.3487],
[-0.5263, 0.5572, 0.2403, 0.6967]])
乘以100个矩阵后
tensor([[ 1.4398e+25, -4.8513e+24, -2.9295e+23, -2.8513e+24],
[ 1.3503e+25, -4.5497e+24, -2.7475e+23, -2.6741e+24],
[-1.8323e+25, 6.1736e+24, 3.7281e+23, 3.6285e+24],
[-1.4487e+25, 4.8811e+24, 2.9476e+23, 2.8689e+24]])
具体的可以参考沐神D2l文章:http://zh.d2l.ai/chapter_multilayer-perceptrons/numerical-stability-and-init.html#id5
对于沐神所说的改变权重的顺序或者重排列,不能够改善梯度爆炸和梯度消失。这里是因为改变权重顺序或者重排列只是让我们的MLP换了另外一种线性表达,本质上还是线性。为了让训练更加稳定,我们有很多种方法可以限制梯度:
- 把梯度限制在一定的范围内。
- 将乘法变成加法: ResNet , LSTM
- 归一化: 梯度归一化。梯度裁剪。
- 合理权重初始化和激活函数。
其中一个比较不错的权重初始化的方式是Xavier。
Xavier初始化
解决(或至少减轻)上述问题的一种方法是进行参数初始化, 优化期间的注意和适当的正则化也可以进一步提高稳定性。
让我们看看某些没有非线性的全连接层输出(例如,隐藏变量)\(o_i\) 的尺度分布。 对于该层 \(n_{in}\) 输入 \(x_j\) 及其相关权重 \(w_{ij}\) ,输出由下式给出
权重 \(w_{ij}\) 都是从同一分布中独立抽取的。 此外,让我们假设该分布具有零均值和方差 \(σ^2\) 。 请注意,这并不意味着分布必须是高斯的,只是均值和方差需要存在。 现在,让我们假设层 \(x_j\) 的输入也具有零均值和方差 \(γ^2\) , 并且它们独立于 \(w_{ij}\) 并且彼此独立。 在这种情况下,我们可以按如下方式计算 \(o_i\) 的平均值和方差:
保持方差不变的一种方法是设置 \(n_{in}σ^2=1\) 。 现在考虑反向传播过程,我们面临着类似的问题,尽管梯度是从更靠近输出的层传播的。 使用与前向传播相同的推断,我们可以看到,除非 \(n_{out}σ^2=1\) , 否则梯度的方差可能会增大,其中 \(n_{out}\) 是该层的输出的数量。 这使得我们进退两难:我们不可能同时满足这两个条件。 相反,我们只需满足:
通常,Xavier初始化从均值为零,方差 \(\sigma^2 = \frac{2}{n_\mathrm{in} + n_\mathrm{out}}\) 的高斯分布中采样权重。我们也可以利用Xavier的直觉来选择从均匀分布中抽取权重时的方差。 注意均匀分布 \(U(−a,a)\) 的方差为 \(\frac{a^2}{3}\) 。 将 \(\frac{a^2}{3}\) 代入到 \(\sigma^2\) 的条件中,将得到初始化值域:
尽管在上述数学推理中,“不存在非线性”的假设在神经网络中很容易被违反, 但Xavier初始化方法在实践中被证明是有效的。
最后做个总结的话就是:
- 需要用启发式的初始化方法来确保初始梯度既不太大也不太小。
- ReLU激活函数缓解了梯度消失问题,这样可以加速收敛。
- 随机初始化是保证在进行优化前打破对称性的关键。
- Xavier初始化表明,对于每一层,输出的方差不受输入数量的影响,任何梯度的方差不受输出数量的影响。
posted on 2022-01-12 12:11 YangShusen' 阅读(2186) 评论(0) 编辑 收藏 举报