0%

反向传播算法

反向传播(英语:Backpropagation,缩写为BP)是“误差反向传播”的简称,是一种与最优化方法(如梯度下降法)结合使用的,用来训练人工神经网络的常见方法。该方法计算对网络中所有权重计算损失函数的梯度。这个梯度会反馈给最优化方法,用来更新权值以最小化损失函数。 在神经网络上执行梯度下降法的主要算法。该算法会先按前向传播方式计算(并缓存)每个节点的输出值,然后再按反向传播遍历图的方式计算损失函数值相对于每个参数的偏导数。

相关资源:

  1. 喜欢研究代码的朋友可以查看我的GitHub 基于Numpy的反向传播算法代码实现
  2. 深度学习框架自动求导和梯度下降的原理

反向传播概述

反向传播算法最初在 1970 年代被提及,但是人们直到 David Rumelhart、Geoffrey Hinton 和 Ronald Williams 的著名的 1986 年的论文中才认识到这个算法的重要性。

反向传播的核心是一个对代价函数 $C$ 关于任何权重 $w$ 和 偏置 $b$ 的偏导数 $\partial{C}/\partial{w}$ 的表达式。

这个表达式告诉我们在改变权重和偏置时,代价函数变化的快慢。

关于代价函数的两个假设

  1. 代价函数可以被写成在每一个训练样本 $x$ 上的代价函数 $C_x$ 的均值 $C=\frac{1}{n}\sum_{x}C_x$。

  2. 代价函数可以写成神经网络输出的函数。

需要假设1的原因是,反向传播实际上是对一个独立的训练样本计算了 $\partial{C_x}/\partial{w}$ 和 $\partial{C_x}/\partial{b}$。然后通过在所有训练样本上进行平均化获得 $\partial{C}/\partial{w}$ 和 $\partial{C}/\partial{w}$ 。

需要假设2的原因是,要把代价函数与神经网络输出联系起来,进而与神经网络的参数联系起来。

符号定义

$W_{jk}^{l}$ 是从 $l-1$ 层的第 $k$ 个神经元到 $l$ 层的第 $j$ 个神经元的权重。

$b_j^l$ 是第 $l$ 层的第 $j$ 个神经元的偏置。

$a_j^l$ 是第 $l$ 层的第 $j$ 个神经元的激活值。

$\sigma$ 是激活函数。

把上面的符号向量化

$W^{l}$ 是权重矩阵,第 $j$ 行 $k$ 列的元素是 $W_{jk}^{l}$。

例如第二层与第三层之间的权重矩阵是

$b^l$ 是偏置向量。第 $j$ 行的元素是 $b_j^l$。

例如第二层的偏置向量是

有了这些表示 $l$ 层的第 $j$ 个神经元的激活值 $a_j^l$ 就和 $l-1$ 层的激活值通过方程关联起来了

把上面式子向量化

例如第三层的激活向量是

$a^{l}$ 是激活向量。第 $j$ 行的元素是 $a_j^l$。

定义

则 $a^l =\sigma(z^l)$

$z^l$ 表示第第 $l$ 层的带权输入。第 $j$ 个元素是 $z_j^l$。

$z_j^l$ 是第 $l$ 层的第 $j$ 个神经元的带权输入。

反向传播的核心是一个对代价函数 $C$ 关于任何权重 $w$ 和 偏置 $b$ 的偏导数 $\partial{C}/\partial{w}$ 的表达式。为了计算这些值,引入一个中间量 $\delta_j^l$ ,表示在 $l$ 层的第 $j$ 个神经元的误差。

定义

$\delta^l$ 是误差向量,$\delta^l$ 的第 $j$ 个元素是 $\delta_j^l$。

反向传播的四个基本方程

$\nabla_a$ 是求梯度运算符,$\nabla_a C$ 结果是一个向量,其元素是偏导数 $\partial C / \partial a^L_j$。

$\odot$ 是按元素乘积的运算符,$ {(s \odot t)}_j = s_j t_j $ ,例如

计算公式 维度变化
$\delta^L =\nabla_a C\odot \dfrac{\partial f^{(L)}}{\partial z^L} $ $(d^L, 1) = (d^L, 1) * (d^L, 1)$
$\delta^{(l)} =({(w^{(l+1)})}^T\delta^{(l+1)})\odot \sigma’(z^l) $ $(d^l, 1) = {({d}^{l+1}, {d}^{l})}^T (d^{l+1}, 1) * (d^l, 1)$
$\dfrac{\partial C}{\partial b^{(l)}} =\delta^{(l)}$ $(d^l, 1) = (d^l, 1)$
$\dfrac{\partial C}{\partial w^l} = \delta^l (a^{l-1})^T $ $(d^l, d^{l-1}) = (d^l,1) {(d^{l-1}, 1)}^T$

反向传播算法

正如我们上面所讲的,反向传播算法对一个训练样本计算代价函数的梯度,$C=C_x$。在实践中,通常将反向传播算法和诸如随机梯度下降这样的学习算法进行组合使用,我们会对许多训练样本计算对应的梯度。特别地,给定一个大小为 m 的小批量数据,下面的算法在这个小批量数据的基础上应用梯度下降学习算法:

反向传播算法与小批量随机梯度下降算法结合的一个示意代码,完整代码参看 network.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def backprop(self, x, y):
"""Return a tuple ``(nabla_b, nabla_w)`` representing the
gradient for the cost function C_x. ``nabla_b`` and
``nabla_w`` are layer-by-layer lists of numpy arrays, similar
to ``self.biases`` and ``self.weights``."""
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w = [np.zeros(w.shape) for w in self.weights]
# feedforward
activation = x
activations = [x] # list to store all the activations, layer by layer
zs = [] # list to store all the z vectors, layer by layer
for b, w in zip(self.biases, self.weights):
z = np.dot(w, activation)+b
zs.append(z)
activation = sigmoid(z)
activations.append(activation)
# backward pass
delta = self.cost_derivative(activations[-1], y) * \
sigmoid_prime(zs[-1])
nabla_b[-1] = delta
nabla_w[-1] = np.dot(delta, activations[-2].transpose())
# Note that the variable l in the loop below is used a little
# differently to the notation in Chapter 2 of the book. Here,
# l = 1 means the last layer of neurons, l = 2 is the
# second-last layer, and so on. It's a renumbering of the
# scheme in the book, used here to take advantage of the fact
# that Python can use negative indices in lists.
for l in range(2, self.num_layers):
z = zs[-l]
sp = sigmoid_prime(z)
delta = np.dot(self.weights[-l+1].transpose(), delta) * sp
nabla_b[-l] = delta
nabla_w[-l] = np.dot(delta, activations[-l-1].transpose())
return (nabla_b, nabla_w)
1
2
3
4
5
6
7
8
def cost_derivative(self, output_activations, y):
"""Return the vector of partial derivatives \partial C_x /
\partial a for the output activations."""
return (output_activations-y)

def sigmoid_prime(z):
"""Derivative of the sigmoid function."""
return sigmoid(z)*(1-sigmoid(z))

四个基本方程的证明

我们现在证明这四个基本的方程(BP)-(BP4)。所有的这些都是多元微积分的链式法则的推论。

证明$\delta^L = \nabla_a C \odot \sigma’(z^L)$

从方程(BP1)开始,它给出了误差 $\delta^l$ 的表达式。根据定义

根据关于代价函数的两个假设2 “代价函数可以写成神经网络输出的函数”,应用链式法测可知可先对神经网络输出求偏导${\partial C}/{\partial a^L_k}$再对带权输出求偏导${\partial a^L_k}/{\partial z^L_j}$。

看起来上面式子很复杂,但是由于第 $k$ 个神经元的输出激活值 $a_k^l$ 只依赖于 当下标 $k=j$ 时第 $j$ 个神经元的输入权重 $z_j^l$。所有当 $k\neq {j}$ 时 $\partial a^L_k / \partial z^L_j$ 消失了。结果我们可以简化上一个式子为

又因为 $a^L_j = \sigma(z^L_j)$ 所以 $\frac{\partial a^L_j}{\partial z^L_j}$ 可以写成 $\sigma’(z^L_j)$,方程变为

这就是分量形式的(BP1),再根据$\nabla_a$ 是求梯度运算符,$\nabla_a C$ 结果是一个向量,其元素是偏导数 $\partial C / \partial a^L_j$。方程可以写成向量形式

(BP1) 得到证明。

证明 $ \delta^l = ((w^{l+1})^T \delta^{l+1}) \odot \sigma’(z^l)$

证明(BP2),它个给出以下一层误差 $\delta^{l+1}$ 的形式表示误差 $\delta^l$。为此,要以 $\delta^l_j = \partial C / \partial z^l_j$的形式重写 $\delta^{l+1}_k = \partial C / \partial z^{l+1}_k$,$\delta^{l+1}$ 和 $\delta^l$ 通过 $z_k^{l+1}$ 和 $z_j^l$ 联系起来,应用链式法测

根据 $z_k^{l+1}$ 的定义有

$z_k^{l+1}$ 对 $z_j^{l}$ 做偏微分,得到

注意虽然$z^{l+1}$ 和 $z^{l}$ 所在的两层神经元连接错综复杂,但两层之间任意一对神经元(同一层内不连接)只有一条连接,即 $z_k^{l+1}$ 和 $z_j^{l}$ 之间只通过 $w_{kj}^{l+1}$ 连接。所以$z_k^{l+1}$ 对 $z_j^{l}$ 做偏微分的结果很简单,只是 $ w^{l+1}_{kj} \sigma’(z^l_j)$。把这个结果带入 $\delta_j^l$ 中

这正是以分量形式写的(BP2)。

写成向量形式

举例

(BP2) 得到证明。

证明 $\frac{\partial C}{\partial b^l_j} =\delta^l_j.$

根据 $z_j^l$ 定义

和 $\delta_j^l$ 定义

因此

又因为

所以

写成向量形式

(BP3) 得到证明。

证明 $\frac{\partial C}{\partial w^l_{jk}} = a^{l-1}_k \delta^l_j$

根据 $z_j^l$ 定义

和 $\delta_j^l$ 定义

又因为

所以

把式子向量化

举例

(BP4) 得到证明。

一个直观的图:

到此关于反向传播的四个方程已经全部证明完毕。

其他学者反向传播四个方程的证明(他写的更简明扼要些):CSDN: oio328Loio

矩阵形式反向传播算法

正如我们上面所讲的,反向传播算法对一个训练样本计算代价函数的梯度,$C=C_x$。在实践中,通常将反向传播算法和诸如随机梯度下降这样的学习算法进行组合使用,我们会对许多训练样本计算对应的梯度。特别地,给定一个大小为 m 的小批量数据,下面的算法在这个小批量数据的基础上应用梯度下降学习算法:

根据上面的小批量数据的符号定义,为了方便用矩阵表示,下面新增了一些符号。

$z^{v,l}$ 表示神经网络第 $l$ 层的小批量样本中的第 $v$ 个样本的带权输入向量,用矩阵 $Z^l$ 来表示就是

$a^{v,l}$ 表示神经网络第 $l$ 层的小批量样本中的第 $v$ 个样本的激活向量,用矩阵 $A^l$ 来表示就是

$\delta^{v,l}$ 表示神经网络第 $l$ 层的小批量样本中的第 $v$ 个样本的误差向量,用矩阵 $\Delta^l$ 来表示就是


的矩阵形式是,


的矩阵形式是,


的矩阵形式是,


的矩阵形式是,

归纳一下,可以得到矩阵形式的反向传播算法:

计算公式 维度变化
$\Delta^L =\nabla_{A^L} C\odot \dfrac{\partial f^{(L)}}{\partial Z^L}$ $(m, d^L) = (m, d^L) * (m, d^L)$
$\Delta^{l} =(\Delta^{l+1}W^{l+1})\odot \sigma’(Z^l)$ $(m, {d}^l) = (m, {d}^{l+1}) ({d}^{l+1}, {d}^l)$
$\dfrac{\partial C}{\partial b^{(l)}} =\dfrac{1}{m}{(sum(\Delta^l, axis=0))}^T$ $(d^l, 1) = {(1, d^l)}^T$
$\dfrac{\partial C}{\partial w^{(l)}} =\dfrac{1}{m}{(\Delta^l)}^TA^{l-1} $ $(d^{l}, d^{l-1}) = {(m, d^l)}^T(m, d^{l-1})$

反向传播:全局观

如上图所示,假设我们对 $w_{jk}^l$ 做一点微小的扰动 $\Delta w_{jk}^l$, 这个扰动会沿着神经网络最终影响到代价函数 $C$, 代价函数的 $\Delta C$ 改变和 $\Delta w_{jk}^l$ 按照下面公式联系起来

可以想象影响代价函数的一条路径是

为了计算 $C$ 的全部改变,我们需要对所有可能的路径进行求和,即

因为

根据上面的三个式子可知

上面的公式看起来复杂,这里有一个相当好的直觉上的解释。我们用这个公式计算 $C$ 关于网络中一个权重的变化率。而这个公式告诉我们的是:两个神经元之间的连接其实是关联于一个变化率因子,这仅仅是一个神经元的激活值相对于其他神经元的激活值的偏导数。路径的变化率因子就是这条路径上众多因子的乘积。整个变化率 $\partial C / \partial w^l_{jk}$ 就是对于所有可能从初始权重到最终输出的代价函数的路径的变化率因子的和。针对某一路径,这个过程解释如下,

如果用矩阵运算对上面式子所有的情况求和,然后尽可能化简,最后你会发现,自己就是在做反向传播!可以将反向传播想象成一种计算所有可能路径变化率求和的方式。或者,换句话说,反向传播就是一种巧妙地追踪权重和偏置微小变化的传播,抵达输出层影响代价函数的技术。

如果你尝试用上面的思路来证明反向传播,会比本文的反向传播四个方程证明复杂许多,因为按上面的思路来证明有许多可以简化的地方。其中可以添加一个巧妙的步骤,上面方程的偏导对象是类似 $a_q^{l+1}$ 的激活值。巧妙之处是改用加权输入,例如 $z_q^{l+1}$ ,作为中间变量。如果没想到这个主意,而是继续使用激活值 $a_q^{l+1}$ ,你得到的证明最后会比前文给出的证明稍稍复杂些。

其实最早的证明的出现也不是太过神秘的事情。因为那只是对简化证明的艰辛工作的积累!

发展分析

瓶颈
BP神经网络无论在网络理论还是在性能方面已比较成熟。其突出优点就是具有很强的非线性映射能力和柔性的网络结构。网络的中间层数、各层的神经元个数可根据具体情况任意设定,并且随着结构的差异其性能也有所不同。但是BP神经网络也存在以下的一些主要缺陷。

  • 学习速度慢,即使是一个简单的问题,一般也需要几百次甚至上千次的学习才能收敛。
  • 容易陷入局部极小值。
  • 网络层数、神经元个数的选择没有相应的理论指导。
    网络推广能力有限。
  • 可解释性瓶颈,对网络输出结果不具备可靠的数学可解释性
  • 神经网络对推理,规划等人工智能领域的其他问题还没有特别有效的办法。另外由于其参数数量巨大,对高计算性能硬件的依赖大,难以部署在轻量级低功耗硬件上,如嵌入式设备等
  • 反向传播算法缺乏仿生学方面的理论依据,显然生物神经网络中并不存在反向传播这样的数学算法

未来发展方向
BP网络主要用于以下四个方面。

  1. 函数逼近:用输入向量和相应的输出向量训练一个网络逼近一个函数。
  2. 模式识别:用一个待定的输出向量将它与输入向量联系起来。
  3. 分类:把输入向量所定义的合适方式进行分类。
  4. 数据压缩:减少输出向量维数以便于传输或存储。

除此之外,在神经网络的可解释性研究方面,向低功耗硬件迁移,以及在认知计算,规划推理等方面和其他传统技术进行结合探索


参考文献

[1] Michael Nielsen. CHAPTER 2 How the backpropagation algorithm works[DB/OL]. http://neuralnetworksanddeeplearning.com/chap2.html, 2018-06-21.

[2] Zhu Xiaohu. Zhang Freeman.Another Chinese Translation of Neural Networks and Deep Learning[DB/OL]. https://github.com/zhanggyb/nndl/blob/master/chap2.tex, 2018-06-21.

[3] oio328Loio. 神经网络学习(三)反向(BP)传播算法(1)[DB/OL]. https://blog.csdn.net/hoho1151191150/article/details/79537246, 2018-06-25.

[4] 机器之心. 反向传播算法 [DB/OL]. https://www.jiqizhixin.com/graph/technologies/7332347c-8073-4783-bfc1-1698a6257db3, 2019-08-04.

本站所有文章和源码均免费开放,如您喜欢,可以请我喝杯咖啡