Back Propagation Neural Networks

Table of Contents

1. 反向传播算法和 BP 网络简介

“误差反向传播算法(Error Back Propagation)”的提出,使得多层感知器的模型中神经元的参数的计算变得简单可行。

误差反向传播算法简称反向传播算法(即 BP 算法)。反向传播算法于 1986 年由 David E. Rumelhart 和 James L. McClelland 发表于书籍 Parallel Distributed Processing 中。使用反向传播算法的多层感知器又称为 BP 神经网络

BP 算法是一个迭代算法,它的基本思想为:(1) 先计算每一层的状态和激活值,直到最后一层(即信号是前向传播的);(2) 计算每一层的误差,误差的计算过程是从最后一层向前推进的(这就是反向传播算法名字的由来);(3) 更新参数(目标是误差变小),迭代前面两个步骤,直到满足停止准则(比如相邻两次迭代的误差的差别很小)。

参考:Parallel Distributed Processing (1986, by David E. Rumelhart, James L. McClelland), Chapter 8 Learning Internal Representations by Error Propagation: http://psych.stanford.edu/~jlm/papers/PDP/Volume%201/Chap8_PDP86.pdf

本文的记号说明:

  • nl 表示第 l 层神经元的个数;
  • f() 表示神经元的激活函数;
  • W(l)Rnl×nl1 表示第 l1 层到第 l 层的权重矩阵;
  • wij(l) 是权重矩阵 W(l) 中的元素,表示第 l1 层第 j 个神经元到第 l 层第 i 个神经元的连接的权重(注意标号的顺序);
  • b(l)=(b1(l),b2(l),,bnl(l))TRnl 表示 l1 层到第 l 层的偏置;
  • z(l)=(z1(l),z2(l),,znl(l))TRnl 表示 l 层神经元的状态;
  • a(l)=(a1(l),a2(l),,anl(l))TRnl 表示 l 层神经元的激活值(即输出值)。

关于记号的特别注意 :不同的文献所采用的记号可能不同,这将导致不同文献的公式结论可能不同。如 Andrew Ng的教程 中用 W(l) 表示的是第 l 层到第 l+1 层的权重矩阵。又如,本文用“下标”来标记一个向量的不同分量,而有一些资料却用“上标”来标记向量的不同分量。

下面以三层感知器(即只含有一个隐藏层的多层感知器)为例介绍“反向传播算法(BP 算法)”。

三层感知器如图 1 所示。例子中,输入数据 x=(x1,x2,x3)T 是 3 维的(对于第一层,可以认为 ai(1)=xi ),唯一的隐藏层有 3 个节点,输出数据是 2 维的。

BP_MLP_3layers.gif

Figure 1: 三层感知器实例

2. 信息前向传播

显然,图 1 所示神经网络的第 2 层神经元的状态及激活值可以通过下面的计算得到:
z1(2)=w11(2)x1+w12(2)x2+w13(2)x3+b1(2)z2(2)=w21(2)x1+w22(2)x2+w23(2)x3+b2(2)z3(2)=w31(2)x1+w32(2)x2+w33(2)x3+b3(2)a1(2)=f(z1(2))a2(2)=f(z2(2))a3(2)=f(z3(2))
类似地,第 3 层神经元的状态及激活值可以通过下面的计算得到:
z1(3)=w11(3)a1(2)+w12(3)a2(2)+w13(3)a3(2)+b1(3)z2(3)=w21(3)a1(2)+w22(3)a2(2)+w23(3)a3(2)+b2(3)a1(3)=f(z1(3))a2(3)=f(z2(3))

可总结出,第 l(2lL) 层神经元的状态及激活值为(下面式子是向量表示形式):
z(l)=W(l)a(l1)+b(l)a(l)=f(z(l))

对于 L 层感知器,网络的最终输出为 a(L) 。前馈神经网络中信息的前向传递过程如下:
x=a(1)z(2)a(L1)z(L)a(L)=y

3. 误差反向传播

“信息前向传播”讲的是已知各个神经元的参数后,如何得到神经网络的输出。但怎么得到各个神经元的参数呢?“误差反向传播”算法解决的就是这个问题。

假设训练数据为 {(x(1),y(1)),(x(2),y(2)),,(x(i),y(i)),,(x(N),y(N))} ,即共有 N 个。又假设输出数据为 nL 维的,即 y(i)=(y1(i),,ynL(i))T

对某一个训练数据 (x(i),y(i)) 来说,其代价函数可写为:
E(i)=12y(i)o(i)=12k=1nL(yk(i)ok(i))2
说明 1: y(i) 为期望的输出(是训练数据给出的已知值), o(i) 为神经网络对输入 x(i) 产生的实际输出。
说明 2:代价函数中的系数 12 显然不是必要的,它的存在仅仅是为了后续计算时更方便。
说明 3:以图 1 所示神经网络为例, nL=2,y(i)=(y1(i),y2(i))T ,从而有 E(i)=12(y1(i)a1(3))2+12(y2(i)a2(3))2 ,如果展开到隐藏层,则有 E(i)=12(y1(i)f(w11(3)a1(2)+w12(3)a2(2)+w13(3)a3(2)+b1(3)))2+12(y2(i)f(w21(3)a1(2)+w22(3)a2(2)+w23(3)a3(2)+b2(3)))2 ,还可以进一步展开到输入层(替换掉 a1(2),a2(2),a3(2) 即可),最后可得: 代价函数 E(i) 仅和权重矩阵 W(l) 和偏置向量 b(l) 相关,调整权重和偏置可以减少或增大代价(误差)。

显然,所有训练数据的总体(平均)代价可写为:
Etotal=1Ni=1NE(i)

我们是目标就是调整权重和偏置使总体代价(误差)变小,求得总体代价取最小值时对应的各个神经元的参数(即权重和偏置)。

如果采用梯度下降法(这里其实是“批量梯度下降法”,除此外还可以采用“随机梯度下降法”),可以用下面公式更新参数 wij(l),bi(l),2lL
W(l)=W(l)μEtotalW(l)=W(l)μNi=1NE(i)W(l)b(l)=b(l)μEtotalb(l)=b(l)μNi=1NE(i)b(l)

由上面公式知,只需求得每一个训练数据的代价函数 E(i) 对参数的偏导数 E(i)W(l),E(i)b(l) 即可得到参数的迭代更新公式。

为简单起见,在下文的推导中,我们去掉 E(i) 的下标,直接记为 E (要理解它是单个训练数据的误差)。

下面将介绍用“反向传播算法”求解单个训练数据误差对参数的偏导数 EW(l)Eb(l) 的过程。我们求解一个简单的情况:图 1 所示神经网络,最后再归纳出通用公式。

参考:
How the backpropagation algorithm works: http://neuralnetworksanddeeplearning.com/chap2.html
Backpropagation Algorithm: http://deeplearning.stanford.edu/wiki/index.php/Backpropagation_Algorithm

3.1. 输出层的权重参数更新

E 展开到隐藏层,有:
E=12yo=12ya(3)=12((y1a1(3))2+(y2a2(3))2)=12((y1f(z1(3)))2+(y2f(z2(3)))2)=12((y1f(w11(3)a1(2)+w12(3)a2(2)+w13(3)a3(2)+b1(3)))2+(y2f(w21(3)a1(2)+w22(3)a2(2)+w23(3)a3(2)+b2(3)))2)

由求导的链式法则,对“输出层神经元的权重参数”求偏导,有:
Ew11(3)=122(y1a1(3))(a1(3)w11(3))=(y1a1(3))f(z1(3))z1(3)w11(3)=(y1a1(3))f(z1(3))a1(2)

如果我们把 Ezi(l) 记为 δi(l) ,即规定下面定义:
δi(l)Ezi(l)
Ew11(3) 显然可以写为:
Ew11(3)=Ez1(3)z1(3)w11(3)=δ1(3)a1(2)

其中: δ1(3)=Ez1(3)=Ea1(3)a1(3)z1(3)=(y1a1(3))f(z1(3))

对于输出层神经元的其它权重参数,同样可求得:
Ew12(3)=δ1(3)a2(2)Ew13(3)=δ1(3)a3(2)Ew21(3)=δ2(3)a1(2)Ew22(3)=δ2(3)a2(2)Ew23(3)=δ2(3)a3(2)
其中, δ2(3)=(y2a2(3))f(z2(3))

说明: 之所以要引入记号 δi(l) ,除了它能简化 Ewij(l)Ebi(l) 的表达形式外;更重要的是我们可以通过 δi(l+1) 来求解 δi(l) (后文将说明),这样可以充分利用之前计算过的结果来加快整个计算过程。

推广到一般情况,假设神经网络共 L 层,则:
δi(L)=(yiai(L))f(zi(L))(1inL)Ewij(L)=δi(L)aj(L1)(1inL,1jnL1)

如果把上面两式表达为矩阵(向量)形式,则为:
δ(L)=(ya(L))f(z(L))W(L)E=δ(L)(a(L1))T

注:符号 表示 Element-wise Product Operator,又称作 Hadamard product 。规则简单,把对应位置的元素分别相乘即可。如:
(a11a12a21a22a31a32)(b11b12b21b22b31b32)=(a11b11a12b12a21b21a22b22a31b31a32b32)

向量式子 δ(L)=(ya(L))f(z(L)) 在前面的例子中,表达的就是这两个式子:
δ1(3)=(y1a1(3))f(z1(3))δ2(3)=(y2a2(3))f(z2(3))

3.2. 隐藏层的权重参数更新

对“隐藏层神经元的权重参数”求偏导,利用 δi(l) 的定义,有:
Ewij(l)=Ezi(l)zi(l)wij(l)=δi(l)zi(l)wij(l)=δi(l)aj(l1)

其中 δi(l),2lL1 的推导如下:
δi(l)Ezi(l)=j=1nl+1Ezj(l+1)zj(l+1)zi(l)=j=1nl+1δj(l+1)zj(l+1)zi(l)

上面式子中为什么有 Ezi(l)=j=1nl+1Ezj(l+1)zj(l+1)zi(l) 呢?其实利用的仅是“函数之和的求导法则”及“求导的链式法则”。如果把 E 从后往前展开,当展开到 l+1 层时, E 可看作是 z(l+1) 的函数;如果再往前展开一层到 l 层, E 可看作是 z(l) 的函数。 El 层的某个 zi(l) 求导时, 由于 l+1 层的每个神经元都和 zi(l) 所在神经元有连接,所以在函数 E 中,自变量 zi(l) 出现了 nl+1 次,出现的每一次对应一个 zj(l+1),1jnl+1 ,从而由“函数之和的求导法则”及“求导的链式法则”有:
Ezi(l)=Ez1(l+1)z1(l+1)zi(l)+Ez2(l+1)z2(l+1)zi(l)++Eznl+1(l+1)znl+1(l+1)zi(l)=j=1nl+1Ezj(l+1)zj(l+1)zi(l)

上面的推导过程可以从图 2 中更清楚地展示出来。

BP_delta.png

Figure 2: δ(l+1)δi(l)

看一个简单的特例,如在图 1 所示神经网络中,有 Ez1(2)=j=12Ezj(3)zj(3)z1(2)

由于 zj(l+1)=i=1nlwji(l+1)ai(l)+bj(l+1)=i=1nlwji(l+1)f(zi(l))+bj(l+1) ,所以有 zj(l+1)zi(l)=zj(l+1)ai(l)ai(l)zi(l)=wji(l+1)f(zi(l)) ,代入到前面计算的 δi(l) 式中,从而有:
δi(l)=j=1nl+1δj(l+1)wji(l+1)f(zi(l))=(j=1nl+1δj(l+1)wji(l+1))f(zi(l))

上式是 BP 算法最核心的公式。它利用 l+1 层的 δ(l+1) 来计算 l 层的 δ(l) ,这就是“误差反向传播算法”名字的由来。 如果把它表达为矩阵(向量)形式,则为:
δ(l)=((W(l+1))Tδ(l+1))f(z(l))

利用上面推导出来的隐藏层通用公式,对于图 1 所示神经网络,有:
Ew11(2)=(δ1(3)w11(3)+δ2(3)w21(3))f(z1(2))a1(1)Ew12(2)=(δ1(3)w11(3)+δ2(3)w21(3))f(z1(2))a2(1)Ew13(2)=(δ1(3)w11(3)+δ2(3)w21(3))f(z1(2))a3(1)Ew21(2)=(δ1(3)w12(3)+δ2(3)w22(3))f(z2(2))a1(1)Ew22(2)=(δ1(3)w12(3)+δ2(3)w22(3))f(z2(2))a2(1)Ew23(2)=(δ1(3)w12(3)+δ2(3)w22(3))f(z2(2))a3(1)Ew31(2)=(δ1(3)w13(3)+δ2(3)w23(3))f(z3(2))a1(1)Ew32(2)=(δ1(3)w13(3)+δ2(3)w23(3))f(z3(2))a2(1)Ew33(2)=(δ1(3)w13(3)+δ2(3)w23(3))f(z3(2))a3(1)

通过把 E 继续展开到输入层可以验证上面这些式子:
E=12yo=12ya(3)=12((y1a1(3))2+(y2a2(3))2)=12((y1f(z1(3)))2+(y2f(z2(3)))2)=12((y1f(w11(3)a1(2)+w12(3)a2(2)+w13(3)a3(2)+b1(3)))2+(y2f(w21(3)a1(2)+w22(3)a2(2)+w23(3)a3(2)+b2(3)))2)=12((y1f(w11(3)f(z1(2))+w12(3)f(z2(2))+w13(3)f(z3(2))+b1(3)))2+(y2f(w21(3)f(z1(2))+w22(3)f(z2(2))+w23(3)f(z3(2))+b2(3)))2)=12(y1f(w11(3)f(w11(2)a1(1)+w12(2)a2(1)+w13(2)a3(1)+b1(2))+w12(3)f(w21(2)a1(1)+w22(2)a2(1)+w23(2)a3(1)+b2(2))+w13(3)f(w31(2)a1(1)+w32(2)a2(1)+w33(2)a3(1)+b3(2))+b1(3)))2+12(y2f(w21(3)f(w11(2)a1(1)+w12(2)a2(1)+w13(2)a3(1)+b1(2))+w22(3)f(w21(2)a1(1)+w22(2)a2(1)+w23(2)a3(1)+b2(2))+w23(3)f(w31(2)a1(1)+w32(2)a2(1)+w33(2)a3(1)+b3(2))+b2(3)))2

上式中, ai(1)=xi ,也就是某个训练数据的第 i 个维度,可参考图 1 中的表示。

3.3. 输出层和隐藏层的偏置参数更新

Ebi(l)=Ezi(l)zi(l)bi(l)=δi(l)
对应的矩阵(向量)形式为:
b(l)E=δl

3.4. BP 算法四个核心公式

前面已经完整地介绍了误差反向传播算法,可总结为下面四个公式:

(BP-1)δi(L)=(yiai(L))f(zi(L))(BP-2)δi(l)=(j=1nl+1δj(l+1)wji(l+1))f(zi(l))(BP-3)Ewij(l)=δi(l)aj(l1)(BP-4)Ebi(l)=δi(l)

这四个公式可以写成对应的矩阵(向量)形式:

(BP-1)δ(L)=(ya(L))f(z(L))(BP-2)δ(l)=((W(l+1))Tδ(l+1))f(z(l))(BP-3)EW(l)=δ(l)(a(l1))T(BP-4)Eb(l)=δl

或者表示为:

(BP-1)δ(L)=(ya(L))f(z(L))(BP-2)δ(l)=((W(l+1))Tδ(l+1))f(z(l))(BP-3)W(l)E=δ(l)(a(l1))T(BP-4)b(l)E=δl

3.5. BP 算法计算某个训练数据的代价函数对参数的偏导数

BP 算法四个核心公式就是求某个训练数据的代价函数对参数的偏导数,它的具体应用步骤总结如下:

第一步,初始化参数 W,b
一般地,把 wij(l),bi(l),2lL 初始化为一个很小的,接近于零的随机值。
注意:不要把 wij(l),bi(l),2lL 全部初始化为零或者相同的其它值,这会导致对于所有 iwij(l) 都会取相同的值。

参考:http://deeplearning.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95

第二步,利用下面的“前向传播”公式计算每层的状态和激活值:
z(l)=W(l)a(l1)+b(l)a(l)=f(z(l))

第三步,计算 δ(l)
首先,利用下面公式计算输出层的 δ(L)
δi(L)=(yiai(L))f(zi(L)),(1inL)
其中, yi 是期望的输出(这是训练数据给出的已知值), ai(L) 是神经网络对训练数据产生的实际输出。
然后,利用下面公式从第 L1 层到第 2 层依次计算隐藏层的 δ(l),(l=L1,L2,L3,,2)
δi(l)=(j=1nl+1δj(l+1)wji(l+1))f(zi(l)),(1inl)

第四步,按下面公式求这个训练数据的代价函数对参数的偏导数:
Ewij(l)=δi(l)aj(l1)Ebi(l)=δi(l)

工程实现中注意事项:
在前面传播的过程中,我们已经计算出了所有的 ai(l) ,反向传播过程中的 f(zi(l)) 可以直接利用 ai(l) 来计算。
假设使用的激活函数为 f(x)=11+ex ,则 f(x)=2×1(1+ex)2×ex×(1)=2ex(1+ex)2 ,容易验证它又等于 f(x)(1f(x)) ,因此: f(zi(l))=ai(l)(1ai(l))

3.5.1. 反向传播中偏导数计算实例

3.6. BP 算法总结:用“批量梯度下降”算法更新参数

“批量梯度下降”算法更新参数的总结如下:
(1) 用 BP 算法四个核心公式求得每一个训练数据的代价函数对参数的偏导数;
(2) 按下面公式更新参数:
W(l)=W(l)μNi=1NE(i)W(l)b(l)=b(l)μNi=1NE(i)b(l)
(3) 迭代执行第(1),(2)步,直到满足停止准则(比如相邻两次迭代的误差的差别很小,或者直接限制迭代的次数)。

说明:每对参数进行一次更新都要遍历整个训练数据集,当训练数据集不大时这不是问题,当训练数据集非常巨大时,可以采用“随机梯度下降法”(每次仅使用一个训练数据来更新参数)。

4. 梯度消失问题及其解决办法

前面介绍过,误差反向传播有下面迭代公式:
δi(l)=(j=1nl+1δj(l+1)wji(l+1))f(zi(l))
其中用到了激活函数 f(x) 的导数。误差从输出层反向传播时,在每一层都要乘以激活函数 f(x) 的导数。

如果我们使用 σ(x)tanh(x) 作为激活函数,则其导数为:
σ(x)=σ(x)(1σ(x))[0,0.25]tanh(x)=1(tanh(x))2[0,1]

可以看到,它们的导数的值域都会小于 1。这样,误差经过每一层传递都会不断地衰减。 当网络导数比较多时,梯度不断地衰减,甚至消失,这使得整个网络很难训练。这就是梯度消失问题(Vanishing gradient problem)。

减轻梯度消失问题的一个方法是使用线性激活函数(比如 rectifier 函数)或近似线性函数(比如 softplus 函数)。这样,激活函数的导数为 1,误差可以很好地传播,训练速度会提高。

参考:
神经网络与深度学习讲义(邱锡鹏)

Author: cig01

Created: <2015-12-25 Fri>

Last updated: <2018-07-19 Thu>

Creator: Emacs 27.1 (Org mode 9.4)