最全的激活函数详解

博客已迁至知乎,本文链接:https://zhuanlan.zhihu.com/p/70821070

前言

这篇文章首先讲了神经网络中为什么要引入激活函数,以及一个激活函数应该具有哪些性质。最后详细地对比了几种常见的激活函数的优缺点,其中重点讲了sigmoid函数的非0均值问题和ReLU函数的Dead ReLU问题。


神经元

图片来自:https://zhuanlan.zhihu.com/p/25110450

上图是一个神经元的设计,其传输模式类似于人类大脑神经元之间的信息传递。在一个神经元中,突触(synapse)接受其它神经元的轴突(axon)传来的信息,通过轴突将信息传递出去。

在这里,所有xix_i是其它神经元的轴突传来的信息,所有wiw_i 是突触接收信息的程度,所有wixiw_ix_i则是其它神经元轴突上传来的信息。这些信息经由神经元整合后,z=wixi+bz=\sum w_ix_i+b,再由激活函数f(z)f(z)激活。

在这里,整合的过程是线性加权的过程,各输入特征xix_i之间没有相互作用。而激活函数都是非线性的,各输入特征xix_i在此处相互作用


在神经网络中,为什么要引入激活函数呢?

简而言之,只有线性的模型表达能力不够,不能拟合非线性函数,激活函数(Activation Function)是非线性的,只要给予网络足够的隐藏单元,线性+激活函数可以无限逼近任意函数(万能近似定理)。

万能近似定理:Hornik et al. 1989; Cybenko, 1989

加与不加的区别:
线性函数 f(x)=Wx+bf(x)= Wx+b 之后添加激活函数g(a)g(a),变成
a(x)=g(f(x))=g(Wx+b)a(x)=g(f(x))=g(Wx+b)

神经网络一般都是多层的,所以拿出前三层(包括输入层)来看:有
a2(x)=g2(f2(g1(f1(x)))a_2(x) = g_2(f_2(g_1(f_1(x)))

而如果不加激活函数,这三层是这样的:
y(x)=f2(f1(x))y(x)=f_2(f_1(x))

f(x)f(x)带入上一个表达式:
y(x)=f2(f1(x))=W2(W1x+b1)+b2=W2W1x+(W2b1+b2)y(x)=f_2(f_1(x))=W_2(W_1x+b_1)+b_2=W_2W_1x+(W_2b_1+b_2)

可以看出来网络还是线性的,还是没有拟合非线性函数的能力,而且不管网络有几层都还是相当於单层线性网络。


一个激活函数应该是什么样子的?

  1. 非线性:这是必须的,也是添加激活函数的原因。
  2. 几乎处处可微:反向传播中,损失函数要对参数求偏导,如果激活函数不可微,那就无法使用梯度下降方法更新参数了。(ReLU只在零点不可微,但是梯度下降几乎不可能收敛到梯度为0)
  3. 计算简单:神经元(units)越多,激活函数计算的次数就越多,复杂的激活函数会降低训练速度。
  4. 非饱和性:饱和指在某些区间梯度接近于零,使参数无法更新。Sigmoid和tanh都有这个问题,而ReLU就没有,所以普遍效果更好。
  5. 有限的值域:这样可以使网络更稳定,即使有很大的输入,激活函数的输出也不会太大。

几种常见的激活函数

Sigmoid

图片来自:https://zhuanlan.zhihu.com/p/25110450

Sigmoid函数公式:
f(x)=11+exf(x)=\frac{1}{1+e^{-x}}

Sigmoid函数将输入的值映射到0~1之间,输入数值 (有正有负,正数>负数) 越小越接近0,数值越大越接近1。Sigmoid激活函数之所以流行过一段时间是因为它能够表达“激活”的意思,0为未激活,1为激活。
但由于以下三个缺点,现在Sigmoid已经不常用了。

1. Sigmoid容易饱和
输入太大或太小都会使其梯度接近0,这点从图像就能看出来,在反向传播中梯度接近0时参数就会难以更新。另外还需要将参数初始化得比较小才能避免刚开始就梯度为0。

2. Sigmoid的输出不是0均值的
比如激活函数:(式中xx是上层神经元的输出,也是这层神经元的输入)
f(x,w,b)=f(wixi+b)f(x,w,b)=f(\sum w_ix_i+b)

训练过程中通过反向传播学习参数,即通过链式法则,求损失函数L(x)L(x)对某一参数wiw_i的偏导数(梯度),通过以下式子更新参数wiw_i:(其中η\eta是学习率)
wiwiηLwiw_i \gets w_i - \eta\cdot\frac{\partial L}{\partial w_i}
L(x)L(x)wiw_i求偏导:
Lwi=Lffwi=Lfxif(1f)\frac{\partial L}{\partial w_i} = \frac{\partial L}{\partial f}\frac{\partial f}{\partial w_i}=\frac{\partial L}{\partial f}\cdot x_i\cdot f(1-f)

参数更新方向:
因为此处的ffsimgoidsimgoid函数,值域为(0, 1),所以f(1f)f(1-f)恒大于0,又因为Lf\frac{\partial L}{\partial f}对所有wiw_i是常数,所以wiw_i更新的方向完全由xix_i的符号决定,xix_i是上层Sigmoid激活函数的输出,即xi>0x_i>0,所有xix_i的符号是一样的,所以所有参数wiw_i的更新方向只能一致。
举个例子:如果向最优解优化,参数w1w_1需要变小,而w2w_2需要变大,而每次梯度下降w1w_1w2w_2只能向一个方向更新,只能一起变大或一起变小,这样模型收敛就需要消耗很多的时间。
而如果所有xix_i是零均值的,有正有负的,就不会出现上面的问题了。

3.幂运算相对比较耗时:这个不算太大的问题

tanh

函数公式:
f(x)=exexex+exf(x)=\frac{e^x-e^{-x}}{e^x+e^{-x}}

图片来自:https://zhuanlan.zhihu.com/p/25110450

tanh激活函数的性质几乎和Sigmoid一样,主要解决了Sigmoid的输出非0均值问题,模型收敛更快,但还是存在梯度消失的问题。另外Sigmoid的这个输出0~1的性质可以使它的输出作为概率使用。

ReLU

ReLU,线性整流函数(Rectified Linear Unit),又称修正线性单元。
函数公式:
f(x)=max(0,x)f(x)=max(0,x)

图片来自:https://zhuanlan.zhihu.com/p/25110450

Relu是近几年最常用且很有效的激活函数,虽然也有缺陷但还是推荐优先使用。
优点:
1.解决了梯度消失问题(正区间)
2.计算速度快,只需要判断正负
3.收敛速度比Sigmoid和tanh快很多
缺点:
1.输出不是0均值的
2.Dead ReLU Problem:一些神经元可能永远不能被激活,导致相应参数不能更新。下面分析一下这个问题的原因:

首先我们把ww参数的更新公式写出来:式中η\eta是学习率
wiwiηLwiw_i \gets w_i - \eta\cdot\frac{\partial L}{\partial w_i}

损失函数对wiw_i求导(激活函数为ReLU):式中xix_i是上层神经元的输出(上层激活函数的输出)
Lwi=Lffwi=Lfxi\frac{\partial L}{\partial w_i} = \frac{\partial L}{\partial f}\frac{\partial f}{\partial w_i}=\frac{\partial L}{\partial f}\cdot x_i

将两个式子合并:
wiwiηLfxiw_i \gets w_i - \eta\cdot \frac{\partial L}{\partial f}\cdot x_i

因为xix_i是上层各个神经元的输出,即上层每个神经元的激活函数的输出,可知其值一定为0或者正数,为方便说明现在假设xix_i都为正数。看上式,现在xix_i为正数,学习率η\eta肯定也是正数,若损失函数对激活函数的导数Lf\frac{\partial L}{\partial f}也是正数且足够大,并假设学习率η\eta也不小,那么很多wiw_i更新这一次后就变成了负数,这会造成什么影响呢?看该层网络的下次前向传播公式:
a=f(x,w,b)=ReLU(wixi+b)a=f(x,w,b)=ReLU(\sum w_ix_i+b)

其中aa是这个神经元的输出,下层网络的输入。由上面假设,所有xix_i都为正数,多数wiw_i为负数,那么:wixi+b\sum w_ix_i+b很大概率是个负数,由ReLU图像可知,输入为负数,输出就为0,即a=ReLU()=0a=ReLU(负数)=0
由前向传播公式可以看出,若神经元的输出为0,那么该神经元的前向传播在该层与下层网络之间就断开了,从而反向传播也就断了。

造成Dead ReLU Problem问题的主要原因可能为:
1.学习率η\eta太大导致参数更新幅度太大
2.糟糕的权重初始化

为了解决成Dead ReLU Problem问题,又有了Leaky ReLU函数和ELU (Exponential Linear Units) 函数。

Leaky ReLU

函数公式:
f(x)=max(0.01x,x)f(x)=max(0.01x,x)

图片来自:https://zhuanlan.zhihu.com/p/25110450

前半段是0.01x而不是0,解决了Dead ReLU Problem问题。
还有一种想法是通过反向传播训练这个前半段函数:f(x)=max(αx,x)f(x)=max(\alpha x,x),其中α\alpha可以训练。
虽然这两种函数理论上比ReLU好,但是实践中并没有完全证明优于ReLU。

ELU (Exponential Linear Units)

函数公式:
f(x)={x,                          x>0α(ex1),x<=0f(x)=\begin{cases} x,\;\;\;\;\;\;\;\;\;\;\;\;\; x>0 \\ \alpha (e^x-1), x<=0\end{cases}

图片来自:https://zhuanlan.zhihu.com/p/25110450

虽然也解决了Dead ReLU Problem,并且输出接近0均值,但是也没有在实践中完全证明优于ReLU。


总结

Sigmoid可以当作概率输出使用,但不建议当作中层激活函数。推荐使用ReLU,需要注意学习率的设置,ReLU变种可以尝试。


references

[1] 深度学习(Deep Learning) Yoshua Bengio & Ian Goodfellow
[2] 神经网络中激活函数的真正意义?一个激活函数需要具有哪些必要的属性?还有哪些属性是好的属性但不必要的?
[3]【机器学习】神经网络-激活函数-面面观(Activation Function)
[4] 谈谈激活函数以零为中心的问题
[5] ‘Dead ReLU Problem’ 产生的原因

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章