一、激活函数原理

激活函数(activation function),就是在神经网络的神经元上运行的函数,负责将神经元的输入映射到输出层,旨在帮组神经网络学习数据中的复杂模式。

二、激活函数的作用

使用激活函数能够为神经网络引入非线性因素,使得神经网络可以任意逼近任何非线性函数,使深层神经网络表达能力更加强大,使得神经网络可以应用到总舵的非线性模型中。如果不使用激活函数,那神经网络的每一层输出都是上层输入的线性函数,无论神经网络的层数是多少,其输出都是输入的线性组合,这样就退化为原始的感知机模型了。

三、激活函数分类

激活函数可以分为饱和激活函数非饱和激活函数

3.1 饱和的概念

假设h(x)是一个激活函数,有如下一个极限:
$$
\lim_{n\rightarrow\pm\infty}h^\prime(x)=0
$$
当n趋于正无穷,激活函数的导数趋于0,则称之为右饱和;若当n趋于负无穷时,激活函数的导数趋于0,则称之为左饱和。当一个函数同时满足左饱和和右饱和时,我们称之为饱和,不然则称之为非饱和。

  • 饱和激活函数:sigmoid、tanh
  • 非饱和激活函数:ReLU、 Leakly ReLU、elu、PReLU、RReLU

相比于饱和激活函数,非饱和激活函数的优势在于两点:

  • 能解决深度神经网络带来的梯度消失问题
  • 能加快收敛速度

四、常见激活函数

4.1 sigmoid

其数学表达式如下,输出范围在[0, 1]之间。
$$
sigmoid(x) = \frac{1}{1+e^{-x}}
$$
其导数表达式为:
$$
sigmoid\prime(x) = sigmoid(x)(1-sigmoid(x)) =\frac{1}{1+e^{-x}}\frac{e^{-x}}{1+e^{-x}}=\frac{e^{-x}}{(1+e^{-x})^2}
$$
其函数图像如下:

图片

其代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
import math
import scipy
# math.exp()只适用于单数值
# numpy.exp()适用于数值、列表、数值、矩阵
# scipy.special.expit()同numpy,但更稳定,速度较慢
def sigmoid(x):
# math
math_y = 1 / (1 + math.exp(-x))
# np
np_y = 1 / (1 + np.exp(-x))
# scipy
sci_y = 1 / (1 + scipy.special.expit(x))
return np_y

def sigmoid_derivative(x):
return sigmoid(x) * (1 - sigmoid(x))

使用场景:

  • sigmoid函数的输出范围是0到1。适合作为模型的输出函数用于输出一个0-1范围内的概率值,如表示二分类的类别或者用于表示置信度。
  • sigmoid函数梯度平滑,方便求导,可以用于防止模型训练过程中出现突变的梯度。

缺点:

  • 容易造成梯度消失。
  • 函数输出不是以0为中心的,梯度可能会向特定方向一点,从而降低权重更新的效率。
  • sigmoid函数执行指数运算,计算速度慢,计算资源需求大。

4.2 Tanh函数

其数学表达式如下,输出范围在[-1, 1]之间。
$$
Tanh(x) = \frac{e^x-e^{-x}}{e^x+e^{-x}}=\frac{e^x-e^{-x}}{e^x+e^{-x}} \frac{e^{-x}}{e^{-x}}=\frac{1-e^{-2x}}{1+e^{-2x}}
$$
实际上,Tanh函数是 sigmoid 的变形:
$$
Tanh(x)=2sigmoid(2x)-1=\frac{1-e^{-2x}}{1+e^{-2x}}
$$
其导数表达式为:
$$
Tanh\prime(x) =\frac{(e^x+e^{-x})^2-(e^x-e^{-x})^2}{({e^x+e^{-x}})^2}=\frac{4}{(1+e^{-x})^2}=\frac{4e^{-2x}}{(1+e^{-2x})^2}
$$
与sigmoid函数不同的三十,tanh是以0为中心的。因此,在实际应用中,tanh会比ssigmoid更好一点。但在饱和神经元的情况下辖,tanh仍没有解决梯度消失的问题。

其函数图像如下:

img

其代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
import math
import scipy
# math.exp()只适用于单数值
# numpy.exp()适用于数值、列表、数值、矩阵
# scipy.special.expit()同numpy,但更稳定,速度较慢
def sigmoid(x):
# math
math_y = (math.exp(x) - math.exp(-x)) / (math.exp(x) + math.exp(-x))
# np
np_y = (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))
# scipy
sci_y = (scipy.special.expit(x) - scipy.special.expit(-x)) / (scipy.special.expit(x) + scipy.special.expit(-x))
return np_y

def sigmoid_derivative(x):
return sigmoid(x) * (1 - sigmoid(x))

Tanh函数优点:

  • Tanh的输出间隔为1,并且整个函数以0为中心,比sigmoid函数更好;
  • 在Tanh函数图中,负输入被强映射为负,二零输入被映射为接近0。

Tanh函数缺点:

  • 仍存在梯度饱和的问题;
  • 依然进行的是指数运算。

4.3 ReLU函数

其数学表达式为:
$$
ReLU(x)=\max(0,x)
$$
函数图像如下:

img

ReLU函数优点:

  • ReLU解决了梯度消失的问题,当输入值为正是,神经元不会饱和;
  • 由于ReLU函数的线性、非饱和性质,在SGD中能够快速收敛;
  • 计算复杂度低,不需要进行指数运算。

ReLU函数缺点:

  • 与simoid函数一样,其输出不是以0为中心的;
  • Dead ReLU问题。当输入为负时,梯度为0。此时,神经元及之后的神经元梯度永远为0,不再对任何数据有所响应,导致相应参数永远不会被更新。

训练神经网络时,若学习率没设置好,第一次更新权重时输入为负值,则这个含有ReLU的神经节点会死亡,再也不会被激活。因此,要设置一个合适的较小学习率,来降低这种情况的发生。