网上对Relu激活函数都是一顿夸,最多的就是说,在深层网络中,能缓解梯度消失的情况,并且由于梯度求解非常容易等优点,被广泛使用。但是,神经网络的激活函数必须是非线性的,否则,无论怎么加深网络,也仅仅只是线性函数的组合而已,仍然是线性,这样根本提升不了网络的表达能力。
大部分资料对于Relu函数的非线性解释都是一句话,分段函数就是非线性。what?这还用你说?
好了,这里做一个比较详细的解释。
一、图像分析
首先,单看Relu函数的左边或者右边,确实是线性的,整体来看,也确实是分段函数,说它是非线性函数也勉强说得过去,但为什么应用到神经网络里面就成了非线性激活函数呢?
这里先对两个隐藏层全连接网络做一个解释。
如果我们的隐藏层输出都是Relu函数,那么在一次前向传播和一次反向传播过程中,他就像一个比较细长的,表达能力较弱的网络。
记住,这里的一次前向和反向,网络是“多分段线性”的。
下面我们做两个实验。
多个Relu函数执行叠加(stack)操作
多个Relu函数执行加法(add)操作
现在来分别看看函数图像:
叠加操作,表达式为: Relu(13Relu(10Relu(-2*x+1, 0) + 2, 0) -2 , 0)
加法操作,表达式为:
可以看到对于stack操作,你无论stack多少次,最终的函数图像都只能是一边是全零,一边是斜率为正或负的线性函数。
但是对于加法操作,可以很大程度上改变图像的样子,我这里做了四个add操作,函数图像就有点像二次函数了。当你add操作足够多,结合stack操作和bias(为了有负值),理论上是能拟合绝大部分在闭区间上的连续函数的。(事实上,Relu函数无法真正意义上拟合所有函数,但对于神经网络来说,已经够用了)
二、训练过程
到这里还只是从函数图像上分析了Relu确实可以通过add和stack的结合,达到丰富的非线性效果。但是,神经网络真的是在执行这样的操作吗?个人认为是的。
对于深度神经网络,在每个隐藏层添加Relu激活函数,一次前向传播过程中,层与层之间在做stack操作;两层之间,上一层经过Relu后,传入下一层,下一层的每个神经元里面含有了上一层的add操作。这样,stack和add操作相互交融,使得Relu有了非线性表达能力(多分段线性)
此外,神经网络基本都是以mini-batch的方式进行训练,针对于多次step来说,因为每个step训练的都是不同的“细小”的网络,某种程度上,也可以看成add操作,更加增强了非线性,并且还有了类似ensemble的效果。
怎么理解呢?其实我们每个step都是在训练一个细长的弱的,并且激活函数是“多分段线性”的神经网络。如果多个step,也可以类比于add操作,整体来看,Relu就成了非线性激活函数。
换一种说法,当我们训练的时候,是一步一步训练的,相当于是训练了很多个细长的弱的,并且激活函数是“多分段线性”的网络,但当训练好网络,使用的时候,我们其实是在使用一个“综合”的 网络。
这一点也就解答了另外一个问题,Relu激活函数不仅是非线性的、能缓解梯度消失;而且它还有防止过拟合的风险。因为我们相当于是在训练很多个“小的”网络,最终使用的是大的“综合”的网络,这和ensemble的思想如出一辙!