原文链接:https://zhuanlan.zhihu.com/p/172254089
目前用到的几个激活函数的发展及简单使用:
Sigmoid 的函数图像如上所示,从图像可以看出,函数两个边缘的梯度约为0,梯度的取值范围为(0, 0.25)。
使用 Sigmoid 作为激活函数时,在多层神经元的网络中浅层和深层网络参数的更新速率相差巨大。该现象就称为 “梯度消失(Vanishing Gradients)”。
import torch.nn as nn import torch t1 = torch.randn(3,3) m = nn.Sigmoid() t2 = m(t1) print(t1) print(t2)
torch.nn.Sigmoid()
没有什么参数,可直接调用。
ReLU 激活函数的提出就是为了解决梯度消失问题,ReLU 的梯度只可以取两个值:0或1,当输入小于0时,梯度为0;当输入大于0时,梯度为1。好处就是:ReLU 的梯度的连乘不会收敛到0 ,连乘的结果也只可以取两个值:0或1 ,如果值为1 ,梯度保持值不变进行前向传播;如果值为0 ,梯度从该位置停止前向传播。 Sigmoid 和 ReLU 函数对比如下:
torch.nn.ReLU(inplace: bool = False) # inplace 为 True,将会改变输入的数据,否则不会改变原输入,只会产生新的输出. # 例子如下: import torch import torch.nn as nn input1 = torch.tensor([50,-2,6,5,3]) input2 = torch.tensor([50,-2,6,5,3]) x1 = nn.ReLU(inplace = True)(input1) x2 = nn.ReLU(inplace = False)(input2) print(x1, input1) print(x2, input2) Output: tensor([50, 0, 6, 5, 3]) tensor([50, 0, 6, 5, 3]) tensor([50, 0, 6, 5, 3]) tensor([50, -2, 6, 5, 3])
若 inplace=True,则对于上层网络传递下来的tensor直接进行修改,可以少存储变量y,节省运算内存。
LeakyReLU的提出是为了解决神经元 ”死亡“ 问题(输入激活函数的值总为-,传播梯度恒为0,神经元无法继续学习),LeakyReLU 与 ReLU 很相似,仅在输入小于0的部分有差别,ReLU 输入小于0的部分值都为0,而 LeakyReLU 输入小于0的部分,值为负,且有微小的梯度。函数图像如下图:
Pytorch 中的用法:
torch.nn.LeakyReLU(negative_slope=0.01, inplace=False) # 例子 import torch import torch.nn as nn m = nn.LeakyReLU(0.1) input = torch.tensor([-0.9, 3064]) print(input) print(m(input)) Output: tensor([-9.0000e-01, 3.0640e+03]) tensor([-9.0000e-02, 3.0640e+03])
理想的激活函数应满足两个条件:
输出的分布是零均值的,可以加快训练速度。
激活函数是单侧饱和的,可以更好的收敛。
输入大于0部分的梯度为1,输入小于0的部分无限趋近于-α,超参数取值一般为 1 。
torch.nn.ELU(alpha=1.0, inplace=False) # 例子 import torch import torch.nn as nn m = nn.ELU() input = torch.tensor([-0.9, 3064]) print(input) print(m(input)) Output: tensor([-9.0000e-01, 3.0640e+03]) tensor([-5.9343e-01, 3.0640e+03])