5.1-反向传播算法过程梳理

1函数求导链式法则

  1. 链式法则①:对于 y = g ( x ) y=g(x) y=g(x) z = h ( y ) z=h(y) z=h(y)

Δ x → Δ y → Δ z \Delta{x}\rightarrow\Delta{y}\rightarrow\Delta{z} ΔxΔyΔz

d z d x = d z d y d y d x \frac{dz}{dx}=\frac{dz}{dy}\frac{dy}{dx} dxdz=dydzdxdy

  1. 链式法则②:对于 x = g ( s ) x=g(s) x=g(s) y = h ( s ) y=h(s) y=h(s)以及 z = k ( x , y ) z=k(x,y) z=k(x,y)
    在这里插入图片描述
    d z d s = ∂ z ∂ x d x d s + ∂ z ∂ y d y d s \frac{dz}{ds}=\frac{\partial{z}}{\partial{x}}\frac{dx}{ds}+\frac{\partial{z}}{\partial{y}}\frac{dy}{ds} dsdz=xzdsdx+yzdsdy

2反向传播基本思想

  1. 对于一个有 N N N个样本的训练集,经神经网络前向传播计算之后,得到输出值,计算每一个样本的输出值与实际值的差值 C n C^n Cn(当然也可以是其他的计算误差的函数),并求和,就得到当前神经网络参数设置下的损失值。如式(1)和下图所示:

在这里插入图片描述

图1

L ( θ ) = ∑ n = 1 N C n ( θ ) (1) L(\theta)=\sum_{n=1}^{N}{C^n(\theta)} \tag{1} L(θ)=n=1NCn(θ)(1)

  1. 根据在线性回归中的梯度下降的思想,需要对代价函数求偏导数,然后用偏导数来更新参数(具体为什么这样做就牵扯到方向导数以及梯度的概念,我暂时没理解,感兴趣的可以看文末的参考文章)。因此在神经网络中,我们沿用这种思想,即计算代价函数对网络中每个参数的偏导数,如式(2)所示。因此,我们只需要计算单个样本的代价函数对参数的偏导数,然后用循环来重复计算所有的样本。

∂ L ( θ ) ∂ θ = ∑ n = 1 N ∂ C n ( θ ) ∂ θ (2) \frac{\partial{L(\theta)}}{\partial{\theta}}=\sum_{n=1}^{N}{\frac{\partial{C^n(\theta)}}{\partial{\theta}}} \tag{2} θL(θ)=n=1NθCn(θ)(2)

3反向传播算法全览

  1. 由式(2)可知,反向传播算法可以是一个遍历所有样本的循环,其中计算每个样本带来的偏导数,如下图所示。
    在这里插入图片描述
图2
  1. 接下来,我们结合李宏毅老师和吴恩达老师的相关讲解来逐步理清反向传播算法的过程。

4反向传播算法理解过程

4.1一个输入层+一个输出层(两层的神经网络)

  1. 对单个样本而言,如果一个神经网络如下图所示(只有两层,第一层是输入层(两个神经元),第二层是输出层(一个神经元))。其中 z = x 1 θ 1 + x 2 θ 2 + b z=x_1\theta_1+x_2\theta_2+b z=x1θ1+x2θ2+b(将 w w w换成 θ \theta θ纯属为了与吴恩达的一致,而 b b b也可以看作是第一层最上面再加一个偏置神经元,其权值为 b b b).我们暂且就让 z = x 1 θ 1 + x 2 θ 2 z=x_1\theta_1+x_2\theta_2 z=x1θ1+x2θ2
    在这里插入图片描述
图3
  • 此时就可以计算代价函数对参数 θ \theta θ的偏导数,如式(3)所示(用到函数求导链式法则①):

∂ C ∂ θ = ∂ C ∂ z ∂ z ∂ θ (3) \frac{\partial{C}}{\partial{\theta}}=\frac{\partial{C}}{\partial{z}}\frac{\partial{z}}{\partial{\theta}} \tag{3} θC=zCθz(3)

  • 很显然, ∂ z ∂ θ 1 = x 1 \frac{\partial{z}}{\partial{\theta_1}}=x_1 θ1z=x1 ∂ z ∂ θ 2 = x 2 \frac{\partial{z}}{\partial{\theta_2}}=x_2 θ2z=x2。而由于存在式(4)所示的关系(其中 y y y是常数,而 a a a是函数),

C = L o s s F u n c t i o n ( a , y ) = L o s s F u n c t i o n ( f u n c t i o n s i g m o i d ( z ) , y ) (4) C=LossFunction(a,y)=LossFunction(function_{sigmoid}(z),y) \tag{4} C=LossFunction(a,y)=LossFunction(functionsigmoid(z),y)(4)

所以 ∂ C ∂ z = ∂ C ∂ a ∂ a ∂ z \frac{\partial{C}}{\partial{z}}=\frac{\partial{C}}{\partial{a}}\frac{\partial{a}}{\partial{z}} zC=aCza。因为此时的神经网络只有两层,所以 ∂ C ∂ a \frac{\partial{C}}{\partial{a}} aC的值可以由具体的代价函数求得,而 ∂ a ∂ z \frac{\partial{a}}{\partial{z}} za则是具体的激活函数的偏导数(导数),也可以直接求得。

4.2多层神经网络

  1. 现在神经网络结构变成了下图的样子。即至少包含三层结构:两个输入单元,第二层有一个神经元,第三层有两个神经元。

在这里插入图片描述

图4
  1. 在两层的神经网络结构中,我们已经知道 ∂ z ∂ θ 1 = x 1 \frac{\partial{z}}{\partial{\theta_1}}=x_1 θ1z=x1 ∂ z ∂ θ 2 = x 2 \frac{\partial{z}}{\partial{\theta_2}}=x_2 θ2z=x2。在多层神经网络中,由于每一个 z z z都是关于 θ \theta θ的线性组合,因此只需知道所有的神经元的激活值 a a a就可以求得所有的 ∂ z ∂ θ \frac{\partial{z}}{\partial{\theta}} θz了。一个实际的例子如下图所示。

在这里插入图片描述

图5
  1. 所以在多层神经网络中,求代价函数对某一个参数的偏导数 ∂ C ∂ θ \frac{\partial{C}}{\partial{\theta}} θC,依旧可以使用 ∂ C ∂ θ = ∂ C ∂ z ∂ z ∂ θ \frac{\partial{C}}{\partial{\theta}}=\frac{\partial{C}}{\partial{z}}\frac{\partial{z}}{\partial{\theta}} θC=zCθz。而问题的关键就还是落在了求解 ∂ C ∂ z \frac{\partial{C}}{\partial{z}} zC上。而此时 ∂ C ∂ z = ∂ C ∂ a ∂ a ∂ z \frac{\partial{C}}{\partial{z}}=\frac{\partial{C}}{\partial{a}}\frac{\partial{a}}{\partial{z}} zC=aCza依旧成立。
  2. 从图4的结构我们可以知道,此时的 ∂ C ∂ a \frac{\partial{C}}{\partial{a}} aC的值不可以直接根据代价函数的具体形式求得(因为后面还有其他隐藏层神经元),而需要根据函数求导的链式法则②来求解,根据图6所示的链式法则,可以得到式(5)。

在这里插入图片描述

图6

∂ C ∂ a = ∂ C ∂ z ′ ∂ z ′ ∂ a + ∂ C ∂ z ′ ′ ∂ z ′ ′ ∂ a (5) \frac{\partial{C}}{\partial{a}}=\frac{\partial{C}}{\partial{z^{'}}}\frac{\partial{z^{'}}}{\partial{a}}+\frac{\partial{C}}{\partial{z^{''}}}\frac{\partial{z^{''}}}{\partial{a}} \tag{5} aC=zCaz+z′′Caz′′(5)

  1. 因此只需要求得 ∂ C ∂ z ′ \frac{\partial{C}}{\partial{z^{'}}} zC ∂ C ∂ z ′ ′ \frac{\partial{C}}{\partial{z^{''}}} z′′C,就可以求得 ∂ C ∂ z \frac{\partial{C}}{\partial{z}} zC。如式(6)所示。而 σ ′ ( z ) \sigma^{'}(z) σ(z)是一个常数(在神经网络正向计算时就已经算出来 z z z了)。式(6)更直观的图示如图7所示。

∂ C ∂ z = ∂ C ∂ a ∂ a ∂ z = ( θ 3 ∂ C ∂ z ′ + θ 4 ∂ C ∂ z ′ ′ ) σ ′ ( z ) (6) \frac{\partial{C}}{\partial{z}}=\frac{\partial{C}}{\partial{a}}\frac{\partial{a}}{\partial{z}}=(\theta_3\frac{\partial{C}}{\partial{z^{'}}}+\theta_4\frac{\partial{C}}{\partial{z^{''}}})\sigma^{'}(z) \tag{6} zC=aCza=(θ3zC+θ4z′′C)σ(z)(6)
在这里插入图片描述

图7
  1. 那么如果图4就是完整的神经网络,则根据 ∂ C ∂ z = ∂ C ∂ a ∂ a ∂ z \frac{\partial{C}}{\partial{z}}=\frac{\partial{C}}{\partial{a}}\frac{\partial{a}}{\partial{z}} zC=aCza可以求得式(7)(8)。其中我们就认为 y 1 y_1 y1 y 2 y_2 y2相当于是激活值 a a a ∂ C ∂ y \frac{\partial{C}}{\partial{y}} yC由具体的代价函数求出, ∂ y ∂ z \frac{\partial{y}}{\partial{z}} zy由激活函数的导数求出。

∂ C ∂ z ′ = ∂ C ∂ y 1 ∂ y 1 ∂ z ′ (7) \frac{\partial{C}}{\partial{z^{'}}}=\frac{\partial{C}}{\partial{y_1}}\frac{\partial{y_1}}{\partial{z^{'}}} \tag{7} zC=y1Czy1(7)

∂ C ∂ z ′ ′ = ∂ C ∂ y 2 ∂ y 2 ∂ z ′ ′ (8) \frac{\partial{C}}{\partial{z^{''}}}=\frac{\partial{C}}{\partial{y_2}}\frac{\partial{y_2}}{\partial{z^{''}}} \tag{8} z′′C=y2Cz′′y2(8)

  1. 而如果后面还有其他神经元,则继续重复上述过程,如图8所示。直到到达了输出层。

在这里插入图片描述

图8

4.3反向传播过程梳理

  1. 纵观4.1和4.2节可以发现,求解代价函数对参数的偏导数,最终将归结到求解 ∂ C ∂ z \frac{\partial{C}}{\partial{z}} zC上。如图9所示。

在这里插入图片描述

图9
  1. 以图9为例,并且还具有以下两个规律:
  • 要求解 ∂ C ∂ z 1 \frac{\partial{C}}{\partial{z_1}} z1C ∂ C ∂ z 2 \frac{\partial{C}}{\partial{z_2}} z2C,就需要知道 ∂ C ∂ z 3 \frac{\partial{C}}{\partial{z_3}} z3C ∂ C ∂ z 4 \frac{\partial{C}}{\partial{z_4}} z4C。以此类推,直到输出层(根据代价函数求得最后的偏导数)。
  • 而某一个 ∂ C ∂ z \frac{\partial{C}}{\partial{z}} zC是由下一层的 ∂ C ∂ z \frac{\partial{C}}{\partial{z}} zC分别乘上对应参数,并与激活函数的导数值相乘,就如同式(6)所示的那样。
  • 一个更加直观的图如图10所示。

在这里插入图片描述

图10
  1. 综上,由于前一层的偏导数需要下一层的偏导数来支撑,因此求偏导数的过程实际上是反过来求的,也就是所谓的反向传播算法了。整个过程关键就是求出 ∂ C ∂ z \frac{\partial{C}}{\partial{z}} zC ∂ z ∂ θ \frac{\partial{z}}{\partial\theta} θz,如图11所示。而 ∂ C ∂ z \frac{\partial{C}}{\partial{z}} zC是关键之关键,也是最麻烦的。

在这里插入图片描述

图11

5反向传播算法过程与第3节算法全览的联系

这一节主要是在第4节理解反向传播过程的基础上,理解反向传播算法的伪代码流程(即第3节所列的算法流程)

  1. 首先,第4节描述的过程是针对某一个样本的,因此实际需要对所有的样本都执行这样的操作,也就对应了算法流程的循环体;
  2. 整个反向传播过程中需要用到的变量的值,如 a a a z z z等也都需要先进行正常的前向计算过程(即forward propagation)。
  3. 以图12为例,计算一下几个偏导数。

在这里插入图片描述

图12
  • 求代价函数对参数矩阵第三层的各参数的偏导数,如图13所示。

在这里插入图片描述

图13
  • 接着计算第二层(这里只计算了一个),如图14所示,并且逐步向第3节反向传播算法中计算 Δ l i j \Delta^l{_{ij}} Δlij的形式靠拢:

在这里插入图片描述

图14
  • 将图14中红框中的式子与图15中红框的式子对比,可以发现式图16所示的联系(需要注意的是,按照吴的视频,图12 z z z a a a的上标均需要加1才能够完全对的上
    在这里插入图片描述
图15

在这里插入图片描述

图16

6总结

  • 本文将李宏毅老师对反向传播算法的过程推导和吴恩达老师关于该算法的算法流程做了对比,希望能够帮助大家加深对该算法的理解
  • 文中可能存在相关符号的错误,公式的不严谨等
  • 之后还会通过神经网络的python的实现来进一步理解该算法。

参考文章

梯度下降原理(个人理解)__ztt.的博客-CSDN博客_梯度下降为什么是减

如何直观形象地理解方向导数与梯度以及它们之间的关系? - 知乎 (zhihu.com)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Understand是一种功能强大的软件开发工具,它提供了多种语言和平台的静态代码分析功能,用于帮助开发人员理解和改进他们的代码质量。 5.1是Understand的一个特定版本号,它表示 Understad软件的第5个大版本中的一个小更新。 Windows64表示这个Understand版本适用于运行在Windows操作系统的64位机器上。 通过使用Understand 5.1-windows64,开发人员可以对代码进行全面的分析和评估,以确保代码的质量和可维护性。它可以帮助开发人员识别潜在的代码缺陷、冗余代码和性能问题,并提供解决方案来改善代码质量。 该版本还具备了适用于Windows 64位机器的优化和兼容性,以确保在这样的机器上能够运行和运行分析任务的平稳性。 总之,Understand 5.1-windows64是一款适用于在Windows 64位操作系统上运行的强大的软件开发工具,它为开发人员提供了全面的代码分析功能,帮助他们提高代码质量和可维护性。 ### 回答2: understand 5.1-windows64 指的是一个软件的版本和系统要求。Understand 是一款用于源代码分析的软件工具,用于帮助开发人员理解和浏览复杂的代码。5.1 是这个软件的版本号,表示该软件经过一系列的更新和改进。windows64 表示该软件支持 64 位的 Windows 操作系统。 对于开发人员来说,使用 Understand 5.1-windows64 有几个优势。首先,它可以帮助他们更好地理解和分析源代码。该软件提供了多种功能,如交互式图表、图形视图和搜索功能,可以帮助开发人员深入了解代码的结构和关系,从而更高效地调试和优化代码。 其次,Understand 5.1-windows64 具有良好的兼容性,可以在 Windows 64 位系统上正常运行。64 位操作系统相比于32位操作系统具有更大的内存容量和更快的处理速度,这对于处理大型代码库和复杂的分析任务非常重要。使用 64 位系统可以提高软件工具的性能和效率。 此外,Understand 5.1-windows64 的更新版本可能还会解决了一些 bug,增加了新功能或提高了软件的稳定性。开发人员可以从该软件的版本迭代中获益。 总之,Understand 5.1-windows64 是一款功能强大的源代码分析工具,适用于 Windows 64 位系统。它可以帮助开发人员更好地理解和分析源代码,提高开发效率,并且与 64 位操作系统相对应,能够更好地支持大型代码库和复杂的分析任务。 ### 回答3: understand5.1-windows64是一款用于软件开发的工具,它是在Windows操作系统下工作的64位版本。Understand是一个功能强大的代码理解工具,它可以帮助程序员对代码进行深入的分析和理解。 使用understand5.1-windows64,程序员可以对源代码进行静态分析,了解代码的结构、功能和相互关系。它支持多种编程语言,包括C、C++、C#、Java等。程序员可以快速地浏览代码,并通过各种视图和图表来可视化分析结果。 此外,understand5.1-windows64还提供了全面的代码检查和度量功能,帮助程序员评估代码的质量和健壮性。它可以检测潜在的错误、重复的代码和性能问题,并生成报告供程序员参考和改进。 另外,understand5.1-windows64还支持代码重构和搜索功能。程序员可以通过重构工具对代码进行重构,提高代码的可读性和可维护性。搜索功能可以帮助程序员快速定位特定的代码片段,提高开发效率。 总而言之,understand5.1-windows64是一款功能强大且易于使用的代码理解工具。它提供了丰富的分析和度量功能,帮助程序员更好地理解和改进源代码。无论是初学者还是经验丰富的开发人员,都可以从中受益并提高代码开发的效率和质量。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值