曾经sigmoid函数 1 1 + e x p ( − x ) \frac{1}{1+exp(-x)} 1+exp(−x)1很流行, 因为它类似于阈值函数。 由于早期的人工神经网络受到生物神经网络的启发, 神经元要么完全激活要么完全不激活(就像生物神经元)的想法很有吸引力。 然而,它却是导致梯度消失问题的一个常见的原因, 让我们仔细看看sigmoid函数为什么会导致梯度消失。
import torch
from d2l import torch as d2l
if __name__ == '__main__':
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 = (10, 6))
d2l.plt.show()
输出结果为:
正如你所看到的,当sigmoid函数的输入很大或是很小时,它的梯度都会消失。
此外,当反向传播通过许多层时,除非我们在刚刚好的地方, 这些地方sigmoid函数的输入接近于零,否则整个乘积的梯度可能会消失。
当我们的网络有很多层时,除非我们很小心,否则在某一层可能会切断梯度。
事实上,这个问题曾经困扰着深度网络的训练。 因此,更稳定的ReLU系列函数已经成为从业者的默认选择(虽然在神经科学的角度看起来不太合理)。
相反,梯度爆炸可能同样令人烦恼。 为了更好地说明这一点,我们生成100个高斯随机矩阵,并将它们与某个初始矩阵相乘。 对于我们选择的尺度( δ 2 = 1 \delta^2 = 1 δ2=1),矩阵乘积发生爆炸。 当这种情况是由于深度网络的初始化所导致时,我们没有机会让梯度下降优化器收敛。
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)
输出结果为:
(PyTorch) D:\CodeProject>D:/Anaconda/envs/PyTorch/python.exe d:/CodeProject/15.动手学深度学习代码手撸/梯度消失和梯度爆炸.py
一个矩阵
tensor([[ 0.8554, 0.1466, 0.3070, -0.6249],
[ 0.7612, -0.0254, -2.9988, -0.7475],
[-0.5296, -0.7743, 1.0385, -0.8141],
[-0.4784, 1.8119, -0.9277, 0.2918]])
乘以100个矩阵后
tensor([[-1.3093e+25, -5.7145e+24, 1.8127e+25, -1.5849e+25],
[ 2.9434e+25, 1.2847e+25, -4.0750e+25, 3.5630e+25],
[ 5.6862e+24, 2.4818e+24, -7.8723e+24, 6.8833e+24],
[-6.1249e+25, -2.6733e+25, 8.4797e+25, -7.4144e+25]])
可见数据的值无比庞大!