反向传播BP算法

神经网络中的前向传播与反向传播微积分推导

前向传播模型

在神经网络中,单个神经元最基础的计算公式是:

\[a=\frac{1}{1+\exp \left(-\left(w^{T} x+b\right)\right)} = \frac{1}{1+\exp \left(-\left[w^{T} \quad b\right] \cdot \left[ \begin{array}{c} x \\ 1 \end{array} \right]\right)} \]

对于隐层有多个神经元的情况,前向计算可以展开为:

\[\begin{array}{l} a_1=\frac{1}{1+\exp \left(w_1^T x+b_1\right)} \\ \vdots \\ a_m=\frac{1}{1+\exp \left(w_m^T x+b_m\right)} \end{array} \]

令激活函数为 \(\sigma(x)\),线性组合记为 \(z = Wx + b\),我们可以将其写成更为简洁的向量/矩阵形式:

\[\left[ \begin{array}{c} a^{(1)} \\ \vdots \\ a^{(m)} \end{array} \right] = \sigma(z) = \sigma(W x+b) \]

在实际中, 我们常常有多层神经网络, 为了把后面的公式说清楚,我们先统一一下第 \(l\) 层的变量(这也是前向传播时必须记录下的数据):

  • \(W^{[l]}\): 第 \(l\) 层的权重矩阵。
  • \(b^{[l]}\): 第 \(l\) 层的偏置向量。
  • \(Z^{[l]}\): 第 \(l\) 层的线性输出,即 \(Z^{[l]}=W^{[l]}A^{[l-1]}+b^{[l]}\)。
  • \(A^{[l]}\): 第 \(l\) 层的激活输出,即 \(A^{[l]}=g(Z^{[l]})\)(\(g\) 为激活函数,如 ReLU 或 Sigmoid)。上面最开始的时候, 我们就用了 Sigmoid 函数.

反向传播中的微积分计算

假设我们有一个三层神经网络,它的损失函数(Cost Function)可以简单表示为包含所有参数的函数:

\[L\left(w_1, b_1, w_2, b_2, w_3, b_3\right) \]

神经网络训练的目的,就是希望通过调整这些参数(权重 \(w\) 和偏置 \(b\)),使得损失函数沿着梯度下降最快的方向减小。

假设每层只有一个神经元的情况

为了方便理解,我们先假设每层只有一个神经元, 也就是说每层网络实际上就是一个参数, 或者说一个线性函数。

我们将神经网络最后一层的神经元输出用 \(a^{(l)}\) 表示。此时, $a^{(l)} = \sigma(w^{(l)} a{(L-1)}+b) $ 对于单个样本,如果使用均方误差(MSE),损失函数可以表示为:

\[L_0 = \left(a^{(l)}-y\right)^{2} \]

当我们从倒数第二层 \(a^{(l-1)}\) 前向传播到 \(a^{(l)}\) 层时,公式如下:

\[\begin{aligned} z^{(l)} &= w^{(l)} a^{(l-1)}+b^{(l)} \\ a^{(l)} &= \sigma\left(z^{(l)}\right) \end{aligned} \]

想要让损失函数下降得越快,我们需要知道损失 \(L_0\) 对参数权重 \(w^{(l)}\) 有多敏感。这里我们使用微积分中的链式法则(Chain Rule):

\[\frac{\partial L_0}{\partial w^{(l)}} = \frac{\partial L_0}{\partial a^{(l)}} \frac{\partial a^{(l)}}{\partial z^{(l)}} \frac{\partial z^{(l)}}{\partial w^{(l)}} \]

现在我们分别对上面链条中的三部分求导:

\[\begin{aligned} \frac{\partial L_0}{\partial a^{(l)}} &= 2\left(a^{(l)}-y\right) \\ \frac{\partial a^{(l)}}{\partial z^{(l)}} &= \sigma^{\prime}\left(z^{(l)}\right) \\ \frac{\partial z^{(l)}}{\partial w^{(l)}} &= a^{(l-1)} \end{aligned} \]

将它们相乘,得到最终的梯度计算公式:

\[\frac{\partial L_0}{\partial w^{(l)}} = 2\left(a^{(l)}-y\right) \cdot \sigma^{\prime}\left(z^{(l)}\right) \cdot a^{(l-1)} \]

注意: 上面的推导只是针对单个样本。在实际训练(如 Batch Gradient Descent)中,我们需要对 \(n\) 个样本的损失求平均,因此真实需要更新的权重梯度应该是:

\[\frac{\partial L}{\partial w^{(l)}} = \frac{1}{n} \sum_{k=1}^{n} \frac{\partial L_k}{\partial w^{(l)}} \]

上述过程展示了对最后一层的权重 \(w^{(l)}\) 求梯度的过程。如果我们要求整个网络的参数梯度,就会得到一个梯度向量 \(\nabla L\):

\[\nabla L = \left[ \begin{array}{c} \frac{\partial L}{\partial w^{(1)}} \\ \frac{\partial L}{\partial b^{(1)}} \\ \vdots \\ \frac{\partial L}{\partial w^{(l)}} \\ \frac{\partial L}{\partial b^{(l)}} \end{array} \right] \]

当每层有多个神经元时

真实的网络通常每层有多个神经元,此时下一层的计算方法本质上是不变的,只是变成了求和公式。例如,假设最后一层为第 \(l\) 层, 第 \(l\) 层第 \(j\) 个神经元的线性组合为:

\[z_j^{(l)} = w_{j 0}^{(l)} a_0^{(l-1)} + w_{j 1}^{(l)} a_1^{(l-1)} + w_{j 2}^{(l)} a_2^{(l-1)} + b_j^{(l)} = W_j^L \times a^{l-1} + b_j^l \]

激活值为:

\[a_j^{(l)} = \sigma\left(z_j^{(l)}\right) \]

假设最后一层有 \(n_l\) 个神经元,此时损失函数为所有输出神经元误差的累加:

\[L_0 = \sum_{j=0}^{n_l-1}\left(a_j^{(l)}-y_j\right)^{2} \]

计算对权重的偏导:

如果我们要看损失函数对某一个连接权重 \(w_{j k}^{(l)}\) 的偏导数,链式法则与单神经元本质上完全一样:

\[\frac{\partial L_0}{\partial w_{j k}^{(l)}} = \frac{\partial L_0}{\partial a_j^{(l)}} \frac{\partial a_j^{(l)}}{\partial z_j^{(l)}} \frac{\partial z_j^{(l)}}{\partial w_{j k}^{(l)}} \]

我们将上述的公式延伸到, 对于损失函数 \(L\), 对深度神经网络模型的最后一层的参数 \(W^{(l)}\) 的偏导, 也就是最后一层的梯度为:

\[\frac{\partial L}{\partial W^{(l)}} = \frac{\partial L}{\partial A^{(l)}} \frac{\partial A^{(l)}}{\partial Z^{(l)}} \frac{\partial Z^{(l)}}{\partial W^{(l)}} \]

这其中我们很容易计算,对于神经网络的每一层来说 \(\frac{\partial Z^{(l)}}{\partial W^{(l)}} = (A^{l-1})^T\). 因此

\[\frac{\partial L}{\partial W^{(l)}} = \frac{\partial L}{\partial A^{(l)}} \frac{\partial A^{(l)}}{\partial Z^{(l)}} \times (A^{l-1})^T \]

其中, 我们记

\[\frac{\partial L}{\partial Z^{(l)}} =\frac{\partial L}{\partial A^{(l)}} \frac{\partial A^{(l)}}{\partial Z^{(l)}} = \delta^{(l)} \]

带入激活函数 \(g\) 的求导公式, 那么

\[\delta^{(l)}=\frac{\partial L}{\partial A^{(l)}} \odot g'(Z^{(l)}) \]

反向传播的链式法则

我们需要求损失函数 \(L\) 对整个神经网络的偏导, 上面仅计算了最后一层的偏导 \(\frac{\partial L}{\partial W^{(l)}}\), 那么如何计算倒数第二层的偏导呢? 我们需要计算

\[\frac{\partial L}{\partial W^{(l-1)}} \]

使用链式求导法则得到:

\[\frac{\partial L}{\partial W^{(l-1)}} = \frac{\partial L}{\partial Z^{(l-1)}} \frac{\partial Z^{(l-1)}}{\partial W^{(l-1)}} = \frac{\partial L}{\partial A^{(l-1)}} \frac{\partial A^{(l-1)}}{\partial Z^{(l-1)}} \frac{\partial Z^{(l-1)}}{\partial W^{(l-1)}} \]

将上面我们在计算最后一层 \(W^l\) 的偏导时候的计算公式带入, 我们可以得到

\[\frac{\partial L}{\partial W^{(l-1)}} = \delta^{(l-1)} (A^{l-2})^T = \frac{\partial L}{\partial A^{(l-1)}} \odot g'(Z^{(l-1)}) \times (A^{l-2})^T \]

在这个公式中, 我们很容易得到, 在计算损失 \(L\) 对神经网络前面很多层的参数 \(W\) 的偏导的时候, \((A^{l-2})^T\) 仅和该层神经网络的输入 \(A^{l-2}\)有关, 与输出无关. 因此我们真正需要链式计算的值是:

\[\delta^{(l-1)} = \frac{\partial L}{\partial Z^{(l-1)}} = \frac{\partial L}{\partial A^{(l-1)}} \odot g'(Z^{(l-1)}) \]

那么反向传播真正的链式法则其实是在这里, 前面是链式求导法则, 这里是当然也用到了链式求导, 但是是将反向传播神经网络从后向前传播形成链式的核心, 我们可以这样计算损失函数 \(L\), 对神经网络上一层输出激活值的偏导:

\[\frac{\partial L}{\partial A^{(l-1)}} = \frac{\partial L}{\partial Z^{(l)}}\frac{\partial Z^{(l)}}{\partial A^{(l-1)}} =\delta^{(l)}\frac{\partial Z^{(l)}}{\partial A^{(l-1)}} \]

这其中的 \(\delta^{(l)}\) 在计算损失对前一层的 \(W^{(l)}\) 的偏导的时候已经计算过了. 因此我们的核心是计算 \(\frac{\partial Z^{(l)}}{\partial A^{(l-1)}}\). 我们知道

\[Z^{(l)} = W^{(l)} \times A^{(l-1)} + b ^ {(l)} \\ A^{(l)} = g(Z^{(l)}) \]

根据矩阵微分(感兴趣的可以自行推导, 这里不做详细推导了), 我们可以很容易的计算得到:

\[\frac{\partial L}{\partial A^{(l-1)}} = (W^{(l)})^T \times \delta^{(l)} \]

将这个计算结果带入, 我们可以得到:

\[\delta^{(l-1)} = \frac{\partial L}{\partial Z^{(l-1)}} = \frac{\partial L}{\partial A^{(l-1)}} \odot g'(Z^{(l-1)}) = (W^{(l)})^T \times \delta^{(l)} \odot g'(Z^{(l-1)}) \]

有了 \(\delta^{(l-1)}\), 我们很容易计算得到:

\[\frac{\partial L}{\partial W^{(l-1)}} = \delta^{(l-1)} (A^{l-2})^T = \frac{\partial L}{\partial A^{(l-1)}} \odot g'(Z^{(l-1)}) \times (A^{l-2})^T = (W^{(l)})^T \times \delta^{(l)} \odot g'(Z^{(l-1)}) \times (A^{l-2})^T \]

因此我们可以得到反向传播中, 真正核心的传播公式, 也就是:

\[\delta^{(l-1)} = (W^{(l)})^T \times \delta^{(l)} \odot g'(Z^{(l-1)}) \]

其中, 最后一层的 \(\delta^{(l)}\) 很容易计算, 和矩阵参数无关, 一直传播到输入的过程中, 会乘以每层神经网络的参数矩阵的转置, 也就是上面函数使用到的 \(W^{(l)}\), 上面的公式也同时解释了神经网络中, 每层神经网络的线性层输出 \(Z^{(l)}\) , 以及每层神经网络的激活层的输出 \(A^{(l)}\) 在反向传播过程中的作用.

posted @ 2019-05-04 11:10  虾野百鹤  阅读(425)  评论(1)    收藏  举报