深度学习之反向传播 BP 算法详解

本文介绍 BP 算法的原理,尤其需要把握的时,损失先对每层输出求误差项,然后将误差项应用于每一层参数,求得所有参数的梯度,然后再使用优化器去更新参数

什么是反向传播算法 (Backpropagation, BP)?

  • 深度学习的基石算法,它通过模型的损失,反向求取模型 “可学习参数的更新梯度”,以便后续通过优化器更新模型参数
  • 反向传播算法由两个过程组成:1)前向计算:将数据输入送入网络以获得预测结果,对预测结果同训练目标求差得到损失;2)反向传播:根据损失更新网络权重
  • 实际上,如果要继续细分,更新权重不是 BP 算法做的,而是优化器做的,BP 只是将损失对权重的梯度返回到每一层网络

反向传播算法计算梯度的原理?

  • Drawing 2023-05-01 17.30.32.excalidraw|369
  • 求取参数梯度的过程,就是模型输出损失 + 链式法则 求偏导数的过程,具体步骤分为 2 个步骤:(1) 根据损失求得损失关于每层网络输出(激活前)的梯度(2) 在每层网络上求取梯度,如果没有可学习参数,则直接输出关于输入的梯度,然后往前面传递,如池化层、dropout 层;如果该层网络有参数,先计算输出关于参数的梯度,然后计算输出关于输入的参数,如线性层、卷积层等
  • 上图是 3 层神经网络的反向梯度传播过程,每一层包含输入、参数计算、输出 3 个过程,其中中间一层没有参数,理想情况下是求得 Loss 关于所有参数的梯度 (红线),实际计算需要按照链式法则求得 Loss 关于每一层输出的梯度(蓝线),然后在每一层内计算损失关于参数的梯度 (紫线)

训练神经网络时的损失、反向传播、优化器的区别与联系?

  • Drawing-2023-04-29-11.46.08.excalidraw
  • 损失:网络前向计算,得到输出后,与 gt 计算损失
  • 反向传播:根据损失反向求得损失对每个权重的梯度
  • 优化器:根据优化规则,使用梯度更新权重

神经网络中 “误差项” 的理解?

  • BP 算法计算损失对每层神经网络输出的梯度前,需要先算出损失在各个网络层的 “误差项”,注意:对于每个网络层,一般数据流程是:输入 -> 权值计算输出 -> 激活 -> 层输出,这里的 “误差项” 是损失关于 “权值计算输出” 的梯度,不是关于 “层输出” 的梯度,所以 “误差项” 包含层输出 -> 激活值的梯度,也就是激活函数求导
  • 误差项 δ(k)\delta^{(k)} 可以认定为该层输出对损失的贡献程度,最后一层 “误差项” 是损失本身,求解时需要反向求得各层输出的 “误差项”,MLP 的求解公式如下,即 k+1 层的误差项乘上权重 (k->k+1 之间) 的转置,然后乘上 k 层的输出

    δ(k)=fk(z(k))((W(k+1))Tδ(k+1))(4)\begin{array}{l}\delta^{(k)}=f_k'\left(z^{(k)}\right)\cdot\left({(\mathbf{W}^{(k+1)})}^T \cdot \delta^{(k+1)}\right) \tag{4}\end{array}

  • 误差项 δ(k)\delta^{(k)} 不是一个实数,而是一组数据,其数量等于 k 层的输出。但是在输出层使用类似交差熵求解损失时,经常使用 mean 求出 1 个实数的损失,后续应该如何更新其他层的误差项呢?主要影响的部分是 ((W(k+1))Tδ(k+1))\left({(\mathbf{W}^{(k+1)})}^T \cdot \delta^{(k+1)}\right),假设 W 是 (L, L’), δ(k+1)\delta^{(k+1)} 长度为 (L’, 1) 或 1 的差别,就是矩阵点乘和矩阵乘实数的问题,都可以计算,不影响后续计算

MLP 网络的前向推理?

  • 本例是一个三层的 MLP 网络 (2 层隐藏层,1 层输出层),前向计算时每层内的所有神经元都感知所有输入(乘积和),以下计算不考虑激活函数
  • 第一层隐藏层输出:

    z1=w(x1,1)x1+w(x2,1)x2+b1z2=w(x1,2)x1+w(x2,2)x2+b2z3=w(x1,3)x1+w(x2,3)x2+b3\begin{array}{c}z_1=w_{(x_1,1)}*x_1+w_{(x_2,1)}*x_2+b_1\\ \\ z_2=w_{(x_1,2)}*x_1+w_{(x_2,2)}*x_2+b_2\\ \\ z_3=w_{(x_1,3)}*x_1+w_{(x_2,3)}*x_2+b_3\end{array}

  • 第二层隐藏层输出:

    z4=w(1,4)z1+w(2,4)z2+w(3,4)z3+b4z5=w(1,5)z1+w(2,5)z2+w(3,5)z3+b5\begin{array}{l}z_{4}=w_{(1,4)}*z_{1}+w_{(2,4)}*z_{2}+w_{(3,4)}*z_{3}+b_{4}\\ \\ z_{5}=w_{(1,5)}*z_{1}+w_{(2,5)}*z_{2}+w_{(3,5)}*z_{3}+b_{5}\end{array}

  • 输出层计算:

    z6=w(4,6)z4+w(5,6)z5+b6z_6=w_{(4,6)}*z_4+w_{(5,6)}*z_5+b_6

MLP 网络使用 BP 算法进行后向传播?

  • Drawing-2023-04-29-13.37.23.excalidraw
  • 以 MLP 为例,上图是对 K-1 层的 p 个输出,使用第 K 层中 q 个感知机进行前向推理的过程(未考虑激活函数),其中红色线表示 BP 算法依次反向求输出或者参数的梯度
  • 前向推理:n->z->L 的过程,即计算神经元输出的过程、损失的过程

    z(k)=W(k)×n(k1)+b(k)L=L(y,y^)\begin{array}{l}z^{(k)}=W^{(k)}\times n^{(k-1)}+b^{(k)} \\ L=L(y,\hat{y})\end{array}

  • 后向传播:根据链式求导法则,有

    L(y,y^)W(k)=L(y,y^)z(k)z(k)W(k)L(y,y^)b(k)=L(y,y^)z(k)z(k)b(k)(1)\begin{array}{l}\dfrac{\partial\mathbf{L}(\mathbf{y},\hat{\mathbf{y}})}{\partial W^{(k)}}=\dfrac{\partial\mathbf{L}(\mathbf{y},\hat{\mathbf{y}})}{\partial\mathbf{z}^{(k)}}*\dfrac{\partial z^{(k)}}{\partial W^{(k)}}\\ \dfrac{\partial\mathbf{L}(\mathbf{y},\hat{\mathbf{y}})}{\partial\mathbf{b}^{(k)}}=\dfrac{\partial\mathbf{L}(\mathbf{y},\hat{\mathbf{y}})}{\partial\mathbf{z}^{(k)}}*\dfrac{\partial z^{(k)}}{\partial\mathbf{b}^{(k)}}\tag{1}\end{array}

  • 求偏导数 z(k)W(k)\frac{\partial z^{(k)}}{\partial W^{(k)}}:根据公式 z(k)=W(k)×n(k1)+b(k)z^{(k)}=W^{(k)}\times n^{(k-1)}+b^{(k)} 结合每个神经元都单独感知全部输入,可知

    z(k)W(k)=[(W1(k)+n(k1)+b(k))W(k)(Wm(k)+n(k1)+b(k))W(k)](n(k1))T(2)\dfrac{\partial\mathbf{z}^{(k)}}{\partial\mathbf{W}^{(k)}}=\begin{bmatrix}\dfrac{\partial(\mathbf{W_1}^{(k)}+\mathbf{n}^{(k-1)}+\mathbf{b}^{(k)})}{\partial\mathbf{W}^{(k)}}\\ \vdots\\ \dfrac{\partial(\mathbf{W_m}^{(k)}+\mathbf{n}^{(k-1)}+\mathbf{b}^{(k)})}{\partial\mathbf{W}^{(k)}}\end{bmatrix}\Longrightarrow{}(\mathbf{n}^{(k-1)})^\mathbf{T}\tag{2}

  • 求偏导数 z(k)b(k)\frac{\partial z^{(k)}}{\partial b^{(k)}}:b 是一个常数项,其偏导数为单位矩阵,大小为该层的神经元格式,这里是 q,所以是 qxq 大小的单位矩阵

    Z(k)b(k)=[(W1(k)+n(k1)+b1)b1(W1(k)+n(k1)+b1)bm(Wm(k)+n(k1)+bm)b1(Wm(k)+n(k1)+bm)bm]=[1001](3)\frac{\partial\mathcal{Z}^{(k)}}{\partial b^{(k)}}=\left[\begin{array}{c c c c}{\frac{\partial(W_{1}^{(k)}+n^{(k-1)}+b_{1})}{\partial b_{1}}}&{\ldots}&{\frac{\partial(W_{1}^{(k)}+n^{(k-1)}+b_{1})}{\partial b_{m}}}\\ {\vdots}&{\ldots}&{\vdots}\\ {\frac{\partial(W_{m}^{(k)}+n^{(k-1)}+b_{m})}{\partial b_{1}}}&{\ldots}&{\frac{\partial(W_{m}^{(k)}+n^{(k-1)}+b_{m})}{\partial b_{m}}}\\ \end{array}\right]=\left[\begin{array}{c c c c}{1}&{\ldots}&{0}\\ {\vdots}&{\ldots}&{\vdots}\\ {0}&{\ldots}&{1}\tag{3} \end{array}\right]

  • 求偏导数 δ(k)=L(yy^)z(k)\delta^{(k)}=\frac{\partial\mathbf{L}(y\hat{y})}{\partial z^{(k)}}表示该层权值输出关于损失的偏导数,称为误差项,可理解为该层输出对误差的贡献,已知 z(k+1)=W(k+1)n(k)+bk+1\text{z}^{(k+1)}=W^{(k+1)}*n^{(k)}+b^{k+1}n(k)=fk(z(k))n^{(k)}=f_{k}(\mathbf{z}^{(k)}),根据链式法则得到

    δ(k)=L(y,y^)z(k)=n(k)z(k)z(k+1)n(k)L(y,y^)z(k+1)=n(k)z(k)z(k+1)n(k)δ(k+1)=fk(z(k))((W(k+1))Tδ(k+1))(4)\begin{array}{l}\delta^{(k)}=\dfrac{\partial\mathbf{L}(y,\hat{y})}{\partial z^{(k)}}\\ =\dfrac{\partial n^{(k)}}{\partial z^{(k)}}\cdot\dfrac{\partial z^{(k+1)}}{\partial n^{(k)}}\cdot\dfrac{\partial\mathbf{L}(y,\hat{y})}{\partial z^{(k+1)}}\\ =\dfrac{\partial n^{(k)}}{\partial z^{(k)}}\cdot\dfrac{\partial z^{(k+1)}}{\partial n^{(k)}}\cdot\delta^{(k+1)}\\ =f_k'\left(z^{(k)}\right)\cdot\left({(\mathbf{W}^{(k+1)})}^T \cdot \delta^{(k+1)}\right) \tag{4}\end{array}

  • 汇总结果:汇总将公式 2,3,4 到 1 得到

    L(yy^)W(k)=L(yy^)z(k)z(k)W(k)=δ(k)(n(k1))TL(yy^)b(k)=L(yy^)z(k)z(k)b(k)=δ(k)(5)\begin{array}{l}\dfrac{\partial\mathbf{L}(\mathbf{y}\hat{\mathbf{y}})}{\partial\mathbf{W}^{(k)}}=\dfrac{\partial\mathbf{L}(\mathbf{y}\hat{\mathbf{y}})}{\partial z^{(k)}}*\dfrac{\partial z^{(k)}}{\partial\mathbf{W}^{(k)}}=\delta^{(k)}*(n^{(k-1)})^T\\ \dfrac{\partial\mathbf{L}(\mathbf{y}\hat{\mathbf{y}})}{\partial b^{(k)}}=\dfrac{\partial\mathbf{L}(\mathbf{y}\hat{\mathbf{y}})}{\partial z^{(k)}}*\dfrac{\partial z^{(k)}}{\partial b^{(k)}}=\delta^{(k)}\tag{5}\end{array}

  • 根据以上公式,可知:1) 神经网络对权重的偏导数,等于当前层关于损失的偏导数乘上输入的转置;2)只要求得每层输出关于权重的误差项,那么权重的更新梯度就很容易求得,根据公式 4 可知,第 k 层的误差项可以通过 k+1 层的误差项求得,而最后一层的误差项是损失函数,所以递归求回去就得到每一层的误差项

MLP 网络中,BP 算法和优化器更新网络参数的流程?

  • Drawing-2023-04-29-15.47.27.excalidraw
  • (1) 前向计算得到损失:前向计算得到网络输出,然后计算损失,需要输入、网络、GT

    z(k)=W(k)×n(k1)+b(k)L=L(y,y^)\begin{array}{l}z^{(k)}=W^{(k)}\times n^{(k-1)}+b^{(k)} \\ L=L(y,\hat{y})\end{array}

  • (2) 通过公式 4 计算每层网络的误差项:通过输出层的损失,结合每层网络的权重和输出,计算得到所有层的偏差项,可理解为该层输出对误差的贡献,需要 Loss (即最后一层误差项)、k+1 层的误差项、k 到 k+1 层的权重 (转置)、k 层激活函数对该层输出的梯度

    δ(k)==fk(z(k))((W(k+1))Tδ(k+1))\begin{array}{l}\delta^{(k)}= =f_k'\left(z^{(k)}\right)\cdot\left({(\mathbf{W}^{(k+1)})}^T \cdot \delta^{(k+1)}\right) \end{array}

  • (3) 通过公式 5 计算每层网络参数的梯度: 得到偏差项后,通过公式 5 计算所有权重的梯度,每个参数都有一个梯度
  • Pythorch 为每个需要训练的参数记录梯度,通过 requires_grad=True 控制,训练时先使用 optim.zero_grad() 清空所有参数的梯度,然后通过 loss.backward() 计算所有参数的梯度,最后使用 optim.step() 根据梯度及优化器更新网络参数

    L(yy^)W(k)=L(yy^)z(k)z(k)W(k)=δ(k)(n(k1))TL(yy^)b(k)=L(yy^)z(k)z(k)b(k)=δ(k)\begin{array}{l}\dfrac{\partial\mathbf{L}(\mathbf{y}\hat{\mathbf{y}})}{\partial\mathbf{W}^{(k)}}=\dfrac{\partial\mathbf{L}(\mathbf{y}\hat{\mathbf{y}})}{\partial z^{(k)}}*\dfrac{\partial z^{(k)}}{\partial\mathbf{W}^{(k)}}=\delta^{(k)}*(n^{(k-1)})^T\\ \dfrac{\partial\mathbf{L}(\mathbf{y}\hat{\mathbf{y}})}{\partial b^{(k)}}=\dfrac{\partial\mathbf{L}(\mathbf{y}\hat{\mathbf{y}})}{\partial z^{(k)}}*\dfrac{\partial z^{(k)}}{\partial b^{(k)}}=\delta^{(k)}\end{array}

  • (4) 更新网络参数: 通过优化器规则更新参数,需要 K 层的梯度、学习率、K 层的权重

    W(k)=W(k)α(δ(k)(n(k1))T+W(k))b(k)=b(k)αδ(k)\begin{array}{l}W^{(k)}=W^{(k)}-\alpha\left(\delta^{(k)}\left(n^{(k-1)}\right)^T+W^{(k)}\right)\\ {b^{(k)}=b^{(k)}-\alpha\delta^{(k)}}\end{array}

例子:MLP 前向计算过程?

  • 假设所以层均使用激活函数 f<!swig0>(z)=11+ezf^ (z)=\frac{1}{1+e^{-z}}
  • 第一层隐藏层输出:
    深度学习之反向传播BP算法详解-20250116162231
  • 第二层隐藏层输出:
    深度学习之反向传播BP算法详解-20250116162218
  • 输出层:
    深度学习之反向传播BP算法详解-20250116162159

例子:MLP 后向传播过程?

  • 计算损失:前向计算网络输出为 0.997520293823002,GT 值为 1,根据损失函数 L(y,y^)=MSE(y,sigmoid(n))=1/2(yY)2L(y,\hat{y})=MSE(y,sigmoid(n))=1/2(y-Y)^2 可得损失是 0.002479706176998,则损失函数关于 z6 输出的梯度是:L(y,y^)=yy^=0.002479706176998L'(y,\hat y)=y-\hat y=0.002479706176998
  • 计算输出层误差项:误差项是损失关于激活前的导数,已知激活函数 f<!swig1>(z)=11+ezf^ (z)=\frac{1}{1+e^{-z}},其导数公式是 f(z)=z(1z)f^{'}(z)=z(1-z),则损失关于输出层的误差项为 f(3)(z3)=0.997520293823002×(10.997520293823002)=0.002473557234274f^{(3)^{'}}(z^{3})=0.997520293823002\times(1-0.997520293823002)=0.002473557234274
    深度学习之反向传播BP算法详解-20250116162141
  • 计算第二层隐藏层误差项:第二层的误差项等于输出层误差项乘上两层之间的权重矩阵,再乘上激活函数的导数,前向计算可知 z4 输出是 Y=0.999874045072167,则 z4 上关于激活函数的导数是 Y (1-Y)= 0.002483519419601,z5 同理计算
    深度学习之反向传播BP算法详解-20250116162124
  • 计算第一层隐藏层误差项:同理,前一层回传的误差项乘上当前层激活函数的导数即可
    深度学习之反向传播BP算法详解-20250116162101
  • 更新参数:已知权重 W 和偏置 b 的更新公式如下

    \begin {array}{l} W^{(k)}=W^{(k)}-\alpha\left (\delta^{(k)}\left (n^{(k-1)}\right)^T+W^{(k)}\right)\\ {b^{(k)}=b^{(k)}-\alpha\delta^{(k)}}\end {array}$$,其中 $\alpha$ 是学习率,设为 0.1,则第一层隐藏层参数 W 更新如下:

    , 参数 b 更新如下:
    深度学习之反向传播BP算法详解-20250116162021

CNN 网络的后向传递过程?

  • 前向计算:假设 αl\alpha^l 是第 l 层的输出,zl+1z^{l+1} 是 l+1 层的输入,那么卷积层计算如下:
    深度学习之反向传播BP算法详解-20250116161953
    每个输出与输入的关系如下:
    深度学习之反向传播BP算法详解-20250116161930
  • 计算误差项:由链式法则,可得 l 层的误差项为

    δijl=Czijl=(nnCzminl+1zminl+1aijl)aijlzijl=(δl+1zl+1aijl)[1111]σ(zijl)\delta_{ij}^l=\dfrac{\partial C}{\partial z_{ij}^l}=\left(\sum_{\text{nn}}\dfrac{\partial C}{\partial z_{\text{min}}^{l+1}}\dfrac{\partial z_{\text{min}}^{l+1}}{\partial a_{ij}^l}\right)\dfrac{\partial a_{ij}^l}{\partial z_{ij}^l}=\left(\delta^{l+1}\odot\dfrac{\partial z^{l+1}}{\partial a_{ij}^l}\right)*\left[\begin{matrix}1&1\\ 1&1\end{matrix}\right]\sigma'\left(z_{ij}^l\right)

    结合前向计算公式,可得如下:
    深度学习之反向传播BP算法详解-20250116161908
  • 计算权重梯度:根据链式法则

    CWijl=mnCzmnlzmnlWijl\dfrac{\partial C}{\partial W_{ij}^l}=\sum_{mn}\dfrac{\partial C}{\partial z_{mn}^l}\dfrac{\partial z_{mn}^l}{\partial W_{ij}^l}

    则有以下结果
    深度学习之反向传播BP算法详解-20250116161835

参考:

  1. 一文彻底搞懂 BP 算法:原理推导 + 数据演示 + 项目实战(下篇) - 知乎
  2. 神经网络学习(十二)卷积神经网络与 BP 算法_bp 神经网络和卷积神经网络区别_oio328Loio 的博客 - CSDN 博客
  3. 卷积神经网络 (CNN) 反向传播算法 - 刘建平 Pinard - 博客园
  4. 如何解读 CNN 的反向传播计算算法? - 知乎