误差反向传播算法很“聪明”地规避了这种冗余,它对于每个路径只访问一次就能求得顶点对所有下层节点的偏导值。为了方便理解,读者可以想象以下场景:数据在神经网络的输入层中流入后,犹如一股水流在分支茂密的树状管道中流淌,现在水流的方向是从所有的叶子分支(输入层)同时向根节点(输出层)流动汇聚的,每一个非叶子节点的水流都将由若干条支流汇聚而来,从这个节点出去之后的水流,可以视为它之前每一条支流相加的结果,这个路径便等同于汇聚前的每一条支流共用的路径。但是若反过来水流方向是从唯一的根节点(输出层)开始向叶子节点(输入层)流动的话,水流会在流过每个节点时自动分配成若干条支流流向下一级节点,这样每条路径上的水流便没有汇聚的过程,解决了共用路径的问题。输入数据的处理是正向的,但误差反向传播算法是把每一层节点的梯度向量从输出层节点开始逐层向输入层节点推导,每一层的导数 $\frac { \partial E } { \partial x _ { i } }$ 都可以依靠其上一层的导数 $\frac { \partial E } { \partial x _ { j } }$ 来计算得出,而最后一层(输出层)的导数 $\frac { \partial E } { \partial y }$ 是我们已知的,它的值就是模型预测值与实际值之间的误差。将求导从正向模式转变为反向模式,就相当于改变了水流的流向。
按照这个思路,如图 7-8 所示,对于三层神经元中的某一个隐层神经元 $x _ { j }$ ,如果我们要计算出导数 $\frac { \partial E } { \partial w _ { i j } }$ 的话,应该意识到误差函数 E 会受到神经元 $x _ { j }$ 的输出值的影响,而权值 $w _ { i j }$ 是通过加权和 $S _ { j }$ 来影响 $x _ { j }$ 的输出的,即有以下公式:
$$
\cfrac { \partial E } { \partial w _ { i j } } = \cfrac { \partial E } { \partial x _ { j } } \enspace \cdot \enspace \frac { \partial x _ { j } } { \partial s _ { j } } \enspace \cdot \enspace \frac { \partial s _ { j } } { \partial w _ { i j } } = \cfrac { \partial E } { \partial x _ { j } } \enspace \cdot \enspace \partial ^ { ' } ( s _ { j } ) x _ { i }
$$
在这里,前一层的输出 $x _ { i }$ 是已知的,所以关键就在于 $\cdot \frac { \partial E } { \partial x _ { j } }$ 的计算,而前面提到了 $\frac { \partial E } { \partial x _ { j } }$ 是可以通过它后面的 $\frac { \partial E } { \partial x _ { k } }$ 得到的,如以下公式所示:
第 7 章 深度学习时代
255