前言
为什么神经网中非要有各种各样的激活函数?他们有什么用?没有他们会怎样?常见的激活函数有哪些,他们都有什么特点?
如果我们不运用激活函数,神经网络的输出信号将仅仅是一个简单的线性函数。线性方程很容易解决,但是它们的复杂性有限,从数据中学习复杂函数映射的能力较小。
一个没有激活函数的神经网络最终只不过是一个线性回归模型罢了,不能解决现实世界中的大多数非线性问题。
现假设只有两层没有激活函数的全连接网络如下:
第一层的权重和偏置为 w 1 w_1 w1和 b 1 b_1 b1,其 输出直接连到第二层的输入,权重和偏置为 w 2 w_2 w2和 b 2 b_2 b2,最后输出预测值。公式化简化后仍然是一个线性函数。
y ^ = w 2 ( w 1 ⋅ x + b 1 ) + b 2 = w 2 ⋅ w 1 ⋅ x + w 2 ⋅ b 1 + b 2 = w ⋅ x + b \begin{aligned} \hat{y} & = w_2(w_1 \cdot x + b_1) + b_2 \\ & = w_2\cdot w_1 \cdot x + w_2 \cdot b_1 + b_2 \\ & = w\cdot x + b \end{aligned} y^=w2(w1⋅x+b1)+b2=w2⋅w1⋅x+w2⋅b1+b2=w⋅x+b
如果我们在第一层的输出加上一个激活函数,则不能有上式的化简。只有加入了激活函数,神经网络才具备分层的非线性的学习能力。
y ^ = w 2 ( σ ( y 1 ) ) + b 2 y 1 = w 1 ⋅ x + b 1 σ ( ⋅ ) 为激活函数 \begin{aligned} \hat{y} & = w_2(\sigma(y_1)) + b_2 \\ & y_1 =w_1 \cdot x + b_1 \\ & \sigma(\cdot) 为激活函数 \\ \end{aligned} y^=w2(σ(y1))+b2y1=w1⋅x+b1σ(⋅)为激活函数
sigmoid
f ( x ) = 1 1 + e − x \begin{aligned} f(x) = \frac{1}{1+e^{-x}} \nonumber \end{aligned} f(x)=1+e−x1
- 输出范围在(0,1)之间,常用于二元分类问题的最后一层,将输出映射到概率值。
- sigmoid函数的输出值均大于0,使得输出不是0的均值,从而发生激活函数的偏移现象
- 从图像中可以看出sigmoid两端的导数接近0,会导致反向传播的梯度也变得非常小,此时网络参数可能得不到更新,难以有效训练。也称梯度消失。
- 一般来说sigmoid网络在5层之内就会产生梯度消失现象。
tanh
f ( x ) = e x − e − x e x + e − x \begin{aligned} f(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} \end{aligned} f(x)=ex+e−xex−e−x
- 输出范围在(-1, 1)之间,输出均值为0,使得它的收敛速度要比sigmoid快。
- 同样会存在梯度消失问题,不过相较于sigmoid稍微缓解了梯度消失的程度。
- 导数dtanh的值域在(0, 1)。
ReLU(Rectified Linear Units)
f ( x ) = { 0 , i f x < 0 x , i f x ≥ 0 \begin{aligned} & f(x) =\left\{ \begin{aligned} 0 &, &if \ x < 0 \\ x &, &if \ x \geq 0 \end{aligned} \right.\\ \end{aligned} f(x)={0x,,if x<0if x≥0
- 当输入大于0时,输出等于输入;当输入小于等于0时,输出为0,权重无法更新。
- 简单且计算效率高,有效缓解了梯度消失的问题。
- 与sigmoid类似,ReLU的输出均值也大于0,偏移现象和神经元死亡会共同影响网络的收敛性。
Leaky-ReLU & L-ReLU
f ( x ) = { α x , i f x < 0 x , i f x ≥ 0 \begin{aligned} & f(x) =\left\{ \begin{aligned} \alpha x &, &if \ x < 0 \\ x &, &if \ x \geq 0 \end{aligned} \right.\\ \end{aligned} f(x)={αxx,,if x<0if x≥0
- 在标准ReLU的基础上,对于负半轴的输入赋予了一个小的斜率,从而弥补了ReLU负半轴输出为0导致权重不更新的问题。
softmax
f ( x ) = e i ∑ i = 1 n e i \begin{aligned} f(x) = \frac{e^{i}}{\sum_{i=1}^{n}e^{i}} \end{aligned} f(x)=∑i=1neiei
- 用于多类分类问题的激活函数,值在[0 , 1]范围内,并且向量中元素总和为1。
- softmax的负半轴的输出接近0,反向传播时该部分的权重几乎不更新。
swish
f ( x ) = x ⋅ s i g m o i d ( β x ) \begin{aligned} f(x) = x\cdot sigmoid(\beta x) \end{aligned} f(x)=x⋅sigmoid(βx)
β \beta β 是常数或者经过学习得到的参数。当 β = 1 \beta = 1 β=1
- 与ReLU不同,swish函数全范围内都连续可微。实验表明,Swish作为激活函数经常会获得比ReLU更高的分类精度。但是,与ELU同样,由于需要计算幂函数,其计算代价较高。
numpy实现
import matplotlib.pyplot as plt
import numpy as npdef sigmoid(x):return 1.0 / (1.0 + np.exp(-x))def dsigmoid(x):return sigmoid(x) * (1 - sigmoid(x))def tanh(x):return (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))def dtanh(x):return 1 - tanh(x) ** 2def relu(x):return np.where(x < 0, 0, x)def drelu(x):x = np.where(x < 0, 0, x)x = np.where(x > 0, 1, x)return xdef lrelu(x, alpha=0.2):y = np.piecewise(x, [x >= 0, x < 0], [lambda x: x, lambda x: alpha * x])x = np.where(x >= 0, 1, x)dy = np.where(x < 0, alpha, x)return (y, dy)def softmax(x):return np.exp(x) / np.sum(np.exp(x))def dsoftmax(x):passdef swish(x, beta=1.0):return x * sigmoid(beta * x)def dswish(x, beta=1.0):sig = sigmoid(beta * x)dy = sig * (1 + x * beta * (1 - sig))return dyif __name__ == "__main__":x = np.linspace(-10.0, 10.0, num=10, endpoint=True)# plt.plot(x, sigmoid(x), label="sigmoid")# plt.plot(x, dsigmoid(x), label="dsigmoid")# plt.plot(x, tanh(x), label="tanh")# plt.plot(x, dtanh(x), label="dtanh")# plt.plot(x, relu(x), label="relu")# plt.plot(x, drelu(x), label="drelu")# plt.plot(x, lrelu(x)[0], label="lrelu")# plt.plot(x, lrelu(x)[1], label="dlrelu")# x = np.linspace(-5.0, 5.0, num=100, endpoint=True)# plt.plot(x, softmax(x), label="softmax")beta = 1plt.plot(x, swish(x, beta), label="swish")plt.plot(x, dswish(x, beta), label="dswish")plt.grid()plt.legend()plt.show()
小结
一句话 激活函数就是为了增加模型的非线性表达能力和学习到更复杂的映射关系。