BP算法是训练神经网络的一种算法,其是一种计算神经网络可训练参数的梯度的高效算法,正是因为BP算法的提出和在工程上的实现,使得深度神经网络模型可以比较轻易的训练。

        BP算法是建立在梯度下降的优化算法基础之上的,正是因为我们使用了梯度下降的方法来优化我们的模型,我们才有计算参数梯度的需求。当然,神经网络已经给了我们目标函数的表达方式,因此,计算梯度其实是一件很显而易见的事情,问题在于,如何更加高效简单的计算,而且具有通用性,这才是这个优化问题的核心所在,BP算法的特点就是高效简单,而且具有通用性。

        BP算法并不需要什么高深的数学,只要对梯度和chain rule有比较好的理解,那么BP算法就是显而易见的。对于梯度的理解,可以参考博主这篇文章《如何直观理解梯度下降算法》。对于chain rule,可以直接看如下推导:

BP 算法预测python_深度学习

 ,如果x变化了

BP 算法预测python_BP 算法预测python_02

,那么

BP 算法预测python_算法_03

,由于

BP 算法预测python_DNN_04

,所以

BP 算法预测python_神经网络_05

.

所以,只要g(x)和f(g(x))在x处是可导的,明显可以得到

BP 算法预测python_神经网络_06

.

        上面的推导的目的是为了理解chain rule这个过程,而不是死记硬背。基本的变量对于最终函数值的影响是可以这样分解为多步的,所以我们要分析一个变量对函数值最终的影响,同时如果这个函数关系比较复杂导致影响过程也比较复杂的话,那么这样逐步的分解去进行分析是一种很好的方式,这基本就是BP算法的分析和推导过程。

        对于DNN,我们随意分析其中的几层,以如下的网络结构为例。假设第k层有5个神经元,k+1层有3个神经元,第k+2层只有1个神经元,并且k+2层是最后一层。同时设当前状态下,每个神经元激活后的值为

BP 算法预测python_深度学习_07

,激活函数设为f。

BP 算法预测python_BP 算法预测python_08

        现在我们要分析第k层第一个神经元对应的

BP 算法预测python_深度学习_09

权重的偏导数。即假设

BP 算法预测python_深度学习_09

发生了微小的变化,那么该变化最终对输出造成的影响是多少,这也是单变量导数的含义。

BP 算法预测python_深度学习_09

的变化是通过中间k+1层的三个神经元传递对最终输出的影响的,即

BP 算法预测python_深度学习_09

的变化先影响k+1层的三个神经元,然后k+1层的三个神经元再对最终k+2层的输出产生影响,从而实现

BP 算法预测python_深度学习_09

对最终输出的影响。对此,我们只需要依次分析和计算,就可以计算出

BP 算法预测python_深度学习_09

对最终输出的影响,从而也就计算出了

BP 算法预测python_深度学习_09

的偏导数。        首先,

BP 算法预测python_深度学习_09

对k+1层的三个神经元的影响是很容易计算的,比如对于k+1层第一个神经元的影响就是k层第一个神经元的值和k+1层第一个神经元的导数的乘积;我们知道

BP 算法预测python_深度学习_09

 对下一层的影响后,接下来可以再分析下一层神经元的变化 对最终输出造成的影响,同样可以用简单的求导法则计算出来。具体如下所示。

BP 算法预测python_算法_18

        可以看到, 

BP 算法预测python_深度学习_09

的偏导就等于和其每条相连路径上所有导数值和函数值乘积之和,这个就类似值前向传播过程的一个逆过程,只是神经元的值变成了神经元对应的导数值,这个导数值和激活函数有关。并且在计算不同变量的偏导时,发现路径很多是重合的,所以实际上网络中每个神经元对应的导数值只需要计算一遍即可,所以只需要反向传播一遍就可以计算所有参数的偏导。

        实际上,上述分析中,我们采用的分析思路是前向传播,最终得到的参数偏导却是一个逆过程,这个逆过程的重要性体现在,在计算梯度时,网络中每个神经元导数只需要计算一次即可,但是如果使用前向分析和计算,那么每个参数都需要前向计算一遍,这个会导致有很多的重复计算。因此,本文的反向传播是通过参数前向分析导出的一种结果,而且在算法实现上可以极大的精简计算。

        上面的分析只是针对简单的DNN而言的,实际上,对于其他的网络结构,比如RNN,或者加入了Attention机制的网络等,分析的思路都是一样的,只是需要记住一个技巧性的地方:对于同一个参数在网络的不同地方多次出现,可以将其看成不同的参数独立使用多变量分析方式,然后再汇总即可,比如RNN。这一技巧的理解,可以参考博主这篇文章《理解两个函数乘积的导数的一种视角》。