Calculus on Computational Graphs: Backpropagation
Calculus on Computational Graphs: Backpropagation
Introduction
Backpropagation is the key algorithm that makes training deep models computationally tractable. For modern neural networks, it can make training with gradient descent as much as ten million times faster, relative to a naive implementation. That’s the difference between a model taking a week to train and taking 200,000 years.
Beyond its use in deep learning, backpropagation is a powerful computational tool in many other areas, ranging from weather forecasting to analyzing numerical stability – it just goes by different names. In fact, the algorithm has been reinvented at least dozens of times in different fields (seeGriewank (2010)). The general, application independent, name is “reverse-mode differentiation.”
Fundamentally, it’s a technique for calculating derivatives quickly. And it’s an essential trick to have in your bag, not only in deep learning, but in a wide variety of numerical computing situations.
Computational Graphs
Computational graphs are a nice way to think about mathematical expressions. For example, consider the expression e=(a+b)∗(b+1). There are three operations: two additions and one multiplication. To help us talk about this, let’s introduce two intermediary variables, c and d so that every function’s output has a variable. We now have:
To create a computational graph, we make each of these operations, along with the input variables, into nodes. When one node’s value is the input to another node, an arrow goes from one to another.

These sorts of graphs come up all the time in computer science, especially in talking about functional programs. They are very closely related to the notions of dependency graphs and call graphs. They’re also the core abstraction behind the popular deep learning framework Theano.
We can evaluate the expression by setting the input variables to certain values and computing nodes up through the graph. For example, let’s set a=2 and b=1:

The expression evaluates to 6.
Derivatives on Computational Graphs
If one wants to understand derivatives in a computational graph, the key is to understand derivatives on the edges. If a directly affects c, then we want to know how it affects c. If achanges a little bit, how does c change? We call this the partial derivative of c with respect to a.
To evaluate the partial derivatives in this graph, we need the sum rule and the product rule:
Below, the graph has the derivative on each edge labeled.

What if we want to understand how nodes that aren’t directly connected affect each other? Let’s consider how e is affected by a. If we change a at a speed of 1, c also changes at a speed of 1. In turn, c changing at a speed of 1 causes e to change at a speed of 2. So e changes at a rate of 1∗2with respect to a.
The general rule is to sum over all possible paths from one node to the other, multiplying the derivatives on each edge of the path together. For example, to get the derivative of e with respect to b we get:
This accounts for how b affects e through c and also how it affects it through d.
This general “sum over paths” rule is just a different way of thinking about the multivariate chain rule.
Factoring Paths
The problem with just “summing over the paths” is that it’s very easy to get a combinatorial explosion in the number of possible paths.

In the above diagram, there are three paths from X to Y, and a further three paths from Y to Z. If we want to get the derivative ∂Z∂X by summing over all paths, we need to sum over 3∗3=9paths:
The above only has nine paths, but it would be easy to have the number of paths to grow exponentially as the graph becomes more complicated.
Instead of just naively summing over the paths, it would be much better to factor them:
This is where “forward-mode differentiation” and “reverse-mode differentiation” come in. They’re algorithms for efficiently computing the sum by factoring the paths. Instead of summing over all of the paths explicitly, they compute the same sum more efficiently by merging paths back together at every node. In fact, both algorithms touch each edge exactly once!
Forward-mode differentiation starts at an input to the graph and moves towards the end. At every node, it sums all the paths feeding in. Each of those paths represents one way in which the input affects that node. By adding them up, we get the total way in which the node is affected by the input, it’s derivative.

Though you probably didn’t think of it in terms of graphs, forward-mode differentiation is very similar to what you implicitly learned to do if you took an introduction to calculus class.
Reverse-mode differentiation, on the other hand, starts at an output of the graph and moves towards the beginning. At each node, it merges all paths which originated at that node.

Forward-mode differentiation tracks how one input affects every node. Reverse-mode differentiation tracks how every node affects one output. That is, forward-mode differentiation applies the operator ∂∂X to every node, while reverse mode differentiation applies the operator ∂Z∂to every node.1
Computational Victories
At this point, you might wonder why anyone would care about reverse-mode differentiation. It looks like a strange way of doing the same thing as the forward-mode. Is there some advantage?
Let’s consider our original example again:

We can use forward-mode differentiation from b up. This gives us the derivative of every node with respect to b.

We’ve computed ∂e∂b, the derivative of our output with respect to one of our inputs.
What if we do reverse-mode differentiation from e down? This gives us the derivative of e with respect to every node:

When I say that reverse-mode differentiation gives us the derivative of e with respect to every node, I really do mean every node. We get both ∂e∂a and ∂e∂b, the derivatives of e with respect to both inputs. Forward-mode differentiation gave us the derivative of our output with respect to a single input, but reverse-mode differentiation gives us all of them.
For this graph, that’s only a factor of two speed up, but imagine a function with a million inputs and one output. Forward-mode differentiation would require us to go through the graph a million times to get the derivatives. Reverse-mode differentiation can get them all in one fell swoop! A speed up of a factor of a million is pretty nice!
When training neural networks, we think of the cost (a value describing how bad a neural network performs) as a function of the parameters (numbers describing how the network behaves). We want to calculate the derivatives of the cost with respect to all the parameters, for use in gradient descent. Now, there’s often millions, or even tens of millions of parameters in a neural network. So, reverse-mode differentiation, called backpropagation in the context of neural networks, gives us a massive speed up!
(Are there any cases where forward-mode differentiation makes more sense? Yes, there are! Where the reverse-mode gives the derivatives of one output with respect to all inputs, the forward-mode gives us the derivatives of all outputs with respect to one input. If one has a function with lots of outputs, forward-mode differentiation can be much, much, much faster.)
Isn’t This Trivial?
When I first understood what backpropagation was, my reaction was: “Oh, that’s just the chain rule! How did it take us so long to figure out?” I’m not the only one who’s had that reaction. It’s true that if you ask “is there a smart way to calculate derivatives in feedforward neural networks?” the answer isn’t that difficult.
But I think it was much more difficult than it might seem. You see, at the time backpropagation was invented, people weren’t very focused on the feedforward neural networks that we study. It also wasn’t obvious that derivatives were the right way to train them. Those are only obvious once you realize you can quickly calculate derivatives. There was a circular dependency.
Worse, it would be very easy to write off any piece of the circular dependency as impossible on casual thought. Training neural networks with derivatives? Surely you’d just get stuck in local minima. And obviously it would be expensive to compute all those derivatives. It’s only because we know this approach works that we don’t immediately start listing reasons it’s likely not to.
That’s the benefit of hindsight. Once you’ve framed the question, the hardest work is already done.
Conclusion
Derivatives are cheaper than you think. That’s the main lesson to take away from this post. In fact, they’re unintuitively cheap, and us silly humans have had to repeatedly rediscover this fact. That’s an important thing to understand in deep learning. It’s also a really useful thing to know in other fields, and only more so if it isn’t common knowledge.
Are there other lessons? I think there are.
Backpropagation is also a useful lens for understanding how derivatives flow through a model. This can be extremely helpful in reasoning about why some models are difficult to optimize. The classic example of this is the problem of vanishing gradients in recurrent neural networks.
Finally, I claim there is a broad algorithmic lesson to take away from these techniques. Backpropagation and forward-mode differentiation use a powerful pair of tricks (linearization and dynamic programming) to compute derivatives more efficiently than one might think possible. If you really understand these techniques, you can use them to efficiently calculate several other interesting expressions involving derivatives. We’ll explore this in a later blog post.
This post gives a very abstract treatment of backpropagation. I strongly recommend reading Michael Nielsen’s chapter on it for an excellent discussion, more concretely focused on neural networks.
Acknowledgments
Thank you to Greg Corrado, Jon Shlens, Samy Bengio and Anelia Angelova for taking the time to proofread this post.
Thanks also to Dario Amodei, Michael Nielsen and Yoshua Bengio for discussion of approaches to explaining backpropagation. Also thanks to all those who tolerated me practicing explaining backpropagation in talks and seminar series!
This might feel a bit like dynamic programming. That’s because it is!↩
Calculus on Computational Graphs: Backpropagation的更多相关文章
- (译)Calculus on Computational Graphs: Backpropagation
Posted on August 31, 2015 Introduction Backpropagation is the key algorithm that makes training deep ...
- [TF] Architecture - Computational Graphs
阅读笔记: 仅希望对底层有一定必要的感性认识,包括一些基本核心概念. Here只关注Graph相关,因为对编程有益. TF – Kernels模块部分参见:https://mp.weixin.qq.c ...
- 谷歌大神Jeff Dean:大规模深度学习最新进展 zz
http://www.tuicool.com/articles/MBBbeeQ 在AlphaGo与李世石比赛期间,谷歌天才工程师Jeff Dean在Google Campus汉城校区做了一次关于智能计 ...
- Recurrent Neural Network系列2--利用Python,Theano实现RNN
作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 本文翻译自 RECURRENT NEURAL NETWORKS T ...
- Recurrent Neural Network系列3--理解RNN的BPTT算法和梯度消失
作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 这是RNN教程的第三部分. 在前面的教程中,我们从头实现了一个循环 ...
- Pytorch 之 backward
首先看这个自动求导的参数: grad_variables:形状与variable一致,对于y.backward(),grad_variables相当于链式法则dz/dx=dz/dy × dy/dx 中 ...
- LSTM与Highway-LSTM算法实现的研究概述
LSTM与Highway-LSTM算法实现的研究概述 zoerywzhou@gmail.com http://www.cnblogs.com/swje/ 作者:Zhouwan 2015-12-22 ...
- What are some good books/papers for learning deep learning?
What's the most effective way to get started with deep learning? 29 Answers Yoshua Bengio, ...
- 本人AI知识体系导航 - AI menu
Relevant Readable Links Name Interesting topic Comment Edwin Chen 非参贝叶斯 徐亦达老板 Dirichlet Process 学习 ...
随机推荐
- FD.io 社区中国行暨未来网络技术沙龙 南京站 参会小结
FD.io 社区中国行暨未来网络技术沙龙 南京站,2018 年 3 月 17 日. 开场致辞 Ray 介绍了一些有的没的 ⁃ (Future Event)DPDK summit, FD.io summ ...
- 浅谈iOS内存管理机制
iOS内存管理机制的原理是引用计数,引用计数简单来说就是统计一块内存的所有权,当这块内存被创建出来的时候,它的引用计数从0增加到1,表示有一个对象或指针持有这块内存,拥有这块内存的所有权,如果这时候有 ...
- 软工网络15团队作业8——Beta阶段敏捷冲刺(Day5)
提供当天站立式会议照片一张 每个人的工作 1.讨论项目每个成员的昨天进展 赵铭: 进一步数据整理,写入数据库. 吴慧婷:主页面.查单词页面的改进.背单词界面改进. 陈敏: 单词学习功能及该界面按钮功能 ...
- elasticsearch6 学习之安装
安装环境:centos6.5 64位 jdk1.8 elasticsearch6.1.1 一.启动 [root@localhost bin]# ./elasticsearch - ...
- Gulp 项目简单构建,自动刷新页面
/** * Created by 1900 on 12/18/2015. */ var plugins={ fs:require("fs"), gulp:require(" ...
- UVALive6442_Coins on a Ring
真正的水题,可惜无法当场机智一下. 这样的,在一个圈圈上给你n个黑点,现在要你移动每一个黑点使得所有的点都是等间距的,每个点中最远需要一定的那个点最小可以是多少? 其实是这样来考虑的,我们可以随便设置 ...
- C++ STL 常用查找算法
C++ STL 常用查找算法 adjacent_find() 在iterator对标识元素范围内,查找一对相邻重复元素,找到则返回指向这对元素的第一个元素的迭代器.否则返回past-the-end. ...
- 【BZOJ4710】[JSOI2011]分特产(容斥)
[BZOJ4710]分特产(容斥) 题面 BZOJ 题解 比较简单吧... 设\(f[i]\)表示至多有\(i\)个人拿到东西的方案数. \(f[i]=\prod_{j=1}^m C_{m+i-1}^ ...
- Alpha 冲刺 —— 十分之三
队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 协助后端界面的开发 搭建项目运行的服务器环境 ...
- Hive权限管理
最近遇到一个hive权限的问题,先简单记录一下,目前自己的理解不一定对,后续根据自己的理解程度更新 一.hive用户的概念 hive本身没有创建用户的命令,hive的用户就是Linux用户,若当前是用 ...