本文共 5051 字,大约阅读时间需要 16 分钟。
神经网络中,在隐藏层接一个线性变换后,再接一个非线性变换(sigmoid、tanh、ReLu等),这种非线性变换叫做激活函数(Activation Function)或者传递函数。
激活函数一般都是非线性函数,神经网络中的激活函数它的主要作用是提供网络的非线性建模能力。如果你的神经网络模型中,使用线性激活函数或者没有使用一个激活函数,那么无论多少层的神经网络模型一直在做的只是计算线性函数,不如去掉全部隐藏层。在实例中证明,在隐藏层使用线性激活函数,输出层用sigmoid函数,这个模型的复杂度和没有隐藏层的logistic回归是一样的。
在神经网络中,隐藏层使用线性激活函数几乎没啥用处,线性函数的组合本身就是线性函数。当引入非线性激活函数才会让模型变得有意义。sigmoid函数: a = g ( z ) = 1 1 + e − z a=g\left ( z \right )=\frac{1}{1+e^{-z}} a=g(z)=1+e−z1
sigmoid函数的导数: g ( z ) ′ = d d z g ( z ) = α ( 1 − α ) g({z})'=\frac{d}{dz}g\left ( z \right )=\alpha (1-\alpha ) g(z)′=dzdg(z)=α(1−α) 缺点: 1.sigmoid在定义域内处处可导,并且导数逐渐趋近于0。如果Z值很大或者很小的时候,函数的梯度(斜率)也就会非常小,在反向传播过程中,导致向底层传输的梯度也变得非常小,此时网络参数很难得到有效训练。这种现象称为梯度消失。 2.sigmoid的输出不是以0为中心。导致在反向传播过程中,要么都往正方向更新要么往负方向更新,使得收敛缓慢。 3.解析式中含有幂运算,计算求解比较耗时。sigmoid代码实现如下:
def sigmoid(x): """sigmoid函数""" return 1 / (1 + np.exp(-x)) def der_sigmoid(x): """sigmoid函数的导数""" return sigmoid() * (1 - sigmoid(x))
tanh函数: a = g ( z ) = t a n h ( z ) = e z − e − z e z + e − z a=g\left ( z \right )=tanh\left ( z \right )=\frac{e^{z}-e^{-z}}{e^{z}+e^{-z}} a=g(z)=tanh(z)=ez+e−zez−e−z
tanh函数的导数: g ( z ) ′ = d d z g ( z ) = 1 − ( t a n h ( z ) ) 2 g(z)'=\frac{d}{dz}g(z)=1-(tanh(z))^{2} g(z)′=dzdg(z)=1−(tanh(z))2 优点: tanh函数解决了sigmoid函数的不是zero-centered输出问题,输出均值是0。缺点:
sigmoid函数和tanh函数两者共同的缺点:在𝑧特别大或者特别小的情况下,导数的梯度或者函数的斜率会变得特别小,最后就会接近于 0,导致降低梯度下降的速度。tanh代码实现如下:
def tanh(x): """tanh函数""" return ((np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))) def der_tanh(x): """tanh函数的导数""" return 1 - tanh(x) * tanh(x)
ReLu函数: a = m a x ( 0 , z ) a=max(0,z) a=max(0,z)
ReLu函数的导数: g ( z ) ′ = { 0 , i f z < 0 1 , i f z > 0 u n d e f i n e d , i f z = 0 } g(z)^{'}=\begin{Bmatrix} 0 ,& if z<0\\ 1,& if z>0\\ undefined,& if z=0 \end{Bmatrix} g(z)′=⎩⎨⎧0,1,undefined,ifz<0ifz>0ifz=0⎭⎬⎫优点:
ReLu函数是目前最常用的默认选择激活函数。当x>0时,不存在饱和问题,在x>0时保持梯度不衰减,缓解梯度消失的问题。并且收敛速度远快于sigmoid和tanh。缺点:
当x<0时,ReLu硬饱和,随着训练的推进,部分输入会落入到硬饱和区,导致权重无法更新。和sigmoid类似,ReLu的输出均值大于0,出现偏移现象。ReLu代码实现如下:
def relu(x): """relu函数""" temp = np.zeros_like(x) if_bigger_zero = (x > temp) return x * if_bigger_zero def der_relu(x): """relu函数的导数""" temp = np.zeros_like(x) if_bigger_equal_zero = (x >= temp) return if_bigger_equal_zero * np.ones_like(x)
PReLu函数: a = m a x ( α z , z ) a=max(αz,z) a=max(αz,z)
ReLu函数的导数: g ( z ) ′ = { α , i f z < 0 1 , i f z ≥ 0 } g(z)^{'}=\begin{Bmatrix} \alpha ,& if z<0\\ 1,& if z\geq 0 \end{Bmatrix} g(z)′={ α,1,ifz<0ifz≥0} PReLU也是针对ReLU的一个改进型,在负数区域内,PReLU有一个很小的斜率,这样也可以避免ReLU死掉的问题。相比于ELU,PReLU在负数区域内是线性运算,斜率虽然小,但是不会趋于0,这算是一定的优势吧。我们看PReLU的公式,里面的参数α一般是取0~1之间的数,而且一般还是比较小的,如零点零几。当α=0.01时,我们叫PReLU为Leaky ReLU,算是PReLU的一种特殊情况吧。
PReLu代码实现如下:
def prelu(x): """prelu函数""" return np.where(x<0,alpha * x,x)def der_prelu(x): """prelu函数的导数""" return np.where(x<0,alpha,1)
softmax用于多分类过程中,它将多个神经元的输出,映射到(0,1)区间内,可以看成概率来理解。
softmax函数公式: S i = e i ∑ j e j S_{i}=\frac{e^{i}}{\sum _{j}e^{j}} Si=∑jejei 接下来对公式进行细分说明:(1)非线性变换之前计算: z ( l ) = W ( l ) a ( l − 1 ) + b ( l ) z^{(l)}=W^{(l)}a^{(l-1)}+b^{(l)} z(l)=W(l)a(l−1)+b(l)
(2)经过非线性变换,临时变量: t = e Z l t=e^{Z^{l}} t=eZl (3)归一化: a l = t i ∑ j = 1 n t j a^{l}=\frac{t_{i}}{\sum_{j=1}^{n}t_{j}} al=∑j=1ntjti (4) a l a^{l} al表示的就是第几个类别的概率值,这些概率值和为1.举例如下:
softmax直白来说就是将原来输出是3,1,-3通过softmax函数一作用,就映射成为(0,1)的值,而这些值的累和为1(满足概率的性质),那么我们就可以将它理解成概率,在最后选取输出结点的时候,我们就可以选取概率最大(也就是值对应最大的)结点,作为我们的预测目标。Maxout模型实际上也是一种新型的激活函数,我们要先知道什么是maxout。我们假设网络某一层的输入特征向量为:X=(x1,x2,……xd),也就是我们输入是d个神经元。Maxout隐藏层每个神经元的计算公式如下:
h i ( x ) = m a x ( Z i j ) j ∈ [ 1 , k ] h_{i}(x)=\underset{j\in \left [ 1,k \right ]}{max (Z_{ij})} hi(x)=j∈[1,k]max(Zij)上面的公式就是maxout隐藏层神经元i的计算公式。其中,k就是maxout层所需要的参数了,由我们人为设定大小。就像dropout一样,也有自己的参数p(每个神经元dropout概率),maxout的参数是k。公式中Z的计算公式为:
z i j = x T W . . . i j + b i j z_{ij}=x^{T}W_{...ij} + b_{ij} zij=xTW...ij+bij 权重w是一个大小为(d,m,k)三维矩阵,b是一个大小为(m,k)的二维矩阵,这两个就是我们需要学习的参数。如果我们设定参数k=1,那么这个时候,网络就类似于以前我们所学普通的MLP网络。我们可以这么理解,本来传统的MLP算法在第i层到第i+1层,参数只有一组,然而现在我们不怎么干了,我们在这一层同时训练n组参数,然后选择激活值最大的作为下一层神经元的激活值。下面还是用一个例子进行讲解,比较容易搞懂。
为了简单起见,假设我们网络第i层有2个神经元x1、x2,第i+1层的神经元个数为1个,如下图所示:
(1)以前MLP的方法。我们要计算第i+1层,那个神经元的激活值的时候,传统的MLP计算公式就是: z = W ∗ X + b z=W*X + b z=W∗X+b o u t = f ( z ) out=f(z) out=f(z) 其中f就是我们所谓的激活函数,比如Sigmod、Relu、Tanh等。(2)Maxout 的方法。如果我们设置maxout的参数k=5,maxout层就如下所示:
相当于在每个输出神经元前面又多了一层。这一层有5个神经元,此时maxout网络的输出计算公式为: z1=w1*x+b1z2=w2*x+b2
z3=w3*x+b3
z4=w4*x+b4
z5=w5*x+b5
out=max(z1,z2,z3,z4,z5)
也就是说第(i+1)层的激活值计算了5次,可我们明明只需要1个激活值,那么我们该怎么办?其实上面的叙述中已经给出了答案,取这5者的最大值来作为最终的结果。
总结一下,maxout明显增加了网络的计算量,使得应用maxout的层的参数个数成k倍增加,原本只需要1组就可以,采用maxout之后就需要k倍了。再叙述一个稍微复杂点的应用maxout的网络,网络图如下:
对上图做个说明,第i层有3个节点,红点表示,而第(i+1)层有4个结点,用彩色点表示,此时在第(i+1)层采用maxout(k=3)。我们看到第(i+1)层的每个节点的激活值都有3个值,3次计算的最大值才是对应点的最终激活值。我举这个例子主要是为了说明,决定结点的激活值的时候并不是以层为单位,仍然以节点为单位。优点:
与常规激活函数不同的是,它是一个可学习的分段线性函数.然而任何一个凸函数,都可以由线性分段函数进行逼近近似。其实我们可以把以前所学到的激活函数:ReLU、abs激活函数,看成是分成两段的线性函数,如下示意图所示: 实验结果表明Maxout与Dropout组合使用可以发挥比较好的效果。 那么,前边的两种ReLU便是两种Maxout,函数图像为两条直线的拼接。转载地址:http://kfulf.baihongyu.com/