在笔试问答题或面试中偶尔有涉及到激活函数的问题,这里简单总结一下深度学习中常见的三种激活函数sigmoid、tanh和ReLU,以及它们各自的特点和用途。
激活函数的主要作用是在神经网络中引入非线性因素。
对于sigmoid函数而言,其输出始终为正,这会导致在深度网络训练中模型的收敛速度变慢,因为在反向传播链式求导过程中,权重更新的效率会降低(具体推导可以参考这篇文章)。
**详解:**sigmoid由于输出始终为正,根据反向传播求导公式可以看出多个权重的更新方向一致,比如在只有两个权重的情况下,二者的更新方向一致,也就是只能在第一象限和第三象限运动,优化路径将会出现zigzag现象,导致收敛速度慢。(上述链接中的公式和图完全正确,认真理解即可,重点注意 a 1 a_1 a1是 w 1 w_1 w1的输出,恒大于0。看反向传播公式,可以看出和sigmoid导数>0无关,而是他输出恒>0导致的)
此外,sigmoid函数的输出均大于0,作为下层神经元的输入会导致下层输入不是0均值的,随着网络的加深可能会使得原始数据的分布发生改变。而在深度学习的网络训练中,经常需要将数据处理成零均值分布的情况,以提高收敛效率,因此tanh函数更加符合这个要求。
sigmoid函数的输出在[0,1]之间,比较适合用于二分类问题。
详细分析可以参考这篇文章。下面简单用自己的话总结一下:
RNN中将tanh函数作为激活函数本身就存在梯度消失的问题,而ReLU本就是为了克服梯度消失问题而生的,那为什么不能直接(注意:这里说的是直接替代,事实上通过截断优化ReLU仍可以在RNN中取得很好的表现)用ReLU来代替RNN中的tanh来作为激活函数呢?这是因为ReLU的导数只能为0或1,而导数为1的时候在RNN中很容易造成梯度爆炸问题。
**为什么会出现梯度爆炸的问题呢?**因为在RNN中,每个神经元在不同的时刻都共享一个参数W(这点与CNN不同,CNN中每一层都使用独立的参数 W i W_i Wi),因此在前向和反向传播中,每个神经元的输出都会作为下一个时刻本神经元的输入,从某种意义上来讲相当于对其参数矩阵W作了连乘,如果W中有其中一个特征值大于1,则多次累乘之后的结果将非常大,自然就产生了梯度爆炸的问题。
**那为什么ReLU在CNN中不存在连乘的梯度爆炸问题呢?**因为在CNN中,每一层都有不同的参数 W i W_i Wi,有的特征值大于1,有的小于1,在某种意义上可以理解为抵消了梯度爆炸的可能。
为什么ReLU会出现神经元死亡的问题
当学习率比较大,而且梯度也很大时,会导致权重更新太多,有可能出现对于所有的训练样本,该神经元输出都<0,那么该神经元的权值就不会再更新了。
比如:
z = W x + 1 , W = 3 z=Wx+1,W=3 z=Wx+1,W=3
如果此时更新步长太大比如 Δ W = − 100 \Delta W=-100 ΔW=−100,那么 z = − 97 x + 1 z=-97x+1 z=−97x+1,那么就很有可能对于所有的训练集z的输出都是小于0的,那么就不会再更新了。
注意:上面输出都小于0的前提是x>0,如果x<0的时候z就变成正值,也就可以更新了。但实际上,经过训练,某一个神经元的输入基本上趋于一致,很少发生忽正忽负的情况,所以如果一个输入的输入为负且很小,那么其他的输入的输入也很难出现大于0的输出。(个人理解)
解决方法
①采用Leaky ReLU等激活函数
使其在该神经元的输出为负时,仍然可以对该神经元进行梯度更新
②设置较小的学习率进行训练
尽可能避免因为梯度过大更新导致对于神经元的所有输入的输入都小于0
③使用momentum优化算法动态调整学习率
有一个假设前提:对于正常的数据,他的更新方向都是比较正常的,而对于造成神经元死亡的异常数据,他的更新方向相比历史的更新方法差异很大,因此使用momentum优化算法,可以抑制这次异常的更新梯度,避免神经元死亡。
在训练过程突然出现神经元输出为负,没有梯度时,可以依据过去的更新趋势对神经元更新,因此就有概率可以解决输入恒为负的情况(个人理解,悖论:本来就是因为上一次的更新导致的神经元死亡,继续按照以往的方向更新,不就加剧死亡了吗?)
参考链接:深度学习中,使用relu存在梯度过大导致神经元“死亡”,怎么理解?
可以用一个近似函数来逼急这个swish,让swish变得硬(hard)。作者选择的是基于ReLU6,作者认为几乎所有的软件和硬件框架上都可以使用ReLU6的优化实现。其次,它能在特定模式下消除了由于近似sigmoid的不同实现而带来的潜在的数值精度损失。
下图是Sigmoid和swish的hard、soft形式:
我们可以简单的认为,hard形式是soft形式的低精度化。作者认为swish的表现和其他非线性相比,能够将过滤器的数量减少到16个的同时保持与使用ReLU或swish的32个过滤器相同的精度,这节省了3毫秒的时间和1000万MAdds的计算量。
也就是h形式提高了运算速率
β是个常数或可训练的参数,Swish 具备无上界有下界、平滑、非单调的特性。
Mish激活函数的表达式为
M i s h = x ∗ t a n h ( l n ( 1 + e x ) ) Mish = x*tanh(ln(1+e^x)) Mish=x∗tanh(ln(1+ex))
使用matplotlib画图可得
从图中可以看出他在负值的时候并不是完全截断,而是允许比较小的负梯度流入,从而保证信息流动。
并且激活函数无边界这个特点,让他避免了饱和这一问题。比如sigmoid,tanh激活函数通常存在梯度饱和问题,在两边极限情况下,梯度趋近于0,而Mish激活函数则巧妙的避开了这一点。
另外Mish函数也保证了每一点的平滑,从而使得梯度下降效果比Relu要好
原文链接:https://blog.csdn.net/weixin_44106928/article/details/103042287
在YOLOv4中使用Mish函数的原因是它的低成本和它的平滑、非单调、上无界、有下界等特点,与其它常用函数如ReLU、Swish相比,提高了它的性能。
Mish的性能如下:
无上界,有下界:无上界是任何激活函数都需要的特性,因为它避免了导致训练速度急剧下降的梯度饱和。因此,加快训练过程。有下界属性属性有助于实现强正则化效果(适当的拟合模型)。(Mish的这个性质类似于ReLU和Swish的性质,其范围是 [≈0.31,∞) )。
非单调函数:这种性质有助于保持小的负值,从而稳定网络梯度流。大多数常用的激活函数,如ReLU,Leaky ReLU,由于其差分为0,不能保持负值,因此大多数神经元没有得到更新。
允许小的负输入产生负输出,非单调性增加了表现力并改善了梯度流。
改善梯度流的原因:输入较小的负input(绝对值大)时可以放大输出,而输入较大的负input(绝对值小)时可以把输出变小。该激活可以保证输入是较小的负数时梯度较小,而输入是较大负数是梯度较大,从而保证整体的回传梯度保证稳定。无穷连续性和光滑性:Mish是光滑函数,具有较好的泛化能力和结果的有效优化能力,可以提高结果的质量。
相比ReLU在0处不光滑,他的光滑特性,使其在求解和模型泛化方面效果更好。因为不平滑会影响模型的收敛速度。计算量较大,但是效果好:与ReLU相比,它的计算量比较大,但在深度神经网络中显示了比ReLU更好的结果。
自门控:此属性受到Swish函数的启发,其中标量输入被共给gate。它优于像ReLU这样的点式激活函数,后者只接受单个标量输入,而不需要更改网络参数。
Mish比Swish好的原因没有说,只是用实验证明了而已,二者性质一样。