DNN

前向传播

从感知机到神经网络

深度神经网络(Deep Neural Networks, 以下简称DNN)是深度学习的基础,而要理解DNN,首先我们要理解DNN模型,下面我们就对DNN的模型与前向传播算法做一个总结。
在这里插入图片描述
输出和输入之间学习到一个线性关系,得到中间输出结果:
z = ∑ i = 1 m w i x i + b z=\sum\limits_{i=1}^mw_ix_i + b z=i=1mwixi+b
接着是一个神经元激活函数:
s i g n ( z ) = { − 1 z &lt; 0 1 z ≥ 0 sign(z)= \begin{cases} -1&amp; {z&lt;0}\\ 1&amp; {z\geq 0} \end{cases} sign(z)={11z<0z0
从而得到我们想要的输出结果1或者-1。

这个模型只能用于二元分类,且无法学习比较复杂的非线性模型,因此在工业界无法使用。

而神经网络则在感知机的模型上做了扩展,总结下主要有三点:
1)加入了隐藏层,隐藏层可以有多层,增强模型的表达能力,如下图实例,当然增加了这么多隐藏层模型的复杂度也增加了好多。

在这里插入图片描述
2)输出层的神经元也可以不止一个输出,可以有多个输出,这样模型可以灵活的应用于分类回归,以及其他的机器学习领域比如降维和聚类等。多个神经元输出的输出层对应的一个实例如下图,输出层现在有4个神经元了。在这里插入图片描述
3) 对激活函数做扩展,感知机的激活函数是sign(z),虽然简单但是处理能力有限,因此神经网络中一般使用的其他的激活函数,比如我们在逻辑回归里面使用过的Sigmoid函数,即:
f ( z ) = 1 1 + e − z f(z)=\frac{1}{1+e^{-z}} f(z)=1+ez1

DNN的基本结构

上一节我们了解了神经网络基于感知机的扩展,而DNN可以理解为有很多隐藏层的神经网络。这个很多其实也没有什么度量标准, 多层神经网络和深度神经网络DNN其实也是指的一个东西,当然,DNN有时也叫做多层感知机(Multi-Layer perceptron,MLP), 名字实在是多。后面我们讲到的神经网络都默认为DNN。

从DNN按不同层的位置划分,DNN内部的神经网络层可以分为三类,输入层,隐藏层和输出层,如下图示例,一般来说第一层是输入层,最后一层是输出层,而中间的层数都是隐藏层。在这里插入图片描述
    层与层之间是全连接的,也就是说,第i层的任意一个神经元一定与第i+1层的任意一个神经元相连。虽然DNN看起来很复杂,但是从小的局部模型来说,还是和感知机一样,即一个线性关系 z = ∑ w i x i + b z=\sum\limits w_ix_i + b z=wixi+b加上一个激活函数σ(z)。

由于DNN层数多,则我们的线性关系系数w和偏倚b的数量也就是很多了。具体的参数在DNN是如何定义的呢?

首先我们来看看线性关系系数w的定义。以下图一个三层的DNN为例,第二层的第4个神经元到第三层的第2个神经元的线性系数定义为 w 24 3 w_{24}^3 w243。上标3代表线性系数w所在的层数,而下标对应的是输出的第三层索引2和输入的第二层索引4。你也许会问,为什么不是 w 42 3 w_{42}^3 w423, 而是 w 24 3 w_{24}^3 w243呢?这主要是为了便于模型用于矩阵表示运算,如果是 w 42 3 w_{42}^3 w423而每次进行矩阵运算是wTx+b,需要进行转置。将输出的索引放在前面的话,则线性运算不用转置,即直接为wx+b。总结下,第l−1层的第k个神经元到第l层的第j个神经元的线性系数定义为 w 42 3 w_{42}^3 w423。注意,输入层是没有w参数的。
在这里插入图片描述
再来看看偏倚b的定义。还是以这个三层的DNN为例,第二层的第三个神经元对应的偏倚定义为 b 3 2 b_3^{2} b32。其中,上标2代表所在的层数,下标3代表偏倚所在的神经元的索引。同样的道理,第三个的第一个神经元的偏倚应该表示为 b 1 3 b_1^{3} b13。同样的,输入层是没有偏倚参数b的。
在这里插入图片描述

DNN前向传播算法数学原理

在上一节,我们已经介绍了DNN各层线性关系系数w,偏倚b的定义。假设我们选择的激活函数是σ(z),隐藏层和输出层的输出值为a,则对于下图的三层DNN,利用和感知机一样的思路,我们可以利用上一层的输出计算下一层的输出,也就是所谓的DNN前向传播算法。
在这里插入图片描述
对于第二层的的输出 a 1 2 , a 2 2 , a 3 2 a_1^2,a_2^2,a_3^2 a12,a22,a32,我们有:
a 1 2 = σ ( z 1 2 ) = σ ( w 11 2 x 1 + w 12 2 x 2 + w 13 2 x 3 + b 1 2 ) a_1^2=\sigma(z_1^2) = \sigma(w_{11}^2x_1 + w_{12}^2x_2 + w_{13}^2x_3 + b_1^{2}) a12=σ(z12)=σ(w112x1+w122x2+w132x3+b12)
a 2 2 = σ ( z 2 2 ) = σ ( w 21 2 x 1 + w 22 2 x 2 + w 23 2 x 3 + b 2 2 ) a_2^2=\sigma(z_2^2) = \sigma(w_{21}^2x_1 + w_{22}^2x_2 + w_{23}^2x_3 + b_2^{2}) a22=σ(z22)=σ(w212x1+w222x2+w232x3+b22)
a 3 2 = σ ( z 3 2 ) = σ ( w 31 2 x 1 + w 32 2 x 2 + w 33 2 x 3 + b 3 2 ) a_3^2=\sigma(z_3^2) = \sigma(w_{31}^2x_1 + w_{32}^2x_2 + w_{33}^2x_3 + b_3^{2}) a32=σ(z32)=σ(w312x1+w322x2+w332x3+b32)
对于第三层的的输出 a 1 3 a_1^3 a13,我们有:
a 1 3 = σ ( z 1 3 ) = σ ( w 11 3 a 1 2 + w 12 3 a 2 2 + w 13 3 a 3 2 + b 1 3 ) a_1^3=\sigma(z_1^3) = \sigma(w_{11}^3a_1^2 + w_{12}^3a_2^2 + w_{13}^3a_3^2 + b_1^{3}) a13=σ(z13)=σ(w113a12+w123a22+w133a32+b13)
将上面的例子一般化,假设第l−1层共有m个神经元,则对于第l层的第j个神经元的输出 a j l a_j^l ajl,我们有
a j l = σ ( z j l ) = σ ( ∑ k = 1 m w j k l a k l − 1 + b j l ) a_j^l = \sigma(z_j^l) = \sigma(\sum\limits_{k=1}^mw_{jk}^la_k^{l-1} + b_j^l) ajl=σ(zjl)=σ(k=1mwjklakl1+bjl)
其中,如果l=2,则对于的 a k 1 a_k^1 ak1即为输入层的xk。

从上面可以看出,使用代数法一个个的表示输出比较复杂,而如果使用矩阵法则比较的简洁。假设第l−1层共有m个神经元,而第l层共有n个神经元,则第l层的线性系数w组成了一个n×m的矩阵 W l W^l Wl, 第l层的偏倚b组成了一个n×1的向量 b l b^l bl , 第l−1层的的输出a组成了一个m×1的向量 a l − 1 a^{l-1} al1,第l层的的未激活前线性输出z组成了一个n×1的向量 z l z^{l} zl, 第l层的的输出a组成了一个n×1的向量 a l a^{l} al。则用矩阵法表示,第l层的输出为:
     a l = σ ( z l ) = σ ( W l a l − 1 + b l ) a^l = \sigma(z^l) = \sigma(W^la^{l-1} + b^l) al=σ(zl)=σ(Wlal1+bl)

DNN前向传播算法

有了上一节的数学推导,DNN的前向传播算法也就不难了。所谓的DNN的前向传播算法也就是利用我们的若干个权重系数矩阵W,偏倚向量b来和输入值向量x进行一系列线性运算和激活运算,从输入层开始,一层层的向后计算,一直到运算到输出层,得到输出结果为值。

输入: 总层数L,所有隐藏层和输出层对应的矩阵W,偏倚向量b,输入值向量x
    输出:输出层的输出aL
    1) 初始化 a 1 = x a^1 = x a1=x
    2) for l=2 to L, 计算:
a l = σ ( z l ) = σ ( W l a l − 1 + b l ) a^l = \sigma(z^l) = \sigma(W^la^{l-1} + b^l) al=σ(zl)=σ(Wlal1+bl)
    最后的结果即为输出aL。

反向传播算法(BP)

DNN反向传播算法要解决的问题

在了解DNN的反向传播算法前,我们先要知道DNN反向传播算法要解决的问题,也就是说,什么时候我们需要这个反向传播算法?

回到我们监督学习的一般问题,假设我们有m个训练样本:{(x1,y1),(x2,y2),…,(xm,ym)},其中x为输入向量,特征维度为n_in,而y为输出向量,特征维度为n_out。我们需要利用这m个样本训练出一个模型,当有一个新的测试样本(xtest,?)来到时, 我们可以预测ytest向量的输出。

如果我们采用DNN的模型,即我们使输入层有n_in个神经元,而输出层有n_out个神经元。再加上一些含有若干神经元的隐藏层。此时我们需要找到合适的所有隐藏层和输出层对应的线性系数矩阵W,偏倚向量b,让所有的训练样本输入计算出的输出尽可能的等于或很接近样本输出。怎么找到合适的参数呢?

如果大家对传统的机器学习的算法优化过程熟悉的话,这里就很容易联想到我们可以用一个合适的损失函数来度量训练样本的输出损失,接着对这个损失函数进行优化求最小化的极值,对应的一系列线性系数矩阵W,偏倚向量b即为我们的最终结果。在DNN中,损失函数优化极值求解的过程最常见的一般是通过梯度下降法来一步步迭代完成的,当然也可以是其他的迭代方法比如牛顿法与拟牛顿法。如果大家对梯度下降法不熟悉,建议先阅读我之前写的梯度下降(Gradient Descent)小结。

对DNN的损失函数用梯度下降法进行迭代优化求极小值的过程即为我们的反向传播算法。

DNN反向传播算法的基本思路

在进行DNN反向传播算法前,我们需要选择一个损失函数,来度量训练样本计算出的输出和真实的训练样本输出之间的损失。你也许会问:训练样本计算出的输出是怎么得来的?这 个输出是随机选择一系列W,b,用我们上一节的前向传播算法计算出来的。即通过一系列的计算: a l = σ ( z l ) = σ ( W l a l − 1 + b l ) a^l = \sigma(z^l) = \sigma(W^la^{l-1} + b^l) al=σ(zl)=σ(Wlal1+bl)。计算到输出层第L层对应的aL即为前向传播算法计算出来的输出。

回到损失函数,DNN可选择的损失函数有不少,为了专注算法,这里我们使用最常见的均方差来度量损失。即对于每个样本,我们期望最小化下式:
     J ( W , b , x , y ) = 1 2 ∣ ∣ a L − y ∣ ∣ 2 2 J(W,b,x,y) = \frac{1}{2}||a^L-y||_2^2 J(W,b,x,y)=21aLy22
其中,aL和y为特征维度为n_out的向量,而||S||2为S的L2范数。

损失函数有了,现在我们开始用梯度下降法迭代求解每一层的W,b。

首先是输出层第L层。注意到输出层的W,b满足下式:
     a L = σ ( z L ) = σ ( W L a L − 1 + b L ) a^L = \sigma(z^L) = \sigma(W^La^{L-1} + b^L) aL=σ(zL)=σ(WLaL1+bL)
   这样对于输出层的参数,我们的损失函数变为:
    J ( W , b , x , y ) = 1 2 ∣ ∣ a L − y ∣ ∣ 2 2 = 1 2 ∣ ∣ σ ( W L a L − 1 + b L ) − y ∣ ∣ 2 2 J(W,b,x,y) = \frac{1}{2}||a^L-y||_2^2 = \frac{1}{2}|| \sigma(W^La^{L-1} + b^L)-y||_2^2 J(W,b,x,y)=21aLy22=21σ(WLaL1+bL)y22
  这样求解W,b的梯度就简单了
   ∂ J ( W , b , x , y ) ∂ W L = [ ( a L − y ) ⊙ σ ′ ( z L ) ] ( a L − 1 ) T \frac{\partial J(W,b,x,y)}{\partial W^L} = [(a^L-y) \odot \sigma^{&#x27;}(z^L)](a^{L-1})^T WLJ(W,b,x,y)=[(aLy)σ(zL)](aL1)T
   ∂ J ( W , b , x , y ) ∂ b L = ( a L − y ) ⊙ σ ′ ( z L ) \frac{\partial J(W,b,x,y)}{\partial b^L} =(a^L-y)\odot \sigma^{&#x27;}(z^L) bLJ(W,b,x,y)=(aLy)σ(zL)
  注意上式中有一个符号⊙,它代表Hadamard积,对于两个维度相同的向量 A ( a 1 , a 2 , . . . a n ) T A(a_1,a_2,...a_n)^T Aa1,a2,...anT B ( b 1 , b 2 , . . . b n ) T B(b_1,b_2,...b_n)^T Bb1,b2,...bnT,则 A ⊙ B = ( a 1 b 1 , a 2 b 2 , . . . a n b n ) T A \odot B = (a_1b_1, a_2b_2,...a_nb_n)^T AB=(a1b1,a2b2,...anbn)T
  我们注意到在求解输出层的W,b的时候,有中间依赖部分 ∂ J ( W , b , x , y ) ∂ z L \frac{\partial J(W,b,x,y)}{\partial z^L} zLJ(W,b,x,y),因此我们可以把公共的部分即对zL先算出来,记为:
   δ L = ∂ J ( W , b , x , y ) ∂ z L = ( a L − y ) ⊙ σ ′ ( z L ) \delta^L = \frac{\partial J(W,b,x,y)}{\partial z^L} = (a^L-y)\odot \sigma^{&#x27;}(z^L) δL=zLJ(W,b,x,y)=(aLy)σ(zL)
  现在我们终于把输出层的梯度算出来了,那么如何计算上一层L−1层的梯度,上上层L−2层的梯度呢?这里我们需要一步步的递推,注意到对于第l层的未激活输出zl,它的梯度可以表示为:
   δ l = ∂ J ( W , b , x , y ) ∂ z l = ( ∂ z L ∂ z L − 1 ∂ z L − 1 ∂ z L − 2 . . . ∂ z l + 1 ∂ z l ) T ∂ J ( W , b , x , y ) ∂ z L \delta^l =\frac{\partial J(W,b,x,y)}{\partial z^l} = (\frac{\partial z^L}{\partial z^{L-1}}\frac{\partial z^{L-1}}{\partial z^{L-2}}...\frac{\partial z^{l+1}}{\partial z^{l}})^T\frac{\partial J(W,b,x,y)}{\partial z^L} δl=zlJ(W,b,x,y)=(zL1zLzL2zL1...zlzl+1)TzLJ(W,b,x,y)
如果我们可以依次计算出第l层的δl,则该层的Wl,bl很容易计算?为什么呢?注意到根据前向传播算法,我们有:
z l = W l a l − 1 + b l z^l= W^la^{l-1} + b^l zl=Wlal1+bl
    所以根据上式我们可以很方便的计算出第l层的Wl,bl的梯度如下:
∂ J ( W , b , x , y ) ∂ W l = δ l ( a l − 1 ) T \frac{\partial J(W,b,x,y)}{\partial W^l} = \delta^{l}(a^{l-1})^T WlJ(W,b,x,y)=δl(al1)T
∂ J ( W , b , x , y ) ∂ b l = δ l \frac{\partial J(W,b,x,y)}{\partial b^l} = \delta^{l} blJ(W,b,x,y)=δl
    其中,第一个式子的推导可以参考机器学习中的矩阵向量求导(四) 矩阵向量求导链式法则中第三节的最后一个公式。

那么现在问题的关键就是要求出δl了。这里我们用数学归纳法,第L层的δL上面我们已经求出, 假设第l+1层的δl+1已经求出来了,那么我们如何求出第l层的δl呢?我们注意到:
δ l = ∂ J ( W , b , x , y ) ∂ z l = ( ∂ z l + 1 ∂ z l ) T ∂ J ( W , b , x , y ) ∂ z l + 1 = ( ∂ z l + 1 ∂ z l ) T δ l + 1 \delta^{l} = \frac{\partial J(W,b,x,y)}{\partial z^l} = (\frac{\partial z^{l+1}}{\partial z^{l}})^T\frac{\partial J(W,b,x,y)}{\partial z^{l+1}} =(\frac{\partial z^{l+1}}{\partial z^{l}})^T \delta^{l+1} δl=zlJ(W,b,x,y)=(zlzl+1)Tzl+1J(W,b,x,y)=(zlzl+1)Tδl+1
可见,用归纳法递推 δ l + 1 \delta^{l+1} δl+1 δ l \delta^{l} δl的关键在于求解 ∂ z l + 1 ∂ z l \frac{\partial z^{l+1}}{\partial z^{l}} zlzl+1
z l + 1 z^{l+1} zl+1 z l z^{l} zl的关系其实很容易找出:
z l + 1 = W l + 1 a l + b l + 1 = W l + 1 σ ( z l ) + b l + 1 z^{l+1}= W^{l+1}a^{l} + b^{l+1} = W^{l+1}\sigma(z^l) + b^{l+1} zl+1=Wl+1al+bl+1=Wl+1σ(zl)+bl+1
这样很容易求出:
∂ z l + 1 ∂ z l = W l + 1 d i a g ( σ ′ ( z l ) ) \frac{\partial z^{l+1}}{\partial z^{l}} = W^{l+1}diag(\sigma^{&#x27;}(z^l)) zlzl+1=Wl+1diag(σ(zl))
将上式带入上面 δ l + 1 \delta^{l+1} δl+1 δ l \delta^{l} δl关系式我们得到:
δ l = ( ∂ z l + 1 ∂ z l ) T ∂ J ( W , b , x , y ) ∂ z l + 1 = d i a g ( σ ′ ( z l ) ) ( W l + 1 ) T δ l + 1 = ( W l + 1 ) T δ l + 1 ⊙ σ ′ ( z l ) \delta^{l} = (\frac{\partial z^{l+1}}{\partial z^{l}})^T\frac{\partial J(W,b,x,y)}{\partial z^{l+1}} = diag(\sigma^{&#x27;}(z^l))(W^{l+1})^T\delta^{l+1} =(W^{l+1})^T\delta^{l+1}\odot \sigma^{&#x27;}(z^l) δl=(zlzl+1)Tzl+1J(W,b,x,y)=diag(σ(zl))(Wl+1)Tδl+1=(Wl+1)Tδl+1σ(zl)

DNN反向传播算法过程

现在我们总结下DNN反向传播算法的过程。由于梯度下降法有批量(Batch),小批量(mini-Batch),随机三个变种,为了简化描述,这里我们以最基本的批量梯度下降法为例来描述反向传播算法。实际上在业界使用最多的是mini-Batch的梯度下降法。不过区别仅仅在于迭代时训练样本的选择而已。

输入: 总层数L,以及各隐藏层与输出层的神经元个数,激活函数,损失函数,迭代步长α,最大迭代次数MAX与停止迭代阈值ϵ,输入的m个训练样本 { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x m , y m ) } \{(x_1,y_1), (x_2,y_2), ..., (x_m,y_m)\} {(x1,y1),(x2,y2),...,(xm,ym)}
    输出:各隐藏层与输出层的线性关系系数矩阵W和偏倚向量b
    1) 初始化各隐藏层与输出层的线性关系系数矩阵W和偏倚向量b的值为一个随机值。

2)for iter to 1 to MAX:

2-1) for i =1 to m:

a) 将DNN输入a1设置为xi
      b) for l=2 to L,进行前向传播算法计算 a i , l = σ ( z i , l ) = σ ( W l a i , l − 1 + b l ) a^{i,l} = \sigma(z^{i,l}) = \sigma(W^la^{i,l-1} + b^l) ai,l=σ(zi,l)=σ(Wlai,l1+bl)
      c) 通过损失函数计算输出层的δi,L
      d) for l= L-1 to 2, 进行反向传播算法计算 δ i , l = ( W l + 1 ) T δ i , l + 1 ⊙ σ ′ ( z i , l ) \delta^{i,l} = (W^{l+1})^T\delta^{i,l+1}\odot \sigma^{&#x27;}(z^{i,l}) δi,l=(Wl+1)Tδi,l+1σ(zi,l)
   2-2) for l = 2 to L,更新第l层的Wl,bl:
W l = W l − α ∑ i = 1 m δ i , l ( a i , l − 1 ) T W^l = W^l -\alpha \sum\limits_{i=1}^m \delta^{i,l}(a^{i, l-1})^T Wl=Wlαi=1mδi,l(ai,l1)T
b l = b l − α ∑ i = 1 m δ i , l b^l = b^l -\alpha \sum\limits_{i=1}^m \delta^{i,l} bl=blαi=1mδi,l
    2-3) 如果所有W,b的变化值都小于停止迭代阈值ϵ,则跳出迭代循环到步骤3。

3) 输出各隐藏层与输出层的线性关系系数矩阵W和偏倚向量b。

损失函数和激活函数的选择

均方差损失函数+Sigmoid激活函数的问题

在讲反向传播算法时,我们用均方差损失函数和Sigmoid激活函数做了实例,首先我们就来看看均方差+Sigmoid的组合有什么问题。

首先我们回顾下Sigmoid激活函数的表达式为:
σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{1+e^{-z}} σ(z)=1+ez1
    σ(z)的函数图像如下:
    在这里插入图片描述
从图上可以看出,对于Sigmoid,当z的取值越来越大后,函数曲线变得越来越平缓,意味着此时的导数σ′(z)也越来越小。同样的,当z的取值越来越小时,也有这个问题。仅仅在z取值为0附近时,导数σ′(z)的取值较大。

在上篇讲的均方差+Sigmoid的反向传播算法中,每一层向前递推都要乘以σ′(z),得到梯度变化值。Sigmoid的这个曲线意味着在大多数时候,我们的梯度变化值很小,导致我们的W,b更新到极值的速度较慢,也就是我们的算法收敛速度较慢。那么有什么什么办法可以改进呢?

使用交叉熵损失函数+Sigmoid激活函数改进DNN算法收敛速度

上一节我们讲到Sigmoid的函数特性导致反向传播算法收敛速度慢的问题,那么如何改进呢?换掉Sigmoid?这当然是一种选择。另一种常见的选择是用交叉熵损失函数来代替均方差损失函数。

我们来看看二分类时每个样本的交叉熵损失函数的形式:
J ( W , b , a , y ) = − [ y l n a + ( 1 − y ) l n ( 1 − a ) ] J(W,b,a,y) = - [y lna + (1-y) ln(1 -a)] J(W,b,a,y)=[ylna+(1y)ln(1a)]
    这个形式其实很熟悉,在逻辑回归原理小结中其实我们就用到了类似的形式,只是当时我们是用最大似然估计推导出来的,而这个损失函数的学名叫交叉熵。

使用了交叉熵损失函数,就能解决Sigmoid函数导数变化大多数时候反向传播算法慢的问题吗?我们来看看当使用交叉熵时,我们输出层δL的梯度情况。
在这里插入图片描述
   可见此时我们的δl梯度表达式里面已经没有了σ′(z),作为一个特例,回顾一下我们上一节均方差损失函数时在δL梯度,
∂ J ( W , b , x , y ) ∂ z L = ( a L − y ) ⊙ σ ′ ( z ) \frac{\partial J(W,b,x,y)}{\partial z^L} = (a^L-y) \odot \sigma^{&#x27;}(z) zLJ(W,b,x,y)=(aLy)σ(z)
    对比两者在第L层的δL梯度表达式,就可以看出,使用交叉熵,得到的的δl梯度表达式没有了σ′(z),梯度为预测值和真实值的差距,这样求得的 W l , b l W^l,b^l Wl,bl的地图也不包含σ′(z),因此避免了反向传播收敛速度慢的问题。

通常情况下,如果我们使用了sigmoid激活函数,交叉熵损失函数肯定比均方差损失函数好用。

使用对数似然损失函数和softmax激活函数进行DNN分类输出

在前面我们讲的所有DNN相关知识中,我们都假设输出是连续可导的值。但是如果是分类问题,那么输出是一个个的类别,那我们怎么用DNN来解决这个问题呢?

比如假设我们有一个三个类别的分类问题,这样我们的DNN输出层应该有三个神经元,假设第一个神经元对应类别一,第二个对应类别二,第三个对应类别三,这样我们期望的输出应该是(1,0,0),(0,1,0)和(0,0,1)这三种。即样本真实类别对应的神经元输出应该无限接近或者等于1,而非改样本真实输出对应的神经元的输出应该无限接近或者等于0。或者说,我们希望输出层的神经元对应的输出是若干个概率值,这若干个概率值即我们DNN模型对于输入值对于各类别的输出预测,同时为满足概率模型,这若干个概率值之和应该等于1。

DNN分类模型要求是输出层神经元输出的值在0到1之间,同时所有输出值之和为1。很明显,现有的普通DNN是无法满足这个要求的。但是我们只需要对现有的全连接DNN稍作改良,即可用于解决分类问题。在现有的DNN模型中,我们可以将输出层第i个神经元的激活函数定义为如下形式:
a i L = e z i L ∑ j = 1 n L e z j L a_i^L = \frac{e^{z_i^L}}{\sum\limits_{j=1}^{n_L}e^{z_j^L}} aiL=j=1nLezjLeziL
其中,nL是输出层第L层的神经元个数,或者说我们的分类问题的类别数。

很容易看出,所有的aLi都是在(0,1) 之间的数字,而 ∑ j = 1 n L e z j L \sum\limits_{j=1}^{n_L}e^{z_j^L} j=1nLezjL作为归一化因子保证了所有的aLi之和为1。

这个方法很简洁漂亮,仅仅只需要将输出层的激活函数从Sigmoid之类的函数转变为上式的激活函数即可。上式这个激活函数就是我们的softmax激活函数。它在分类问题中有广泛的应用。将DNN用于分类问题,在输出层用softmax激活函数也是最常见的了。

下面这个例子清晰的描述了softmax激活函数在前向传播算法时的使用。假设我们的输出层为三个神经元,而未激活的输出为3,1和-3,我们求出各自的指数表达式为:20,2.7和0.05,我们的归一化因子即为22.75,这样我们就求出了三个类别的概率输出分布为0.88,0.12和0。
    在这里插入图片描述
从上面可以看出,将softmax用于前向传播算法是也很简单的。那么在反向传播算法时还简单吗?反向传播的梯度好计算吗?答案是Yes!

对于用于分类的softmax激活函数,对应的损失函数一般都是用对数似然函数,即:
     J ( W , b , a L , y ) = − ∑ k y k l n a k L J(W,b,a^L,y) = - \sum\limits_ky_klna_k^L J(W,b,aL,y)=kyklnakL
其中yk的取值为0或者1,如果某一训练样本的输出为第i类。则yi=1,其余的j≠i都有yj=0。由于每个样本只属于一个类别,所以这个对数似然函数可以简化为:
J ( W , b , a L , y ) = − l n a i L J(W,b,a^L,y) = -lna_i^L J(W,b,aL,y)=lnaiL
其中i即为训练样本真实的类别序号。

可见损失函数只和真实类别对应的输出有关,这样假设真实类别是第i类,则其他不属于第i类序号对应的神经元的梯度导数直接为0。对于真实类别第i类,他对应的第j个w链接 w i j L w_{ij}^L wijL对应的梯度计算为:
  在这里插入图片描述
  同样的可以得到bLi的梯度表达式为:
∂ J ( W , b , a L , y ) ∂ b i L = a i L − 1 \frac{\partial J(W,b,a^L,y)}{\partial b_i^L} = a_i^L -1 biLJ(W,b,aL,y)=aiL1
    可见,梯度计算也很简洁,也没有第一节说的训练速度慢的问题。举个例子,假如我们对于第2类的训练样本,通过前向算法计算的未激活输出为(1,5,3),则我们得到softmax激活后的概率输出为:(0.015,0.866,0.117)。由于我们的类别是第二类,则反向传播的梯度应该为:(0.015,0.866-1,0.117)。

梯度爆炸梯度消失与ReLU激活函数

学习DNN,大家一定听说过梯度爆炸和梯度消失两个词。尤其是梯度消失,是限制DNN与深度学习的一个关键障碍,目前也没有完全攻克。

什么是梯度爆炸和梯度消失呢?从理论上说都可以写一篇论文出来。不过简单理解,就是在反向传播的算法过程中,由于我们使用了是矩阵求导的链式法则,有一大串连乘,如果连乘的数字在每层都是小于1的,则梯度越往前乘越小,导致梯度消失,而如果连乘的数字在每层都是大于1的,则梯度越往前乘越大,导致梯度爆炸。

比如我们在前一篇反向传播算法里面讲到了δ的计算,可以表示为:
δ l = ∂ J ( W , b , x , y ) ∂ z l = ( ∂ z L ∂ z L − 1 ∂ z L − 1 ∂ z L − 2 . . . ∂ z l + 1 ∂ z l ) T ∂ J ( W , b , x , y ) ∂ z L \delta^l =\frac{\partial J(W,b,x,y)}{\partial z^l} = (\frac{\partial z^L}{\partial z^{L-1}}\frac{\partial z^{L-1}}{\partial z^{L-2}}...\frac{\partial z^{l+1}}{\partial z^{l}})^T\frac{\partial J(W,b,x,y)}{\partial z^L} δl=zlJ(W,b,x,y)=(zL1zLzL2zL1...zlzl+1)TzLJ(W,b,x,y)
    如果不巧我们的样本导致每一层 ∂ z l + 1 ∂ z l \frac{\partial z^{l+1}}{\partial z^{l}} zlzl+1的都小于1,则随着反向传播算法的进行,我们的δl会随着层数越来越小,甚至接近越0,导致梯度几乎消失,进而导致前面的隐藏层的W,b参数随着迭代的进行,几乎没有大的改变,更谈不上收敛了。这个问题目前没有完美的解决办法。

而对于梯度爆炸,则一般可以通过调整我们DNN模型中的初始化参数得以解决。

对于无法完美解决的梯度消失问题,目前有很多研究,一个可能部分解决梯度消失问题的办法是使用ReLU(Rectified Linear Unit)激活函数,ReLU在卷积神经网络CNN中得到了广泛的应用,在CNN中梯度消失似乎不再是问题。那么它是什么样子呢?其实很简单,比我们前面提到的所有激活函数都简单,表达式为:
σ ( z ) = m a x ( 0 , z ) \sigma(z) = max(0,z) σ(z)=max(0,z)
    也就是说大于等于0则不变,小于0则激活后为0。就这么一玩意就可以解决梯度消失?至少部分是的。具体的原因现在其实也没有从理论上得以证明。这里我也就不多说了。

DNN其他激活函数

除了上面提到了激活函数,DNN常用的激活函数还有:

1) tanh:这个是sigmoid的变种,表达式为:
t a n h ( z ) = e z − e − z e z + e − z tanh(z) = \frac{e^z-e^{-z}}{e^z+e^{-z}} tanh(z)=ez+ezezez
    tanh激活函数和sigmoid激活函数的关系为:
t a n h ( z ) = 2 s i g m o i d ( 2 z ) − 1 tanh(z) = 2sigmoid(2z)-1 tanh(z)=2sigmoid(2z)1
    tanh和sigmoid对比主要的特点是它的输出落在了[-1,1],这样输出可以进行标准化。同时tanh的曲线在较大时变得平坦的幅度没有sigmoid那么大,这样求梯度变化值有一些优势。当然,要说tanh一定比sigmoid好倒不一定,还是要具体问题具体分析。

2) softplus:这个其实就是sigmoid函数的原函数,表达式为:
s o f t p l u s ( z ) = l o g ( 1 + e z ) softplus(z) = log(1+e^z) softplus(z)=log(1+ez)
    它的导数就是sigmoid函数。softplus的函数图像和ReLU有些类似。它出现的比ReLU早,可以视为ReLU的鼻祖。
    在这里插入图片描述
    3)PReLU:从名字就可以看出它是ReLU的变种,特点是如果未激活值小于0,不是简单粗暴的直接变为0,而是进行一定幅度的缩小。如下图。当然,由于ReLU的成功,有很多的跟风者,有其他各种变种ReLU,这里就不多提了。
    在这里插入图片描述

DNN损失函数和激活函数小结

上面我们对DNN损失函数和激活函数做了详细的讨论,重要的点有:1)如果使用sigmoid激活函数,则交叉熵损失函数一般肯定比均方差损失函数好。2)如果是DNN用于分类,则一般在输出层使用softmax激活函数和对数似然损失函数。3)ReLU激活函数对梯度消失问题有一定程度的解决,尤其是在CNN模型中.

正则化

DNN的L1&L2正则化

想到正则化,我们首先想到的就是L1正则化和L2正则化。L1正则化和L2正则化原理类似,这里重点讲述DNN的L2正则化。

而DNN的L2正则化通常的做法是只针对与线性系数矩阵W,而不针对偏倚系数b。利用我们之前的机器学习的知识,我们很容易可以写出DNN的L2正则化的损失函数。

假如我们的每个样本的损失函数是均方差损失函数,则所有的m个样本的损失函数为:
J ( W , b ) = 1 2 m ∑ i = 1 m ∣ ∣ a L − y ∣ ∣ 2 2 J(W,b) = \frac{1}{2m}\sum\limits_{i=1}^{m}||a^L-y||_2^2 J(W,b)=2m1i=1maLy22
    则加上了L2正则化后的损失函数是:
J ( W , b ) = 1 2 m ∑ i = 1 m ∣ ∣ a L − y ∣ ∣ 2 2 + λ 2 m ∑ l = 2 L ∣ ∣ w ∣ ∣ 2 2 J(W,b) = \frac{1}{2m}\sum\limits_{i=1}^{m}||a^L-y||_2^2 + \frac{\lambda}{2m}\sum\limits_{l=2}^L||w||_2^2 J(W,b)=2m1i=1maLy22+2mλl=2Lw22
    其中,λ即我们的正则化超参数,实际使用时需要调参。而w为所有权重矩阵W的所有列向量。

如果使用上式的损失函数,进行反向传播算法时,流程和没有正则化的反向传播算法完全一样,区别仅仅在于进行梯度下降法时,W的更新公式。

回想我们在深度神经网络(DNN)反向传播算法(BP)中,W的梯度下降更新公式为:
W l = W l − α ∑ i = 1 m δ i , l ( a x , l − 1 ) T W^l = W^l -\alpha \sum\limits_{i=1}^m \delta^{i,l}(a^{x, l-1})^T Wl=Wlαi=1mδi,l(ax,l1)T
    则加入L2正则化以后,迭代更新公式变成:
W l = W l − α ∑ i = 1 m δ i , l ( a i , l − 1 ) T − α λ W l W^l = W^l -\alpha \sum\limits_{i=1}^m \delta^{i,l}(a^{i, l-1})^T -\alpha \lambda W^l Wl=Wlαi=1mδi,l(ai,l1)TαλWl
    注意到上式中的梯度计算中1m我忽略了,因为α是常数,而除以m也是常数,所以等同于用了新常数α来代替αm。进而简化表达式,但是不影响损失算法。

类似的L2正则化方法可以用于交叉熵损失函数或者其他的DNN损失函数,这里就不累述了。

DNN通过集成学习的思路正则化

除了常见的L1&L2正则化,DNN还可以通过集成学习的思路正则化。在集成学习原理小结中,我们讲到集成学习有Boosting和Bagging两种思路。而DNN可以用Bagging的思路来正则化。常用的机器学习Bagging算法中,随机森林是最流行的。它 通过随机采样构建若干个相互独立的弱决策树学习器,最后采用加权平均法或者投票法决定集成的输出。在DNN中,我们一样使用Bagging的思路。不过和随机森林不同的是,我们这里不是若干个决策树,而是若干个DNN的网络。

首先我们要对原始的m个训练样本进行有放回随机采样,构建N组m个样本的数据集,然后分别用这N组数据集去训练我们的DNN。即采用我们的前向传播算法和反向传播算法得到N个DNN模型的W,b参数组合,最后对N个DNN模型的输出用加权平均法或者投票法决定最终输出。

不过用集成学习Bagging的方法有一个问题,就是我们的DNN模型本来就比较复杂,参数很多。现在又变成了N个DNN模型,这样参数又增加了N倍,从而导致训练这样的网络要花更加多的时间和空间。因此一般N的个数不能太多,比如5-10个就可以了。

DNN通过dropout 正则化

这里我们再讲一种和Bagging类似但是又不同的正则化方法:Dropout。

所谓的Dropout指的是在用前向传播算法和反向传播算法训练DNN模型时,一批数据迭代时,随机的从全连接DNN网络中去掉一部分隐藏层的神经元。

比如我们本来的DNN模型对应的结构是这样的:
    在这里插入图片描述
    在对训练集中的一批数据进行训练时,我们随机去掉一部分隐藏层的神经元,并用去掉隐藏层的神经元的网络来拟合我们的一批训练数据。如下图,去掉了一半的隐藏层神经元:在这里插入图片描述
    然后用这个去掉隐藏层的神经元的网络来进行一轮迭代,更新所有的W,b。这就是所谓的dropout。

当然,dropout并不意味着这些神经元永远的消失了。在下一批数据迭代前,我们会把DNN模型恢复成最初的全连接模型,然后再用随机的方法去掉部分隐藏层的神经元,接着去迭代更新W,b。当然,这次用随机的方法去掉部分隐藏层后的残缺DNN网络和上次的残缺DNN网络并不相同。

总结下dropout的方法: 每轮梯度下降迭代时,它需要将训练数据分成若干批,然后分批进行迭代,每批数据迭代时,需要将原始的DNN模型随机去掉部分隐藏层的神经元,用残缺的DNN模型来迭代更新W,b。每批数据迭代更新完毕后,要将残缺的DNN模型恢复成原始的DNN模型。

从上面的描述可以看出dropout和Bagging的正则化思路还是很不相同的。dropout模型中的W,b是一套,共享的。所有的残缺DNN迭代时,更新的是同一组W,b;而Bagging正则化时每个DNN模型有自己独有的一套W,b参数,相互之间是独立的。当然他们每次使用基于原始数据集得到的分批的数据集来训练模型,这点是类似的。

使用基于dropout的正则化比基于bagging的正则化简单,这显而易见,当然天下没有免费的午餐,由于dropout会将原始数据分批迭代,因此原始数据集最好较大,否则模型可能会欠拟合。

DNN通过增强数据集正则化

增强模型泛化能力最好的办法是有更多更多的训练数据,但是在实际应用中,更多的训练数据往往很难得到。有时候我们不得不去自己想办法能无中生有,来增加训练数据集,进而得到让模型泛化能力更强的目的。

对于我们传统的机器学习分类回归方法,增强数据集还是很难的。你无中生有出一组特征输入,却很难知道对应的特征输出是什么。但是对于DNN擅长的领域,比如图像识别,语音识别等则是有办法的。以图像识别领域为例,对于原始的数据集中的图像,我们可以将原始图像稍微的平移或者旋转一点点,则得到了一个新的图像。虽然这是一个新的图像,即样本的特征是新的,但是我们知道对应的特征输出和之前未平移旋转的图像是一样的。

其他DNN正则化方法

DNN的正则化的方法是很多的,还是持续的研究中。在Deep Learning这本书中,正则化是洋洋洒洒的一大章。里面提到的其他正则化方法有:Noise Robustness, Adversarial Training,Early Stopping等

  • 19
    点赞
  • 73
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值