本课程笔记是基于今年斯坦福大学Feifei Li, Andrej Karpathy & Justin Johnson联合开设的Convolutional Neural Networks for Visual Recognition课程的学习笔记。目前课程还在更新中,此学习笔记也会尽量根据课程的进度来更新。


1. 引子

在这一章中,我们将介绍backpropagation,也就是反向传播算法,理解这一过程对于学习神经网络很重要。
之前的章节中我们定义了一个loss function,它是输入数据x和网络参数W的函数,我们希望通过调节W使得网络的loss最小——这在Optimazation那一节中讲过,通过梯度下降法来更新W。但是神经网络是一个多层的结构,直接用输出对输入求导计算非常复杂,因此我们会用到反向传播算法来进行逐层的梯度传播与更新。


我们先来简单地回顾一下偏导数的计算和链式法则。比如函数f(x,y,z)=(x+y)*z, 为了求得f对三个输入x,y,z的偏导(即梯度),我们可以首先把它看成一个两层的组合函数,分解成q=x+y,f=q*z。这样逐层地计算偏导数就简单了:;其中q又是x和y的函数,对x,y的偏导数又可以写成
那么根据链式法则,,也就是说输出对输入的偏导可以通过两层网络组合得到。如下图,假设我们代入x=-2,y=5,z=-4,计算上述函数f的值和导数分别如图中绿色数字和红色数字所示。我们可以发现计算值的过程是从输入向输出逐层计算,我们称为前向传播;而计算导数的过程则是从输出向输入逐层计算得,称为反向传播

注意每一层的门电路都能够独立地根据局部的输入计算当前门电路的输出以及局部的梯度,而不需要去考虑其他层的操作。

  • 比如以“+”门为例,输入为x=-2,y=5,计算得输出为3(前向传播),又由于进行的是加法运算,因此,对于两个输入的局部梯度均为+1(反向传播)。
  • 接着进行“ ∗ *”门的运算,此时输入为上一层的输出q=3,及z=-4,相乘得到最终输出为-12,又由于进行的是乘法运算,,对于两个输入的局部梯度分别为z和q,即-4和3。
  • 那么在反向传播过程中,局部梯度会通过链式法得到最终梯度,即,因此最终f对x的偏导就是两个门电路的局部梯度相乘,也就是1*-4=-4。梯度为负表示的意思是如果x,y减小,则+门的输出会减小,而最终*门的输出会增大。

说了这么多,主要想表达的意思就是 通过链式法则进行逐层的梯度反向传播,你get到了吗?

2. Sigmoid function

任何可微函数都可以看成门运算,并且我们还可以把多个门组合成一个,让我们来看一个常用的函数,叫做sigmoid激活函数:

这个表达式包含w和x 2个输入,我们可以把这个复杂的表达式拆分成多层的门电路的组合:

其中不同门的偏导数如下,

在这个例子中我们看到7层的一个网络,但其实我们可以把其中的部分看成一个整体:

这整个表达式叫做sigmoid function,对它求偏导很简单:

因此我们会把一连串的运算组合成一个sigmoid门,那么反向传播算法是这样的:

w = [2,-3,-3] # assume some random weights and data
x = [-1, -2]# forward pass
dot = w[0]*x[0] + w[1]*x[1] + w[2]
f = 1.0 / (1 + math.exp(-dot)) # sigmoid function# backward pass through the neuron (backpropagation)
ddot = (1 - f) * f # gradient on dot variable, using the sigmoid gradient derivation
dx = [w[0] * ddot, w[1] * ddot] # backprop into x
dw = [x[0] * ddot, x[1] * ddot, 1.0 * ddot] # backprop into w
# we're done! we have the gradients on the inputs to the circuit

3. 反向传播代码实现

现在我们来举一个例子具体得说明如何进行反向传播的运算。f(x,y)如下式,注意我们并不需要显式地去计算∂f/∂x\partial f/\partial x或 ∂f/∂y \partial f/\partial y,我们只需要知道如何对这个函数进行拆分,然后分层计算局部梯度再利用链式法则进行整合即可。

在前向传播中,我们将整个等式进行如下拆分:

x = 3 # example values
y = -4# forward pass
sigy = 1.0 / (1 + math.exp(-y)) # sigmoid in numerator   #(1)
num = x + sigy # numerator                               #(2)
sigx = 1.0 / (1 + math.exp(-x)) # sigmoid in denominator #(3)
xpy = x + y                                              #(4)
xpysqr = xpy**2                                          #(5)
den = sigx + xpysqr # denominator                        #(6)
invden = 1.0 / den                                       #(7)
f = num * invden # done!                                 #(8)

那么通过上述代码,我们其实是把整个函数拆分成了多个简单的表达式,每个表达式相当于之前所说的一个门,这些简单的表达式使得我们可以很方便地计算局部梯度。这样在进行反向传播时只需将局部梯度相乘,在下面的代码中每个局部梯度用d…表示:

# backprop f = num * invden
dnum = invden # gradient on numerator                             #(8)
dinvden = num                                                     #(8)
# backprop invden = 1.0 / den
dden = (-1.0 / (den**2)) * dinvden                                #(7)
# backprop den = sigx + xpysqr
dsigx = (1) * dden                                                #(6)
dxpysqr = (1) * dden                                              #(6)
# backprop xpysqr = xpy**2
dxpy = (2 * xpy) * dxpysqr                                        #(5)
# backprop xpy = x + y
dx = (1) * dxpy                                                   #(4)
dy = (1) * dxpy                                                   #(4)
# backprop sigx = 1.0 / (1 + math.exp(-x))
dx += ((1 - sigx) * sigx) * dsigx # Notice += !! See notes below  #(3)
# backprop num = x + sigy
dx += (1) * dnum                                                  #(2)
dsigy = (1) * dnum                                                #(2)
# backprop sigy = 1.0 / (1 + math.exp(-y))
dy += ((1 - sigy) * sigy) * dsigy                                 #(1)
# done! phew

这样在最后我们就实现了梯度的反向传播。这里需要注意两点:
1.在进行前向传播的过程中保存好拆分变量是有必要的,这能够帮助我们快速地在反向传播过程中计算梯度。
2.前向传播的过程中涉及多次x,y的使用,因此我们在反向传播计算梯度时特别注意f对x,y的梯度是一个累加的过程(也就是说我们用的是+=,而不是=),这遵循了微分学中多变量的链式法则。

4. 反向传播常用门的直观理解

在反向传播中几个常用的门电路,如+,*,max(),其实包含了一些实际的意义。比如以下图的电路为例:

  • +门的作用是将其输出处接收到的梯度按原样传递给其所有的输入。这是因为加法的局部梯度是1,所以输入处的梯度=输出的梯度*1,保持不变。在本例中,+门将2这个梯度反向传播给了他的两个输入,使得这两个输入的梯度也同样为2.
  • max门的含义是梯度的选择性。和+门的“平等对待”不同,max门选择前向传播过程中值最大的那个输入来传递梯度,其他输入梯度为0。在本例中,max门将2的梯度传递给了z和w中值更大的z,也就是z处的梯度为2,而w处的梯度为0.
  • ∗ *门则是将输出的梯度乘以输入的值得到输入的梯度(不过乘的是除自己以外其他输入的值)。比如上图中x处的梯度-8,是由输出梯度2,乘以另一个输入值y(-4)得到的。另外对于∗*门还需要注意的一点是,如果这个门的一个输入非常小,另一个输入非常大,那么 ∗ *门就会给小的输入一个较大的梯度,而给大的输入一个很小的梯度。在线性分类器中常用的乘门是用于计算点乘wTxiw^Tx_i的,上述情况说明输入x的数值范围其实对于w的梯度的量级是有影响的。比如在预处理过程中给所有的训练数据 xi x_i都乘以1000,那么w的梯度就会变成现有的1000倍,你就必须减小学习率来抵消这个因素。这就是为什么预处理过程如归一化等非常重要的原因,他会在很细微的地方影响我们的结果。

总结

我们对梯度的反向传播进行了直观的理解,它们是如何经过分层的计算最终得到输出对输入的梯度。这里的重点就是在正向传播的过程中对整个函数进行分层次的拆分,然后在反向传播过程中计算每个门电路的局部梯度。在下一章中,我们将开始介绍神经网络。

参考

Automatic differentiation in machine learning: a survey

【Stanford CNN课程笔记】4. 反向传播算法相关推荐

  1. [AI 笔记] BP反向传播算法

    [AI 笔记] BP反向传播算法 说明 BP算法 链式法则 计算图 简单例子 前向传播 反向传播 聚焦计算节点,深入理解 计算节点的代码实现 例子 各种门的功能 多元链式法则 向量化BP算法 参考资料 ...

  2. 随时间反向传播算法(BPTT)笔记

    随时间反向传播算法(BPTT)笔记 1.反向传播算法(BP) 以表达式f(w,x)=11+e−(w0x0+w1x1+w2)f(w,x)=\frac{1}{1+e^{-(w_0x_0+w_1x_1+w_ ...

  3. 卷积神经网络(CNN)反向传播算法推导

    作者丨南柯一梦宁沉沦@知乎(已授权) 来源丨https://zhuanlan.zhihu.com/p/61898234 编辑丨极市平台 导读 在本篇文章中我们将从直观感受和数学公式两方面来介绍CNN反 ...

  4. 深度学习(四):卷积神经网络(CNN)模型结构,前向传播算法和反向传播算法介绍。

    在前面我们讲述了DNN的模型与前向反向传播算法.而在DNN大类中,卷积神经网络(Convolutional Neural Networks,以下简称CNN)是最为成功的DNN特例之一.CNN广泛的应用 ...

  5. 四张图彻底搞懂CNN反向传播算法(通俗易懂)

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转自:机器学习算法那些事 阅读本文之前,可以先阅读之前讲述的全 ...

  6. 卷积神经网络(CNN)反向传播算法

    在卷积神经网络(CNN)前向传播算法中,我们对CNN的前向传播算法做了总结,基于CNN前向传播算法的基础,我们下面就对CNN的反向传播算法做一个总结.在阅读本文前,建议先研究DNN的反向传播算法:深度 ...

  7. Stanford UFLDL教程 反向传播算法(BP算法)

    反向传播算法(BP算法) 假设我们有一个固定样本集 ,它包含  个样例.我们可以用批量梯度下降法来求解神经网络.具体来讲,对于单个样例,其代价函数为: 这是一个(二分之一的)方差代价函数.给定一个包含 ...

  8. 深度学习中反向传播算法简单推导笔记

    反向传播算法简单推导笔记 1.全连接神经网络 该结构的前向传播可以写成: z(1)=W(1)x+b(1)z^{(1)} = W^{(1)}x+b^{(1)}z(1)=W(1)x+b(1) a(1)=σ ...

  9. 深度学习入门笔记(六):误差反向传播算法

    专栏--深度学习入门笔记 推荐文章 深度学习入门笔记(一):机器学习基础 深度学习入门笔记(二):神经网络基础 深度学习入门笔记(三):感知机 深度学习入门笔记(四):神经网络 深度学习入门笔记(五) ...

最新文章

  1. Eclipse的Git插件下载项目出现 No project found
  2. C语言反转二叉树的递归和迭代解决方案(附完整源码)
  3. C++中的继承(三)
  4. 【PAT甲级 大数运算】1065 A+B and C (64bit) (20 分) Python 全部AC
  5. 时间序列的截尾和拖尾_R语言:时间序列(一)
  6. cmake mysql 编译参数_Cmake-MySQL编译参数说明
  7. 又有程序员把产品经理给打了!
  8. jeecg框架日常开发问题解决方法
  9. 泰坦尼克号是怎么从2D转成3D的?
  10. SpringMV工作流程分析
  11. WPF 资源路径设置
  12. 工具(1)---wireshark抓包
  13. 读书百客:《渔家傲·天接云涛连晓雾》评赏
  14. 计算机平面设计是计算机类吗,计算机平面设计是什么?平面设计就业前景怎么样?...
  15. 7.7.4 积分卡管理系统示例
  16. 用Pandas秒秒钟搞定24张Excel报表,还做了波投放分析!
  17. 用 Python 实现英文单词纠错功能!这样就不担心不会辅导孩子了!
  18. ESP8266 12F 点灯科技APP 控制两个舵机
  19. 快递业大动作!京东已收购德邦快递?最新回应
  20. CRC/SoftPLC/OpenCASCADE/CAD/CAM/SVG开源项目收藏

热门文章

  1. Step7中有关时间和定时器的使用和例程2
  2. 快速找出一个数组中的最大数、第二大数
  3. BetaFlight统一硬件配置文件研读之set命令
  4. Redis介绍及其简单使用方法
  5. c语言程序设计迷宫问题,C语言迷宫问题
  6. 【Java】Java零基础学习笔记
  7. Spring - Spring配置文件-Spring配置数据源详解
  8. 单片机执行指令过程详解
  9. 【Spring】依赖注入的几种方式
  10. java高内聚低耦合