反向传播(Backpropagation)算法详细解释以及推导(浅显易懂)
反向传播(Backpropagation)算法详细解释以及推导(浅显易懂)
反向传播算法是深度学习中的核心算法之一,用于计算神经网络中各层参数的梯度。本文将从链式法则开始,逐步介绍正向传播和反向传播的步骤,并通过数学公式和计算图的方式,清晰地展示梯度计算的过程。
前置知识:链式法则
链式法则在高数中应该就已经学过,我在这里放一张图片进行简单的介绍。
正向传播
首先介绍一下正向传播求误差。顾名思义正向传播求误差实际就是正向的计算每一层直到算出输出结果,有了输出结果和实际结果我们就可以算出误差了,我先来举一个例子。给出一个如图所示的计算图:
该图是一层网络,我们正向逐层计算得到了输出结果F,然后与真实值y相减得到损失L。一般我们使用平方误差作为损失函数,即
$$
Loss = \frac{1}{2}\left \langle sigma (w\cdot x+b) \right \rangle^{2}
$$
扩展到多层神经网络也一样,只需逐层计算即可,如下图所示:
只需按照顺序计算出输出结果然后再计算损失即可。正向传播就介绍到这里,应该很简单理解,下面的反向传播才是重头戏。
反向传播
当你通过正向传播求完误差之后该做什么呢?那当然就是通过反向传播来求梯度,这样我们就可以进行梯度下降来减少误差了。我们先来手动推导一下反向传播,对于如图所示的神经网络:
如上图所示我画了某个模型中间的三层神经网络,分别为第t-1层、第t层、第t+1层。h代表z经过激活函数后的输出,z代表上一层h经过权重w和偏置b后的输出,现在我们来求第t层第j个参数的梯度,L为损失函数。先把我们的待求目标列出来,由链式法则可得:
$$
\frac { \partial L } { \partial w _ { j i } ^{t}} = \frac { \partial L } { \partial z _ { j } ^ { t} } . \frac { \partial z _ { j } ^ { t } } { \partial w _ { j i }^{t} }
$$
$$
\frac { \partial L } { \partial b_{j} ^ { t } } = \frac { \partial L } { \partial z _ { j } ^ { t} } \cdot \frac { \partial z _{j}^ { t } } { \partial b _ { j }^{t}}
$$
之后我们设一个参数,并将其称为误差,用δ来表示
$$
\delta_{ j }^{t} = \frac { \partial L } { \partial z _ { j } ^ { t} }
$$
对于z与w和b之间,我们有如下关系
$$
z_{j}^{t}=\sum_{i=1}w_{ji}^{t} \cdot h_{i}^{t-1} +b_{j}^{t}
$$
可以将其看为一条直线的求导,那么分别对w和b求偏导有
$$
\frac { \partial z _ { j } ^ { t } } { \partial w _ { j i }^{t} }= h_{i}^{t-1}
$$
$$
\frac { \partial z _{j}^ { t } } { \partial b _ { j }^{t}}=1
$$
我们将上述式子代入可得
$$
\frac { \partial L } { \partial w _ { j i } ^{t}} =\delta_{ j }^{t} . \ h_{i}^{t-1}
$$
$$
\frac { \partial L } { \partial b_{j} ^ { t } } = \delta_{ j }^{t}
$$
代入之后表达式就简单了很多,接下来我们就只需要计算出误差δ即可。我们利用t+1层的数据来计算出第t层的误差。(图上均已画出)那么就有:
$$
\delta_{ j }^{t}=\frac { \partial L } { \partial z _ { j } ^ { t} }=\sum_{i=1}\frac { \partial L } { \partial z _ { i } ^ { t+1} }.\frac {\partial z _ { i } ^ { t+1}} { \partial h_{j}^{t} }.\frac { \partial h_{j}^{t} } {\partial z _ { j } ^ { t}}
$$
之后我们分别计算出式子的各项,a代表激活函数的导数:
$$
\frac { \partial L } { \partial z _ { i } ^ { t+1} }=\delta_{ i }^{t+1}
$$
$$
\frac {\partial z _ { i } ^ { t+1}} { \partial h_{j}^{t} }=w_{ij}^{t+1}
$$
$$
\frac { \partial h_{j}^{t} } {\partial z _ { j } ^ { t}}={a}
$$
将上述式子代入可把误差δ简化为
$$
\delta_{ j }^{t}=a\sum_{i=1}\delta_{ i }^{t+1}.w_{ij}^{t+1}
$$
如此一来式子中的误差δ我们就求出来了。观察你会发先第t层的误差δ实际上就是激活函数的导数乘以第t+1层的所有误差δ与权重的积的和。再看看我们的待求式子你就会发现计算某一层权重与偏置的梯度需要上一层的输出以及下一层的误差和权重。而上一层的输出在正向传播中已经计算了出来,对此我们只需要下一层的计算数据。如此一来我们就可以反着来计算,从后向前计算梯度,这样就可以提高计算效率,一遍就可以计算出所有的梯度。
现在我们整体来梳理一遍反向传播算法。
整体梳理
我们首先进行正向传播得到各层的输出:
$$
h_{1}, \ h_{2} , \ h_{3} ,.........., \ h_{n}
$$
之后就可以进行反向传播了。有了每一层的输出h之后,我们还需要得到每一层的误差δ以及激活函数的导数。我们首先计算最后一层的误差,最后一层的误差为最终输出h减去实际值y。
$$
\delta_{n}=h_{n}-y
$$
有了最后一层的误差我们就可以计算前面每一层的误差了,首先来计算梯度:
$$
\Delta w_{n-1}= \frac { \partial L } { \partial w _ {n-1} } =\delta_{n} \cdot h_{n-2}
$$
$$
\Delta b_{n-1}= \frac { \partial L } { \partial b _ {n-1} } =\delta_{n}
$$
之后就可以更新参数了
$$
w _ {n-1}=w_{n-1}-\eta\Delta w_{n-1}
$$
$$
b _ {n-1}=b_{n-1}-\eta\Delta b_{n-1}
$$
然后我们从后向前计算第n-1层的误差,我们设激活函数的导数为a,那么就可以得到计算式
$$
\delta_{n-1}=a \cdot (\delta_{n} \cdot w_{n})
$$
之后我们重复上述操作计算第n-2层、n-3层等等,直到更新完所有层的参数即可。