一、Sigmoid
对于一个定义域在R中的输入,sigmoid函数将输入变换为区间(0, 1)上的输出:
f
(
x
)
=
1
1
+
e
?
x
f(x)=\frac{1}{1+e^{-x}}
f(x)=1+e?x1? sigmoid被广泛用作二分类问题输出单元上的激活函数(你可以将sigmoid视为softmax的特例)。sigmoid在隐藏层中已经较少使用,它在大部分时候被更简单、更容易训练的ReLU所取代。
import torch
import matplotlib.pyplot as plt
x = torch.arange(-8.0, 8.0, 0.1, requires_grad=True)
y = torch.sigmoid(x)
plt.plot(x.detach(), y.detach())
plt.title('Sigmoid')
plt.show()
y.backward(torch.ones_like(x), retain_graph=True)
plt.plot(x.detach(), x.grad)
plt.title('Gradient of Sigmoid')
plt.show()
此外,当反向传播通过许多层时,除非我们在刚刚好的地方,这些地方sigmoid函数的输入接近于零,否则整个乘积的梯度可能会消失。当 我们的网络有很多层时,除非我们很小心,否则在某一层可能会切断梯度。
缺点:
1.当sigmoid函数的输入很大或是很小时,它的梯度都会接近0,在深度神经网络中梯度反向传递时导致梯度消失。
2.Sigmoid 的 output 不是0均值(即zero-centered)。
3.含有幂运算,对于规模比较大的深度网络,这会较大地增加训练时间。
二、Tanh
与sigmoid函数类似,tanh(双曲正切)函数也能将其输入压缩转换到区间(-1, 1)上。tanh函数的公式如下:
f
(
x
)
=
e
x
?
e
?
x
e
x
+
e
?
x
f(x)=\frac{e^x-e^{-x}}{e^x+e^{-x}}
f(x)=ex+e?xex?e?x? 注意,当输入在0附近时,tanh函数接近线性变换。函数的形状类似于sigmoid函数,不同的是tanh函数关于坐标系原点中心对称。
import torch
import matplotlib.pyplot as plt
x = torch.arange(-4.0, 4.0, 0.1, requires_grad=True)
y = torch.tanh(x)
plt.plot(x.detach(), y.detach())
plt.title('Tanh')
plt.show(
y.backward(torch.ones_like(x), retain_graph=True)
plt.plot(x.detach(), x.grad)
plt.title('Gradient of Tanh')
plt.show()
解决了Sigmoid函数的不是zero-centered输出问题,然而,梯度消失的问题和幂运算的问题仍然存在。
三、ReLU
最受欢迎的激活函数是修正线性单元(Rectified linear unit,ReLU),因为它实现简单,同时在各种预测任务中表现良好。ReLU提供了一种非常简单的非线性变换:
f
(
x
)
=
m
a
x
(
0
,
x
)
f(x)=max(0,x)
f(x)=max(0,x) ReLU函数仅保留正元素并丢弃所有负元素。
使用ReLU的原因是,它求导表现得特别好:要么让参数消失,要么让参数通过。这使得优化表现的更好,并且ReLU减轻了困扰以往神经网络的梯度消失问题。
import torch
import matplotlib.pyplot as plt
x = torch.arange(-5.0, 5.0, 0.1, requires_grad=True)
y = torch.relu(x)
plt.plot(x.detach(), y.detach())
plt.title('ReLU')
plt.show()
y.backward(torch.ones_like(x), retain_graph=True)
plt.plot(x.detach(), x.grad)
plt.title('Gradient of ReLU')
plt.show()
优点: 1)解决了gradient vanishing问题 (在正区间) 2)计算速度非常快,只需要判断输入是否大于0 3)收敛速度远快于sigmoid和tanh
缺点: 1)ReLU的输出不是zero-centered 2)Dead ReLU Problem,指的是某些神经元可能永远不会被激活,导致相应的参数永远不能被更新。有两个主要原因可能导致这种情况产生: (1) 非常不幸的参数初始化,这种情况比较少见; (2) learning rate太高导致在训练过程中参数更新太大,不幸使网络进入这种状态。解决方法是可以采用Xavier初始化方法,以及避免将learning rate设置太大或使用adagrad等自动调节learning rate的算法。
四、LeakyReLU
为解决Dead ReLU Problem问题,设计了ReLU的变种Leaky ReLU(LReLU),其形式表示为:
f
(
x
)
=
m
a
x
(
0.01
x
,
x
)
f(x)=max(0.01x,x)
f(x)=max(0.01x,x)
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
x = torch.arange(-20.0, 4.0, 0.1, requires_grad=True)
y = nn.LeakyReLU(0.01)
plt.plot(x.detach(), y(x).detach())
plt.title('LeakyReLU')
plt.show()
五、PReLU(Parameterized ReLU)
为ReLU添加了一个线性项,因此即使参数是负的,某些信息仍然可以通过: KaTeX parse error: Undefined control sequence: \mbox at position 74: …in{cases} x, & \?m?b?o?x?{if }x\ge \mbox…
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
x = torch.arange(-8.0, 4.0, 0.1, requires_grad=True)
y = nn.PReLU()
plt.plot(x.detach(), y(x).detach())
plt.title('PReLU')
plt.show()
面试常见问题
1.为什么Sigmoid和Tanh激活函数会导致梯度消失的现象?
Sigmoid激活函数的曲线如图所示,它将输入
x
x
x映射到区间(0,1),当
x
x
x很大时,
f
(
x
)
f(x)
f(x)趋近于1;当
x
x
x很小时,
f
(
x
)
f(x)
f(x)趋近于0。其导数在
x
x
x很大或很小时都会趋近于0,造成梯度消失的现象。
Tanh激活函数的曲线如图所示。当
x
x
x很大时,
f
(
x
)
f(x)
f(x)趋近于1;当
x
x
x很小时,
f
(
x
)
f(x)
f(x)趋近于?1。其导数在
x
x
x很大或很小时都会趋近于0,同样会出现“梯度消失”。
Tanh激活函数相当于Sigmoid的平移:
t
a
n
h
(
x
)
=
2
s
i
g
m
o
i
d
(
2
x
)
?
1
tanh(x)=2sigmoid(2x)?1
tanh(x)=2sigmoid(2x)?1 2. ReLU系列的激活函数相对于Sigmoid和Tanh激活函数的优点是什么?它们有什么局限性以及如何改进?
■ 优点
(1)从计算的角度上,Sigmoid和Tanh激活函数均需要计算指数,复杂度高,而ReLU只需要一个阈值即可得到激活值。
(2)ReLU的非饱和性可以有效地解决梯度消失的问题,提供相对宽的激活边界。
(3)ReLU的单侧抑制提供了网络的稀疏表达能力。
■ 局限性
ReLU的局限性在于其训练过程中会导致神经元死亡的问题。这是由于ReLU函数导致负梯度在经过该ReLU单元时被置为0,且在之后也不被任何数据激活,即流经该神经元的梯度永远为0,不对任何数据产生响应。在实际训练 中,如果学习率(Learning Rate)设置较大,会导致超过一定比例的神经元不可逆死亡,进而参数梯度无法更新,整个训练过程失败。
|