**函数(Sigmoid, tanh, Relu)

重新看了一下,发现写的时候思绪乱了也没有检查。现在重新更改,特别是输出不以零为中心(non-zero center)的问题。


按照进程这章总结的是**函数(Activation Function)。其实这节CS231n讲的就很细了,但是!!!我感觉困惑还是有的。我沿着它的步骤慢慢来讲。

Sigmoid

**函数(Sigmoid, tanh, Relu)
来自CS231n

Sigmoid的函数和导数为:

σ(x)=11+exσ(x)=σ(x)(1σ(x))

CS231n说它有两个优点,一个是可以将输入缩放到(0, 1)这个范围,另外一个是符合神经学的放电率,也是因为数值在0~1之间。

但是缺点却是致命的。

第一是,我们可以看到它在最左或者最右的时候,曲线几乎是平缓的,这意味着这里的导数趋近于0。那么按照我们之前权重更新的说法,假设L为我们的Loss函数,f=σ(wixi+bi)v=wixi+bi,有:

wi=wiαLwiLwi=Lffvvwifv0wiwi

这样会导致权重根本没有更新到。

第二它不是non-zero center,即不对原点对称。这个我也是看了很多回答才能够理解的。按照上面的说法,我们有:

fwi=xiσ(v)(1σ(v))wi=wiαxiσ(v)(1σ(v))Lf

在权重的更新过程中,σ(v)(1σ(v))是一个常数,因为输出是介于(0,1)之间。学习率\alpha也是一个常数。也就是说wi变化的方向其实是由xiLf决定的。

假设xi>0(其实如果前一层的**函数是sigmoid,那你这一层的输入也肯定为正)那么试举例子:

L=fyLf=1>0

或者one-hot格式分类,有
L=ln(f)Lf=1f<0(f>0)

所以wi总体变化的方向就被L函数的形式限定下来了。也就是说,随着Loss函数的形式改变了,wi变化的方向也会跟着改变。但我们可以确定的是,它的变化趋势是整体的。如果我们得到一个理想权重需要的是部分wi降低,部分wi上升,会有:

**函数(Sigmoid, tanh, Relu)
来自CS231n

右边的Zig zag path就是会出现的问题。我们只可能先全部变大,然后再全部变小,所以权重更新的路径就是红色的阶梯型而不能像蓝色的直线那样下降。举个二维的例子:

例子来自:https://liam0205.me/2018/04/17/zero-centered-active-function/
f(xw+b)=f(w0x0+w1x1+b)

现在假设,参数 w0 , w1 的最优解 w0 , w1 满足条件

{w0<w0,w1w1.

这也就是说,我们希望 w0 适当增大,但希望 w1 适当减小。考虑到Sigmoid函数的求导形式,这就必然要求 x0x1 符号相反——这又跟Sigmoid函数相矛盾了。

第三个缺点是,它的函数形式包括e的指数幂,计算比较麻烦。当然,这个比起前两个来不算什么大麻烦。

Tanh

**函数(Sigmoid, tanh, Relu)
来自:CS231n

很明显看出来它就是为了克服Sigmoid的不对原点对称的坏毛病。可惜的是它在两边还是有梯度饱和(也就是梯度趋近于0)的问题。

还需要提的一点是,它的函数形式为:

tanh(x)=exexex+ex

可以看出来它计算的形式更复杂了,这也是它不好的地方。

Relu

**函数(Sigmoid, tanh, Relu)

斯坦福课程很赞赏这个函数。认为Relu函数在左边是抑制的,右边是打开的(即有梯度),很符合人的神经节运作方式。而且Relu的函数形式是:

max(0,x)

计算形式非常简单,而且在实验中它拟合的速度也是很快,声称比sigmoid/tanh快6倍。

但我们也可以看到,它在左边的平缓的部分也是梯度饱和的状态。课程上面提到了一个Dead Relu的现象。我查了很多资料,知乎没有人提及,网上的资料也很少,大部分只是说现象。

所谓的Dead Relu意思是无论什么输入都不会打开(也就是一直在左边梯度为0的情况),也就是权重不会更新。

还是假设Loss=fy, f=Relu(wixi+bi)=max(wixi+bi),那可以算出:

Lwi=Lffwifwi={xi,f>00,f0

(33)Lwi={xi,f>00,f0

就是说,一旦你的f不管输入是什么样都小于0的话,那么权重是不会再更新的,因为返回的梯度永远都是0。这个时候我们称这个Relu已经死了。

看完上面,接下来是我的理解。斯坦福课程也说Dead Relu(死亡的Relu听起来太奇怪了),是在反向传播中,对于任何输入都是返回0的梯度,并且无法复活!查了许多,Dead Relu还是有可能复活的。重点是,我认为课程上面认为的任何输入其实就是Data Cloud,就是全部数据集,因为我想了很久,都不觉得f在什么时候能对所有的输入都能小于0,因为xi可正可负。

**函数(Sigmoid, tanh, Relu)
来自:CS231n

那么一共有两种原因很有可能导致Dead Relu太多。

第一个,权重初始化不对。其实在讲全连接层解决MNIST我把w全部初始化成0是很不对的,一般我们都会以高斯分布来给它初值。就像这个讲的Relu,一旦你权重都为0,那么永远返回的梯度都为0。一般现在的权重初始化是用Xavier。

第二个,学习率太大。虽然我们讲xi可以为负,但Relu你仔细看,它也是non-zero center,这就很尴尬了,因为它的输出也都是大于0的。所以一旦你更新的太多,也就是学习率很大,那么就会有有一个很大的梯度(也就是f很大)传过去,所有的权重wi都小了太多,甚至有可能都是小于0的,那么输入也都是为正,就会一直导致f<0,权重无法更新。

参考链接最后两个都是关于这方面的,我不保证我的理解不出错

Leaky Relu

竟然有毛病了,肯定就有方法。后面有很多种Relu的变体,Leaky Relu也就是最典型的一个了。

**函数(Sigmoid, tanh, Relu)
来自:CS231n

函数形式改变了一点,这可以让左边部分也有了梯度,自然也不会产生Dead Relu。0.01是可以自己更改的,不过我也没改过就是了。

**函数(Sigmoid, tanh, Relu)
来自:CS231n

还有很多种变体,用到再说吧。

Maxout

**函数(Sigmoid, tanh, Relu)
来自:CS231n

其实也来自于Relu的变体,最大的区别是它使用了两个权重。这个还是GAN的作者Goodfellow提出的。

虽然添加了一个权重导致计算变得更复杂了,但是也克服了很多缺点,例如Dead Relu和梯度饱和的问题。

其实就像课程上面说的一样,现在大部分人还是使用Relu类的**函数,Sigmoid很少了,至少我看的几个网络案例里,Sigmoid几乎只是新手的那么几个。

下一章,大概是总结权重的初始化,正则化,不然总结下优化器也行。

参考
https://liam0205.me/2018/04/17/zero-centered-active-function/(about non-zero center)
http://study.163.com/course/courseLearn.htm?courseId=1004697005#/learn/video?lessonId=1050369427&courseId=1004697005(CS231n)
https://datascience.stackexchange.com/questions/5706/what-is-the-dying-relu-problem-in-neural-networks/9431#9431?newreg=bf4a4424c00f44a0857f148fc05da831
https://www.quora.com/What-is-the-dying-ReLU-problem-in-neural-networks