2.9 反向传播
理解反向传播(Backpropagation)算法可能需要一些时间,读者也可以跳过本节内容,因为很多软件库都具有自动区分和执行整个训练过程的能力。但是,理解这个算法肯定会让你深入了解与深度学习相关的问题(学习问题、缓慢学习、梯度爆炸、梯度下降)。
让我们首先看一张典型的神经网络结构图,如图2-15所示。
图2-15 神经网络结构图
图2-15是一个包含了输入层L1、隐藏层L2和输出层L3的简单神经网络,它的处理流程为根据输入层的input以及相应的权重值和配置(图中黑色带箭头的边),通过隐藏层的加工,最终将结果映射到输出层得到结果的输出。模型可以抽象表示为y=f(x),x,y分别表示输入和输出向量。
根据神经网络的处理流程,我们如果要得到输出y,就必须知道图2-15中每条边的参数值,这也是神经网络中最重要的部分。在神经网络中是通过迭代的方法来计算这些参数的,具体来讲就是,首先初始化这些参数,通过神经网络的前向传导过程来计算得到输出y,但这些值与真实值存在着误差,我们假设累计误差函数为err(x),然后利用梯度方法极小化err(x)来更新参数,直至误差值达到符合要求而停止计算。在更新参数这一过程中,我们就用到了著名的反向传播算法。
为了更好地去说明神经网络的传播算法,我们这里取图2-15中的一条路径来做说明,但这不失一般性,假设路径如图2-16所示。
图2-16 神经网络传播路径示例
图2-16中的边表示偏导数,如α=(∂Y⁄∂X)。
想要知道输入X对输出Z的影响,我们可以用偏导数(∂Z⁄∂X)=(∂Z⁄∂Y)⋅(∂Y⁄∂X),即:
我们如果直接使用链式法则进行求导就会遇到一个问题,当路径数量增加时,式(2.5)中的子项目数会呈指数增长,所以这时我们需要把上式右侧部分进行合并,合并后,我们只需要进行一次乘法就可以获得所需要的结果,这样大幅度提升了模型的运算效率,合并后的式子如下:
接下来,我们解决式(2.6)的实现问题。根据计算方向的不同,可以分为正向微分与反向微分。我们先看针对图2-16的正向微分算法,如图2-17所示。
图2-17 正向微分算法
可以看到,正向微分算法根据路径的传播方向,依次计算路径中的各结点对输入X的偏导数,结果中保留了输入对各结点的影响。
下面,我们看一下反向微分算法(见图2-18)。
图2-18 反向微分算法
可以看到,该算法从后向前进行计算,结果中保留了路径中各结点对输出的影响。
这里就有一个问题了,既然正向反向都可以实现式(2.6)的计算,那么我们应该选择哪个算法来实现呢?答案是反向微分算法,理由如下:
首先我们看一个计算式子e=(a+b)∗(b+1)的图模型(见图2-19)。
图2-19 图模型计算示例
其中,c,d表示中间结果,边的方向表示一个结点是另一个结点的输入。
假设输入变量a=2、b=1,图2-19中各结点的偏导计算结果如图2-20所示。
图2-20 利用正向微分算法得到各结点的偏导计算结果
利用正向微分算法,我们得到关于变量b的偏导计算结果如图2-21所示。
图2-21 利用正向微分算法得到变量b的偏导计算结果
利用反向微分算法,我们得到的偏导计算结果如图2-22所示。
图2-22 利用反向微分算法得到的偏导计算结果
由此可见,反向微分算法保留了所有变量(包括中间变量)对结果e的影响。若e为误差函数,则对图进行一次计算,可以得出所有结点对e的影响,也就是梯度值,下一步就可以利用这些梯度值来更新边的权重值了;而正向微分算法得到的结果是只保留了一个输入变量对误差e的影响,显然,想要获得多个变量对e的影响,我们就需要进行多次计算。所以正向微分算法在效率上明显不如反向微分,这也是我们选择反向微分算法的原因。