深度学习之激活函数

转自[深度学习中常用激活函数总结 - 知乎]

0. 前言

本文总结了几个在深度学习中比较常用的激活函数:Sigmoid、ReLU、LeakyReLU以及Tanh,从激活函数的表达式、导数推导以及简单的编程实现来说明。

1. Sigmoid激活函数

Sigmoid激活函数表达式

深度学习之激活函数_第1张图片

Sigmoid导数表达式

Sigmoid编程实现

Sigmoid激活函数以及导函数图像

Sigmoid激活函数也叫做Logistic函数,因为它是线性回归转换为Logistic(逻辑回归)的核心函数,这也是Sigmoid函数优良的特性能够把X ∈ R的输出压缩到X ∈ (0, 1)区间。Sigmoid激活函数在其大部分定义域内都会趋于一个饱和的定值。当x取绝对值很大的正值的时候,Sigmoid激活函数会饱和到一个高值(无限趋近于1);当x取绝对值很大的负值的时候,Sigmoid激活函数会饱和到一个低值(无限趋近于0)。Sigmoid函数是连续可导函数,在零点时候导数最大,并在向两边逐渐降低,可以简单理解成输入非常大或者非常小的时候,梯度为0没有梯度,如果使用梯度下降法,参数得不到更新优化。

Sigmoid函数最大的特点就是将数值压缩到(0, 1)区间,在机器学习中常利用(0, 1)区间的数值来表示以下意义:

  1. 概率分布:根据概率公理化定义知道,概率的取值范围在[0, 1]之间,Sigmoid函数的(0, 1)区间的输出和概率分布的取值范围[0, 1]契合。因此可以利用Sigmoid函数将输出转译为概率值的输出。这也是Logistic(逻辑回归)使用Sigmoid函数的原因之一;
  2. 信号强度:一般可以将0~1理解成某种信号的强度。由于RNN循环神经网络只能够解决短期依赖的问题,不能够解决长期依赖的问题,因此提出了LSTM、GRU,这些网络相比于RNN最大的特点就是加入了门控制,通过门来控制是否允许记忆通过,而Sigmoid函数还能够代表门控值(Gate)的强度,当Sigmoid输出1的时候代表当前门控全部开放(允许全部记忆通过),当Sigmoid输出0的时候代表门控关闭(不允许任何记忆通过)。

上面介绍了Sigmoid激活函数将输出映射到(0, 1)区间在机器学习中的两个意义,这也是Sigmoid激活函数的优点。接下来介绍一下Sigmoid激活函数的缺点:

  • 经过Sigmoid激活函数输出的均值为0.5,即输出为非0均值;

Sigmoid激活函数输出均值不为0

反向传播时候更新方向要不往正向更新,要不往负向更新,会导致捆绑效果,使得收敛速度减慢。当然,如果使用小批量梯度下降法,由于每个小batch可能会得到不同的信号,所以这个问题还是有可能缓解的。2015年loffe提出的批标准化(Batch Normalization)就是为了适应性的将每层输出分布都进行统一,以便网络学习更加稳定、更快的传播。

  • 计算求解的时候计算量较大,相对来说会比较耗时。这其实很好理解,因为观察Sigmoid激活函数表达式会发现其中有幂函数参与了运算,而且在反向传播求导过程中涉及到除法运算;
  • 对于Sigmoid激活函数最致命的缺点就是容易发生梯度弥散(Gradient vanishing)现象(当然也可能会发生梯度爆炸Exploding gradient,前面层的梯度通过模型训练变的很大,由于反向传播中链式法则的原因,导致后面层的梯度值会以指数级增大。但是在Sigmoid激活函数中梯度保障发生的概率非常小),所谓梯度弥散故名思议就是梯度值越来越小。在深度学习中,梯度更新是从后向前更新的,这也就是所谓的反向传播(Backpropagation algorithm),而反向传播的核心是链式法则。如果使用Sigmoid激活函数,训练的网络比较浅还比较好,但是一旦训练较深的神经网络,会导致每次传过来的梯度都会乘上小于1的值,多经过几层之后,梯度就会变得非常非常小(逐渐接近于0),梯度因此消失了,对应的参数得不到更新。因此使用Sigmoid激活函数,随着神经网络层数的增加,会出现靠近输出的层参数更新幅度比较大,而靠近输入的层参数更新幅度比较小。因而使用Sigmoid激活函数容易出现梯度弥散的现象,无法完成深层网路的训练;

在Tensorflow2.X中Sigmoid激活函数只有函数式接口的实现方式:

  1. 函数式接口:tf.nn.sigmoid(x, name = None);

Sigmoid激活函数实现

3. ReLU激活函数

ReLU激活函数表达式

ReLU导数表达式

ReLU编程实现

ReLU激活函数以及导函数图像

2012年ImageNet竞赛的冠军模型是由Hinton和他的学生Alex设计的AlexNet,其中使用了一个新的激活函数ReLU(REctified Linear Unit,修正线性单元)。在这之前Sigmoid函数通常是神经网络激活函数的首选,上面也提到过,Sigmoid函数在输入值较大或较小的时候容易出现梯度值接近于0的现象,也就是梯度弥散。出现梯度弥散现象,网络参数会长时间得不到更新,很容易导致训练不收敛或停滞不动的现象发生,网络层数较深的网络模型更容易发生梯度弥散现象,使得对神经网络的研究一直停留在浅层网络。值得一提的是,AlexNet是一个8层的网络,而后续提出的上百层的卷积神经网络也多是采用ReLU激活函数。

通过ReLU激活函数的函数图像可以看到,ReLU对小于0的值全部抑制为0;对于正数则直接输出,这是一种单边抑制的特性,而这种单边抑制来源于生物学。ReLU函数的导数计算也非常简单,x大于等于0的时候,导数值为1,在反向传播的过程中,它既不会放大梯度,造成梯度爆炸;也不会缩小梯度,造成梯度弥散的现象。

上面从ReLU函数的起源以及Relu函数图像角度来阐述ReLU激活函数,接下来详细的来看看ReLU函数的优缺点。

优点:

  • 不饱和(梯度不会过小)。对于ReLU函数,当输入值为正的时候,梯度恒为1,没有梯度弥散的现象,收敛速度快;
  • 增大了网络的稀疏性。当输入值x < 0的时候,该层的输出为0,训练完成后为0的神经元越来越多,稀疏性会变大,网络的协同性会被破坏,更够迫使网络学习到更一般性的特征,泛化能力会变强。这也正是dropout的原理;
  • 计算量变小。ReLU函数和Sigmoid函数相比少了复杂的幂运算,计算量变小;

缺点:

  • 输出均值非0。ReLU函数与Sigmoid函数相同,输出均值都是非0的,这一点在前面介绍Sigmoid函数的时候提到过,这里不再赘述;
  • Dead ReLU。如果某个层的正向梯度值特别大,会导致w优化参数更新后的值变的特别大,由梯度更新公式可知,该层的输入x < 0,相应的输出值为0,那么此时该层就会"死亡",参数不会更新,而且这是不可逆转的"死亡",这个神经元永远的失效,这会失去数据样本的多样化。如果开始选定的学习率比较大的话很可能40%的神经元在训练开始的时候就会"死亡",因此使用ReLU激活函数的时候,需要选定一个合适的学习率让这种情况发生的概率降低;

在Tensorflow2.X中ReLU激活函数有两种实现方式:

  1. 函数式接口:tf.nn.relu(x, name = None);
  2. 激活函数类:tf.keras.layers.ReLU()。可以像Dense层一样将ReLU函数作为一个网络层添加到网络中,一般来说,激活函数类并不是主要的网络运算层,因此不计入网络的层数;

ReLU激活函数函数式接口

深度学习之激活函数_第2张图片

ReLU激活函数类

4. LeakyReLU激活函数

LeakyReLU激活函数表达式

LeakyReLU导数表达式

LeakyReLU函数以及导函数实现

LeakyReLU激活函数以及导函数图像

LeakyReLU函数是针对ReLU函数的Dead ReLU而提出来的。ReLU激活函数在x < 0的时候导数恒为0,很可能致使很多神经元为0,参数得不到更新。通过LeakyReLU函数表达式也可以看出,与ReLU函数唯一的不同就是在x < 0的部分输出不在为0而是px,p为超参数,通常是一个较小的值。当p = 0的时候,LeakyReLU函数退化成ReLU函数;当p ≠ 0的时候,在x < 0的时候能够得到较小的导数值p。从而避免出现Dead ReLU的现象。

当然了其实ReLU激活函数当x < 0的时候输出为0也有它的优点。也就是增大网络的稀疏性,这往往会提高模型的泛化能力(类似dropout作用)。因此虽然提出了LeakyReLU这种激活函数,但是目前使用比较广泛的还是ReLU激活函数。

在Tensorflow2.X中LeakyReLU激活函数有两种实现方式:

  1. 函数式接口:tf.nn.leaky_relu(x, name = None);
  2. 激活函数类:tf.keras.layers.LeakyReLU()。可以像Dense层一样将LeakyReLU函数作为一个网络层添加到网络中,一般来说,激活函数类并不是主要的网络运算层,因此不计入网络的层数;

深度学习之激活函数_第3张图片

LeakyReLU激活函数函数式接口

深度学习之激活函数_第4张图片

LeakyReLU激活函数类

4. Tanh激活函数

Tanh激活函数表达式

Tanh导函数表达式

Tanh函数实现

Tanh函数以及导函数图像

Tanh激活函数(hyperbolic tangent, 双曲正切),通过函数表达式可以看出,tanh可由sigmoid激活函数平移缩放得到。tanh函数将输出值映射到(-1, 1)区间,有点类似于幅度增大的sigmoid激活函数。

接下来依然介绍tanh函数的优点和缺点。

优点:

  • 输出均值为0。这是tanh非常重要的一个优点;
  • tanh在原点附近与y = x函数形式相近,当激活值比较低的时候,训练相对比容易;
  • tanh的变化敏感区间较宽,缓解梯度弥散的现象。tanh导数取值范围在0到1之间,要优于sigmoid激活函数的0到0.25,相比于Sigmoid激活函数能够缓解梯度弥散的现象;
  • tanh的输出和输入能够保持非线性单调上升和下降的关系,符合反向传网络梯度的求解,容错性好,有界;

缺点:

  • 计算量比较大;

在Tensorflow2.X中tanh激活函数只有函数式接口的实现方式:

  1. tf.nn.tanh(x, name = None);

深度学习之激活函数_第5张图片

Tanh函数实现

你可能感兴趣的