详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)

一、激活函数定义

激活函数 (Activation functions) 对于人工神经网络模型去学习、理解非常复杂和非线性的函数来说具有十分重要的作用。它们将非线性特性引入到神经网络中。在下图中,输入的 inputs 通过加权,求和后,还被作用了一个函数f,这个函数f就是激活函数。引入激活函数是为了增加神经网络模型的非线性。没有激活函数的每层都相当于矩阵相乘。就算你叠加了若干层之后,无非还是个矩阵相乘罢了。

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第1张图片

为什么使用激活函数?

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

激活函数有哪些性质?

  • 非线性:当激活函数是非线性的,一个两层的神经网络就可以基本上逼近所有的函数。但如果激活函数是恒等激活函数的时候,即f(x) = x,就不满足这个性质,而且如果MLP使用的是恒等激活函数,那么其实整个网络跟单层神经网络是等价的。
  • 可微性:当优化方法是基于梯度的时候,就体现的该本质。
  • 单调性:当激活函数是单调的时候,单层网络能够保证是凸函数。
  • 输出值的范围:当激活函数输出值是有限的时候,基于梯度的优化方法会更加稳定,因为特征的表示受有限权值的影响更显著;当激活函数的输出是无限的时候,模型的训练更加高效,不过这种情况很小,一般需要更小的learning rate。

二、梯度消失与梯度爆炸   

1.什么是梯度消失与梯度爆炸

梯度消失与梯度爆炸

        层数比较多的神经网络模型在训练的时候会出现梯度消失(gradient vanishing problem)梯度爆炸(gradient exploding problem)问题。梯度消失问题和梯度爆炸问题一般会随着网络层数的增加变得越来越明显。

        例如,一个网络含有三个隐藏层,梯度消失问题发生时,靠近输出层的hidden layer 3的权值更新相对正常,但是靠近输入层的hidden layer1的权值更新会变得很慢,导致靠近输入层的隐藏层权值几乎不变,仍接近于初始化的权值。这就导致hidden layer 1 相当于只是一个映射层,对所有的输入做了一个函数映射,这时此深度神经网络的学习就等价于只有后几层的隐藏层网络在学习。梯度爆炸的情况是:当初始的权值过大,靠近输入层的hidden layer 1的权值变化比靠近输出层的hidden layer 3的权值变化更快,就会引起梯度爆炸的问题。
 

2.梯度消失的根本原因

梯度消失的根本原因

以下图的反向传播为例:

假设σ为sigmoid,C为代价函数。

下图(1)式为该网络的前向传播公式。

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第2张图片

根据前向传播公式,我们得出梯度更新公式:

其中由公式(1)得出

\frac{\partial y_{i}}{\partial z_{i}}=\sigma ^{'}(z_{i})

\frac{\partial z_{i}}{\partial x_{i}}=w_{i}

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第3张图片

 sigmoid函数的导数如下图所示

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第4张图片

\sigma ^{'}(x)

的最大值是

\frac{1}{4}

,而我们一般会使用标准方法来初始化网络权重,即使用一个均值为0标准差为1的高斯分布。因此,初始化的网络权值通常都小于1,从而有\left | \sigma ^{'}(z)w \right |\leq \frac{1}{4}。对于2式的链式求导,层数越多,求导结果越小,前面的网络层比后面的网络层梯度变化更小,故权值变化缓慢,最终导致梯度消失的情况出现。

梯度爆炸的根本原因

    当\left | \sigma ^{'}(z)w \right |> 1,也就是w比较大的情况。则前面的网络层比后面的网络层梯度变化更快,引起了梯度爆炸的问题。

当激活函数为sigmoid时,梯度消失和梯度爆炸那个更容易发生?

梯度消失较容易发生

        量化分析梯度爆炸时x的取值范围:因导数最大为0.25,故|w|>4,才可能出现;按照可计算出x的数值变化范围很窄,仅在公式3范围内,才会出现梯度爆炸。画图如5所示,可见x的数值变化范围很小;最大数值范围也仅仅0.45,当|w|=6.9时出现。因此仅仅在此很窄的范围内会出现梯度爆炸的问题。

\frac{2}{\left | w \right |}ln(\frac{\left | w \right |(1+\sqrt{1-4/\left | w \right |})}{2}-1)

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第5张图片

3.如何解决梯度消失与梯度爆炸问题 

如何解决梯度消失和梯度爆炸问题?

        梯度消失和梯度爆炸问题都是因为网络太深网络权值更新不稳定造成的,本质上是因为梯度反向传播中的连乘效应。对于更普遍的梯度消失问题,可以考虑一下三种方案解决:

1.    用ReLU、Leaky-ReLU、P-ReLU、R-ReLU、Maxout等替代sigmoid函数。

2.    用Batch Normalization。

3.    LSTM的结构设计也可以改善RNN中的梯度消失问题。

三、常用激活函数

激活函数分为两类,饱和激活函数和非饱和激活函数。

饱和激活函数包括sigmoid、tanh;非饱和激活函数包括ReLU、PReLU、Leaky ReLU、RReLU、ELU等。

那什么是饱和函数呢?

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第6张图片

        sigmoid和tanh是“饱和激活函数”,而ReLU及其变体则是“非饱和激活函数”。使用“非饱和激活函数”的优势在于两点:(1)"非饱和激活函数”能解决所谓的“梯度消失”问题。(2)它能加快收敛速度。

        Sigmoid函数将一个实值输入压缩至[0,1]的范围---------σ(x) = 1 / (1 + exp(−x))
        tanh函数将一个实值输入压缩至 [-1, 1]的范围---------tanh(x) = 2σ(2x) − 1
        由于使用sigmoid激活函数会造成神经网络的梯度消失和梯度爆炸问题,所以许多人提出了一些改进的激活函数,如:tanh、ReLU、Leaky ReLU、PReLU、RReLU、ELU、Maxout。

1.Sigmoid

sigmoid的数学公式为\sigma (x)=\frac{1}{1+e^{-x}}

其导数公式为\sigma ^{'}(x)=\frac{e^{-x}}{(1+e^{-x})^{2}}=\sigma (x)(1-\sigma (x))

如下图所示,左图为sigmoid的函数图,右图为其导数图.

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第7张图片

特点:它能够把输入的连续实值变换为0和1之间的输出,特别的,如果是非常大的负数,那么输出就是0;如果是非常大的正数,输出就是1。

在什么情况下适合使用 Sigmoid 激活函数?

Sigmoid 函数的输出范围是 0 到 1。由于输出值限定在 0 到 1,因此它对每个神经元的输出进行了归一化;用于将预测概率作为输出的模型。由于概率的取值范围是 0 到 1,因此 Sigmoid 函数非常合适;梯度平滑,避免「跳跃」的输出值;函数是可微的。这意味着可以找到任意两个点的 sigmoid 曲线的斜率;明确的预测,即非常接近 1 或 0。

缺点:

容易出现梯度消失函数输出并不是zero-centered(零均值)幂运算相对来讲比较耗时

1.梯度消失

        优化神经网络的方法是梯度回传:先计算输出层对应的 loss,然后将 loss 以导数的形式不断向上一层网络传递,修正相应的参数,达到降低loss的目的。 Sigmoid函数在深度网络中常常会导致导数逐渐变为0,使得参数无法被更新,神经网络无法被优化。原因在于两点:

当σ(x)中的x较大或较小时,导数接近0,而后向传递的数学依据是微积分求导的链式法则,当前层的导数需要之前各层导数的乘积,几个小数的相乘,结果会很接近0。Sigmoid导数的最大值是0.25,这意味着导数在每一层至少会被压缩为原来的1/4,通过两层后被变为1/16,…,通过10层后为1/1048576。请注意这里是“至少”,导数达到最大值这种情况还是很少见的。

2.零均值

       零均值是不可取的,因为这会导致后一层的神经元将得到上一层输出的非0均值的信号作为输入。 Sigmoid函数的输出值恒大于0,这会导致模型训练的收敛速度变慢。举例来讲,对\sigma (\sum_{i}^{}w_{i}x_{i}+b),如果所有x_{i}均为正数或负数,那么其对w_{i}的导数总是正数或负数,这会导致如下图红色箭头所示的阶梯式更新,这显然并非一个好的优化路径。深度学习往往需要大量时间来处理大量数据,模型的收敛速度是尤为重要的。所以,总体上来讲,训练深度学习网络尽量使用zero-centered数据 (可以经过数据预处理实现) 和zero-centered输出。

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第8张图片

不是zero-centered产生的一个结果就是:如果数据进入神经元的时候是正的,那么 w 计算出的梯度也会始终都是正的。当然了,如果你是按batch去训练,那么那个batch可能得到不同的信号,所以这个问题还是可以缓解一下的。因此,非0均值这个问题虽然会产生一些不好的影响,不过跟上面提到的梯度消失问题相比还是要好很多的。

3.幂运算相对耗时

        相对于前两项,这其实并不是一个大问题,我们目前是具备相应计算能力的,但面对深度学习中庞大的计算量,最好是能省则省。之后我们会看到,在ReLU函数中,需要做的仅仅是一个thresholding,相对于幂运算来讲会快很多。

2.Tanh

tanh的数学公式为:tanh(x)=\frac{2}{1+e^{-2x}}-1

其导数为:tanh^{'}(x)=\frac{4e^{2x}}{(1+e^{-2x})^{2}}

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第9张图片

sigmoid与tanh的比较

        首先,当输入较大或较小时,输出几乎是平滑的并且梯度较小,这不利于权重更新。二者的区别在于输出间隔,tanh 的输出间隔为 1,并且整个函数以 0 为中心,比 sigmoid 函数更好;

        在 tanh 图中,负输入将被强映射为负,而零输入被映射为接近零。

        注意:在一般的二元分类问题中,tanh 函数用于隐藏层,而 sigmoid 函数用于输出层,但这并不是固定的,需要根据特定问题进行调整。

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第10张图片

3.ReLU

ReLU的数学表达式为

其导数公式为

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第11张图片

ReLU的优点:

解决了梯度消失问题 (在正区间),ReLU的非饱和性可以有效地解决梯度消失的问题, 提供相对宽的激活边界。Sigmoid和Tanh激活函数均需要计算指数, 复杂度高, 而ReLU只需要一个阈值即可得到激活值。ReLU 函数中只存在线性关系,因此它的计算速度比 sigmoid 和 tanh 更快。计算速度非常快,只需要判断输入是否大于0。收敛速度远快于sigmoid和tanhReLU使得一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的互相依存关系,缓解了过拟合问题的发生

ReLU存在的问题

ReLU 函数的输出为 0 或正数,不是zero-centered对参数初始化和学习率非常敏感;ReLU 函数的输出均值大于0,偏移现象和神经元死亡会共同影响网络的收敛性。存在神经元死亡,指的是某些神经元可能永远不会被激活,导致相应的参数永远不能被更新。这是由于函数导致负梯度在经过该ReLU单元时被置为0, 且在之后也不被任何数据激活, 即流经该神经元的梯度永远为0, 不对任何数据产生响应。 当输入为负时ReLU 完全失效,在正向传播过程中,这不是问题。有些区域很敏感,有些则不敏感。但是在反向传播过程中,如果输入负数,则梯度将完全为零,sigmoid 函数和 tanh 函数也具有相同的问题。有两个主要原因可能导致这种情况产生: (1) 非常不幸的参数初始化,这种情况比较少见; (2) learning rate太高导致在训练过程中参数更新太大,会导致超过一定比例的神经元不可逆死亡, 进而参数梯度无法更新, 整个训练过程失败。解决方法是可以采用Xavier初始化方法,以及避免将learning rate设置太大或使用adagrad等自动调节learning rate的算法。

怎样理解ReLU(<0)时是非线性激活函数?

 从图像可看出具有如下特点:

单侧抑制相对宽阔的兴奋边界稀疏激活性

        ReLU函数从图像上看,是一个分段线性函数,把所有的负值都变为0,而正值不变,这样就成为单侧抑制。

        因为有了这单侧抑制,才使得神经网络中的神经元也具有了稀疏激活性。

        稀疏激活性:从信号方面来看,即神经元同时只对输入信号的少部分选择性响应,大量信号被刻意的屏蔽了,这样可以提高学习的精度,更好更快地提取稀疏特征。当x<0时,ReLU硬饱和,当x>0时,则不存在饱和函数。ReLU能够在在x>0时保持梯度不衰减,从而缓解梯度消失问题。

4.Leaky ReLU

人们为了解决失效神经元,提出了将ReLU的前半段设为αx而非0。

Leaky ReLU的数学表达式为

其导数公式为

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第12张图片

为什么 Leaky ReLU 比 ReLU 更好?

Leaky ReLU 通过把 x 的非常小的线性分量给予负输入(αx)来调整负值的零梯度(zero gradients)问题;leak 有助于扩大 ReLU 函数的范围,通常 a 的值为 0.01 左右;Leaky ReLU 的函数范围是(负无穷到正无穷)。

     但另一方面, a值的选择增加了问题难度, 需要较强的人工先验或多次重复训练以确定合适的参数值。

LeakyReLU与ReLU和PReLU之间区别

if α=0 ,则函数是ReLUif α>0 ,则函数是Leaky ReLUif α是可学习参数,则函数是PReLU(Parametric ReLU)

5.ELU

        ELU 的提出也解决了 ReLU 的问题。与 ReLU 相比,ELU 有负值,这会使激活的平均值接近零。均值激活接近于零可以使学习更快,因为它们使梯度更接近自然梯度。

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第13张图片

显然,ELU 具有 ReLU 的所有优点,并且:

没有 Dead ReLU 问题,输出的平均值接近 0,以 0 为中心;ELU 通过减少偏置偏移的影响,使正常梯度更接近于单位自然梯度,从而使均值向零加速学习;ELU 在较小的输入下会饱和至负值,从而减少前向传播的变异和信息。

       一个小问题是它的计算强度更高。与 Leaky ReLU 类似,尽管理论上比 ReLU 要好,但目前在实践中没有充分的证据表明 ELU 总是比 ReLU 好。

6.softmax

        Softmax 是用于多类分类问题的激活函数,在多类分类问题中,超过两个类标签则需要类成员关系。对于长度为 K 的任意实向量,Softmax 可以将其压缩为长度为 K,值在(0,1)范 围内,并且向量中元素的总和为 1 的实向量。

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第14张图片

        Softmax 与正常的 max 函数不同:max 函数仅输出最大值,但 Softmax 确保较小的值具有较小的概率,并且不会直接丢弃。我们可以认为它是 argmax 函数的概率版本或「soft」版本。        

        Softmax 函数的分母结合了原始输出值的所有因子,这意味着 Softmax 函数获得的各种概率彼此相关。

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第15张图片

Softmax 激活函数的主要缺点是:

在零点不可微;负输入的梯度为零,这意味着对于该区域的激活,权重不会在反向传播期间更新,因此会产生永不激活的死亡神经元。

7.Swish

Swish的表达式为y = x * sigmoid (x)

详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等)_第16张图片

        Swish 的设计受到了 LSTM 和高速网络中 gating 的 sigmoid 函数使用的启发。我们使用相同的 gating 值来简化 gating 机制,这称为 self-gating。

        self-gating 的优点在于它只需要简单的标量输入,而普通的 gating 则需要多个标量输入。这使得诸如 Swish 之类的 self-gated 激活函数能够轻松替换以单个标量为输入的激活函数(例如 ReLU),而无需更改隐藏容量或参数数量。

  Swish 激活函数的主要优点如下:

「无界性」有助于防止慢速训练期间,梯度逐渐接近 0 并导致饱和;(同时,有界性也是有优势的,因为有界激活函数可以具有很强的正则化,并且较大的负输入问题也能解决);导数恒 > 0;平滑度在优化和泛化中起了重要作用。

到此这篇关于Python中常用的激活函数(Sigmoid、Tanh、ReLU等)的文章就介绍到这了,更多相关激活函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

你可能感兴趣的:(详解Python中常用的激活函数(Sigmoid、Tanh、ReLU等))