这可能是我见过的反向传播算法理论中最易理解的解释和最简洁形式的公式推导了 ????
本文以多层感知机为例, 但不局限于某种激活函数或损失函数.
先上精简版的图示, 帮助解释:
反向传播的目的是更新神经元参数,而神经元参数正是 \(z=wx+b\) 中的 (w,b).
对参数的更新,利用损失值loss对参数的导数, 并沿着负梯度方向进行更新:
\[w=w-\eta \nabla w \\
b=b-\eta \nabla b
\]
运用链式法则先求误差对当前神经元的线性加权的结果 \(z\) 的梯度,再求对当前神经元输入连接的权重 (w,b) 的梯度.
\[\begin{align}
{\partial E\over \partial z_i^l} &=\sum_j[{\partial E\over \partial z_j^{l+1}}{\partial z_j^{l+1}\over\partial a_i^l}{\partial a_i^l\over\partial z_i^l}] \\
&= \sum_j[{\partial E\over \partial z_j^{l+1}} w_{ji}^{l+1} \sigma'(z_i^l)]
\end{align}
\]
其中\(\sigma(\cdot)\)为激活函数, \(\sigma'(\cdot)\) 为激活函数的导数.
\(a_j^{l+1}, a_i^l\) 分别代表当前第\(l+1\)层第\(j\)个神经元与前一层(第\(l\)层)第\(i\)个神经元的激活输出值.
\(a_i^l=\sigma(z_l^l)\)
\(z_j^{l+1}=w_{ji}^{l+1}a_i^l+b_j^{l+1}\)
注意的是式子和图示中的 \(E\) 是单个训练样本的损失, 而式子中的求和符号 \(\sum\) 是对应层的神经元求和. 不要和代价损失的求和混淆了(cost function 是对所有训练样本的损失求平均值).
从上式中,你应该能看出来损失对每层神经元的\(z_i\)的梯度是个从后往前的递推关系式. 即:
\[\delta_i^l=\sum_j[{\delta_j^{l+1}} w_{ji}^{l+1} \sigma'(z_i^l)]
\]
(w,b) 梯度
我们想要的(w,b)的梯度也能够立刻计算出来:
第\(l\)层的第\(i\)个神经元与第\(l+1\)层的第\(j\)个神经元的权重:
\[\begin{align}
{\partial E\over \partial w_{ji}^{l+1}} &={\partial E\over \partial z_i^l} {\partial z_i^l\over \partial w_{ji}^{l+1}}= \delta_j^{l+1}a_i^l \\
{\partial E\over \partial b_j^{l+1}} &=\delta_j^{l+1}
\end{align}
\]
往前一层(第 i 层)的权重:
\[\begin{align}
{\partial E\over \partial w_{ih}^l} &=\delta_i^la_h^{l-1} \\
{\partial E\over \partial b_i^l} &=\delta_i^l
\end{align}
\]
就这样, 梯度从后往前一层一层传播计算, 每层的梯度等于后一层的梯度与当前层的局部偏导数的乘积, 这正是链式法则的简单应用。
矩阵乘
对上面的公式稍加变化便能改成矩阵乘法形式:
\[\delta_i^l=\sum_j[{\delta_j^{l+1}} w_{ji}^{l+1} \sigma'(z_i^l)] \\
\Rightarrow[\delta^\ell]_{j\times 1}=[(w^{\ell+1})_{k\times j}^T\times(\delta^{\ell+1})_{k\times 1}]_{j\times 1}\odot\sigma'(z^\ell)_{j\times 1} \\
[\frac{\partial\,E}{\partial\,w^{\ell +1}}]_{j\times i}=[\delta^{\ell +1}]_{j\times 1}\cdot [a^{\ell}]_{1\times i}
\]
参考
- 神经网络中 BP 算法的原理与 Python 实现源码解析: https://www.jianshu.com/p/679e390f24bb#
- BP神经网络——从二次代价函数(Quadratic cost)到交叉熵(cross-entropy cost)代价函数 https://blog.csdn.net/lanchunhui/article/details/50086025