引言
在神经网络中,为了更有效的计算梯度,需要用到反向传播算法。我们先从链式求导法则开始。
链式求导法
先介绍下链式求导法则,在后面的反向传播算法中会用到。
有y=g(x),z=h(y)
那么dxdz=dydzdxdy;
有x=g(s),y=h(s),z=k(x,y)

改变了s会改变x和y,从而改变了z。
dsdz=∂x∂zdsdx+∂y∂zdsdy
注意,如果改变s会改变多个变量,它们的关系也是成立的。
损失函数

假设给定一组参数θ,把一个训练数据xn代入NN(神经网络)中,会得到输出yn。
Cn是输出yn和实际y^n距离函数,值越大代表越距离远,也就是效果越不好。
那在神经网络训练算法中,损失函数定义为:
L(θ)=n=1∑NCn(θ)
如果把损失函数对参数w做微分的话,得到
∂w∂L(θ)=n=1∑N∂w∂Cn(θ)
只要计算出某一笔数据对w的微分,就可以得到L(θ)对w的微分。

假设我们先考虑这个神经元。

假设只有两个输入x1,x2,计算z=x1w1+x2w2+b得到z后再代入**函数,经过多次运算会得到最终的输出y1,y2。

现在问题是如何计算损失(距离函数)C对w的偏微分∂w∂C
利用链式求导法
∂w∂C=∂z∂C∂w∂z
计算∂w∂z的过程叫做正向过程(Forward pass);计算∂z∂C的过程叫做反向过程(Backward pass)。
正向过程
z=x1w1+x2w2+b
∂w1∂z=x1∂w2∂z=x2

如上图所示,假设输入是1,−1,上面蓝色神经元的参数:w1=1,w2=−2,b=1,**函数是Sigmoid
函数;
下面蓝色神经元的参数:w1=−1,w2=1,b=0
对下面的神经元来说,计算w2的偏微分,可以很快得出∂w∂z=−1,也就是输入x2(−1),随着从前往后计算每个神经元的输出,整个过程就可以很快结束,因此叫正向过程。
反向过程

困难的是如何计算∂z∂C
a=1+e−z1
假设**函数是Sigmoid
函数a=σ(z),然后得到的函数值a会乘上某个权重(比如w3)再加上其他值得到z′(注意这里只是一个符号,不是z的导数);a也会乘上权重(比如w4)再加上其他东西得到z′′(注意这里只是一个符号,不是z的二阶导数);

∂z∂C=∂a∂C∂z∂a
可以这样理解,z通过影响a来影响C。
而
∂z∂a=∂z∂σ(z)=σ′(z)
那就剩下
∂a∂C=∂z′∂C∂a∂z′+∂z′′∂C∂a∂z′′
改变了a会改变z′和z′′,从而改变了C
我们先计算简单的
z′=aw3+⋯
有
∂a∂z′=w3
同理
∂a∂z′′=w4
现在难点就是∂z′∂C和∂z′′∂C
我们这里先假装我们知道这两项的值。然后整理下原来的式子:
∂z∂C=σ′(z)[w3∂z′∂C+w4∂z′′∂C]

假设有另外一个特殊的神经元,它是上图的样子,输入就是∂z′∂C和∂z′′∂C,它们分别乘以w3和w4,然后求和得到的结果再乘上σ′(z)
就得到了∂z∂C
z在正向传播的过程中已经知道了,因此这里的σ′(z)是一个常数。
说了这么多,还是没说怎么计算∂z′∂C和∂z′′∂C啊。别急,下面就开始计算。
这里要分两种情况考虑:

情形一: 红色的两个神经元就是输出层,它们能直接得到输出。
根据链式法则有:
∂z′∂C=∂z′∂y1∂y1∂C
只要知道**函数是啥就能计算出∂z′∂y1
∂y1∂C也可以根据我们选取的损失函数简单的计算出来。
同理∂z′′∂C的计算也一样
情形二:红色的不是输出层

红色的是中间层,它们的**函数的值会当成下一层的输入继续参数计算。

如果我们知道∂za∂C和∂zb∂C
同理(回顾一下上面那个特殊的神经元)我们就可以计算∂z′∂C

问题就会这样反复循环下去,我们不停的看下一层,直到遇到了输出层。然后就可以由输出层往前计算出整个NN的所有的参数。
那我们为何不换个角度考虑问题,我们直接先算输出层的偏微分,然后依次往前计算。

这就是反向传播算法的思想。