反向传播算法工作原理
在上一篇文章,我们看到了神经网络如何通过梯度下降算法学习,从而改变权重和偏差。但是,前面我们并没有讨论如何计算代价函数的梯度,这是一个很大的遗憾。这一篇文章,我们将介绍一种称为反向传播的快速计算梯度的算法。
使用反向传播算法学习的神经网络比其他早期的方法要快很多,这使得使用神经网络可以解决之前不能解决的问题。如今,反向传播算法是神经网络中最重要的组成部分。
你完全可以忽略反向传播算法,把它当作一个黑盒子去使用神经网络。那么我们为什需要详细的了解这个算法呢?这当然是为了理解神经网络的学习过程。反向传播算法的核心是一个对于任何权重或者偏差计算其关于代价函数的偏导数的表达式。这个表达式告诉我们改变权重和偏差时,代价函数的变化快慢。虽然这个表达式很复杂,但是它却有自己的数学之美,每一个元素拥有一个自然的直观解释。因此反向传播不仅仅是为了学习的一个快速算法,它实际上给了我们一个视角去深入了解在改变权重和偏差时,网络整体的行为的变化。这才是我们详细了解反向传播算法的意义所在。
热身:一种基于矩阵计算神经网络输出的快速方法
在讨论反向传播算法之前,我们使用一种基于矩阵的计算神经网络输出的快速方法来做预热。这可以让我们在学习反向传播时更加熟悉各种记号和表示方法。
首先我们给出权重一个清楚的记号。我们将使用 wljk 来定义 (l−1) 层第 k 个神经元到第
l 层第 j 个神经元之间的权重。比如,下图展示了第2层第4个神经元到第3层第2个神经元之间的权重:
这个记号刚开始很绕,需要一点时间熟悉。经过一段时间的掌握一会发现这样的表达很简单自然。这个记号很别扭的地方在于j和k的顺序,你可能和我一样刚开始觉得j和k的位置需要换一下更舒服,但是下面我将告诉你为什么这样做。
我们对于网络的激活值(神经元的输出值)和偏差采用类似的记号。我们使用
blj 来表示第 l 层第j 个神经元的偏差,用 alj 来表示第 l 层第j 个神经元的激活值。下图展示了一个例子:
有了这些记号,激活值 alj 可以由第 l−1 层的激活值来计算:
其中求和是对第 l−1 层所有神经元进行的。为了使用矩阵重写上面的表达式,我们对每一层 l ,都定义了一个权值矩阵
wl ,矩阵中的每一个元素表示的是连接到第 l 层神经元的权值,也就是说第j 行 k 列的元素的值正是wljk 。同样的,我们对每一层都定义一个偏差矩阵(向量) bl 。我想你可以自己给出它的定义,显然它是一个只有一列多行的矩阵,它的组成元素表达的值就是上段中的 blj 。最后我们同样给出激活矩阵(向量) al ,它的每一个元素的值为 alj 。最后我们需要引入向量化函数(如 σ ),用矩阵的方式重写公式(23)。其实在上一篇文章中我们已经接触到向量化了,它的思想就是应用函数到向量中的每一个元素中。前面我们曾使用 σ(v) 来表示这种对每个元素进行函数求值的计算过程。举个例子,如果我们给定一个函数 f(x)=x2 ,那么对给定向量之后的计算过程为:
即,向量化 f 就是对向量中所有元素进行平方计算。
有了这些定义,公式(23)就可以重写为下面这个美妙而简介的向量形式了:
这个表达式让我们可以在全局范围内审视某一层的激活值与其前一层激活值的关系:我们仅仅对前一层的激活值乘以权值,并加上偏差,最后在应用
σ 函数。(这里其实可以解释前面j和k的顺序的问题,如果我们对调j和k的顺序,那么这里在作 wlal−1 时,就应该是 wl 矩阵的转置矩阵来运算)。这种全局层面的表达式要比使用神经元层面的表达式更加简单简洁。在实践中,表达式同样很有⽤,因为⼤多数矩阵库提供了实现矩阵 乘法、向量加法和向量化的快速方法。实际上,上篇文章的代码其实已经隐式使用了这种表达式来计算网络行为。当使用公式(25)去计算 al 时,我们需要计算中间量 zl=wlal−1+bl 。这个值是非常有用的,我们称之为: zl 为第 l 层神经元的带权输入。在后面的章节中,我们将大量使用带权输入
zl 。等式(25)因此可以简写为 al=