激活函数在神经网络中是非常重要的。没有激活函数,神经网络跟普通的多项式运算没什么不同,无论你神经网络有多少层,输出都是输入的线性组合,都是线性计算的。引入激活函数就是为了引入非线性,强化网络的学习能力,就相当于给了它更多的选择,更多的可能性,更多的变化。
下面逐一介绍各种激活函数的特点。
sigmoid
公式:
导数:
它的公式我们已经非常熟悉,取值范围在(0,1),代入它的导数,可知导数的范围是(0,0.25)。这样的导数取值范围非常不好,为什么呢?因为由于神经网络反向传播的“链式传播效果”,会出现梯度消失的情况。我们来看看下面这个图。
此外,因为sigmod的均值为0.5而不是0,它会改变数据的原始分布。什么意思呢?就是假设原始数据是0均值的,经过一层激活函数为sigmod的神经网络后,输出数据分布均值就为0.5了,随着网络的加深,数据分布会面目全非,这不利于学习,就像你一直学蛙泳的话很快就能学会,但是一开始就让你学花式泳,会让你不知所措一样。
tanh
公式:导数:tanh(双曲正切函数)跟sigmod十分相似,只是:
1.对sigmod做了向下平移,使本来均值0.5变为0. 解决了sigmod函数zero-centered的问题。
2.对sigmod做了拉伸,使其导数的变化也更激烈,导数取值范围为(0,1)。可以看到虽然导数取值范围更大了,但仍然有可能导致梯度消失。
Relu
公式:
导数:
可以看到:
1.在relu<0时,输出为0,导数也为0,也就是说这个样本对神经网络不起作用,是“死”的。在训练过程中,第一轮可能有很多样本经过relu都是“死”的,但是神经网络能从“活”的样本中学习到东西,从而更新了神经网络的权重,神经网络变得更加了解这个样本集。那么第二轮的时候会有更多的“活”样本,“死”样本就会少了些,如此迭代,最后仍然是“死”的样本大概率也是没用的样本,该学习的学习完了,不该学习的咱们就丢了它。这相当于起了过滤噪音的作用。
当然,有可能有用的样本也被过滤了,所以我们要把学习率设置小一点,因为一旦权值更新过头了,就很多有用的样本被误判为“死”样本了。
2.在relu>0时,导数为1,在反向传播中梯度不会消失,梯度消失问题得以解决。但是会出现梯度爆炸的现象,因为这时梯度的强度完全取决于多个权值的累乘,如果这些都很大,那么最后梯度会非常大,神经网络权值更新会非常离谱。
怎么解决呢?两个办法:1.控制的值,使其不要太大。2.控制的值,使其不要太大,这就是所谓的“梯度裁剪”。(附上我的文章(Tensorflow 梯度裁剪--防止梯度爆炸))
Leaky Relu
Leaky Relu是Relu的变种,就是将z<0部分设为一个很小的梯度,而不是0。这是因为不想让太多样本“死亡”,因为你知道你的这些样本其实都是有用的,没那么多噪音,所以还是可以用于学习的。那就设一个较小的梯度吧~
PRelu
将z<0部分设为一个可以学习的参数,使其在训练过程中进行更新,也就是说让这个“过滤器”也有智慧,不要那么死板。
RReLU
也是Relu的变种。将z<0部分设为一个在均匀分布U(a,b)中随机抽取的值。而不是固定为一个很小的值。使“过滤器”更加没那么绝对。
CRelu
CRelu是用于图像的激活函数,也是Relu的变体。就是有人发现多层的卷积网络中,网络的前部的卷积核的参数有较强的负相关性,就是比如第一层卷积网络的两个卷积核,对应的参数是互为相反数,这个是-1,那个是1。也就是说,网络的前部倾向于同时捕获正负相位的信息,但ReLU会抹掉负响应。 这造成了一部分卷积核没有起到作用。所以就有了CRelu。
CReLU的定义很简单:CReLU(x)=[ReLU(x),ReLU(−x)]。就是两边的信息都考虑。
Selu
上面不是说均值非0的激活函数会改变原始数据的分布。以上的各种Relu明显是会有这个问题的。Selu就是为了解决这个问题。
α = 1.6732632423543772848170429916717
λ = 1.0507009873554804934193349852946
这样设定就使z<0部分不存在死区,但也不会无限增大,它存在饱和区,负无穷时, 趋于两个参数的负乘积 - αλ。
这样的话,假设z的分布均值为0,方差为1,使用Selu后,输入的分布均值仍然会为0,方差仍然会为1。这里就不证明了,有兴趣的读者可以参考论文https://arxiv.org/abs/1706.02515
最后附上代码:Tensorflow 实现各种激活函数
对你有帮助的话点个赞呗,谢谢。