反向传播算法

反向传播算法是神经网络中的基础。神经网络通过梯度下降算法来学习权重和参数,其中用来计算代价 Loss 函数的梯度的最常用方法就是反向传播算法。下面通过实例和公式加深对反向传播算法的学习及理解。

举个例子

下图是典型的神经网络示意图。它由输入层、隐含层和输出层共三层组成。这里的神经网络是监督型,所以我们的目标是将原始数据通过某一种映射,输出得到我们想要的另外一种数据 Label 。希望这种映射关系可以越准确地描述输入与输出的关系,也就是所说的损失值 Loss 越小。

neural-network

激活函数采用 sigmoid 函数,初始的输入值为:
i1=0.05,i2=0.1 ;
w1=0.15,w2=0.2,w3=0.25,w4=0.3;
w5=0.4,w6=0.45;w7=0.5,w8=0.55;
我们的目标是使得输出 o1、o2 分别与 0.01、0.99 越接近。

neural-network

前向传播

隐含层

h1 的输入加权和:

$$
\begin{equation}\begin{split}
net_{h_1} &= w_1\times i_1 + w_2\times i_2 + b_1\\
&=0.15\times 0.05 + 0.2\times 0.1 + 0.35 \\
&=0.3775
\end{split}\end{equation}
$$

h1 的输出:

sigmoid 函数为 $f(x) = \frac{1}{1+e^{-x}}$ ,所以 h1 的输出为:

$$
\begin{equation}\begin{split}
out_{h_1} &= \frac{1}{1+e^{-net_{h_1}}}\\
&= 0.59326992
\end{split}\end{equation}
$$

同理得到 h2 的输出为:

$$
out_{h_2} = 0.596884378
$$

输出层

o1 的输入加权和:

$$
\begin{equation}\begin{split}
net_{o_1} &= w_5\times out_{h_1} + w_6\times out_{h_2} + b_2\\
&=0.4\times 0.59326992+ 0.45\times 0.596884378 + 0.6 \\
&=1.105905967
\end{split}\end{equation}
$$

o1 的输出:

$$
\begin{equation}\begin{split}
out_{o_1} &= \frac{1}{1+e^{-net_{o_1}}}\\
&= 0.75136507
\end{split}\end{equation}
$$

同理得到 o2 的输出为:

$$
out_{o_2} = 0.772928465
$$

反向传播

误差

$$
\begin{equation}\begin{split}
E_{total} &= \sum \frac{1}{2}(target - output)^2\\
&=\frac{1}{2}(0.01 - 0.75136507)^2 + \frac{1}{2}(0.99 - 0.772928465)^2\\
&=0.274811083 + 0.023560026\\
&=0.298371109
\end{split}\end{equation}
$$

输出层权值更新

比如求 w5 对上面的整体误差的影响值,可以用整体误差对 w5 求导即可。

$$
\frac{\partial E_{total}}{\partial w_5} = \frac{\partial E_{total}}{\partial out_{o_1}} \times \frac{\partial out_{o_1}}{\partial net_{o_1}} \times \frac{\partial net_{o_1}}{\partial w_5}
$$

backpropagation

其中:

$$
\begin{equation}\begin{split}
\frac{\partial E_{total}}{\partial out_{o_1}} &= -(target_{o_1} - out_{o_1})\\
&=-(0.01 - 0.75136507)\\
&= 0.74136507
\end{split}\end{equation}
$$

因为 sigmoid 函数的导函数为:$f(x)\times (1 - f(x))$ 。

$$
\begin{equation}\begin{split}
\frac{\partial E_{total}}{\partial w_5} &= out_{o_1}(1-out_{o_1})\\
&=0.75136507(1 - 0.75136507)\\
&=0.186815602
\end{split}\end{equation}
$$

$$
\begin{equation}\begin{split}
\frac{\partial E_{total}}{\partial w_5} &= out_{h_1}\\
&=0.593269992
\end{split}\end{equation}
$$

所以三者相乘就可以得到 w5 对总误差的影响值为:

$$
\begin{equation}\begin{split}
\frac{\partial E_{total}}{\partial w_5} &= 0.74136507 \times 0.186815602 \times 0.593269992\\
&=0.082167041
\end{split}\end{equation}
$$

为了表述方便,用 $\delta _{o_1}$ 来表示输出层的误差。

$$
\delta _{o_1} = \frac{\partial E_{total}}{\partial out_{o_1}} \times \frac{\partial out_{o_1}}{\partial net_{o_1}}
$$

所以对 w5 的偏导为:

$$
\frac{\partial E_{total}}{\partial w_5} = \delta _{o_1}\times out_{h_1}
$$

接下来就是更新 w5 到 w8 的权值:

$$
\begin{equation}\begin{split}
w_5^+ &= w_5 - \eta \times \frac{\partial E_{total}}{\partial w_5}\\
&=0.4 - 0.5\times 0.082167041\\
&=0.35891648\\
w_6^+ &= 0.408666186\\
w_7^+ &= 0.511301270\\
w_8^+ &= 0.561370121
\end{split}\end{equation}
$$

其中 $\eta$ 就是很重要的超参数:学习速率

隐含层权值更新

比如求 w1 对整体误差的影响值,可以用整体误差对 w1 求导即可。注意 h1 会接受 o1 和 o2 两个地方的误差。

backpropagation

$$
\frac{\partial E_{total}}{\partial out_{h_1}} = \frac{\partial E_{o_1}}{\partial out_{h_1}} + \frac{\partial E_{o_2}}{\partial out_{h_1}}
$$

其中:

$$
\begin{equation}\begin{split}
\frac{\partial E_{o_1}}{\partial out_{h_1}} &= \frac{\partial E_{o_1}}{\partial net_{o_1}}\times \frac{\partial net_{o_1}}{\partial out_{h_1}}\\
\frac{\partial E_{o_1}}{\partial net_{o_1}}&= \frac{\partial E_{o_1}}{\partial out_{o_1}}\times \frac{\partial out_{o_1}}{\partial net_{o_1}}\\
\frac{\partial E_{o_1}}{\partial out_{o_1}}&=0.74136507\times 0.186815602\\
&=0.138498562\\
net_{o_1} &= w_5\times out_{h_1} + w_6\times out_{h_2} + b_2\\
\frac{\partial out_{o_1}}{\partial out_{h_1}} &= w_5 = 0.4\\
\frac{\partial E_{o_1}}{\partial out_{h_1}} &= 0.138498562\times 0.4\\
&=0.055399425
\end{split}\end{equation}
$$

同理得到

$$
\frac{\partial E_{o_2}}{\partial out_{h_1}} = -0.019049119
$$

所以

$$
\begin{equation}\begin{split}
\frac{\partial E_{total}}{\partial out_{h_1}} &= \frac{\partial E_{o_1}}{\partial out_{h_1}} + \frac{\partial E_{o_2}}{\partial out_{h_1}}\\
&=0.055399425 + -0.019049119\\
&=0.036350306
\end{split}\end{equation}
$$

计算 $\frac{\partial out_{h_1}}{\partial net_{h_1}}$ :

$$
\begin{equation}\begin{split}
{net_{h_1}}&=\frac{1}{1+e^{-net_{h_1}}}\\
\frac{\partial out_{h_1}}{\partial net_{h_1}}&=out_{h_1}\times \left(1-out_{h_1}\right)\\
&=0.593226999\times \left(1-0.593226999\right)\\
&=0.241300709
\end{split}\end{equation}
$$

计算 $\frac{\partial net_{h_1}}{\partial w_1}$ :

$$
\begin{equation}\begin{split}
net_{h_1} &=w_1\times i_1 + w_2\times i_2 + b_1\\
\frac{\partial net_{h_1}}{\partial w_1} &= i_1 =0.05
\end{split}\end{equation}
$$

最终得到:

$$
\begin{equation}\begin{split}
\frac{\partial E_{total}}{\partial w_1} &= \frac{\partial E_{total}}{\partial out_{h_1}}\times \frac{\partial out_{h_1}}{\partial net_{h_1}} \times \frac{\partial net_{h_1}}{\partial w_1} \\
&=0.036350306\times 0.241300709\times 0.05\\
&=0.000438568
\end{split}\end{equation}
$$

然后同输出层权值更新方法一样,更新隐含层的权值:

$$
\begin{equation}\begin{split}
w_1^+ = 0.14978072\\
w_2^+ = 0.19956143\\
w_3^+ = 0.24975114\\
w_4^+ = 0.29950229\\
\end{split}\end{equation}
$$

至此一次反向传播已经完成,然后需要不断迭代,输出就会不断迫近我们的目标输出。

公式推导

通过上面的例子,可以辅助理解下面反向传播的公式推导。和例子中一样,约定误差函数为 $E = \frac{1}{2}\left(t - y\right)^2$,激活函数为 sigmoid 函数。

对于每一个神经元的输出 $o_j$
$$
o_j = \phi\left(net_j\right) = \phi\left(\sum_{k=1}^n w_{kj}o_k\right)
$$

激活函数 sigmoid :

$$
\begin{equation}\begin{split}
\phi\left(z\right) &= \frac{1}{1+e^{-z}}\\
\frac{\partial \phi}{\partial z} &= \phi\times \left(1-\phi \right)
\end{split}\end{equation}
$$

对误差对权值的偏导数,通过链式求导即可。但是在输出层和隐含层的表述上稍有点不同。

$$
\frac{\partial E}{\partial w_{ij}} = \frac{\partial E}{\partial o_{j}} \times \frac{\partial o_{j}}{\partial net_{j}} \times \frac{\partial net_{j}}{\partial w_{ij}}
$$

其中第三项

$$
\frac{\partial net_{j}}{\partial w_{ij}} = \frac{\partial}{\partial w_{ij}}\left(\sum_{k=1}^n w_{kj}o_k\right) = o_i
$$

第二项

$$
\frac{\partial o_{j}}{\partial net_{j}} = \frac{\partial}{\partial net_j}\phi\left(net_j\right) = \phi\left(net_j\right)\left(1-\phi\left(net_j\right)\right)
$$

接下来,第一项需要分情况,分 $j$ 在不在输出层。
如果 $j$ 在输出层,那么和上面求关于 w5 的导函数一样:
$$
\begin{equation}\begin{split}
\frac{\partial E}{\partial o_{j}} &= \frac{\partial E}{\partial y}\\
&=\frac{\partial}{\partial y}\frac{1}{2}\left(t - y\right)^2\\
&=y - t
\end{split}\end{equation}
$$

如果 $j$ 不在输出层,而在隐含层,那么导函数稍微复杂点,就像上面求关于 w1 的导函数一样。接受来自 $j$ 作为输入的所有神经元 $L = u,v,…,w$ ,$E$ 是 $L$ 的输入函数。所有:

$$
\begin{equation}\begin{split}
\frac{\partial E}{\partial o_j} &= \sum_{l\in L}\left(\frac{\partial E}{\partial net_l}\frac{\partial net_l}{\partial o_j}\right)\\
&=\sum_{l\in L}\left(\frac{\partial E}{\partial o_l} \frac{\partial o_l}{\partial net_l} \frac{\partial net_l}{\partial o_j}\right)\\
&=\sum_{l\in L}\left(\frac{\partial E}{\partial o_l} \frac{\partial o_l}{\partial net_l} w_{jl}\right)
\end{split}\end{equation}
$$

为了表述方便,可以记为下式:

$$
\frac{\partial E}{\partial w_{ij}} = \delta _j o_i
$$

其中 $\delta _j$ 为:

$$
\delta _j =
\begin{cases}
\left(o_j - t_j \right) \phi \left(net_j\right) \left(1- \phi \left(net_j\right)\right) & \text{$j$ 为输出层} \\
\left(\sum_{l\in L} \delta _l w_{jl}\right)\phi \left(net_j\right) \left(1- \phi \left(net_j\right)\right) & \text{$j$ 为隐含层}
\end{cases}
$$

得到导函数之后,就可以和例子中一样更新权重,新的权重等于旧的权重减去学习速率与梯度的乘积。其中的学习速率是需要自己设定的超参数。