激活函数:
-
使用激活函数的原因:
神经网络中每一层的输入输出都是一个线性求和的过程,下一层的输出只是承接了上一层输入函数的线性变换,如果没有激活函数,无论构造的神经网络多么复杂,有多少层,最后的输出都是输入的线性组合,纯粹的线性组合并不能够解决更为复杂的问题。而引入激活函数之后,常见的激活函数都是非线性的,因此也会给神经元引入非线性元素,使得神经网络可以逼近其他的任何非线性函数,这样可以使得神经网络应用到更多非线性模型中。
-
Sigmoid函数: f ( z ) = 1 1 + e − z f(z)=\frac{1}{1+e^{-z}} f(z)=1+e−z1 导数 f ( z ) ( 1 − f ( z ) ) f(z)(1-f(z)) f(z)(1−f(z))
下图是Sigmoid函数(左)及其导数的图像(右),求导过程:Sigmoid函数求导
-
值域为(0,1),相当于对每个神经元的输出进行了归一化,适合用于将预测概率作为输出的模型,且预测明确,预测值十分接近1/0。
-
导数最大值为0.25,很多输出接近 0 或 1 的神经元其梯度趋近于 0(饱和神经元)。因链式法则需要连乘,故进行反向传播时容易导致梯度消失。前边神经元的权重可能得不到更改。
-
导数计算是指数运算,计算成本高。
-
输出不以零为中心的,导致梯度下降的收敛速度变慢。关于原点对称的输入和中心对称的输出
-
Tanh函数: f ( x ) = e x − e − x e x + e − x f(x)=\frac{e^x-e^{-x}}{e^x+e^{-x}} f(x)=ex+e−xex−e−x 导数 f ′ ( x ) = 1 − f ( x ) 2 f'(x)=1-f(x)^2 f′(x)=1−f(x)2
-
解决了sigmoid函数输出不以零为中心的问题
-
导数范围在(0,1)之间,梯度消失问题有所缓解
-
在一般的二元分类问题中,tanh 函数用于隐藏层,而 sigmoid 函数用于输出层
-
ReLU函数: f ( x ) = m a x ( 0 , x ) f(x)=max(0,x) f(x)=max(0,x) 导数 1/0
- 当输入为正时,导数为1,一定程度上改善了梯度消失问题,加速梯度下降的收敛速度
- 没有指数运算,计算简单高效
- 被认为具有生物学合理性,比如单侧抑制(在输入是负值的情况下,它会输出0,那么神经元就不会被激活。这意味着同一时间只有部分神经元会被激活,从而使得网络很稀疏,对计算来说是非常有效率的)、宽兴奋边界(即兴奋程度可以非常高)
- Dead ReLU: 如果输入激活函数的值总是负的,那么反向传播过程经过该处的梯度恒为0,对应的权重和偏置参数此次无法得到更新。如果对于所有的样本输入,该激活函数的输入都是负的,那么该神经元再也无法学习,称为神经“死亡”。
- 输出不以零为中心的问题
-
Leaky ReLU函数: 用于解决ReLU神经元死亡的问题,LeakyReLU输入小于0的部分,值为负,且有微小的梯度α,α取值一般为0.01。
-
PReLU函数: 可以看作是Leaky ReLU的一个变体。在PReLU中,负值部分的斜率是根据数据来定的,而非预先定义的。
-
ELU函数: ELU(Exponential Linear Unit),函数定义及图像如下图:
总结: 通过上述的讨论可以看出,理想的激活函数应满足两个条件:1)输出的分布是零均值的,可以加快训练速度。2)激活函数是单侧饱和的,可以更好的收敛。
梯度爆炸 :梯度可能在更新过程中累积到很大,造成网络权重的大量更新,进而导致网络不稳定,模型损失在训练过程中变为NaN(训练过程中由于学习率等超参数设置的不合理,导致优化过程中没有减小loss,反而因为震荡导致loss逐渐增大,最终超过了float表示范围,出现NaN)
梯度消失 :梯度可能在更新过程中不断衰减直到接近0,导致神经元无法更新。
梯度爆炸/消失的可能原因 :1)隐藏层的层数过多;2)激活函数不合适;3)初始权重过大;4)使用不合适的学习率
解决梯度爆炸办法:
-
梯度裁剪(Gradient Clipping): 通过设定一个阈值来限制梯度的最大值,如果梯度超过了这个阈值,就将其缩放到阈值范围内。
-
权重初始化(Weight Initialization): 合理的权重初始化确保每一层的输出不会太大,避免了反向传播中梯度的放大效应。
-
使用合适的激活函数: ReLU 激活函数容易导致梯度爆炸,尤其是当输入值非常大时,ReLU 的导数保持为 1,导致梯度的快速传播,可使用 Leaky ReLU、ELU等激活函数,在输入较大时提供更好的梯度控制。
-
使用自适应优化器: 使用如 Adam、RMSprop 这样的自适应优化器,它们会根据梯度的大小动态调整学习率,从而防止在梯度过大时,更新的步伐过大。
解决梯度消失办法:
-
使用合适的激活函数: 如ReLU 和其变种在正区间的梯度恒定为 1,不会出现梯度过小的问题,因此能够有效避免梯度消失。
-
权重初始化(Weight Initialization): 合适的初始化方法可以确保梯度在传播过程中不会迅速衰减,从而防止梯度消失。
-
Batch Normalization(批量归一化): 通过对每一层输入进行标准化来加速训练,它对每一层的输入进行均值和方差归一化,使得每一层的输入分布保持稳定。
-
使用残差网络(ResNet): 通过引入跳跃连接将输入直接传递到下一层或跳过某些层,这样可以直接传递梯度,避免了梯度在深层网络中逐渐消失的问题。
-
调整学习率: 较小的学习率在一定情况下有助于训练过程的稳定性,特别是在处理梯度消失的问题时(但也会导致收敛速度变慢)
参考:详解激活函数(Sigmoid/Tanh/ReLU/Leaky ReLu等)
一文搞懂激活函数(Sigmoid/ReLU/LeakyReLU/PReLU/ELU)