Seyed Masoud Hosseini · Overview · Study log · Weekly summaries · Ideas · Search · Transcript · RSS feed

Deep Learning Systems · Lecture 5 of 25 · 1:03:34

Lecture 4: Automatic Differentiation

Lecture 4 - Automatic Differentiation on YouTube

Study guide

What this lecture covers

Taught by co-instructor Tianqi Chen, this lecture asks how deep learning frameworks actually compute gradients, having established in prior lectures that manual derivation doesn't scale. It surveys numerical differentiation (useful for gradient checking, not training) and symbolic differentiation (exact but wasteful, since it doesn't reuse shared subcomputations), then introduces the computational graph as the tool used to derive both forward mode and reverse mode automatic differentiation.

The bulk of the lecture works through reverse mode AD by hand on a small example, defining the "adjoint" of each node and showing how to accumulate contributions when a value feeds into multiple downstream nodes. It then contrasts this with the classic backpropagation algorithm covered in Lecture 3, explaining why modern frameworks build an extended computational graph for the gradient computation rather than running backprop in place, including the ability to get gradients of gradients for free. It closes by generalizing the technique from scalars to tensors and briefly to other data structures.

Key ideas

  • Numerical differentiation: approximates gradients via finite differences; the centered-difference formula (f(theta + eps*e_i) - f(theta - eps*e_i)) / (2*eps) has lower error than the one-sided version, but is costly (2n function evaluations for n parameters) and used mainly for gradient checking, not training.
  • Symbolic differentiation: derives an exact closed-form gradient expression by applying calculus rules, but naively applied it duplicates work across parameters, leading to unnecessary computation that a smarter method avoids.
  • Computational graph: a directed acyclic graph where each node is an intermediate computation with defined inputs and outputs; evaluating it in topological order computes the function, and it's the foundation for deriving automatic differentiation.
  • Forward mode AD: propagates derivatives with respect to one input forward through the graph; efficient when there are few inputs and many outputs, but requires one pass per input, making it costly for typical deep learning models (many parameters, one scalar loss).
  • Reverse mode AD and the adjoint: defines the adjoint of a node as the partial derivative of the final output with respect to that node, computed backward from the output (where the adjoint is 1) toward the inputs; when a node feeds multiple downstream nodes, its adjoint sums the contributions ("partial adjoints") from each path.
  • Reverse mode AD by extending the computational graph: rather than computing concrete adjoint values immediately, the algorithm builds new graph nodes representing the adjoint computations, producing a graph that can be evaluated at any input and reused, and that naturally supports gradients of gradients.
  • Reverse mode AD vs. backpropagation: classic backpropagation runs backward operations in place on the original graph with no new graph created; reverse mode AD as computational-graph extension produces a separate, evaluable gradient graph, which modern frameworks (following Theano's lead, unlike earlier ones like Caffe) prefer because it enables higher-order gradients and further compiler-style optimization.
  • Generalizing to tensors: the same adjoint definitions extend to matrices and tensors elementwise, giving standard rules like the linear-layer gradient X_adjoint = Z_adjoint @ W^T.

Walkthrough

Why automatic differentiation, and numerical differentiation (0:48)

The lecture recaps that gradient computation is the shared bottleneck across all machine learning algorithms, then introduces numerical differentiation from the calculus definition of a partial derivative, showing why the centered-difference formula is more accurate and why numerical differentiation, despite being costly, remains essential for gradient checking.

Symbolic differentiation and its inefficiency (14:06)

Working through a product-of-parameters example, the lecture shows how manually deriving a symbolic gradient formula wastes computation, since naive symbolic differentiation doesn't reuse intermediate results shared across different partial derivatives, motivating a better approach.

Computational graphs and forward mode AD (18:27)

The lecture defines the computational graph, walks through evaluating one by hand in topological order, then derives forward mode automatic differentiation by propagating a derivative forward from the inputs, noting its inefficiency when there are many input parameters and few outputs (the typical deep learning case).

Deriving reverse mode AD via adjoints (29:45)

The lecture defines the adjoint of a node as the derivative of the scalar output with respect to that node, and derives it recursively backward from the output node (adjoint = 1) through the graph. It works through the multi-pathway case explicitly, showing that when a node feeds multiple outputs, its adjoint is the sum of partial adjoints from each downstream path, and introduces notation for these partial adjoints attached to graph edges.

Implementing reverse mode AD by extending the graph (43:40)

Rather than computing numeric adjoint values directly, the lecture shows building new computational graph nodes that represent each adjoint computation, illustrated on a small example. This produces a reusable gradient graph that can be evaluated at any input, and sets up the comparison with traditional backpropagation.

Reverse mode AD vs. backpropagation, and gradients of gradients (51:50)

The lecture contrasts backpropagation (running backward operations in place on the same graph, as in early frameworks like Caffe) with reverse mode AD as graph extension (pioneered by Theano, adopted by TensorFlow and PyTorch). It highlights two advantages of the graph-extension approach: computing gradients of gradients by simply differentiating the gradient graph again, and more opportunities for compiler-style optimization of the resulting computation.

Generalizing to tensors and other data structures (57:40)

The lecture extends the scalar adjoint definition to matrices and tensors elementwise, deriving the standard linear-layer gradient rule, then briefly notes that adjoints can be generalized to structured data types like dictionaries and tuples, gesturing at the broader idea of differentiable programming.

Before you watch

  • Watch Lecture 3 (Parts I and II) first, since this lecture directly compares reverse mode AD to the manual backpropagation derived there.
  • Be comfortable with partial derivatives and the multivariable chain rule.
  • Having pen and paper to trace through the computational graph examples is recommended, as the lecture itself suggests.

Check your understanding

  1. Why is the centered-difference numerical gradient formula more accurate than the one-sided version, and why is numerical differentiation still used despite this cost?
  2. Why does forward mode AD become inefficient for typical deep learning training, where there's one scalar loss but many parameters?
  3. How is a node's adjoint computed when that node feeds into more than one downstream computation?
  4. What is the key difference between traditional backpropagation and reverse mode AD implemented by extending the computational graph, and why does that difference matter for computing gradients of gradients?

Vocabulary

differentiation (noun)
The process of finding the derivative, or rate of change, of a function.
This lecture compares three ways of doing differentiation on a computer.
numerical differentiation (noun)
Estimating a derivative by testing small changes in the input and measuring the change in output.
Numerical differentiation is used mainly to check other gradient methods.
symbolic differentiation (noun)
Getting an exact derivative formula by applying calculus rules directly to an expression.
Symbolic differentiation gives an exact answer but can repeat work.
finite difference (noun)
A small difference between two nearby input values, used to estimate a derivative.
The finite difference formula approximates the gradient.
closed-form (adjective)
Written as an exact formula, not an approximation.
Symbolic differentiation produces a closed-form expression.
subcomputation (noun)
A smaller calculation that is part of a larger one.
Naive symbolic differentiation fails to reuse shared subcomputations.
computational graph (noun)
A diagram of connected steps showing how a calculation is built from smaller operations.
We evaluate the computational graph in topological order.
directed acyclic graph (noun)
A graph where connections point in one direction and never form a loop.
A computational graph is a directed acyclic graph.
topological order (noun)
An ordering of steps so that each one comes after everything it depends on.
We evaluate the graph's nodes in topological order.
forward mode (noun)
A way of computing derivatives by tracking how one input affects every later value, moving forward.
Forward mode AD is efficient with few inputs and many outputs.
reverse mode (noun)
A way of computing derivatives by tracking how the final output depends on every earlier value, moving backward.
Reverse mode AD is efficient for many parameters and one loss.
adjoint (noun)
The derivative of the final output with respect to one node in the graph.
The adjoint of the output node is always 1.
partial derivative (noun)
The rate of change of a function with respect to just one of its inputs.
Each edge in the graph carries a partial derivative.
downstream (adjective)
Coming later in a process, after a certain point.
A node's adjoint sums contributions from every downstream path.
sum contributions (phrase)
To add together several separate effects into one total.
We sum contributions from each path that uses the node.
gradient checking (noun)
Testing that a computed gradient is correct by comparing it to a numerical estimate.
Numerical differentiation is mainly used for gradient checking.
bottleneck (noun)
The part of a process that limits how fast the whole thing can run.
Gradient computation is the shared bottleneck across ML algorithms.
wasteful (adjective)
Using more time or resources than necessary.
Naive symbolic differentiation is wasteful because it repeats work.
in place (phrase)
Changing existing data directly, without creating a new copy.
Classic backpropagation updates gradients in place on the same graph.
extend (verb)
To add more parts onto something that already exists.
Reverse mode AD extends the computational graph with new nodes.
evaluable (adjective)
Able to be calculated or run to get a result.
The extended graph is evaluable at any input.
higher-order gradient (noun)
A gradient of a gradient, showing how a first derivative itself changes.
Graph extension makes higher-order gradients possible.
compiler-style optimization (noun)
Techniques that rearrange or simplify code automatically to make it run faster.
A separate gradient graph allows compiler-style optimization.
gesture at (phrasal verb)
To hint at something without explaining it fully.
The lecture gestures at the idea of differentiable programming.

Chapters

From the YouTube description

Lecture 4 of the online course Deep Learning Systems: Algorithms and Implementation.

This lecture introduces automatic differentiation. We will go through numerical differentiation and gradient checking, forward mode automatic differentiation, and reverse mode automatic differentiation.

Sign up for the course for free at http://dlsyscourse.org.

Contents
00:00 - Introduction
00:48 - How does differentiation fit into machine learning
05:11 - Numerical differentiation
11:36 - Numerical gradient checking
14:06 - Symbolic differentiation
18:27 - Computational graph
22:47 - Forward mode automatic differentiation (AD)
28:25 - Limitations of forward mode AD
29:45 - Reverse mode automatic differentiation (AD)
36:34 - Derivation for the multiple pathway case
40:14 - Reverse AD algorithm
43:40 - Reverse mode AD by extending the computational graph
51:50 - Reverse mode AD vs Backprop
57:40 - Reverse mode AD on Tensors
01:00:12 - Reverse mode AD on data structures

← Lecture 3 (Part II): Manual Neural Networks · Lecture 5: Automatic Differentiation Implementation →