常用激活函数优缺点及性能对比

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/EngineerHe/article/details/100126694

激活函数(Activation Function)

什么是激活函数?

人工神经网络的激活函数就是模仿生物神经网络。在生物神经网络中,信息的传递是通过神经元的树突和轴突的结合,在前膜的内侧有致密突起和网格形成的囊泡栏栅,其空隙处正好容纳一个突触小泡,它可能有引导突触小泡与前膜接触的作用,促进突触小泡内递质的释放。当突触前神经元传来的冲动到达突触小体时,小泡内的递质即从前膜释放出来,进入突触间隙,并作用于突触后膜;如果这种作用足够大时,即可引起突触后神经元发生兴奋或抑制反应,黄字部分是来自某百科的解释,高中也学过,读不懂也没有关系,下面来点大白话的。如下图红色的圈圈,树突会产生一些物质,不断断积累,当到达一定程度的时候,信息就会传递给轴突,差不多就是这个过程,当然严谨的来说,信息传递的过程十分的复杂,就如黄字部分说的那样。

在这里插入图片描述

对于人工神经网络而言,是想用机器来尽可能的模仿生物神经元信息传递的过程。人工神经网络的定义通常是 y = w x + b y=wx+b 的形式,通过多层神经元的叠加,来拟合复杂的函数。考虑一个问题,如果只是简单的通过累加的形式进行处理的话,那么神经网络能实现的功能是十分有限的。简单的例子,如下图所示,下面的数据是线性不可分的,是一个异或问题,只是通过 w x + b wx+b 是无法实现的。这时就需要加入非线性元素来改变,可以使得神经网络输出非线性决策边界。特别是多层神经网络,加入非线性元素,可以使得神经网络任意逼近任何非线性函数。

img

另一方面,激活函数还可以起到将数据特征映射到新的特征空间的作用,这样可以更加有利于数据的训练,加速模型的收敛。

激活函数

常用的激活函数SigmoidTanhReLULeaky ReLUPReLU,还有一些他们的变体以及其他的函数。这篇文章列举了26种激活函数,这里是原文,可能需要翻墙,小伙伴可以点击去看一下。

step function

f ( x ) = { 1 x > 0 0 x 0 f\left( x \right) = \left\{ {\begin{array}{c} {\begin{array}{c} 1&{x > 0} \end{array}}\\ {\begin{array}{c} 0&{x \le 0} \end{array}} \end{array}} \right.

import numpy as np
import matplotlib.pyplot as plt

def step_func(x):
#    if x > 0:
#        return 1
#    else:
#        return 0
    return np.array(x > 0, dtype=np.int)


x = np.arange(-3,3,0.01)
y = step_func(x)

plt.xlabel("Input")
plt.ylabel("Output")
plt.plot(x,y)
plt.ylim(-0.1,1.1)
plt.show()

在这里插入图片描述

Sigmoid

Sigmoid函数是传统神经网络中最常用的激活函数,虽然现在已经不常用,但当年还是十分受欢迎的。Sigmoid函数也叫Logistic 函数,值域在0到1之间。

Sigmoid函数的表达式及其求导:
σ ( x ) = 1 1 + e x σ ( x ) x = e x 1 + e x = σ ( x ) ( 1 σ ( x ) ) \begin{array}{l} \sigma \left( x \right) = \frac{1}{{1 + {e^{ - x}}}}\\ \frac{{\partial \sigma \left( x \right)}}{{\partial x}} = \frac{{{e^{ - x}}}}{{1 + {e^{ - x}}}} = \sigma \left( x \right)\left( {1 - \sigma \left( x \right)} \right) \end{array}

import numpy as np
# sigmoid函数
def sigmoid(x):
    y = 1/(1+np.exp(-x))
    return y
# sigmoid函数求导
def d_sigmoid(x):
    dx = sigmoid(x)*(1-sigmoid(x))
    return dx

sigmoid激活函数

在这里插入图片描述

sigmoid函数导数

在这里插入图片描述

当x的值趋近负无穷的时候,y趋近于0;x趋近于正无穷的时候,y趋近于1;在 [ 2 , 2 ] [-2, 2] 区间内,梯度变化比较明显,即x发生很小的变化,y变化的也比较明显。

sigmoid的优缺点:

优点:

  • Sigmoid函数的输出映射在(0,1)之间,单调连续,输出范围有限,优化稳定
  • 求导容易

缺点:

  • 幂运算,计算成本高
  • 容易出现梯度弥散(反向传播时,很容易就会出现梯度消失的情况,从而无法完成深层网络的训练)
  • 不是以0为中心,为导致收敛速度下降(具体解释可以参考这里

tanh

双曲正切函数,tanh函数输出以0为中心,区间为 [ 1 , 1 ] [-1, 1] ,tanh可以想象成两个sigmoid函数放在一起,性能要高于sigmoid函数
σ ( x ) = e x e x e x + e x \sigma \left( x \right) = \frac{{{e^x} - {e^{ - x}}}}{{{e^x} + {e^{ - x}}}}
tanh函数的变形:
σ ( x ) = 1 e 2 x 1 + e 2 x = 2 s i g m o i d ( 2 x ) 1 \sigma \left( x \right) = \frac{{1 - {e^{ - 2x}}}}{{1 + {e^{ - 2x}}}} = 2sigmoid\left( {2x} \right) - 1
求导:
σ ( x ) x = ( e x + e x ) 2 ( e x e x ) 2 ( e x + e x ) 2 = 1 σ 2 ( x ) \frac{{\partial \sigma \left( x \right)}}{{\partial x}} = \frac{{{{\left( {{e^x} + {e^{ - x}}} \right)}^2} - {{\left( {{e^x} - {e^{ - x}}} \right)}^2}}}{{{{\left( {{e^x} + {e^{ - x}}} \right)}^2}}} = 1 - {\sigma ^2}\left( x \right)

def tanh(x):
    # y = np.tanh(x)
    y = 2*sigmoid(2*x)-1
    return y

def d_tanh(x):
    dx = 1- tanh(x)*tanh(x)
    return dx

tanh激活函数

在这里插入图片描述

tanh激活函数求导

在这里插入图片描述

tanh函数的优缺点:

优点:只要是解决了sigmoid关于zero-centered的输出问题。导数范围变大,在 0 , 1 (0,1) 之间,而sigmoid在 ( 0 , 0.25 ) (0, 0.25) 之间,梯度消失问题有所缓解。

缺点:

  • 幂运算,计算成本高
  • 梯度消失问题

ReLU

Relu(Rectified Linear Unit)-修正线性单元函数,函数的表达式:
σ ( x ) = { x x > 0 0 x 0 \sigma \left( x \right) = \left\{ {\begin{array}{ccc} {\begin{array}{ccc} x&{x > 0} \end{array}}\\ {\begin{array}{ccc} 0&{x \le 0} \end{array}} \end{array}} \right.
ReLU=max(0, x)

def relu(x):
    # 1
#    y = np.maximum(0, x)
    # 2
#    y = np.where(x>0, x, 0)
    # 3
    y = (x + np.abs(x))/2
    
    return y

ReLU激活函数

在这里插入图片描述

从图上可以看出,当 x 0 x \le 0 的时候,ReLu有饱和问题,当 x &gt; 0 x&gt;0 的时候,则存在硬饱和(当x<0时,导数恒等于0;软饱和,导数趋近于0)。所以当 x &gt; 0 x&gt;0 的时候不会存在梯度消失的问题。为了解决左硬饱和问题,提出了Leaky ReLU**、**PReLU解决方法。Leaky ReLU的函数公式为: σ ( x ) = max ( α x , x ) \sigma \left( x \right) = \max (\alpha x,x) ,其中 α \alpha 是一个很小的值,这样做可以使得负轴的信息不会全部丢失,解决ReLU神经元死亡问题

def leaky_relu(x, leak):
    y = np.maximum(leak*x, x)
    return y

Leaky ReLU:

在这里插入图片描述
PReLU和Leaky ReLU的表达式相同, σ ( x ) = max ( α x , x ) \sigma \left( x \right) = \max (\alpha x,x) ,区别在于这里的 α \alpha 不是固定的,而是一个可以学习的参数。

ReLU激活函数的优缺点

优点:

  • 梯度不饱和,收敛速度快;
  • 相对于sigmoid/tanh激活函数,极大的改善了梯度消失的问题;
  • 不需要进行指数运算,因此运算速度快、复杂度低

缺点:

  • 对参数初始化和学习率非常敏感,存在神经元死亡;
  • ReLU的输出均值也大于0,偏移现象和 神经元死亡会共同影响网络的收敛性;

ReLU激活函数为什么比sigmoid和tanh好?

  • 相比Sigmoid和tanh,ReLU摒弃了复杂的计算(这里指的是幂运算),提高了运算速度;
  • 对于深层的网络而言,Sigmoid和tanh函数反向传播的过程中,和容易出现梯度消失的问题;
  • ReLU会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。

ReLU激活函数为什么能解决梯度消失问题?

img
C b 1 = σ ( z 1 ) w 2 σ ( z 2 ) w 3 σ ( z 3 ) w 4 σ ( z 4 ) C a 4 \frac{{\partial C}}{{\partial b1}} = \sigma &#x27;\left( {{z_1}} \right){w_2}\sigma &#x27;\left( {{z_2}} \right){w_3}\sigma &#x27;\left( {{z_3}} \right){w_4}\sigma &#x27;\left( {{z_4}} \right)\frac{{\partial C}}{{\partial {a_4}}}
上面的内容图片公式点 这里。假如对 b1进行反向传播,求梯度,公式如上, σ ( . ) \sigma(.) 表示激活函数,假如我们选择的是sigmoid函数,可以从上文中得知,sigmoid最大的梯度是0.25,所以在反向传播的过程中,梯度的下降呈指数下降,所以很容易造成梯度消失,使得前层网络的权值无法更新或者更新的很慢。选用ReLu函数,当 x &gt; 0 x&gt;0 时,激活函数的梯度恒等于1,所以就可以大大解决了梯度消失的问题。

ReLU激活函数导致神经元“死亡”问题

y = w x + b y=wx+b 经过 σ ( x ) \sigma(x) 激活以后为a(其中的 σ \sigma 表示ReLU),定义损失函数为 L L

一个简单的前馈网络传递的过程可以见到的表示如下:

在这里插入图片描述

y = w x + b , a = σ ( y ) y=wx+b, a=\sigma(y)

反向传播的话就是根据链式求导法则,要更新 w w ,所以对 w w 进行求导:
L w = L a a y y w = L a a y x T = L y x T \begin{array}{l} \frac{{\partial L}}{{\partial w}} &amp;= \frac{{\partial L}}{{\partial a}} \cdot \frac{{\partial a}}{{\partial y}} \cdot \frac{{\partial y}}{{\partial w}}\\ &amp;= \frac{{\partial L}}{{\partial a}} \cdot \frac{{\partial a}}{{\partial y}} \cdot {x^T}\\ &amp;= \frac{{\partial L}}{{\partial y}} \cdot {x^T} \end{array}
设学习率 l r lr (learning rate)为定值,权重 w w 的更新取决于 L w \frac{{\partial L}}{{\partial w}} L w \frac{{\partial L}}{{\partial w}} 越大,则更新的越多, 即:
w = w + l r L w w = w + lr \cdot \frac{{\partial L}}{{\partial w}}
就上式而言,如果 l r lr 的值设置的太大,权重就会更新的很多,这么一种情况,由于权重更新的太多,可能对于任意训练数据 x x ,输出结果 y y 都小于零,此时经过 ReLU 后, a = m a x ( 0 , x ) = 0 a = max(0, x) = 0 。这样的话会出现什么情况,根据上文我们说的ReLU函数求导,当 0 \le 0 的时候,梯度为0;当 &gt; 0 &gt;0 的时候梯度为1, 所以 a y = 0 \frac{{\partial a}}{{\partial y}} = 0 ,即 L w = L a 0 y w = 0 \frac{{\partial L}}{{\partial w}} = \frac{{\partial L}}{{\partial a}} \cdot 0 \cdot \frac{{\partial y}}{{\partial w}} = 0 , 可以看出此后 w w 就会停止更新,所以就会好造成该部分的神经元 “死亡”。

猜你喜欢

转载自blog.csdn.net/EngineerHe/article/details/100126694
今日推荐