前言

之前讲了前向传播,这篇文章讲一下反向传播的原理,以及神经网络怎么更新参数的,讲了一下梯度下降法的计算过程和收敛过程。

梯度与梯度下降

简单介绍

摘自百科上的一段话:

梯度(英语:gradient)是一种关于多元导数的概括。平常的一元(单变量)函数的导数是标量值函数,而多元函数的梯度是向量值函数多元可微函数𝑓在点𝑃上的梯度,是以𝑓在𝑃上的偏导数为分量的向量[1]

通俗的话来说,多元函数的梯度,是由每个偏导数组成的向量,每一点的梯度方向就是多元函数在该点梯度值所表示得向量方向。对于一元函数来说,梯度就相当于一元函数的微分/导数,下面从一元函数开始出发,演示一下梯度是如何作用的。

一元函数导数

对于函数f(x)=x2f(x)=x^2,其导数为f(x)=2xf^{'}(x)=2x来说,很容易知道其极值点/最小值点在x=0x=0取得,即fmin(x)=f(0)=0f_{\min}(x)=f(0)=0。那么如何用梯度下降的方法来让计算机寻找极值/最值呢?

  1. 随机取一个x=x0x=x_0,在该点的导数值(“梯度值”)为f(x)=2x0f^{'}(x)=2x_0
  2. 更新参数,利用梯度值如何更新呢?梯度下降法,顾名思义,沿着梯度的负方向更新即可,就变成:xnew=xf(x)=x02x0=x0x_{new}=x-f^{'}(x)=x_0-2x_0=-x_0
  3. 我们发现,xx确实更新了,而且变成了x0-x_0,但是又发现一个问题,距离真的极值点的距离没有变。
  4. 继续按照上述方法计算下去,明显都不收敛了,所以需要引入一个机制让过程收敛才行——那便是学习率,记为lrl_r,通常取很小的值,比如lr=0.1l_r=0.1

引入学习率lr=0.1l_r=0.1之后,会发生什么呢?

  1. 继续第二步,xnew=xlr×f(x)=x00.1×2x0=0.8x0x_{new}=x-l_r\times f^{'}(x) = x_0-0.1\times2x_0=0.8x_0,发现离真实值近了很多。
  2. 不如继续用这种方法更新,假设x0=1000x_0=1000,那么在进行100次之后,x02.04×107x_0\approx2.04\times10^{-7}f(x0)4.15×1014f(x_0)\approx4.15\times10^{-14}​,很明显非常接近真实值了。

多元函数梯度

对于函数f(x,y)=x2+y2f(x,y)=x^2+y^2,其偏导数为fx=2x,fy=2y\frac{\partial f}{\partial x}=2x,\frac{\partial f}{\partial y}=2y,极值点也很明显在(x,y)=(0,0)(x,y)=(0,0)取得。

  1. 随机选取初始值X=(x0,y0)X=(x_0,y_0),同样的分别求出该点的偏导数值,然后利用更新公式进行更新
  2. Xnew(x,y)=(x0lr×2x0,y0lr×2y0)X_{new}(x,y)=(x_0-l_r\times2x_0,y_0-l_r\times2y_0),计算个许多次,就可以发现该函数收敛了

一个思考

上述两个例子,都是直接把导数的解析式写出来的,但是在神经网络这么多参数中,不可能都写出导数解析式,该如何求这个导数呢?而且,神经网络如何快速求导数来快速更新参数呢?下面就要讲到反向传播的原理了。

反向传播

简单介绍

摘自百科上的一段话:

反向传播(英语:Backpropagation,意为误差反向传播,缩写为BP)是对多层人工神经网络进行梯度下降的算法,也就是用链式法则以网络每层的权重为变量计算损失函数的梯度,以更新权重来最小化损失函数。[2]

简单来说,反向传播是为了快速更新权重的方法。所以一次神经网络的计算会分为两个步骤,先进行前向传播计算预测值,然后再反向传播链式更新参数。

单个神经元的反向传播

注: 先前的一元/多元函数例子中,并没有介绍什么是损失函数,也没有关注损失函数是啥。而是简单用函数来替代损失函数了(上述损失函数实际上是:Loss(x)=x2L_{oss}(x)=x^2以及Loss(x,y)=x2+y2L_{oss}(x,y)=x^2+y^2),仅仅是因为这两个函数可以反应与真实值的误差,因为梯度下降法是要求损失函数关于各个参数的偏导数,下面会引入损失函数来计算。


先用单个神经元举例子

wxbC

xx经过上述神经元计算出来的是预测值y^=f(wx+b)\hat{y}=f(wx+b),其中ww是权重,bb是偏置,ff是激活函数,假设真实值输出为yy,损失函数记为ll

我们可以写出损失函数来:Loss=l(y^,y)L_{oss}=l(\hat{y},y)。这里有两个量需要更新,一个是权重,一个是偏置。

lw=ly^×y^w=ly^×y^wlb=ly^×y^b=ly^×y^b\frac{\partial l}{\partial w}=\frac{\partial l}{\partial\hat{y}}\times\frac{\partial\hat{y}}{\partial w}\\ =\frac{\partial l}{\partial\hat{y}}\times\frac{\partial\hat{y}}{\partial w}\\\\ \frac{\partial l}{\partial b}=\frac{\partial l}{\partial\hat{y}}\times\frac{\partial\hat{y}}{\partial b}\\ =\frac{\partial l}{\partial\hat{y}}\times\frac{\partial\hat{y}}{\partial b}

由高等数学可知上述的公式(假设激活函数可导)。假设损失函数为MSELoss,激活函数为sigmoid

loss:1ni=1n(y^iyi)2sigmoid:S(x)=11+ex,S(x)=ex(1+ex)2=S(x)(1S(x))loss: \frac{1}{n}\sum\limits_{i=1}^n(\hat{y}_i-y_i)^2\\ sigmoid: S(x)=\frac{1}{1+e^{-x}},\quad S^{'}(x) = \frac{e^{-x}}{(1+e^{-x})^2}=S(x)(1-S(x))

下面来分布计算一下每个函数过程,先是在输出层C处的计算

l(y^,y)=(y^y)2,ly^=2(y^y)l(\hat{y},y)=(\hat{y}-y)^2,\quad \frac{\partial l}{\partial\hat{y}}=2(\hat{y}-y)

上述式子可以计算出第一步来,而且只需要代值进去即可。然后在神经元b处的计算

y^=f(wx+b)=11+e(wx+b),y^w=xS(wx+b)(1S(wx+b))=vwy^b=S(wx+b)(1S(wx+b))=vb\hat{y}=f(wx+b)=\frac{1}{1+e^{-(wx+b)}},\\ \frac{\partial\hat{y}}{\partial w}=xS(wx+b)\left(1-S(wx+b)\right)=v_w\\ \frac{\partial\hat{y}}{\partial b}=S(wx+b)\left(1-S(wx+b)\right)=v_b\\

可以看出,在某一层计算的时候,只需要下一层给一个值,然后就能够在当前进行计算了,然后利用更新式子更新即可wnew=wlr×vw,bnew=blr×vbw_{new}=w-l_r\times v_w,b_{new}=b-l_r\times v_b,实现反向传播,下面给出多层的例子。

多层神经元举例子

用下述神经网络举例子

x1L11L12L13x2x3L21L22L22L31L32L32L41L42L42

之前的博客已经讲过了前向传播,符合记法也在之前的博客中有,前向传播就是从输入到输出。假设已经完成了前向传播,现在开始反向传播。

继续假设损失函数为MSELoss,激活函数为sigmoid

  1. 先计算损失值,并写出损失函数

Loss=l(y^1,y^2,y^3,y1,y2,y3)=13[(y^1y1)2+(y^2y2)2+(y^3y3)2]ly^1=2(y^1y1)3L_{oss}=l(\hat{y}_1,\hat{y}_2,\hat{y}_3,y_1,y_2,y_3)=\frac{1}{3}\left[(\hat{y}_1-y_1)^2+(\hat{y}_2-y_2)^2+(\hat{y}_3-y_3)^2\right]\\ \frac{\partial l}{\partial\hat{y}_1}=\frac{2(\hat{y}_1-y_1)}{3}

  1. 先算输出层,一层中各个神经元之间并没有什么练习,所以对某个神经元偏导是不会包含其他神经元的参数的。记任何一层神经元的输入为Xi(i=1,2,3,y)X_i\quad(i=1,2,3,y),某个神经元的输入就是xij(i=1,2,3,y),(j=1,2,3)x_{ij}\quad (i=1,2,3,y),(j=1,2,3),下面来计算y1这个神经元吧

lw411=ly^1y^1w411=ly^1x411\frac{\partial l}{\partial w_{411}}=\frac{\partial l}{\partial\hat{y}_1}\cdot\frac{\partial\hat{y}_1}{\partial w_{411}}\\=\frac{\partial l}{\partial\hat{y}_1}\cdot x_{411}

  1. 还有一个点需要被意识到,x411x_{411}实际上也是y31y_{31},也就是L31的输出,我们在前向传播中已经求过了,这里可以直接用,就能够非常快的求出上述式子的导数值了,记为vv,根据梯度下降法可以很快的更新参数了,w411=w411lr×vw_{411}=w_{411}-l_r\times v,即可更新一次
  2. 继续计算L31这一层的权重,这里有三个的原因是,L31这个神经元经过三条路才到达损失函数,L31->L41, L31->L42, L31->L43,因为L31和后一层是全连接的

lw311=ly^1y^1x411x411w311+ly^2y^2x412x412w311+ly^3y^3x413x413w311\frac{\partial l}{\partial w_{311}}=\frac{\partial l}{\partial\hat{y}_1}\cdot\frac{\partial\hat{y}_1}{\partial x_{411}}\cdot\frac{\partial x_{411}}{\partial w_{311}} +\frac{\partial l}{\partial\hat{y}_2}\cdot\frac{\partial\hat{y}_2}{\partial x_{412}}\cdot\frac{\partial x_{412}}{\partial w_{311}} +\frac{\partial l}{\partial\hat{y}_3}\cdot\frac{\partial\hat{y}_3}{\partial x_{413}}\cdot\frac{\partial x_{413}}{\partial w_{311}}

  1. 用同样的方法来计算上述公式,就以第一项为例

ly^1y^1x411x411w311\frac{\partial l}{\partial\hat{y}_1}\cdot\frac{\partial\hat{y}_1}{\partial x_{411}}\cdot\frac{\partial x_{411}}{\partial w_{311}}

  1. 计算上述公式,第一项不用说了,前面算过了

    1. 值得注意的是,y^1=x411+x421+x431\hat{y}_1=x_{411}+x_{421}+x_{431},所以中间这一项为1,不用算

    2. 对于右边这一项,由于引入了激活函数,所以还需要计算激活函数的值

x411w311=y31f(w311y31+b31)\frac{\partial x_{411}}{\partial w_{311}}=y_{31}f^{'}(w_{311}y_{31}+b_{31})

  1. 同样,可以快算在该层算出来,继续用梯度下降法更新即可

参考链接


  1. 维基百科编者. 梯度[G/OL]. 维基百科, 2023(20230917)[2023-09-17]. https://zh.wikipedia.org/w/index.php?title=%E6%A2%AF%E5%BA%A6&oldid=78965959. ↩︎

  2. 维基百科编者. 反向传播算法[G/OL]. 维基百科, 2024(20240108)[2024-01-08]. https://zh.wikipedia.org/w/index.php?title=%E5%8F%8D%E5%90%91%E4%BC%A0%E6%92%AD%E7%AE%97%E6%B3%95&oldid=80417683. ↩︎