深度学习——前馈神经网络详解

目录

  1. 简介
  2. 感知机
  3. 前馈神经网络
  4. BP算法
  5. 总结

1. 简介

         不久前Google旗下DeepMind公司开发的围棋程序AlphaGo以4:1的成绩绩战胜韩国职业九段棋手李世石,让深度学习足足又火了一把。根据WHR算法,如果一名选手从未遭受失利,就不会进入排名统计,AlphaGo的一次失败,也让它拥有了世界排名,我们来看下图,排名第二,仅次于中国选手柯洁,加上之前5:0战胜欧洲围棋冠军樊麾,出赛九场就已经战绩斐然。

gorating

随着AlphaGo的出名,现在很多人将深度学习比作大脑、人工智能。但是,探究过深度学习的人将会知道,深度学习只是对大脑的简单模拟,实际上两者很不一样,我们对自己的智能几乎仍处于一无所知的状态。近年来深度学习这个领域炒作很热,Geoffrey Hinton说:人工智能会继续发展,请不要误用。

        深度学习源于人工神经网络,是神经网络的品牌重塑,根据拓扑结构划分,神经网络网络主要分为前馈网络和反馈网络。为了避免枯燥,本文将从神经元讲起,进而介绍感知机,最后讲解典型的前馈神经网络BP网络和参数训练算法——BP算法(Backpropagation Algorithm)。

2. 感知机

2.1 神经元

        我们知道,人脑具有很强的学习、记忆以及联想功能,虽然我们并不知道人脑完成信息处理的具体过程,但是我们知道其基本组成单位神经元的结构,如下图所示。shenjingyuan

一个神经元具有细胞核,细胞体,树突,轴突,突触等结构。当前神经元通过树突上的受体接受前面神经元的神经刺激,然后再通过神经电流的方式在轴突上传递,最后释放兴奋性或抑制性的神经递质。

2.2 感知机结构

        为了模拟生物神经元的特性,1957年就职于Cornell航空实验室的美国心理学家Frank Rosenblatt构造出了一种简化的数学模型——感知机,如下图所示:
perceptron

它以一组二进制作为输入值(类似当前神经元之前的神经元传递过来的信号),$x_{0}$作为偏置项始终为1,然后将每个输入值乘以一个权重后求和(类似每个神经元传递过来的信号强度),如果最终的结果大于设定的阈值,就输出1,否则输出0(类似于神经元进行信息处理后是否放电),模型假设如下:

$$h_{\theta }(x)=\begin{cases}1
& \text { if } \theta^{T}x\geq 0 \\
0 & \text{ if } \theta^{T}x< 0
\end{cases}$$

 式中的$\theta^{T}x=\sum_{i=0}^{n}w_{i}x_{i}$,我们统计一下错分的情况,损失函数如下:

$$\begin{align*}
J_{p}(\theta) &=\sum_{x^{(i)}\in M_{0}}\theta^{T}x^{(i)}-\sum_{x^{(j)}\in M_{1}}\theta^{T}x^{(j)} \\
&=\sum_{i=1}^{n}((1-y^{i})h_{\theta}(x^{(i)})-y^{(i)}(1-h_\theta(x^{(i)})))\theta^{T}x^{(i)} \\
&= \sum_{i=1}^n(h_\theta(x^{(i)})-y^{(i)})\theta^{T}x^{(i)}
\end{align*}$$

分析可知,误差来源于有两种情况,一种是真实类别为0预测类别为1,另一种是真实类别为1预测类别为0,我们将误差求和,第一类求和就是$\sum_{x^{(i)}\in M_{0}}\theta^{T}x^{(i)}$,第二类因为预测类别为0,所以$\theta^{T}x^{(j)} <0$,为了和第一类误差不相互抵消,我们在前面加上一个负号,即$-\sum_{x^{(j)}\in M_{1}}\theta^{T}x^{(j)}$,将两者求和就是总误差。为了使总误差最小,我们求误差对参数的梯度,然后用SGD更新参数如下:

$$\begin{align*}
\omega :&=\omega + \alpha(y-h_{\theta}(x)) \\
&= \begin{cases}
\omega+\alpha x& \text{ if } y=1~and~h_{\theta}(x)=0 \\
\omega-\alpha x& \text{ if } y=0~and~h_{\theta}(x)=1 \\
\omega& ~others
\end{cases}
\end{align*}$$

2.3 感知机缺陷

        起初,Rosenblatt等人希望用这种简单的神经元结构解决人工智能难题。但是,MIT人工智能实验室创始人Marvin Minsky和Seymour Paper不这么认为,他们在《感知机》一书中指出感知机不能解决线性不可分问题,连简单布尔代数XOR也学习不了,将XOR画成二维分布如下左图所示:

xor

由图可知,我们找不到任何一条直线对XOR函数进行正确分类。

2.4 MLP(多层感知机)

        Minsky和Paper不仅指出不可能用单个感知机来解决XOR问题,还指出需要多层感知机才可以完成这个任务,而且Rosenblatt的学习算法对多层结构并不管用,因为感知机算法只能对输出层的输出结果进行校正,并不能调整输出层之前的层结构权值。后面我们将介绍利用BP算法进行参数学习,在此之前我们构造一个MLP,看看能否解决异或问题,如下图所示:
mlp

x1和x2表示特征输入节点,o3是特征输出节点,中间节点均为感知机单元,输入为1的节点均为偏置项,将XOR函数代入验证一下,如下表所示:

xor2

由此可见,多层结构能够解决线性不可分问题。

3 前馈神经网络

3.1 激活函数

        前馈神经结构和MLP类似,每个神经元节点都可以理解为一个感知机,不同的是激活函数不同,我们通过感知机模型来感受一下激活函数的概念,如下图所示:perceptron-activition由图我们知道,感知机中的激活函数只是将求和的结果和一个阈值比较大小,然后再决定输出0或1,下面我们将看到神经网络中通常采用的激活函数。

        传统神经网络中最常用的激活函数是sigmoid型函数,比如logistic函数$\sigma(x)$和tanh函数。

$$\sigma(x)=\frac{1 }{1+e^{-x}}\\tanh(x)=\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}}$$

sigmoid函数具有中间增益两侧抑制的特性,对不同区域的信号反应不同,对中间输入有兴奋作用,对两侧输入有抑制作用,具有生物神经元的某些特性。除此之外,还有rectifier函数:

$$rectifier(x)=max(0,x)$$

rectifier函数具有很好的稀疏性,被认为有生物上的解释性,因为神经学家发现神经元具有单侧抑制、宽兴奋边、稀疏激活性等特性。使用rectifier函数的网络只有比较、加、乘操作,计算上更加高效。另一种是softplus函数:

$$softplus(x)=log(1+e^{x})$$

softplus导数是logistic函数,具有单侧抑制,宽兴奋边界的特性,没有稀疏激活性。四种函数的形状如下图所示:

fourfunction

 

3.2 网络结构

        这里我们以前馈神经网络中最典型的网络——BP网络为例,如下图所示,图中第一层为特征输入层(input layer),第二层为隐藏层(hidden layer)(隐藏层层数不同,训练复杂度和训练效果也会有所不同),第三层为输出层(output layer)。每层神经元之间采用全连接,无反馈,每条边都有自己的权重,标有“+1”的圆圈代表偏置项。

BP-net

为了方便表示网络结构,我们引入一些符号:

  • $n_{l}$:表示网络层数,本例中$n_{l}$=3;
  • $L_{l}$:表示第$l$层,则input layer为$L_{1}$,output layer为$L_{n_{l}}$
  • $s_{l}$:表示第$l$层的节点数(偏置单元不计在内);
  • $W_{ij}^{(l)}$:表示第$l$层第$j$单元与第$l+1$层第$i$单元之间的权重,则这里$l$的范围是$1\leqslant l<n_{l}$;
  • $b_{i}^{(l)}$:表示第$l+1$层第$i$单元的偏置项;
  • $z_{i}^{(l)}$:表示第$l$层第$i$单元输入加权和,我们称为活性值,例如在本例中,$z_{i}^{(2)}=\sum_{j=1}^{3}W_{ij}^{(1)}x_{j}+b_{i}^{(l)}$;
  • $a_{i}^{(l)}$:表示第$l$层第$i$单元的输出值(激活值),则$a_{i}^{(l)}=f(z_{i}^{(l)})$;
  • $h_{W,b}(x)$:表示最终输出结果。

本例中有参数$(W,b)=(W^{(1)},b^{(1)},W^{(2)},b^{(2)}),W^{(1)}\in R^{3\times 3},W^{(2)}\in R^{1\times 3}$,则该神经网络计算过程如下:

$$a_{1}^{(2)}=f(W_{11}^{(1)}x_{1}+W_{12}^{(1)}x_{2}+W_{13}^{(1)}x_{3}+b_{1}^{(1)})  \\ a_{2}^{(2)}=f(W_{21}^{(1)}x_{1}+W_{22}^{(1)}x_{2}+W_{23}^{(1)}x_{3}+b_{2}^{(1)}) \\ a_{3}^{(2)}=f(W_{31}^{(1)}x_{1}+W_{32}^{(1)}x_{2}+W_{33}^{(1)}x_{3}+b_{3}^{(1)}) \\ h_{W,b}(x)= a_{1}^{(3)}=f(W_{11}^{(2)}a_{1}^{(2)}+W_{12}^{(2)}a_{2}^{(2)}+W_{13}^{(2)}a_{3}^{(2)}+b_{1}^{(2)})$$

将激活函数表示为向量形式,则$f([z_{1}, z_{2},z_{3}])=[f(z_{1},f(z_{2}),f(z_{3}]$,上述计算过程表示可简化如下:

$$z^{(2)}=W^{(1)}x+b^{(1)} \\ a^{(2)}=f(z^{(2)}) \\ z^{(3)}=W^{(2)}a^{(2)}+b^{(2)} \\ h_{W,b}(x)=a^{(3)}=f(z^{(3)})$$

如果用$a^{(1)}=x$表示输入层的激活值,那么BP网络的前向传播过程可做如下表示:

$$z^{(l+1)}=W^{(l)}a^{(l)}+b^{(l)} \\ a^{(l+1)}=f(z^{(l+1)})$$

将参数矩阵化之后,我们可以利用线性代数的优势对神经网络进行快速求解。

4. BP算法

4.1 算法详解

        在了解前馈网络的结构之后,我们需要确定网络中的参数$(W,b)$来达到训练神经网络的目的,整个过程可以通过梯度下降法和BP算法求解。

        BP算法大致的思路如下:对于给定的一个样例$(x,y)$,我们运用之前讲过的前向传播计算出网络中所有的激活值,包括$h_{W,b}(x)$的输出值。然后,对于第$l$层的每一个节点$i$,我们定义其“残差”(也称为敏感度)为$\delta_{i}^{(l)}=\frac {\partial} {\partial z_{i}^{(l)}} J(W,b;x,y)$,该残差表明了该节点对最终输出值的残差所做的贡献。对于最终节点,我们可以根据激活值和实际值直接计算出残差$\delta_{i}^{(n_{l})}$,对于隐藏层第$l$层中的节点,我们可以用第$l+1$层节点残差的加权平均值计算$\delta_{i}^{(l)}$,下面将具体讲解BP算法。

假设我们的样本数据集为$\left \{(x^{(1)},y^{(1)}),…,(x^{(m)},y^{(m)}) \right \}$,共m个输入输出样例,对于单个样例$(x,y)$,我们定义其损失函数为:

$$J(W,b;x,y)=\frac {1} {2} ||h_{W,b}(x)-y||^{2}$$

注意,式子前面没有求和符号,这只是单个样例的方差损失,对于总的样本集我们定义其损失函数为:

$$\begin{align*}
J(W,b) &=\left [\frac {1} {m} \sum_{i=1}^{m}J(W,b;x^{(i)},y^{(i)}) \right ]+\frac {\lambda} {2}\sum_{l=1}^{n_{l}-1}\sum_{i=1}^{s_{l}}\sum_{j=1}^{s_{l+1}}\left (W_{ji}^{(l)}\right )^{2} \\ &=\left [\frac {1}{m}\sum_{i=1}^{m}\left (\frac {1}{2}||h_{W,b}(x^{(i)})-y^{(i)}||^{2}\right ) \right ] + \frac {\lambda} {2}\sum_{l=1}^{n_{l}-1}\sum_{i=1}^{s_{l}}\sum_{j=1}^{s_{l+1}}\left(W_{ji}^{(l)} \right )^{2}
\end{align*}$$

上式中第一项是均方差项,第二项是正则化项,正则化项用来减小权重的幅度,防止过拟合。权重衰减参数$\lambda$用来控制均方差项和正则化项的相对重要性。

我们的目标是最小化$J(W,b)$,首先我们将网络中的每一个参数$W_{i,j}^{(l)}$和$b_{i}^{(l)}$随机初始化一个接近于零的值。注意,不能将参数初始为相同的值,因为我们的网络采用的是全连接,每一层的节点在结构上是对称的。例如在之前的网络结构中,第2层的节点都与第一层的节点全连接,如果参数初始为相同的值,则对于任意输入都有$a_{1}^{(2)}=a_{2}^{(2)}=a_{3}^{(2)}$。

随机初始化参数之后,用梯度下降法对参数$(W,b)$进行更新:

$$W_{i,j}^{(l)}=W_{i,j}^{(l)}-\alpha \frac{\partial }{\partial W_{i,j}^{(l)}}J(W,b) \\ b_{i}^{(l)}=b_{i}^{(l)}-\alpha \frac{\partial }{\partial b_{i}^{(l)}}J(W,b)$$

现在的问题变为如何求上述式子中的偏导数,BP算法就是计算偏导数的一种有效工具。$\frac{\partial }{\partial W_{i,j}^{(l)}}J(W,b) $和$\frac{\partial }{\partial b_{i}^{(l)}}J(W,b)$是总损失函数的偏导数,它们与单个样例$(x,y)$损失函数$J(W,b;x,y)$的偏导数关系如下:

$$\frac {\partial}{\partial W_{ij}^{(l)}}J(W,b)=\left [\frac {1} {m} \sum_{i=1}^{m}\frac {\partial}{\partial W_{ij}^{(l)}}J(W,b;x^{(i)},y^{(i)})\right ]+\lambda W_{ij}^{(l)} \\
\frac {\partial}{\partial b_{i}^{(l)}}J(W,b)=\frac {1} {m} \sum_{i=1}^{m}\frac {\partial}{\partial b_{i}^{(l)}}J(W,b;x^{(i)},y^{(i)})$$

用BP算法求出每个样例损失函数$J(W,b;x,y)$的偏导数,问题也就迎刃而解了,下面具体讲解BP算法思路:

1. 利用前向传播公式,计算$L_{2},L_{3},…,L_{n_{l}}$的激活值。

2. 对于输出层(第$n_{l}$层)的每个单元i (神经网络可以有多个输出单元),我们计算其残差(最终误差贡献度):

$$\begin{align*}
\delta_{i}^{(n_{l})} &=\frac{\partial }{\partial z_{i}^{n_{l}}}J(W,b;x,y)=\frac{\partial}{\partial z_{i}^{n_{l}}}\frac{1}{2}\left \| y-h_{W,b}(x) \right \|^{2} \\
&=\frac{\partial}{\partial z_{i}^{n_{l}}}\frac{1}{2}\sum_{j=1}^{s_{n_{l}}}(y_{j}-a_{j}^{n_{l}})^2=\frac{\partial}{\partial z_{i}^{n_{l}}}\frac{1}{2}\sum_{j=1}^{s_{n_{l}}}(y_{j}-f(z_{j}^{n_{l}}))^2 \\
&=-(y_{i}-f(z_{i}^{n_{l}}))\cdot f'(z_{i}^{n_{l}})=-(y_{i}-a_{i}^{(n_{l})})\cdot f'(z_{i}^{n_{l}})
\end{align*}$$

3. 当$l=n_{l}-1,n_{l}-2,n_{l}-3,…,2$时,第$l$层的第$i$个节点按如下公式计算残差:

$$\delta_{i}^{(l)}=\left (\sum_{j=1}^{s_{l+1}}W_{ji}^{(l)}\delta_{j}^{(l+1)}  \right )f'(z_{i}^{(l)})$$

因为,当$l=n_{l}-1$时,

$$\begin{align*}
\delta_{i}^{n_{l}-1}&=\frac{\partial}{\partial z_{i}^{n_{l}-1}} J(W,b;x,y)=\frac{\partial}{\partial z_{i}^{n_{l}-1}}\frac{1}{2}\left \| y-h_{W,b}(x) \right \|^{2}=\frac{\partial}{\partial z_{i}^{n_{l}-1}}\frac{1}{2}
\sum_{j=1}^{s_{n_{l}}}(y_{j}-a_{j}^{(n_{l})})^{2} \\
&=\frac{1}{2}\sum_{j=1}^{s_{n_{l}}}\frac{\partial}{\partial z_{i}^{n_{l}-1}}(y_{j}-a_{j}^{(n_{l})})^{2}=\frac{1}{2}\sum_{j=1}^{s_{n_{l}}}\frac{\partial}{\partial z_{i}^{n_{l}-1}}(y_{j}-f(z_{j}^{(n_{l})}))^{2} \\
&=\sum_{j=1}^{s_{n_{l}}}-(y_{j}-f(z_{j}^{n_{l}}))\cdot\frac{\partial}{\partial z_{i}^{n_{l}-1}}f(z_{j}^{(n_{l})})=\sum_{j=1}^{s_{n_{l}}}-(y_{j}-f(z_{j}^{n_{l}}))\cdot f'(z_j^{(n_{l})})\cdot \frac{\partial z_{j}^{(n_{l})}}{\partial z_{j}^{(n_{l}-1)}} \\
&=\sum_{j=1}^{s_{n_{l}}}\delta_{j}^{(n_{l})}\cdot \frac{\partial z_{j}^{(n_{l})}}{\partial z_{j}^{(n_{l}-1)}}=\sum_{j=1}^{s_{n_{l}}}\left ( \delta_{j}^{(n_{l})}\cdot \frac{\partial}{\partial z_{i}^{(n_{l}-1)}}\sum_{k=1}^{s_{n_{l}-1}}f(z_{k}^{(n_{l}-1)})\cdot W_{jk}^{n_{l}-1} \right ) \\
&=\sum_{j=1}^{s_{n_{l}}}\delta_{j}^{(n_{l})}\cdot W_{ji}^{n_{l}-1}\cdot f'(z_{i}^{(n_{l}-1)})=\left ( \sum_{j=1}^{s_{n_{l}}}W_{ji}^{n_{l}-1}\delta_{j}^{(n_{l})} \right )f'(z_{i}^{(n_{l}-1)})
\end{align*}$$

用$l$和$l+1$替换上式中的$n_{l}-1$和$n_{l}$,即:

$$\delta_{i}^{(l)}=\left (\sum_{j=1}^{s_{l+1}}W_{ji}^{(l)}\delta_{j}^{(l+1)}  \right )f'(z_{i}^{(l)})$$

4. 计算单个样例误差$J(W,b;x,y)$的偏导数,如下:

$$\begin{align*}
\frac{\partial}{\partial W_{ij}^{(l)}}J(W,b;x,y)&=\frac{\partial J(W,b;x,y)}{\partial z_{i}^{(l+1)}}\cdot \frac{\partial z_{i}^{(l+1)}}{\partial W_{ij}^{(l)}}\\
&=\delta_{i}^{(l+1)}\cdot \frac{\partial }{\partial W_{ij}^{(l)}} z_{i}^{(l+1)}\\
&=\delta_{i}^{(l+1)}\cdot \frac{\partial }{\partial W_{ij}^{(l)}}\left ( \sum_{k=1}^{s_{l}}W_{ik}^{(l)}a_{k}^{(l)}+ b_{i}^{(l)} \right ) \\
&=\delta_{i}^{(l+1)}a_{j}^{(l)}
\end{align*}$$

同理:

$$\frac{\partial }{\partial b_{i}^{(l)}}J(W,b;x,y)=\delta_{i}^{(l+1)}$$

小结:至此,我们已经掌握了BP算法的过程,再通过梯度下降法最小化损失函数$J(W,b)$的值,我们就可以求解神经网络了。下面我们用矩阵和向量对上述过程重新表述,这样就能用线性代数的优势优化神经网络过程中的运算。我们将函数也做向量表示,即$f'([z_{1},z_{2},z_{3}])=[f'(z_{1}),f'(z_{2}),f'(z_{3})]$。

反向传播算法步骤:

1. 利用前向传播公式,计算$L_{2},L_{3},…,L_{n_{l}}$的激活值。

2. 计算输出层(第$n_{l}$层)的残差:

$$\delta^{(n_{l})}=-(y-a^{n_{l}})\bullet f'(z^{n_{l}})$$

3. 当$l=n_{l}-1,n_{l}-2,n_{l}-3,…,2$时,残差计算如下:

$$\delta^{(l)}=\left ((W^{(l)})^{T}\delta^{(l+1)} \right )\bullet f'(z^{(l)})$$

4. 计算单个样例的误差函数$J(W,b;x,y)$对参数矩阵的偏导数:

$$\nabla_{W^{(l)}}J(W,b;x,y)=\delta^{(l+1)}(a^{(l)})^{T} \\
\nabla_{b^{(l)}} J(W,b;x,y)=\delta^{(l+1)}$$

有了BP算法求出的梯度,我们可以用批量梯度下降法求解神经网络,定义两个中间变量$\Delta W^{(l)}$和$\Delta b^{(l)}$,分别和矩阵$W^{(l)}$、向量$b^{(l)}$的维数相同,整个过程如下:

1. 对于所有$l$,将$W^{(l)}$和$b^{(l)}$随机初始化为接近于零的极小值

2. $while(未达到终止条件)$

3.            对所有$l$,令$\Delta W^{(l)}:=0,\Delta b^{(l)}:=0$

4.            $for\ i = 1…m\ do$

                            用BP算法计算$\nabla_{W^{(l)}}J(W,b;x,y)$和$\nabla_{b^{(l)}} J(W,b;x,y)$

                            计算$\Delta W^{(l)}:=\Delta W^{(l)}+\nabla_{W^{(l)}}J(W,b;x,y)$

                            计算$\Delta b^{(l)}:=\Delta b^{(l)}+\nabla_{b^{(l)}} J(W,b;x,y)$

5.            更新权重参数:$$W^{(l)}=W^{(l)}-\alpha \left [ \left ( \frac{1}{m}\Delta W^{(l)} \right )+\lambda W^{(l)} \right ]\\
b^{(l)}=b^{(l)}-\alpha \left [ \frac{1}{m}\Delta b^{(l)} \right ]$$

4.2 梯度消失问题

        虽然BP算法能够用来求解我们的神经网络,但是它也有一个典型的问题——梯度消失问题。我们来看一下算法过程中的残差反向传播公式:

$$\delta^{(l)}=\left ((W^{(l)})^{T}\delta^{(l+1)} \right )\bullet f'(z^{(l)})$$

假设我们的激活函数是sigmoid型函数,如logistic函数$\sigma (x)$和$tanh$函数,它们的导数为:

$$\sigma'(x)=\sigma (x)(1-\sigma (x))\in [0,0.25] \\
tanh'(x)=1-(tanh(x))^{2}\in[0,1]$$

我们可以看到,sigmoid型函数导数的取值通常都小于1,这样随着网络层数的增多残差必然会不断衰减,甚至消失,这就是梯度消失问题。梯度消失不仅限制了神经网络的层数和性能,也增加了训练难度。

解决梯度消失问题的一个方法是使用我们之前提到的线性激活函数(如rectifier函数)或近似线性函数(如softplus函数),它们的导数近乎为1,可以很好地传递残差,训练速度也会有很大提高。

5 总结

        本文主要讲到了前馈神经网络结构和BP算法的详细推导。虽然BP网络具有很好的非线性映射能力、自学习和自适应能力、泛化能力以及容错能力,但随着应用范围的扩大,BP网络也暴露了一些缺点与不足,如局部最小化、收敛速度慢、样本依赖性等问题。此外,网络结构的选取没有具体的理论指导,一般只能依靠经验选定,这也增加了模型确定的难度和模型训练的工作量。

        了解了前馈神经网络之后,下一篇我们将讲到深度学习中在NLP领域展露头角的神经网络——RNN(循环神经网络)。

参考资料:
[1]Andrew Ng, Jiquan Ngiam, Chuan Yu Foo, Yifan Mai, Caroline Suen.UFLDL Tutorial
[2]Yoshua Bengio, Ian Goodfellow, and Aaron Courville.How the backpropagation algorithm works
[3]邱锡鹏.《神经网络与深度学习》讲义
[4]Yoshua Bengio, Ian Goodfellow, and Aaron Courville.Why are deep neural networks hard to train?

此条目发表在其他分类目录。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已用*标注