TensorFlow2.0深度学习(七)反向传播算法

        有了深度学习框架自动求导、自动更新权值的功能,算法设计者几乎不需要对反向传播算法有深入的了解也可以搭建复杂的模型和网络,通过优化工具方便地训练网络模型。但是反向传播算法和梯度下降算法是神经网络的核心算法,深刻理解其工作原理十分重要。本章先回顾导数、梯度等数学概念,然后推导常用激活函数、损失函数的梯度形式,并开始逐渐推导感知机、多层神经网络的梯度传播方式。

1. 导数与梯度

        导数被定义为自变量x在x_0处产生一个微小扰动△x后,函数的输出值的增量△y与自变量增量△x的比值在△x趋于0时的极限a,如果存在,a即为在x_0处的导数:

a=\lim_{\Delta x\to0}\frac{\Delta y}{\Delta x}=\lim_{\Delta x\to0}\frac{f(x+x_0)-f(x)}{\Delta x}

        从几何角度来看,一元函数在某处的导数就是函数的切线在此处的斜率,函数值沿着x方向的变化率。

        实际上,(方向)导数是一个非常宽泛的概念,只是因为我们以前接触到的函数大多是一元函数,自变量△x只有2个方向:x^+, x^-。当函数的自变量大于一个时,函数的导数拓展为函数值沿着任意△x方向的变化率。导数本身是标量,没有方向,但是导数表征了函数值在某个方向△x的变化率。在这些任意△x方向中,沿着坐标轴的几个方向比较特殊,此时的导数也叫做偏导数。

        考虑为多元函数的神经网络模型,比如 shape 为[784,256]的权值矩阵 W,它包含了784*256 个连接权值,我们需要求出 784*256 个偏导数。需要注意的是,在数学公式中,我们一般要讨论的自变量是x,但是在神经网络中,x一般用来表示输入,比如图片,文本,语音数据等,网络的自变量是网络参数集\theta=\{w_1,b_1,w_2,b_2,...\},我们关心的也是误差对网络参数的偏导数\frac{\partial \mathcal{L}}{\partial w_1},\frac{\partial \mathcal{L}}{\partial b_1}等。它其实就是函数输出\mathcal{L}沿着某个自变量\theta_i;变化方向上的导数,即偏导数。利用梯度下降算法优化网络时,需要求出网络的所有偏导数。我们把函数所有偏导数写成向量形式:

\nabla\mathcal{L}=\begin{pmatrix}\frac{\partial\mathcal{L}}{\partial\theta_1},&\frac{\partial\mathcal{L}}{\partial\theta_2},&\frac{\partial\mathcal{L}}{\partial\theta_3},&...\frac{\partial\mathcal{L}}{\partial\theta_n}\end{pmatrix}

此时梯度下降算法可以按着向量形式进行更新:

\theta'=\theta-\eta*\nabla\mathcal{L}

梯度下降算法一般是寻找函数的最小值,有时希望求解函数的最大值,如增强学习中希望最大化奖励函数,则可按着梯度方向更新

\theta'=\theta+\eta*\nabla\mathcal{L}

这种方式的更新称为梯度上升算法。梯度的方向表示函数值上升最快的方向,梯度的反向表示函数值下降最快的方向。

        通过梯度下降算法并不能保证得到全局最优解,这主要是目标函数的非凸性造成的。如下图。深蓝色区域为极小值区域,不同的优化轨迹可能得到不同的最优数值解。

2. 导数常见性质

2.1 基本函数的导数

2.2 常用导数性质

3. 激活函数导数

3.1 Sigmoid函数导数

表达式:

\sigma(x)=\frac{1}{1+e^{-x}}

导数表达式:

\frac{\mathrm{d} }{\mathrm{d} x}\sigma(x)=\sigma(x)-\sigma(x)^2=\sigma(1-\sigma)

3.2 ReLU函数导数

表达式:

ReLU(x):=max(0,x)

导数表达式:

\left.\frac d{dx}ReLU=\left\{\begin{matrix}1&x\geq0\\0&x<0\end{matrix}\right.\right.

3.3 LeakyReLU函数导数

表达式:

\left.LeakyReLU=\left\{\begin{matrix}x\quad x\geq0\\p*x\quad x<0\end{matrix}\right.\right.

导数表达式:

\frac{\mathrm{d} }{\mathrm{d} x}\left.LeakyReLU=\left\{\begin{matrix}1\quad x\geq0\\p\quad x<0\end{matrix}\right.\right.

3.4 Tanh函数梯度

表达式:

tanh(x)=\frac{(e^x-e^{-x})}{(e^x+e^{-x})}=2*sigmoid(2x)-1

导数表达式:

\begin{aligned}\frac d{dx}tanh(x)&=\frac{(e^x+e^{-x})(e^x+e^{-x})-(e^x-e^{-x})(e^x-e^{-x})}{(e^x+e^{-x})^2}\\&=1-\frac{(e^x-e^{-x})^2}{(e^x+e^{-x})^2}=1-tanh^2(x)\end{aligned}

4. 损失函数梯度

4.1 均方差函数梯度

        均方差损失函数表达式为:

\mathcal{L}=\frac12\sum_{k=1}^K(y_k-o_k)^2

则它的偏导数\frac{\partial \mathcal{L}}{\partial o_i}可以展开为

\frac{\partial\mathcal{L}}{\partial o_i}=\frac12\sum_{k=1}^K\frac\partial{\partial o_i}(y_k-o_k)^2

利用链式法则分解为

\begin{aligned}\frac{\partial\mathcal{L}}{\partial o_i}&=\frac12\sum_{k=1}^K2*(y_k-o_k)*\frac{\partial(y_k-o_k)}{\partial o_i}\end{aligned}

\frac{\partial\mathcal{L}}{\partial o_i}=\sum_{k=1}^K(y_k-o_k)*-1*\frac{\partial o_k}{\partial o_i}

均方差的导数可以推导为:

\frac{\partial\mathcal{L}}{\partial o_i}=(o_i-y_i)

4.2 交叉熵函数梯度

        在计算交叉熵损失函数时,一般将Softmax函数与交叉熵函数统一实现。先给出Softmax函数的梯度,再给出交叉熵函数的梯度。

Softmax梯度

        Softmax表达式:

p_i=\frac{e^{z_i}}{\Sigma_{k=1}^Ke^{z_k}}

        梯度:

\frac{\partial p_i}{\partial z_j}=\begin{cases}p_i(1-p_j)&i=j\\-p_i\cdot p_j&i\neq j\end{cases}

交叉熵梯度

        表达式

$\mathcal{L}=-\sum_ky_klog(p_k)$

        梯度

$\frac{\partial\mathcal{L}}{\partial\mathrm{z}_i}=p_i-y_i$

5. 全连接层梯度

        以全连接层,激活函数采用Sigmoid函数,误差函数为softmax+MSE损失函数的神经网络为例,推导其梯度传播方式。

5.1 单个神经元梯度

        对于采用Sigmoid激活函数的神经元模型,它的数学模型可以写为

$o^1=\sigma(w^1x+b^1)$

其中变量的上标表示层数,x表示网络的输入,以权值w的偏导数推导为例。神经元模型如下图所示,图中未画出偏置b,输入节点数为J。其中输入第j个节点到输出o^1的权值连接记为w_{j1}^1,上标表示权重属于的层数,下标表示当前连接的起始节点号和终止节点号。经过激活函数\sigma之前的变量叫做z_1^1,经过激活函数\sigma之后的变量叫o_1^1,由于只有一个输出节点,o_1^1=o^1。输出与真实标签之间计算误差,误差记为\mathcal{L}

        如果采用均方差误差函数,考虑到单个神经元只有一个输出o_1^1,那么损失可以表达为

$\mathcal{L}=\frac12(o_0^1-t)^2$

其中t为真实标签值,添加系数并不影响梯度的方向,计算更简便。以权值连接的第j∈[1,J]号节点的权值w_{j1}为例,考虑损失函数\mathcal{L}对其的偏导数:

$\frac{\partial\mathcal{L}}{\partial w_{j1}}=(o_1-t)\frac{\partial o_1}{\partial w_{j1}}$

o_1=\sigma(z_1)分解,考虑到Sigmoid函数的导数\sigma'=\sigma(1-\sigma)

$\begin{gathered} \frac{\partial\mathcal{L}}{\partial w_{j1}}=(o_{1}-t)\frac{\partial\sigma(z_{1})}{\partial w_{j1}} \\ =(o_{1}-t)\sigma(z_{1})\big(1-\sigma(z_{1})\big)\frac{\partial z_{1}^{1}}{\partial w_{j1}} \end{gathered}$

\sigma(z_1)写成o_1,继续推导:

$\frac{\partial\mathcal{L}}{\partial w_{j1}}=(o_1-t)o_1(1-o_1)\frac{\partial z_1^1}{\partial w_{j1}}$

考虑\frac{\partial z_1^1}{\partial w_{j1}}=x_j,可得:

$\frac{\partial\mathcal{L}}{\partial w_{j1}}=(o_1-t)o_1(1-o_1)x_j$

        从上式可以看到,误差值对权值w_{j1}的偏导数只与输出值o_1、真实值t以及当前权值连接的输入x_j有关。

5.2 全连接层梯度

        把单个神经元模型推广到单层全连接层的网络上,如下图所示。输入层通过一个全连接层得到输出向量o^1,与真实标签向量t计算均方差。输入节点数为J,输出节点数为K。

        多输出的全连接网络层模型与单个神经元模型的不同之处在于,它多了很多的输出节点o_1^1, o_2^1, o_3^1,...,o_k^1,同样的每个输出节点分别对应到真实标签t_1,t_2,...,t_K。均方差的误差可以表达为

$\mathcal{L}=\frac{1}{2}\sum_{i=1}^{K}(o_i^1-t_i)^2$

由于\frac{\partial \mathcal{L}}{\partial w_{jk}}只与节点o_k^1有关联,上式中的求和符号可以去掉,即i=k:

$\frac{\partial\mathcal{L}}{\partial w_{jk}}=(o_k-t_k)\frac{\partial o_k}{\partial w_{jk}}$

o_k=\sigma(z_k)代入

$\frac{\partial\mathcal{L}}{\partial w_{jk}}=(o_k-t_k)\frac{\partial\sigma(z_k)}{\partial w_{jk}}$

考虑Sigmoid函数的导数\sigma'=\sigma(1-\sigma)

$\frac{\partial\mathcal{L}}{\partial w_{jk}}=(o_k-t_k)\sigma(z_k)(1-\sigma(z_k))\frac{\partial z_k^1}{\partial w_{jk}}$

\sigma(z_k)记为o_k

$\frac{\partial\mathcal{L}}{\partial w_{jk}}=(o_k-t_k)o_k(1-o_k)\frac{\partial z_k^1}{\partial w_{jk}}$

最终可得

$\frac{\partial\mathcal{L}}{\partial w_{jk}}=(\mathrm{o}_{\mathrm{k}}-t_k)o_k(1-o_k)x_j$

由此可以看到,某条连接w_{jk}上面的连接,只与当前连接的输出节点o_k^1,对应的真实值节点的标签t_k^1,以及对应的输入节点x_j有关。

        令\delta_k=(\mathrm{o}_{\mathrm{k}}-t_k)o_k(1-o_k),则\frac{\partial\mathcal{L}}{\partial w_{jk}}可以表达为

\frac{\partial\mathcal{L}}{\partial w_{jk}}=\delta_kx_j

其中\delta_k变量表征连接线的终止节点的梯度传播的某种特性,使用\delta_k表示后,\frac{\partial\mathcal{L}}{\partial w_{jk}}偏导数只与当前连接的起始节点x_j,终止节点处\delta_k有关,理解起来比较直观。

6. 链式法则

        考虑复合函数y=f(u), u=g(x),则\frac{\mathrm{d} y}{\mathrm{d} x}可由\frac{\mathrm{d} y}{\mathrm{d} u}\frac{\mathrm{d} u}{\mathrm{d} x}推导出:

$\frac{dy}{dx}=\frac{dy}{du}\cdot\frac{du}{dx}=f^{\prime}(g(x))\cdot g^{\prime}(x)$

        神经网络的损失函数\mathcal{L}来自于各个输出节点o_k^K,其中输出节点o_k^K又与隐藏层的输出节点o_j^J相关联,因此链式法则非常适合于神经网络的梯度推导。

        前向传播时,数据经过w_{ij}^J传到倒数第二层的节点o_j^J,再传播到输出层的节点o_k^K。在每层只有一个节点时,\frac{\partial\mathcal{L}}{\partial w_{jk}^1}可以利用链式法则,逐层分解为:

$\frac{\partial\mathcal{L}}{\partial w_{ij}^J}=\frac{\partial\mathcal{L}}{\partial o_{j}^J}\frac{\partial o_{j}^J}{\partial w_{ij}^J}=\frac{\partial\mathcal{L}}{\partial o_{k}^K}\frac{\partial o_{k}^K}{\partial o_{j}^J}\frac{\partial o_{j}^J}{\partial w_{ij}^J}$

其中,\frac{\partial\mathcal{L}}{\partial o_{k}^K}可以由误差函数直接推导出,\frac{\partial o_{k}^K}{\partial o_{j}^J}可以由全连接层公式推导出,\frac{\partial o_{j}^J}{\partial w_{ij}^J}的导数即为输入x_i^I。可以看到,通过链式法则,不需要显示计算误差函数的具体数学表达式,直接可以将偏导数分解,层层迭代即可推导出。

7. 反向传播算法

        现在来推导隐藏层的反向传播算法。回顾一下输出层的偏导数公式:

$\frac{\partial\mathcal{L}}{\partial w_{jk}}=(o_k-t_k)o_k(1-o_k)x_j=\delta_kx_j$

考虑网络倒数第二层的导数\frac{\partial\mathcal{L}}{\partial w_{ij}},如下图所示,输出层节点数为K,输出为o^K=[o_1^K,o_2^K,...,o_K^K];倒数第二层节点数为J,输出为o^J=[o_1^J,o_2^J,...,o_J^J];倒数第三层的节点数为I,输出为o^I=[o_1^I,o_2^I,...,o_I^I]

        首先将均方差误差函数展开:

$\frac{\partial\mathcal{L}}{\partial w_{ij}}=\frac\partial{\partial w_{ij}}\frac12\sum_k(o_k-t_k)^2$

由于\mathcal{L}通过每个输出节点o_kw_{ij}相关联,故此处不能去掉求和符号,运用链式法则将均方差函数拆解:

$\frac{\partial\mathcal{L}}{\partial w_{ij}}=\sum_k(o_k-t_k)\frac\partial{\partial w_{ij}}o_k$

o_k=\sigma(z_k)代入

$\frac{\partial\mathcal{L}}{\partial w_{ij}}=\sum_k(o_k-t_k)\frac\partial{\partial w_{ij}}\sigma(z_k)$

利用Sigmoid函数的导数\sigma'=\sigma(1-\sigma)进一步分解

$\frac{\partial\mathcal{L}}{\partial w_{ij}}=\sum_k(o_k-t_k)\sigma(z_k)(1-\sigma(z_k))\frac{\partial z_k}{\partial w_{ij}}$

\sigma(z_k)写回o_k形式,并利用链式法则分解

$\frac{\partial{\mathcal L}}{\partial w_{ij}}=\sum_{k}(o_{k}-t_{k})o_{k}(1-o_{k})\frac{\partial z_{k}}{\partial o_{j}}\cdot\frac{\partial o_{j}}{\partial w_{ij}}$

其中\frac{\partial z_{k}}{\partial o_{j}}=w_{jk},因此

$\frac{\partial\mathcal{L}}{\partial w_{ij}}=\sum_k(o_k-t_k)o_k(1-o_k)w_{jk}\frac{\partial o_j}{\partial w_{ij}}$

考虑到\frac{\partial o_j}{\partial w_{ij}}与k无关可提取公共项

$\frac{\partial\mathcal{L}}{\partial w_{ij}}=\frac{\partial o_j}{\partial w_{ij}}\sum_k(o_k-t_k)o_k(1-o_k)w_{jk}$

进一步利用o_j=\sigma(z_j),并利用Sigmoid导数\sigma'=\sigma(1-\sigma)\frac{\partial o_j}{\partial w_{ij}}拆分为

$\frac{\partial\mathcal{L}}{\partial w_{ij}}=o_j(1-o_j)\frac{\partial z_j}{\partial w_{ij}}\sum_k(o_k-t_k)o_k(1-o_k)w_{jk}$

其中\frac{\partial z_j}{\partial w_{ij}}的导数可直接推导出为o_i,上式可写为

$\frac{\partial\mathcal{L}}{\partial w_{ij}}=o_j(1-o_j)o_i\sum_k\underbrace{(o_k-t_k)o_k(1-o_k)}_{\delta_k^K}w_{jk}$

表达式可简写为

$\frac{\partial\mathcal{L}}{\partial w_{ij}}=o_j(1-o_j)o_i\sum_{\mathrm{k}}\delta_k^Kw_{jk}$

仿照输出层\frac{\partial\mathcal{L}}{\partial w_{jk}}=\delta_k^Kx_j的书写方式,将\delta_j^J定义为

$\delta_j^J:=o_j(1-o_j)\sum_k\delta_k^Kw_{jk}$

此时,\frac{\partial\mathcal{L}}{\partial w_{ij}}可以写为当前连接的起始节点的输出值o_i与终止节点j的梯度信息\delta_j^J的简单相乘运算:

$\frac{\partial\mathcal{L}}{\partial w_{ij}}=\delta_j^Jo_i^I$

通过定义δ变量,每一层的梯度表达式变得更加清晰简洁,其中δ可以简单理解为当前连接w_{ij}对误差函数的贡献值。

        小结一下每层的偏导数的计算公式。

输出层

$\begin{aligned}\frac{\partial\mathcal{L}}{\partial w_{jk}}&=\delta_k^Ko_j\\\delta_k^K&=o_k(1-o_k)(o_k-t_k)\end{aligned}$

倒数第二层

$\begin{gathered} \frac{\partial\mathcal{L}}{\partial w_{ij}}=\delta_j^Jo_i \\ \delta_{j}^{J}=o_{j}(1-o_{j})\sum_{k}\delta_{k}^{K}w_{jk} \end{gathered}$

倒数第三层

$\begin{aligned}\frac{\partial\mathcal{L}}{\partial w_{ni}}&=\delta_i^lo_n\\\delta_i^I&=o_i(1-o_i)\sum_j\delta_j^Jw_{ij}\end{aligned}$

其中o_n为倒数第三层的输入,即倒数第四层的输出。

        依照此规律,只需要循环迭代计算每一层每个节点的$\delta_{k}^{K},\delta_{j}^{J},\delta_{i}^{I},\ldots $等值即可求得当前层的偏导数,从而得到每层权重矩阵W的梯度,在通过梯度下降算法迭代优化网络参数即可。

8. Himmelblau函数优化实战

step 19: x = [-2.805118   3.1313124], f(x) = 2.2737367544323206e-13
step 39: x = [-2.805118   3.1313124], f(x) = 2.2737367544323206e-13
step 59: x = [-2.805118   3.1313124], f(x) = 2.2737367544323206e-13
step 79: x = [-2.805118   3.1313124], f(x) = 2.2737367544323206e-13
step 99: x = [-2.805118   3.1313124], f(x) = 2.2737367544323206e-13
step 119: x = [-2.805118   3.1313124], f(x) = 2.2737367544323206e-13
step 139: x = [-2.805118   3.1313124], f(x) = 2.2737367544323206e-13
step 159: x = [-2.805118   3.1313124], f(x) = 2.2737367544323206e-13
step 179: x = [-2.805118   3.1313124], f(x) = 2.2737367544323206e-13
step 199: x = [-2.805118   3.1313124], f(x) = 2.2737367544323206e-13
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值