我们来了解下为什么神经网络需要激活函数?
首先从简单的例子开始着手,先考虑第一个问题,什么是线性可分类?比如说,我们有4个圆圈,其中两个圆圈是红色,另外两个圆圈是黑色这样的布局是非常容易使用一条线来进行划分的,但是在现实中,往往存在非常复杂的线性不可分的情况,比如现在有一个二分类问题,就是说,在这个平面里,找不到一条直线可以将图中的绿色圆点和红色圆点完全分开。
在所有的隐藏层之间添加一个激活函数,这里的激活函数我们使用的是Sigmoid函数(稍后篇章中,我们会详细介绍几个常见的激活函数)。
这样输出的就是一个非线性函数了,有了这样的非线性激活函数以后,神经网络的表达能力更加强大了。
这样能够解决我们一开始提出的线性不可分问题。
一般情况下不会考虑在隐藏层与输出层之间使用激活函数(分类问题除外,如果面对的是二分类的问题,则可以考虑使用Sigmoid函数作为隐藏层和输出层之间的激活函数;如果面对的是多分类的问题,则可以考虑使用Softmax作为隐藏层和输出层之间的激活函数)。
另外,我们再来思考一个问题,如果使用线性函数作为激活函数(通过增加隐藏层的层数,然后使用线性函数作为激活函数),那么是否可以达到非线性函数的效果,以此来解决线性不可分的问题?
答案肯定是不可以的,不管如何加深层数总会存在与之等效的“无隐藏层的神经网络”,这里我们考虑将线性函数f(x)=w1*x作为激活函数(为了方便说明问题这里省略了bias),然后我们使用三层隐藏层,最后对应的结果就是f(x)=w3*(w2*(w1*x))),稍加整理就是f(x)=w1*w2*w3*x,这依然是一个线性函数。
如果在三维空间里,则会变成一个超平面。因此激活函数必须使用非线性函数。 在了解了激活函数的作用之后,我们来介绍一些比较常用的激活函数,对于不常用的激活函数,本书就不讨论了。
1.Sigmoid函数
Sigmoid非线性激活函数,e是纳皮尔常数,其值为2.7182…,。当x为0的时候,Sigmoid函数值为0.5,随着x的不断增大,对应的Sigmoid值将无线逼近于1;而随着x的不断的减小,Sigmoid值将不断逼近于0。所以它的值域是在(0,1)之间。
Sigmoid函数之前曾被大量使用,但是近几年使用Sigmoid函数的人已经越来越少了,其主要原因是sigmoid函数会造成梯度消失;Sigmoid函数有一个非常不好的特点就是,其在靠近0和1这两端的时候,因为曲线变得非常的平缓,所以梯度几乎变为了0,我们在之前的篇章里曾提到过 使用梯度下降法来更新参数(权重),因此如果梯度接近于0,那就几乎没有任何信息来更新了,这样会造成模型不收敛。
另外,如果使用Sigmoid函数,那么在初始化权重的时候也必须非常小心;如果初始化的时候权重太大,那么激活会导致大多数神经元变得饱和,从而没有办法更新参数了。 Python实现Sigmoid函数的代码如下:
import numpy as np
def _sigmoid(x):
return 1 / (1 + np.exp(-x))
2.Tanh函数
Tanh是双曲正切函数 ,Tanh函数和Sigmoid函数的曲线是比较相近的。相同的是,这两个函数在输入很大或是很小的时候,输出都几乎是平滑的,当梯度很小时,将不利于权重更新;
不同之处在于输出区间,tanh的输出区间是在(-1,1)之间,而且整个函数是以0为中心的,这个特点比Sigmoid要好。
3.ReLU函数
线性整流函数(Rectified Linear Unit,ReLU),又称为修正性线性单元,ReLU是一个分段函数,其公式为f(x)=max(0,x)。
ReLU函数 ,大于0的数将直接输出,小于0的数则输 出为0,在0这个地方虽然不连续,但其也同样适合做激活函数。
ReLU是目前应用较为广泛的激活函数,其优点为在随机梯度下降的训练中收敛很快,在输入为正数的时候,不存在梯度饱和问题,ReLU函数只有线性关系,不管是前向传播还是反向传播都比Sigmoid函数要快很多(Sigmoid要计算指数,计算速度会比较慢)。
1 Python实现ReLU函数的代码如下:
import numpy as np
def _relu(x):
return np.maximum(0,x)
网友评论