美文网首页
激活函数

激活函数

作者: xieyan0811 | 来源:发表于2020-06-11 21:25 被阅读0次

    为什么使用激活函数

    如果没有激活函数,神经网络就变成了线性模型,输出是输入的线性组合,使用一层与使用多层没有区别。如下式所示,输入为x,经过线性层计算出a1,将a1输入下个线性层得到a2,展开后可以看出,最终得到的仍然是wx+b的线性组合,只是参数值不同。

    图片.png

    另外,线性层无法解决非线性问题,如在预测房价问题中,如果不使用激活函数,则房价可能计算成负值,这也与实际不符。理论上,加了激活函数后,模型可以逼近任意函数。

    激活函数又分线性激活函数和非线性激活函数,一般使用的都是非线性激活函数,线性激活函数与线性层类似,只在输出层偶尔使用,不在此展开讨论。

    何时使用激活函数

    激活函数一般放置在线性变换之后,在线性变换和激活函数之间,常常插入归一化层,用于解决饱和的非线性激活函数问题(下面Sigmoid函数部分详细说明)。

    如何选择激活函数

    从一些当前流行的深度学习网络代码中,可以看到,当前使用的激活函数绝大部分是ReLU;在一些特殊情况下,也使用Sigmoid,比如二分类问题的最后一层使用Sigmoid将输出转换到0-1之间;又如使用注意力网络时,注意力加权需要使用0-1之间的权值时,也用到Sigmoid函数。作为一般的夹在线性层之间的普通激活函数,ReLU是默认选择。

    常用激活函数

    下面介绍常用激活函数的方法、原理、梯度计算、直观图示,以及使用中可能遇到的问题。

    sigmoid激活函数

    sigmoid是较早期的激活函数,它的输入是任意的x,输出在0-1之间,实现数据映射。

    其公式如下:

    其求导过程如下:

    Python代码实现:

    def sigmoid(x):  
        return 1. / (1 + np.exp(-x))
    

    试想将值代入时,当x趋近正无穷,分母为1,计算结果为1;当x趋近负无穷,分母为无穷大,计算结果为0。当x为0时,分母为2,计算结果为0.5。

    函数图示如下:

    如图所示,映射过程中将值压缩到0-1之间,它对0附近的值比较敏感,其图形接近线性,而其它部分的数值在sigmoid后绝对值缩小很多。

    梯度是x方向上变化引起的y方向的变化,在x值较大的情况下,x的变化对y影响很小,这就是所谓的“非线性激活函数的饱和”问题。在使用梯度下降法给网络调参时,接近0的梯度使学习的速度变得非常缓慢。这一现象在调试程序时尤为明显:大不把网络参数以及输入数据设置得比较小,且不使用归一化层的情况下,使用Sigmoid函数收敛得非常慢。

    此外,sigmoid还包括幂运算,运算量也比较大,目前除了上述比较特殊的场景,已很少使用。

    tanh激活函数

    tanh激活函数可视为sigmoid函数的改进版本,其图示如下:

    在数学上,tanh是sigmoid的平移,它把数据范围压缩到-1~1之间,均值为0。前人证明0均值的tanh激活函数效果更好。0均值同样可应用于其它场景提高模型效果。

    其公式如下:

    Python代码实现:

    import numpy as np  
    np.tanh(x)
    

    尽管tanh略优于sigmoid,但它也有sigmoid同样的缺点:计算量大及饱和问题,目前也很少使用,另外,0均值也可通过归一化层实现。因此,只做简单介绍,不再展开。

    ReLU激活函数

    ReLU激活函数,原理,计算以及求导都非常简单:如果x大于0,则y=x,如果小于0,则y=0,其图示如下:

    其公式如下:

    其导数是:

    需要注意的是,ReLU在0值不可微,但一般情况下,不会遇到太多的0值,因此将0值的梯度置为0或1都可以。

    Python代码实现:

    def relu(x):  
        return np.maximum(0,x)
    

    ReLU非常简单,运算速度非常快,收敛也快,由于它没有压缩数据,因此,也避免了由激活函数引起的梯度问题。另外,处理结果不能为负(如房价不能为负,或者避免sum累积时正负抵消)的问题时,也可以在层后添加ReLU激活函数。

    ReLU衍生的激活函数

    虽然ReLU相对于之前算法表现优异,但也存在问题,试想当梯度大幅变化时,由于ReLU在大于0的情况下,不做处理直接向后传递,则可能造成之前线性层参数的大幅变化,因此,很可能产生大量小于0的数据输入ReLU。若ReLU的输入大多是负数,则会导致大部分梯度无法向后传递,从而引起“Dead ReLU”问题。其现象是由于某些特殊数据引发了无法继续收敛。

    为解决这一问题,出现了一些ReLU变种,来处理小于0的数据,比如ELU,Leaky RELU。

    ELU公式如下:

    做图如下:

    Python代码如下:

    def elu(x,a):  
        y = []  
        for i in x:  
            if i<0:  
                i = a * (np.exp(i)-1)  
            y.append(i)  
        return y
    

    它的均值趋近0,没有Dead ReLU的问题,但计算量略大。更简单一点的还有Leaky ReLU,如下图所示:

    它对于0以下的部分乘一个较小的a值,一般是0.01。另外,引入归一化层也可解决Dead ReLU问题,因此,推荐以ReLU作为默认的激活函数。

    相关文章

      网友评论

          本文标题:激活函数

          本文链接:https://www.haomeiwen.com/subject/zymitktx.html