AI / ML Theory
Chapter 0 · 22 min

0.3 — Chain rule and computational graphs

Goal: Write the multivariable chain rule as a sum over paths in a DAG and compute ∂f/∂x for f(x) = sin(x²)·exp(x) by hand in reverse mode.

1. Why this session exists

All of backpropagation is one thing: the chain rule applied to a directed acyclic graph (DAG). If you leave this session knowing how to write the chain rule as a sum over paths in the graph, all of Chapter 2 (MLPs and backprop) becomes bookkeeping rather than mystery.

You already know the scalar version from Calc I. What we'll do here is lift it first to several intermediate variables, then to general DAGs, and finally walk through the canonical example pen-in-hand.

2. Refresher: scalar chain rule

If y=f(g(x))y = f(g(x)) and we set u=g(x)u = g(x), then y=f(u)y = f(u) and

dydx=dydu dudx.\frac{dy}{dx} = \frac{dy}{du}\,\frac{du}{dx}.

Conceptually, a small perturbation Δx\Delta x produces Δu≈g′(x) Δx\Delta u \approx g'(x)\,\Delta x, which in turn produces Δy≈f′(u) Δu=f′(u) g′(x) Δx\Delta y \approx f'(u)\,\Delta u = f'(u)\,g'(x)\,\Delta x. In the limit, the ratio Δy/Δx\Delta y/\Delta x is the product of the two local derivatives.

Warm-up example: y=sin⁡(x2)y = \sin(x^2), set u=x2u = x^2, y=sin⁡(u)y = \sin(u), so

dydx=cos⁡(u)⋅2x=2xcos⁡(x2).\frac{dy}{dx} = \cos(u) \cdot 2x = 2x\cos(x^2).

Nothing new. But notice the structure: we multiply the local derivative at every link in the chain. This structure is the only thing that survives the generalisation.

3. Multivariable with one scalar input

Suppose now that yy depends on nn intermediates u1,…,unu_1, \dots, u_n, and that each uiu_i depends on xx:

y=h(u1,u2,…,un),ui=gi(x).y = h(u_1, u_2, \dots, u_n), \qquad u_i = g_i(x).

A perturbation Δx\Delta x now propagates through nn parallel paths — one per uiu_i — and the effects add linearly to first order:

Δy≈∑i=1n∂h∂ui(u) Δui=∑i=1n∂h∂ui(u) gi′(x) Δx.\Delta y \approx \sum_{i=1}^{n} \frac{\partial h}{\partial u_i}(u)\,\Delta u_i = \sum_{i=1}^{n} \frac{\partial h}{\partial u_i}(u)\,g_i'(x)\,\Delta x.

Dividing by Δx\Delta x and taking the limit,

  dydx=∑i=1n∂y∂ui duidx.  \boxed{\;\frac{dy}{dx} = \sum_{i=1}^{n} \frac{\partial y}{\partial u_i}\,\frac{du_i}{dx}.\;}

This is the multivariable chain rule with one input. Note its shape: a sum over links, each link carrying a product of local derivatives. This is more than coincidence; it's the special case of a much more general identity, coming next.

4. DAGs and the sum over paths

In any deep learning model, the output LL (say, the loss) is computed from an input xx through a potentially complicated sequence of intermediate operations. We represent this computation as a directed acyclic graph: each node is a variable (scalar, vector, or tensor), and each directed edge u→vu \to v indicates that vv is a direct function of uu (and possibly of other variables).

The question is: how does LL depend on xx overall? In the scalar case the answer is the sum over paths:

  ∂L∂x=∑directed pathsp:x→L  ∏edge u→v ∈ p∂v∂u.  \boxed{\;\frac{\partial L}{\partial x} = \sum_{\substack{\text{directed paths} \\ p:\, x \to L}} \;\prod_{\text{edge } u \to v \,\in\, p} \frac{\partial v}{\partial u}.\;}

In words: to find how LL responds to xx, walk every directed path in the DAG from xx to LL; along each path, multiply the local partials along its edges; sum the results.

The proof is an easy induction on graph depth. For a node vv fed directly by u1,…,uku_1, \dots, u_k,

∂v∂x=∑i=1k∂v∂ui ∂ui∂x,\frac{\partial v}{\partial x} = \sum_{i=1}^{k} \frac{\partial v}{\partial u_i}\,\frac{\partial u_i}{\partial x},

and expanding each ∂ui/∂x\partial u_i/\partial x recursively until reaching xx, each term in the final expansion corresponds to one path x→⋯→vx \to \cdots \to v. Applying this with v=Lv = L gives the identity.

5. The computational graph as a data structure

In practice, a deep learning framework builds the DAG in two phases:

  1. Forward pass. Evaluate each node in topological order from input xx to output LL, storing the intermediate values uiu_i (because they appear in the local derivatives).
  2. Backward pass. Walk the graph in reverse topological order, accumulating ∂L/∂ui\partial L/\partial u_i at each node by summing contributions from its children. When it reaches xx, you have ∂L/∂x\partial L/\partial x ready.

Each edge carries one local partial (scalar, vector, or matrix depending on the node types); each node is responsible for summing the contributions arriving from its children. That's it.

The advantage of the graph framing over memorising chain-rule formulas is scalability: the same algorithm handles linear chains, branches, joins (multiple paths meeting at the same node), and any DAG, with no special cases.

6. Worked example: f(x)=sin⁡(x2)⋅exf(x) = \sin(x^2)\cdot e^{x}

Computing ∂f/∂x\partial f/\partial x two ways: (a) by the direct scalar chain rule, as a check, and (b) by the sum over paths in the DAG, to internalise the method that will scale to deep networks.

6.1 Identifying intermediate nodes

Decompose the function into elementary operations:

a=x2,b=sin⁡(a),c=ex,f=b⋅c.\begin{aligned} a &= x^2, \\ b &= \sin(a), \\ c &= e^{x}, \\ f &= b\cdot c. \end{aligned}

xx appears in two places in the original formula — once inside sin⁡(x2)\sin(x^2) and once in exe^x. This will become a branch in the DAG.

6.2 The DAG

Directed acyclic graph for f(x) = sin(x²)·exp(x). Node x on the left feeds two nodes: a = x² (above) and c = eˣ (below). a feeds b = sin(a), which together with c feeds the terminal node f = b·c on the right.
DAG for the computation of f(x) = sin(x²)·exp(x). The node x has two outgoing edges, reflecting the two occurrences of x in the original formula. There are exactly two directed paths from x to f.

6.3 Local derivatives (one per edge)

For each edge u→vu \to v of the DAG, compute ∂v/∂u\partial v/\partial u alone, treating the other parents of vv as constants:

∂a∂x=2x,∂b∂a=cos⁡(a),∂c∂x=ex,∂f∂b=c,∂f∂c=b.\begin{aligned} \frac{\partial a}{\partial x} &= 2x, & \frac{\partial b}{\partial a} &= \cos(a), \\[2pt] \frac{\partial c}{\partial x} &= e^{x}, & \frac{\partial f}{\partial b} &= c, \\[2pt] \frac{\partial f}{\partial c} &= b. & & \end{aligned}

Five local derivatives, one per edge. Each is trivial in isolation — that's why the method scales.

6.4 The paths from xx to ff

Inspecting the DAG, there are exactly two directed paths:

Path 1:x→a→b→f,Path 2:x→c→f.\begin{aligned} \textbf{Path 1:}\quad & x \to a \to b \to f, \\ \textbf{Path 2:}\quad & x \to c \to f. \end{aligned}

6.5 Contribution of each path

The rule: multiply the local derivatives along the edges of the path.

Path 1:

(∂a∂x)(∂b∂a)(∂f∂b)=(2x) (cos⁡(a)) (c)=2x cos⁡(x2) ex.\Big(\frac{\partial a}{\partial x}\Big) \Big(\frac{\partial b}{\partial a}\Big) \Big(\frac{\partial f}{\partial b}\Big) = (2x)\,\big(\cos(a)\big)\,(c) = 2x\,\cos(x^2)\,e^{x}.

Path 2:

(∂c∂x)(∂f∂c)=(ex) (b)=ex sin⁡(x2).\Big(\frac{\partial c}{\partial x}\Big) \Big(\frac{\partial f}{\partial c}\Big) = (e^{x})\,(b) = e^{x}\,\sin(x^2).

6.6 Final sum

  ∂f∂x=2x cos⁡(x2) ex  +  sin⁡(x2) ex=ex[ 2xcos⁡(x2)+sin⁡(x2) ].  \boxed{\;\frac{\partial f}{\partial x} = 2x\,\cos(x^2)\,e^{x} \;+\; \sin(x^2)\,e^{x} = e^{x}\big[\,2x\cos(x^2) + \sin(x^2)\,\big].\;}

6.7 Sanity check via direct scalar chain rule

To validate, differentiate by the product rule and the classical chain rule. With f(x)=sin⁡(x2)⋅exf(x) = \sin(x^2)\cdot e^{x} and (uv)′=u′v+uv′(uv)' = u'v + uv':

dfdx=ddx[sin⁡(x2)]⋅ex  +  sin⁡(x2)⋅ddx[ex]=2xcos⁡(x2)⋅ex  +  sin⁡(x2)⋅ex=ex[ 2xcos⁡(x2)+sin⁡(x2) ].\begin{aligned} \frac{df}{dx} &= \frac{d}{dx}[\sin(x^2)] \cdot e^{x} \;+\; \sin(x^2) \cdot \frac{d}{dx}[e^{x}] \\ &= 2x\cos(x^2) \cdot e^{x} \;+\; \sin(x^2)\cdot e^{x} \\ &= e^{x}\big[\,2x\cos(x^2) + \sin(x^2)\,\big]. \end{aligned}

Identical. The sum-over-paths is not a different technique — it is the same chain rule, reorganised to make the combinatorial structure explicit when a variable shows up in multiple places.

7. Why this is already (almost) backprop

Look again at §6.5. To compute Path 1's contribution, we walked the edges in the direction x→fx \to f (forward mode). But notice that we could equally have walked in the direction f→xf \to x (reverse mode) and obtained the same product — multiplication is commutative. What changes is the order in which partial products are accumulated.

In reverse mode, we start with ∂f/∂f=1\partial f/\partial f = 1 at the terminal node and walk backwards, multiplying by each edge's local partial and accumulating the sum at nodes where paths meet. The result at xx is ∂f/∂x\partial f/\partial x.

The advantage of reverse mode when there are many inputs and one output (the case for every ML loss function): a single backward pass computes ∂L/∂θj\partial L/\partial \theta_j for every parameter θj\theta_j simultaneously. Cost is proportional to the number of edges, not to the number of parameters. This is the asymptotic win that makes training networks with billions of parameters tractable.

We'll formalise the algorithm in Chapter 2. For now it's enough to know that backprop is sum-over-paths, computed from output to input.

Self-test

Let g(x,y)=(x+y)⋅sin⁡(xy)g(x, y) = (x + y)\cdot\sin(xy).

  1. Identify the intermediate nodes (hint: u=x+yu = x+y, v=xyv = xy, w=sin⁡(v)w = \sin(v), g=u⋅wg = u\cdot w) and draw the DAG.
  2. List every edge and its local derivative.
  3. How many directed paths exist from xx to gg? From yy to gg?
  4. Use the sum over paths to compute ∂g/∂x\partial g/\partial x and ∂g/∂y\partial g/\partial y. Verify by direct calculation with the product rule.