sigmoid函数_激活函数

为什么使用激活函数

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

sigmoid函数_激活函数_第1张图片

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

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

何时使用激活函数

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

如何选择激活函数

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

常用激活函数

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

sigmoid激活函数

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

其公式如下:

f32ce5b8ba26ceba0ff30f12fd0f3c29.png

其求导过程如下:

sigmoid函数_激活函数_第2张图片

Python代码实现:

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

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

函数图示如下:

sigmoid函数_激活函数_第3张图片

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

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

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

tanh激活函数

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

sigmoid函数_激活函数_第4张图片

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

其公式如下:

e6b55e7228519fa2388944189e349763.png

Python代码实现:

import numpy as np  
np.tanh(x)

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

ReLU激活函数

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

sigmoid函数_激活函数_第5张图片

其公式如下:

c935260fc065fdcaa82be9b6a2e339da.png

其导数是:

e642c92866d6b0a2a72fd756896a1626.png

需要注意的是,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公式如下:

2c82cb78c958c214048949b4fe6e9a05.png

做图如下:

sigmoid函数_激活函数_第6张图片

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,如下图所示:

sigmoid函数_激活函数_第7张图片

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

你可能感兴趣的:(sigmoid函数,sigmoid函数求导)