一、激活函数
1.1 为什么使用激活函数
如果不使用激活函数,那么在神经网络中,每一层的节点的输入都是上一层输出的线性函数。那么神经网络不论有多少层,输出的都是输入的线性组合,这时候网络的逼近或者说表达能力就十分有限了,所以引入了非线性函数作为激活函数,增强网络的表达能力,使其能够逼近于任何函数。
1.2 常用的激活函数
1.2.1 sigmoid
s i g m o i d = σ ( x ) = 1 1 + e − x sigmoid = \sigma(x)=\frac{1}{1+e^{-x}} sigmoid=σ(x)=1+e−x1
优点:
- 便于求导的平滑函数
- 能够压缩数据,保证数据幅度不会有问题
- 适用于前向传播
缺点:
- 容易造成梯度爆炸或者梯度消失,梯度值最大是0.25
- 非0均值问题,导致模型收敛速度慢
- 幂运算相对耗时
import numpy as np
class SigmoidActivator(object):
def forward(self, weighted_input):
return 1.0/(1.0 + np.exp(-weighted_input))
def backward(self, output):
return output * (1 - output)
1.2.2 tanh
t a n h ( x ) = e x − e − x e x + e − x tanh(x) = \frac{e^x-e^{-x}}{e^x+e^{-x}} tanh(x)=ex+e−xex−e−x
优点:
- 解决了非0均值问题
缺点:
- 仍然容易造成梯度爆炸和梯度消失问题 ,梯度值在(0,1)之间。
class TanhActivator(object):
def forward(self, weighted_input):
return 2.0/(1.0 + np.exp(-2 * weighted_input)) - 1.0
def backward(self, output):
return 1 - output * output
1.2.3 relu
r e l u ( x ) = m a x ( 0 , x ) relu(x)=max(0,x) relu(x)=max(0,x)
优点:
- 在正区间解决了梯度消失问题,永远为1
- 收敛速度很快
- 计算复杂度低,不需要进行指数运算
- 适合反向传播
缺点
- 非0均值问题
- 神经元坏死现象。某些神经元可能永远不会被激活,导致相应参数永远不会被更新(在负数部分,梯度为0)。
- Relu函数不会对数据的幅度进行压缩,所以数据的幅度会随着层数的增加不断扩张。
改进
- Leaky-ReLU 解决了神经元坏死现象, l e a k y _ r e l u = m a x ( 0.01 x , x ) leaky\_relu=max(0.01x,x) leaky_relu=max(0.01x,x)
- Relu6 仅仅是在 ReLU 的基础上进行了 clip 操作,即限制了最大输出 r e l u 6 = m i n ( m a x ( 0 , x ) , 6 ) relu6=min(max(0,x),6) relu6=min(max(0,x),6)
- ELU 指数线性函数 f ( x ) = { x x > 0 α ( e x − 1 ) o t h e r w i s e f(x)=\begin{cases}x & x>0\\ \alpha(e^x-1) & otherwise \end{cases} f(x)={ xα(ex−1)x>0otherwise
class ReLUActivator(object):
def forward(self, weighted_input):
return weighted_input[weighted_input<0] = 0
def backward(self, output):
grad[output > 0] = 1
gard[output <= 0] = 0
return gard
1.3 神经元坏死现象
定义: ReLU在负数区域被kill的现象叫做神经元坏死现象。当 x < 0 x<0 x<0 的时候,梯度为0。这个神经元及之后的神经元梯度都为0,不再对任何数据有所响应,导致相应的参数永远不会更新。
原因: 产生神经元坏死的原因有两个,一个是参数初始化问题,另一个是学习率太高导致在训练过程中参数更新太大导致权重成为了负数。
解决办法:
- 使用MSRA、Xavier初始化方法(简单的说就是实现某种均匀分布)
- 使用leaky_relu、ELU等改进激活函数
- 避免使用太大的学习率
1.4 激活函数的0均值问题
以sigmoid函数及tanh函数为例子,解释非0均值问题带来的影响
1.4.1 收敛速度
首先需要给收敛速度做一个诠释。模型的最优解即是模型参数的最优解。通过逐轮迭代,模型参数会被更新到接近其最优解。这一过程中,迭代轮次多,则我们说模型收敛速度慢;反之,迭代轮次少,则我们说模型收敛速度快。
1.4.2 参数更新
深度学习一般的学习方法是反向传播。简单来说,就是通过链式法则,求解全局损失函数 L L L 对于某一参数 w w w 的偏导数(梯度),而后辅以学习率 η \eta η,向梯度的反方向更新参数 w w w w ← w − η ⋅ ∂ L ∂ w w \leftarrow w -\eta \cdot \frac{\partial L}{\partial w} w←w−η⋅∂w∂L
考虑学习率 η \eta η 是全局设置的超参数,参数更新的核心步骤就是计算 ∂ L ∂ w \frac{\partial L}{\partial w} ∂w∂L。再考虑到对于某个神经元来说,其输入和输出的关系是 f ( x ; w , b ) = f ( z ) = f ( ∑ i w i x i + b ) f(x;w,b)=f(z)=f(\sum_i w_ix_i+b) f(x;w,b)=f(z)=f(i∑wixi+b)
因此,对于参数 w i w_i wi 来说 ∂ L ∂ w i =