激活函数介绍

激活函数介绍

如果不用激励函数(其实相当于激励函数是f(x) = x),在这种情况下你每一层节点的输入都是上层输出的线性函数,很容易验证,无论你神经网络有多少层,输出都是输入的线性组合,与没有隐藏层效果相当,这种情况就是最原始的感知机(Perceptron)了,那么网络的逼近能力就相当有限。正因为上面的原因,我们决定引入非线性函数作为激励函数,这样深层神经网络表达能力就更加强大(不再是输入的线性组合,而是几乎可以逼近任意函数)。

Sigmoid 函数

Sigmoid 是常用的非线性的激活函数,它的数学形式如下:

特点:
它能够把输入的连续实值变换为0和1之间的输出,特别的,如果是非常大的负数,那么输出就是0;如果是非常大的正数,输出就是1.
缺点:
sigmoid函数曾经被使用的很多,不过近年来,用它的人越来越少了。主要是因为它固有的一些 缺点。
缺点1:在深度神经网络中梯度反向传递时导致梯度爆炸和梯度消失,其中梯度爆炸发生的概率非常小,而梯度消失发生的概率比较大。首先来看Sigmoid函数的导数,如下图所示:

如果我们初始化神经网络的权值为 [0,1]之间的 值,由反向传播算法的数学推导可知,梯度从后向前传播时,每传递一层梯度值都会减小为原来的0.25倍,如果神经网络隐层特别多,那么梯度在穿过多层后将变得非常小接近于0,即出现梯度消失现象;当网络权值初始化为 (1,+∞)区间内的值,则会出现梯度爆炸情况。

缺点2:Sigmoid 的 output 不是0均值(即zero-centered)。这是不可取的,因为这会导致后一层的神经元将得到上一层输出的非0均值的信号作为输入。对w求局部梯度则都为正,这样在反向传播的过程中w要么都往正方向更新,要么都往负方向更新,导致有一种捆绑的效果,使得收敛缓慢。 当然了,如果按batch去训练,那么那个batch可能得到不同的信号,所以这个问题还是可以缓解一下的。因此,非0均值这个问题虽然会产生一些不好的影响,不过跟上面提到的梯度消失问题相比还是要好很多的。
缺点3:其解析式中含有幂运算,计算机求解时相对来讲比较耗时。对于规模比较大的深度网络,这会较大地增加训练时间。

from torch import nn

m = nn.Sigmoid()
input = torch.randn(2)
output = m(input)

ReLU函数

ReLU函数的解析式:

ReLU函数其实就是一个取最大值函数,注意这并不是全区间可导的,但是我们可以取sub-gradient,如上图所示。ReLU虽然简单,但却是近几年的重要成果,有以下几大优点:
1) 解决了gradient vanishing问题 (在正区间)
2)计算速度非常快,只需要判断输入是否大于0
3)收敛速度远快于sigmoid和tanh

ReLU也有几个需要特别注意的问题:
1)ReLU的输出不是zero-centered
2)Dead ReLU Problem,指的是某些神经元可能永远不会被激活,导致相应的参数永远不能被更新。有两个主要原因可能导致这种情况产生: (1) 非常不幸的参数初始化,这种情况比较少见 (2) learning rate太高导致在训练过程中参数更新太大,不幸使网络进入这种状态。解决方法是可以采用Xavier He化方法,以及避免将learning rate设置太大或使用adagrad等自动调节learning rate的算法。

尽管存在这两个问题,ReLU目前仍是最常用的activation function,在搭建人工神经网络的时候推荐优先尝试!

from torch import nn

m = nn.ReLU()
input = torch.randn(2)
output = m(input)

Leaky ReLU (PReLU)

函数表达式:

人们为了解决Dead ReLU Problem,提出了将ReLU的前半段设为αx而非0,通常α=0.01。
可由方向传播算法学出来。理论上来讲,Leaky ReLU有ReLU的所有优点,外加不会有Dead ReLU问题,但是在实际操作当中,并没有完全证明Leaky ReLU总是好于ReLU。

from torch import nn

m = nn.PReLU(num_parameters=1, init=0.25)
# num_parameters:需要学习的a的个数,默认等于1
# init:a的初始值,默认等于0.25

input = torch.randn(2)
output = m(input)

ELU(Exponential Linear Units) 函数

函数表达式:

ELU也是为解决ReLU存在的问题而提出,显然,ELU有ReLU的基本所有优点,以及:

  • 不会有Dead ReLU问题
  • 输出的均值接近0,zero-centered

它的一个小问题在于计算量稍大。类似于Leaky ReLU,理论上虽然好于ReLU,但在实际使用中目前并没有好的证据ELU总是优于ReLU。

from torch import nn

m = nn.ELU(alpha=1.0, inplace=False)
input = torch.randn(2)
output = m(input)

MaxOut函数

Maxout是深度学习网络中的一层网络,就像池化层、卷积层一样等,我们可以把maxout 看成是网络的激活函数层,我们假设网络某一层的输入特征向量为:X=(x1,x2,……xd),也就是我们输入是d个神经元。Maxout隐藏层每个神经元的计算公式如下:

上面的公式就是maxout隐藏层神经元i的计算公式。其中,k就是maxout层所需要的参数了,由我们人为设定大小。就像dropout一样,也有自己的参数p(每个神经元dropout概率),maxout的参数是k。公式中Z的计算公式为:

为了简单起见,假设我们网络第i层有2个神经元x1、x2,第i+1层的神经元个数为1个,如下图所示:

(1)以前MLP的方法。我们要计算第i+1层,那个神经元的激活值的时候,传统的MLP计算公式就是:

其中f就是我们所谓的激活函数,比如Sigmod、Relu、Tanh等。

(2)Maxout 的方法。如果我们设置maxout的参数k=5,maxout层就如下所示:

img

相当于在每个输出神经元前面又多了一层。这一层有5个神经元,此时maxout网络的输出计算公式为:

所以这就是为什么采用maxout的时候,参数个数成k倍增加的原因。本来我们只需要一组参数就够了,采用maxout后,就需要有k组参数。

Tanh 函数

函数表达式:

优点:

<1> 函数输出以(0,0)为中学

<2> 收敛速度相对于Sigmoid更快

缺点:

<1> tanh并没有解决sigmoid梯度消失的问题

from torch import nn

m = nn.Tanh()
input = torch.randn(2)
output = m(input)

Softmax 函数

softmax用于多分类过程中,它将多个神经元的输出,映射到(0,1)区间内,可以看成概率来理解,从而来进行多分类!

假设我们有一个数组,X,xi表示X中的第i个元素,那么这个元素的softmax值就是

from torch import nn

m = nn.Softmax(dim=1)
# dim(int) - 计算Softmax的维度(因此沿着dim的每个切片将总和为1)。
input = torch.randn(2, 3)
output = m(input)

LogSoftmax 函数

torch.nn.LogSoftmax(dim=None)
from torch import nn

m = nn.LogSoftmax()
# Input: (∗) where * means, any number of additional dimensions
input = torch.randn(2, 3)
# Output: (∗) , same shape as the input
output = m(input)

如何选择正确的激活函数

根据问题的性质,我们可以为神经网络更快更方便地收敛作出更好的选择。

用于分类器时,Sigmoid函数及其组合通常效果更好。

由于梯度消失问题,有时要避免使用sigmoid和tanh函数。

ReLU函数是一个通用的激活函数,目前在大多数情况下使用。

如果神经网络中出现死神经元,那么PReLU函数就是最好的选择。

请记住,ReLU函数只能在隐藏层中使用。

参考

https://blog.csdn.net/tyhj_sf/article/details/79932893

Author: pangzibo243
Link: https://litianbo243.github.io/2019/09/12/激活函数介绍/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
支付宝打赏
微信打赏