计算图上的微积分:反向传播
Calculus on Computational Graphs: Backpropagation
计算图上的微积分:反向传播(翻译)
作者:Chris Olah’s
英文地址:http://colah.github.io/posts/2015-08-Backprop/
描述:
小亮最近在看以色列大佬的NLP书籍《Neural Network Methods for Natural Language Processing 》这里是第五章里面的内容中的推荐部分:关于微分的资料,详情请见下文!
这里是小亮的blog地址:https://legendtianjin.github.io/NextLegend.github.io/
笔者信息:Next_Legend QQ:1219154092 机器学习 深度学习 模式识别 自然语言处理 计算机视觉
——2018.9.5于天津大学
一、介绍
反向传播是一种关键的算法,它可以使训练深度模型在计算上易于处理。对于现代神经网络来说,相对于一个简单的实现,它可以使梯度下降的训练速度达到1000万倍。这就是一周训练和用20万年时间训练的模型之间的区别。
除了在深度学习中使用之外,反向传播在许多其他领域是一个强大的计算工具,从天气预报到分析数字稳定性,它只是在不同的领域用不同的名字。事实上,该算法在不同的领域至少被重新改造了几十次(见Griewank(2010))。一般,应用程序独立,名称是“反向模式区分”。
从根本上说,这是一种快速计算微分的技术。在你的包里,这是一个很重要的技巧,不仅在深度学习中,而且在各种各样的数字计算环境中。
二、计算图
计算图是一种思考数学表达式的好方法。例如,考虑表达式e =(a + b)∗(b + 1)。这里有三个操作:两个加法和一个乘法。为了帮助我们讨论这个问题,让我们引入两个中间变量,
c和d,所以每个函数的输出都有一个变量。我们现在有:
c=a + b
d=b + 1
e=c * d
为了创建一个计算图,我们将这些操作连同输入变量一起放入节点。当一个节点的值是另一个节点的输入时,一个箭头从一个节点到另一个节点。
在计算机科学中,这些图表一直都在出现,尤其是在谈论功能程序的时候。它们与依赖关系图和调用图的概念密切相关。它们也是流行的深度学习框架Theano背后的核心抽象。
我们可以通过将输入变量设置为特定的值和通过图表计算节点来评估表达式。例如,让我们设置a = 2和b = 1 :
表达式的求值结果为6。
三、计算图的导数
如果想要在计算图中理解导数,关键是要理解导数的边界。如果a直接影响c,然后我们想知道它是如何影响的c。如果a稍微改变一下,那c如何改变?我们称其c是关于a的偏导数。
为了求出这张图中的偏导数,我们需要求和规则和乘积法则:
下图中每条边都有导数。
如果我们想要了解没有直接连接的节点是如何相互影响的呢?让我们考虑一下e是如何被a影响的。如果我们以1的速度改变a,c同样的变化速度1改变。反过来, c以1的速度变化导致e以2的改变速率。所以e变化速率1∗2关于a。一般规则是对从一个节点到另一个节点的所有可能路径求和,将路径的每个边的导数相乘。例如,要得到e关于b的导数。我们得到:
这就解释了b是如何影响e到c的,以及它是如何通过d来影响它的。这种一般的“对路径求和”规则只是一种不同的关于多元链式法则的思考方式。
四、因式分解路径
仅仅“对路径求和”的问题是,在可能的路径中,很容易得到一个组合爆炸。
在上面的图中,从X到Y有三条路径,从Y到Z还有三条路径。如果我们想求导∂Z/∂X的话,通过对所有路径求和,我们需要求和3∗3 = 9条道路:
上面只有9条路径,但是当图形变得更加复杂时,很容易就会有成倍增长的路径。与其简单地对路径求和,不如把它们因式分解:
这就是“前向传播”和“反向传播”。它们是通过分解路径来有效计算总和的算法。它们不是显式地对所有路径求和,而是通过在每个节点上合并路径来更有效地计算相同的总和。事实上,这两种算法都能精确地触碰到每条边!
前向传播从图的输入开始,然后向末端移动。在每个节点上,它都能计算出所有的路径。每条路径都代表了输入影响该节点的一种方式。通过把它们加起来,我们得到了节点受输入影响的总方式,它是导数。
虽然你可能没有从图的角度来考虑它,但是向前模式的微分和你在微积分课上做过的介绍是非常相似的。另一方面,反向传播的微分,从图的输出开始,向开始移动。在每个节点上,它合并了源自该节点的所有路径。
前向传播微分研究一个输入如何影响每个节点。反向传播微分研究每个节点如何影响一个输出。也就是说,正向模式微分应用算子∂/∂X对每个节点,反向模式微分应用算子∂Z/∂每一个节点。
五、Computational Victories
在这一点上,您可能想知道为什么有人会关心反向传播的微分。这看起来像是一种奇怪的方法,可以做与前模一样的事情。有什么好处吗?让我们再来看看我们最初的例子:
我们可以使用正向模式的微分b向上,这就给了我们每个结点的导数b。
我们计算∂e/∂b,这个导数是我们的输出对我们的输入的导数。如果我们做反向模式的微分从e开始? 这就得到了e对于每个节点的微分。
当我说反向传播微分给我们对每个结点的导数时,我确实是指每个结点。我们得到两个∂e/∂a和∂e/∂b,e的导数是关于两个输入。前向传播的微分给了我们输出对单个输入的导数,但是反向模式的微分给了我们所有的结果。对于这个图,这只是两个因子的加速,但是想象一个有上百万个输入和一个输出的函数。前向传播的微分要求我们通过这个图上百万次来得到导数。反向传播的微分可以一下子把它们都弄到手!一个百万分之一的速度是相当不错的!在训练神经网络时,我们考虑的是成本(描述神经网络的糟糕程度)作为参数的函数(描述网络行为的数字)。我们想要计算所有参数的成本的导数,用于梯度下降。现在,在神经网络中,通常有数百万甚至数千万个参数。所以,反向模式的分化,在神经网络的背景下被称为反向传播,给我们一个巨大的速度!
(有任何情况下,正向模式的分化更有意义吗?是的,有! 当反向模式给出一个输出对所有输入的导数时,正向模式给出了所有输出对一个输入的导数。如果一个函数有大量的输出,那么正向模式的微分就会大大加快。)
六、这不是简单的吗?
Isn’t This Trivial?
当我第一次理解反向传播的时候,我的反应是:“哦,这就是链式法则!我们怎么花了这么长时间才弄明白?“我不是唯一一个有这种反应的人。”的确,如果你问“在前馈神经网络中有一种聪明的计算导数的方法吗?”“答案并不难。
但我认为这比表面上看起来要困难得多。你看,在反向传播发明的时候,人们并不是很关注我们研究的前馈神经网络。同样不明显的是,微分是培训它们的正确方式。一旦你意识到你可以快速计算出导数,这些就很明显了。这是一种循环依赖。
更糟糕的是,在不经意的想法中,把循环依赖的任何部分都写下来是很容易的。用微分工具训练神经网络?你肯定会被困在局部最优解里。很明显,计算所有这些导数都很昂贵。这只是因为我们知道这种方法是有效的,我们不会立即开始列出它可能不会的原因。
这是事后诸葛亮的好处。一旦你提出了这个问题,最困难的工作就已经完成了。
七、结论
微分比你想象的要便宜。这是我们从这篇文章中得到的主要教训。事实上,它们的价格并不便宜,而美国愚蠢的人不得不反复发现这一事实。在深度学习中,这是很重要的一点。在其他领域中,这也是一件非常有用的事情,只有当它不是常识的时候才会知道。还有其他的教训吗?我认为有。反向传播也是理解微分如何流经模型的有用工具。这对于解释为什么有些模型很难优化是非常有用的。最典型的例子是在重复的神经网络中消失的梯度问题。最后,我认为从这些技术中可以得到一个广泛的算法教训。反向传播和正向模式的区别使用强大的一对技巧(线性化和动态规划)来比人们想象的更有效地计算导数。如果您真正理解了这些技术,您可以使用它们来有效地计算其他涉及到微分的有趣表达式。我们将在以后的博客文章中探讨这个问题。这篇文章给出了一个非常抽象的反向传播的方法。我强烈建议阅读Michael Nielsen关于它的章节,进行精彩的讨论,更具体地关注神经网络。
八、致谢
感谢Greg Corrado,Jon Shlens,Samy Bengio和an利亚Angelova,感谢他们花时间校对这篇文章。也要感谢达里奥阿米迪、迈克尔尼尔森和约书亚本吉奥讨论解释反向传播的方法。也要感谢那些在演讲和研讨会系列中允许我练习解释反向传播的人!