数值微分的速度太慢
上一章我们用数值微分的方法计算梯度,每计算一个点(参数矩阵中的一个元素,即一个参数),我们都要做两次预测操作(算出一前一后两个微小变化处的函数值),再做两次算术运算(两个函数值做差,再除以2 * h)——这太慢了。
利用知识降低复杂度
降低复杂度的撒手锏是知识。如果能发现问题内在的数学规律,也就是比较深刻地理解问题,则可以极大地降低计算复杂度。我们的数值微分方法是直接依照导数的定义式编写的,没有利用具体函数的信息。如果结合具体函数,就可以利用微积分知识得到导函数,即斜率关于输入(或输出)的函数。在这个问题中,得到梯度的解析解之后,求梯度的速度可以大大加快。
反向传播的动因
我们的想法是,利用解析解为求解提速。神经网络的损失是输入和网络参数的函数,取一批训练样本作为输入,把参数视为变量,可以对它们求导。损失函数再复杂(神经网络层数越多,损失函数越复杂)也是若干仿射变换、激活函数以及softmax的叠加。利用链式法则,我们总能把导函数求出来。但是经实践发现,这样直接求解(试图把导数用各个参数表示出来)至少有两方面缺陷:
- 求解过程费时费力,并且随着神经网络加深变得越发艰难
- 不同的网络有不一样的导数,每次创建新网络都要计算一次导函数,不能一劳永逸地解决问题
怎么克服这个困难呢,有没有一劳永逸的办法?
我们的思路是,根据链式法则,一个量A关于另一个量W的导数与W是怎么计算出来的无关,又由于神经网络同一层的神经元执行相同的运算(因此具有相同形式的局部导数(这一层的输出关于这一层的输入(也许这是上一层的输出)的导数)),我们可以让层记忆与求局部导数相关的计算(做预测)的中间结果,再从后往前(从输出向输入)逐层逐中间变量计算导数,最终得到损失关于输入的导数。
计算图,表达式树
利用计算图可以直观地理解反向传播,
上面的计算图表达算式( :=
, 这是python内建幂运算语法):
如