激活函数可视化

前言

简单来说,激活函数在神经网络里的作用就是引入Non-linearity。假如没有激活函数的话,一个多层的神经网络等同于一个一层的神经网络。简单来说,一个神经网络的层可以写成$act(WX)$,其中$W$是权重,$act$是激活函数。两层也就是 $act(W_2(act(W_1X)))$,如果现在没有了$act$,那这两层就能写成$W_2W_1X$,然后我们简单的用$W=W_2W_1$替换,就变成了$WX$。也就是一个两层的神经网络退化成了一个单层的神经网络。

所以说激活函数在神经网络里面是必要的,但不同的激活函数有各自的优缺点,在不同的任务中,大家会选择不同的激活函数。现在很难一概而论说哪个激活函数一定就最好。所以最好还是多试几个,找到最适合自己任务的。

所以这篇文章也不会给出一个最好的激活函数,也就是讲讲每种激活函数的特性。看看激活函数是如何引入非线性的,以及神经网络如何利用这个非线性做而分类的。

激活函数介绍

S形(Sigmoidal)函数

Sigmoid函数是神经网络初期的激活函数。更早的是在Percepton里面使用的threshold函数,不过threshold函数零点不可导,其他部分导数又全是0,无法通过Backpropagation(BP)训练,故这里不做介绍。Sigmoid函数可以看作threshold函数的soft版本,它从0平滑的过渡到1。在之后又发展出多种S形的激活函数,先上公式和图像(函数图$f(x)$及导数图$f'(x)$):

$$\text{Sigmoid: } f(x) = \frac{1}{1+e^{-x}}$$
$$\text{Tanh: } f(x) = \frac{e^{x} - e^{-x}}{e^{x} + e^{-x}}$$
$$\text{Arctan: } f(x) = arctan(x)$$
$$\text{Softsign: } f(x) = \frac{x}{1 + |x|}$$
$$\text{ISRU: } f(x)={\frac {x}{\sqrt {1+\alpha x^{2}}}}$$

激活函数可视化
激活函数可视化

从图中可以看到sigmoid导数小,最大的地方导数才0.25,这样在BP的时候,往后乘一乘梯度就没有嘞,也就是深层网络经常会遇到的Gradient Vanishing(梯度消失)。另外sigmoid的输出在0-1之间,而神经网络更好的输入的值是关于原点对称的。

tanh作为sigmoid的改进版,一定程度上减轻了以上的两个问题,tanh在原点附近接近$f(x)=x$,关于原点对称且在原店附近导数接近1。就是希望能够做到原点附近的数据不被压缩能够很好的传递到下一层,而周边的数据被一定程度的压缩来引入非线性。

其他不常用的激活函数如反正切$arctan$,$softsign$,以及Inverse Square Root Unit(ISRU)同样减轻了以上问题。从导数的函数图中可以看到$arctan$的导数较大,估计对学习速度应该会有帮助。sigmoid和tanh被广泛使用据说是因为导数比较好求(来自这里)。$\sigma'(x) = \sigma(x) (1-\sigma(x)) $,$tanh'(x) = 1 - tanh^2(x) $。

ReLU及其变体

上面说的Sigmoidal函数都或多或少都存在梯度消失的问题,这使得深层的网络难以训练。后来出现的ReLU(Rectified Linear Unit)基本解决了这个问题,它保证了至少在$x>0$的时候导数是不会减少的。这样在BP的过程中梯度就不会莫名消失。只不过ReLU有个dead neuron的问题,从函数图上可以看到,负半轴的值为0导数也为0,也就是forward pass和backward pass都不能传递任何信息。在使用ReLU的时候不要用太大的learning rate,否则很容易造成一堆dead neuron。

后来出现了Leaky ReLU(LReLU)解决了dead neuron的问题,而且使得输出数据分布在0的两侧,一定程度上对学习有帮助。后来有人做了一些改进如Parametric ReLU (PReLU)以及Randomized ReLU (RReLU)。在PReLU里,下面公式里的$\alpha$是变量,可通过BP学习,Randomized ReLU则是在训练时随机在一定范围内选择$\alpha$,而在测试中则是使用均值。如训练时$\alpha$在 $\left[0.1,0.3\right]$ 范围内随机选择,则在测试时$\alpha$的值即为$0.2$。

$$\text{ReLU: }f(x) =\begin{cases}0, & \text{x < 0} \\x, & \text{x $\ge$ 0}\end{cases}$$

$$\text{ReLU6: }f(x) =\begin{cases}0, & \text{x < 0} \\x, & \text{0 $\le$ x $\le$ 6} \\6, & \text{x > 6}\end{cases}$$

$$\text{Leaky ReLU: }f(x) =\begin{cases}\alpha x, & \text{x < 0} \\x, & \text{x $\ge$ 0}\end{cases}, \text{ where $0 < \alpha < 1$}$$

形状差不多的还有Softplus,Swish,Exponential Linear Unit (ELU),以及Scaled ELU(SELU),公式如下:

$$\text{Softplus: } f(x) = log(1 + e^x)$$

$$\text{ELU: }f(x) =\begin{cases}\alpha e^x -1, & \text{x < 0} \\x, & \text{x $\ge$ 0}\end{cases}$$

$$\text{SELU: }f(x) =\begin{cases}s(\alpha e^x -1), & \text{x < 0} \\sx, & \text{x $\ge$ 0}\end{cases}$$

其中SELU的$a = 1.6732632423543772848170429916717$,$s = 1.0507009873554804934193349852946$。这两个数字都是作者在论文中算出来的。90页的推导过程,简直神一般。

Softplus相对ReLU的好处是其在每个点的导数都不为0,避免了使用ReLU出现的dead neuron的问题。ELU相对于ReLU的优点是其输出在原点两侧且在每个点导数都不为0。SELU在论文中介绍的优点是,如果输入是均值为0,标准差为1的话,经过SELU激活之后,输出的均值也为0,标准差也为1,如果是这样的话,不知道是不是能少用几层Batch Norm。这三个激活函数的计算时间较ReLU,Leaky ReLU要长,当想要极限的优化网络速度的时候,这也能是一个优化点。

上图!
激活函数可视化
激活函数可视化

其他激活函数

Swish是最近(2017.10) Google Brain提出的激活函数,据说效果不错,Tanh-shrink和Bent-identity分别是在pytorch内建的激活函数库和Wikipedia上看到的,在此也附上图。后续想做个测试,应该也蛮有意思的!在这儿就先附上公式和图。

$$\text{Swish: } f(x) = x\sigma(x), \text{ where $\sigma$ is sigmoid function}$$

$$\text{Tanh-shrink: } f(x) = x - tanh(x)$$

$$\text{Bent-identity: } f(x) = \frac{\sqrt{x^2 + 1} - 1}{2} +x$$

激活函数可视化
激活函数可视化

神经网络如何改变数据分布

上面的分析给出了激活函数的定义,接下来我们看看激活函数如何改变数据分布。这里用一个中心点在原点的螺旋状的数据(见下图中identity一列)来表示数据分布,为了让图形简单一点,咱们忽略bias,于是一个层可以写作$H=act(WX)$。从公式可以看出,神经网络的一层会对输入的数据先做一个线形的变换,然后再通过激活函数做非线性的变换。之后我们再把激活后的数据映射回原来的空间($X' = W^{-1}H$)。这么做的结果是,对于激活函数不改变的点,它该在什么位置就还在什么位置,也就可以和原图的螺线比较着看激活函数的效果。

这个螺线的数据的$x, y$可以作为两个节点的输入层的输入数据。这里的$W$的维度可以有多种理解。

1\. 假设$W$是一个$n\times2$的矩阵,那么这个$act(WX)$就相当与一个$n$个节点的隐层;
2\. 从空间的角度上说,这相当于把数据映射到一个$n​$维的空间后,再在新的空间中做非线性变换;
3\. 把$W$拆成$n$个$1\times2$的矩阵,就还可以理解成$n$个$X$的线形组合,在思考决策边界的时候有用。

这里主要采用第二种思维,下面这张图各列显示了不同的激活函数在$n=2,5,30$时对应的变换。让$W$的值都在$[-1,1]$之间取值,这样$W$就能在映射到$2,5,30$维空间时产生旋转、缩放、斜切、拉伸等效果(不包括平移)。
激活函数可视化

这里我就选了几种激活函数玩玩。可以看到identity函数($f(x)=x$)是不改变数据形状的,不管映射到多少维。S型函数将周围的一圈都映射到了一起去,其中sigmoid挤压的最甚(所以输入的时候一定得standardize,否则信息全都被压缩了)。ReLU很好的保留了其中的一部分信息,且醉着维度的增加,保留的信息也增加(MobileNet V2就是基于这种想法设计了Inverted Residual Block)。ELU其实在低维就能够保存不少信息,看起来图形会稍微好看一些,实际的效果还是有待验证。tanhshrink觉得比较有意思也就加上去了。

神经网络学习的过程

上面给出了神经网络如何扭曲数据分布的,其实在$W$随机取值的情况下,我们很难去理解神经网络如何去学习的,下面来看看神经网络如何根据标签改变扭曲的过程。这里就选了ReLU和Sigmoid,4个节点的隐层。最后使用了softmax做分类,下图显示了输入数据和对应的神经网络。

激活函数可视化

不同于以上的图在输入数据$(x, y)$的二维空间,下面这些图的横坐标和纵坐标分别是$x', y'$,这两个值是unnormalized probability。对于一个坐标点$(x', y')$,假如 $x'>y'$,则预测类别为蓝点,反之则为红点。所以这里我们也把$y'=x'$这条线画出来,代表了在$x', y'$这个平面的决策边界。以下是以ReLU为激活函数的神经网络学习的过程,从螺线可以看出来原始的数据分布正在慢慢的被扭曲,直到这条黑线能够穿过红线和蓝线之间。在训练的过程中,每个红点都会把它周围的空间(蓝线)往左上角拉,相反每个蓝点都会往右下角拉,在这两个力以及权重衰减的力的作用下,空间就会被扭曲成需要的样子(如右下角所示)。

激活函数可视化

下面这张图显示了Sigmoid学习的过程。和ReLU的情况很像,只是它扭曲的方式不太一样

激活函数可视化

两个学习的过程都特别的像折纸,对,就是折纸!当你发现直直的一剪刀剪不出个圆的时候,你就可以考虑折出几个皱褶,然后再给一剪刀。再提一下,如果是多个隐层的话,相当于把上面的图当作输入再进行扭曲。从折纸的角度上说,就类似于“对折再对折再对折”这种做法,这样就能用少量的隐层节点做出更多的非线性(褶子)。

神经网络学习的结果

最后来看看不同激活函数的决策边界(下图)。这次的坐标还是原始输入的$(x, y)$,这相当于把上面的图往回展平以后,上图的黑线所在的位置。Sigmoid 4的意思就是对于一个4个节点的隐层,使用Sigmoid作为激活函数的神经网络。可以看出决策边界是由3个不同斜率的决策边界组成的(实际上这里有4条边界,有两个决策边界太近了就没体现出来)。Softplus可以看出来这4条边,ReLU这张图虽然只有6个边界,但它其实可以有8条,这是因为当两个ReLU形成的决策边界相交时,会产生两个转折点,4个决策边界能产生8条线。

最后试了一下300个隐层的情况,可以看出来决策边界已经很接近圆了。是的!等于多折几下,再给一刀。

激活函数可视化

激活函数可视化

如果想玩动图,就上这儿http://playground.tensorflow....

结论

所以说,神经网络就像剪纸,激活函数决定怎么折,节点数决定在原图上折几个折痕,隐层的数量决定折几次。

如果想让结果在$(0,1)$之间,使用sigmoid(如LSTM的各种gates);如果想训练的很深,不要用S系的;ReLU,LReLU什么的多试几个,不会错的。

需要注意如果使用ReLU,则最好使用He Initialization。实际上这次的实验中所有ReLU系的激活函数(除了Softplus),使用He Initialization都收敛的比较快。如果使用Sigmoid,则使用Xavier Initialization,要不真的能把空间扭曲成一个奇怪的形状,然后长时间不收敛。

相关推荐