1 引言
作为一个学通信的人来说,对激活函数的启蒙恐怕要从《信号与系统》中的阶跃函数谈起,阶跃信号作为一种特殊的时间函数,是一个从0跳变为1的过程。在电路分析中,阶跃函数是研究动态响应电路的基础,利用阶跃函数可以进行信号处理、积分变换。
在信号处理中,可以通过阶跃信号及其时延信号的线性组合进行复杂信号的表达。由于阶跃函数将小于0的信号输入置为0,大于零的信号输入置为1,其本质也是一个非线性的变换,神经网络的鼻祖感知机就是运用阶跃函数作为其激活函数来进行模式分类。再进一步,如果将输入信号通过级联的方式通过多个阶跃函数就构成了多层感知机模型,也就是我们所熟悉的深度神经网络的雏形。
2 为什么需要激活函数(激活层)?
这个在很多博客中都有介绍,首先深度学习想要学习到的函数不是简单的线性关系,而是复杂的非线性关系,需要有非线性变换,而深度神经网络中的卷积层和池化层都是线性变换(乘的是权重矩阵,矩阵的几何意义就是线性变换,无论经过多少卷积层都是线性的),因此要给深度学习增加非线性的话,就需要非线性层,就是我们所说的激活层。
3 理想激活函数
很多博客,上来就是介绍几种激活函数,还有他们的优缺点,没有从一个更高的视角来审视激活函数本质。我也是看了CS231n上的解释才彻底明白不同激活函数所遵从的设计思想,明白了设计思想就能对不同激活函数进行分析,同时也可以根据自己的任务特点选用甚至是设计自己的激活函数。本文从以下两个方面介绍激活函数:什么样的函数可以做激活函数、什么样的函数是好的激活函数。
3.1 什么样的函数可以做激活函数?
- 有界、单增且连续
前面已经说过,激活函数是为了增加深度学习的非线性,因此激活函数必须要是非线性函数。训练深度神经网络目的就是找到一个复合函数,有足够的建模能力。实践证明,其实只要激活函数选择得好,神经元足够多,包含一个隐层的3层神经网络就可以实现对输入信号到输出信号映射关系的逼近,这符合万能逼近定理。对于万能逼近定理,其要求函数必须是非常数、有界、单调递增并且连续。
- 几乎处处可导
然而只满足有界、单增且连续可不行,由于在神经网络中往往使用BP算法进行参数更新,因此激活函数又必须是可导的。理论和工程实现总是需要相互权衡,在实际应用中,往往只需要要求激活函数“几乎处处可导”就可以了,比如常用的ReLU函数在零点处就不可导。
3.2 什么样的函数是好的激活函数?
- 零对称性
我们都知道,tanh激活函数是以0为中心的中心对称函数,sigmoid函数是以0.5为中心的中心对称函数。因此tanh在后来取代了sigmoid函数。那么为什么零对称要更好呢?可以参考谈谈激活函数以零为中心的问题(https://liam.page/2018/04/17/zero-centered-active-function/),主要原因是非零中心的函数sigmoid函数输出总为正值,即所有维度的输出都为正值,所有梯度的更新方向总是向正或者向负,导致梯度更新的Z字走向,更新缓慢。
从反面看,这也是为什么我们期望每层的输入的信号都是零对称的原因,从而有了批归一化层的提出。(题外话)
- 无饱和区域
BP算法计算误差项时每一层都要乘以激活函数的导数。如果激活函数导数的绝对值小于1,那么多次连乘后误差项就会很快衰减到0,从而导致权重没有得到有效更新,这就是所谓的梯度消失。
对于sigmoid和tanh激活函数而言,都存在左右饱和区,从而有梯度消失的问题。- 梯度计算高效
对于深度学习,训练速度一直是个痛点。因此设计梯度计算高效的激活函数对训练速度的提升有较大的帮助。对于sigmoid和tanh函数而言,它们的梯度计算需要涉及指数运算,计算复杂度高,相反ReLU函数就相当简单。
4 常见激活函数优缺点
我们如果从上文的零对称、非饱和区域和梯度计算高效三个特性来看常见的激活函数,就比较容易理解激活函数的发展史。
- sigmoid
缺点:非零对称、有饱和区(容易梯度消失)、梯度计算复杂度高
- tanh
优点:零对称
缺点:有饱和区(容易梯度消失)、梯度计算复杂度高
- ReLU
优点:右半轴无饱和区(不会梯度消失)、梯度计算高效(收敛快)
缺点:非零对称、负半轴永远不会被激活(权重初始化不好会导致某些神经元dead)
- Leaky ReLU
优点:不会饱和(两边都不会)、梯度计算高效(收敛快)、不会出现dead神经元
5 激活函数使用建议
- 使用ReLu,设定合适的学习率
- 尝试Leaky ReLU
- 尝试tanh,但不期待它
- 不使用sigmoid