导言
为什么需要激活函数?
什么样的函数能用作激活函数?
什么样的函数是好的激活函数?
激活函数实现的是一对一的变换,即用相同的函数对输入向量的每个分量进行映射,得到输出向量,输入和输出向量的维数相同:
其中x和y都是n维向量。写成分量的形式为:
在工程实现时,如果将激活函数作为一个单独的层,则在正向传播时对输入向量的每个分量计算激活函数值f(x)。在反向传播时对输入数据计算导数值f’(x),然后乘以后一层送入的误差项,得到本层的误差项,送人前一层中:
由于当前被提出的激活函数众多,为了便于大家理解与记忆,我们对此做了总结。各种常用的激活函数与它们的导数如下表所示:
根据这些函数的定义,我们很容易计算出它们的导数。
下面我们以Caffe为例,介绍这些激活函数的具体实现细节。在Caffe中,激活函数是一个单独的层,把它和全连接层,卷据层拆开的好处是更为灵活,便于代码复用和组合。因为无论是全连接层,还是卷据层,它们激活函数的实现是相同的,因此可以用一套代码来完成。
激活函数由神经元层完成,它们的基类是NeuronLayer,所有的激活函数层均从它派生得到,下面分别进行介绍,限于篇幅,我们只介绍一部分,其他的原理类似。此外,Dropout机制也由神经元层实现。
SigmoidLayer类实现了标准sigmoid激活函数。正向传播函数对每个输入数据计算sigmoid函数值,在这里count是输入数据的维数。实现代码如下:
TanHLayer类实现了tanh激活函数。正向传播函数实现代码如下:
类ReLULayer实现ReLU激活函数,和前面介绍的标准ReLU不同,这里做了改进,定义为:
其中a是人工设定的大于0的参数。显然该函数的导数为:
下面来看正向传播函数的代码:
反向传播函数的实现如下:
这样可以通过函数值得到导数值,减少计算量。正向传播函数的实现如下:
类PReLULayer实现了PReLU激活函数。正向传播函数的实现如下:
反向传播函数的实现如下:
类DropoutLayer实现Dropout机制。在训练阶段,随机丢掉一部分神经元,用剩下的节点进行前向和后向传播。这里实现时通过二项分布随机数来控制神经元是否启用,如果随机数取值为1则启用,否则不启用。正向传播函数的实现如下:
推荐阅读