Calculus and Matrix Calculus for ML

Chain Rule for Computation Graphs

The chain rule as composition of local derivative maps, made operational through forward and backward passes on computation graphs.

Lesson
37

Goal

Turn the chain rule from a formula about nested functions into an algorithm for differentiating a program.

The central idea is:

A large derivative is assembled from small local derivatives, following the same dependency structure as the original computation.

Why Composition Creates A New Problem

Lesson 36 described one function near one point with one Jacobian:

ΔyJF(x)Δx.\Delta y\approx J_F(x)\Delta x.

Real models are compositions. An input becomes a linear transformation, then an activation, then another transformation, and eventually a scalar loss. Writing the entire model as one expanded formula would hide the reusable structure and create a large bookkeeping problem.

A computation graph keeps that structure explicit:

input -> intermediate values -> prediction -> loss

Each node performs a small operation. The chain rule explains how their local derivatives combine.

The Invariant: Derivatives Must Connect Compatible Spaces

Suppose:

F:RnRmF:\mathbb R^n\to\mathbb R^m

and:

G:RmRk.G:\mathbb R^m\to\mathbb R^k.

The composition is:

GF:RnRk.G\circ F:\mathbb R^n\to\mathbb R^k.

Its derivative must map an nn-dimensional input displacement to a kk-dimensional output displacement. The Jacobian chain rule is:

JGF(x)=JG(F(x))JF(x).J_{G\circ F}(x) = J_G(F(x))J_F(x).

The shapes force the order:

JGF(x)k×n=JG(F(x))k×mJF(x)m×n.\underbrace{J_{G\circ F}(x)}_{k\times n} = \underbrace{J_G(F(x))}_{k\times m} \underbrace{J_F(x)}_{m\times n}.

This is the same composition rule as matrix transformations. FF acts first, so its Jacobian is closest to the input displacement on the right.

Notation / Symbol Table

SymbolPlain-English nameMeaning
xxgraph inputValue supplied to the first operation.
u,v,zu,v,zintermediate valuesNamed results stored by graph nodes.
LLscalar lossFinal scalar output whose sensitivities we want.
GFG\circ FcompositionApply FF first, then apply GG.
JF(x)J_F(x)local Jacobian of FFMaps a small displacement through the FF node.
vu\frac{\partial v}{\partial u}local scalar derivativeSensitivity of child value vv to parent value uu.
vˉ=Lv\bar v=\frac{\partial L}{\partial v}reverse sensitivitySensitivity of the final loss to intermediate value vv.
xˉ=xL\bar x=\nabla_x Linput sensitivityGradient of the final loss with respect to the graph input.

The bar in vˉ\bar v does not mean an average. In this lesson it is compact notation for the derivative of the final scalar loss with respect to vv.

First Example: A Scalar Chain

Let:

u=x2,L=3u+1.u=x^2, \qquad L=3u+1.

The graph is:

x --square--> u --scale and shift--> L

The local derivatives are:

ux=2x,Lu=3.\frac{\partial u}{\partial x}=2x, \qquad \frac{\partial L}{\partial u}=3.

The chain rule multiplies them:

dLdx=Luux=3(2x)=6x.\frac{dL}{dx} = \frac{\partial L}{\partial u} \frac{\partial u}{\partial x} =3(2x)=6x.

At x=2x=2, the forward values are:

u=4,L=13.u=4, \qquad L=13.

The backward sensitivities are:

Lˉ=LL=1,uˉ=LˉLu=3,xˉ=uˉux=3(4)=12.\bar L=\frac{\partial L}{\partial L}=1, \qquad \bar u=\bar L\frac{\partial L}{\partial u}=3, \qquad \bar x=\bar u\frac{\partial u}{\partial x}=3(4)=12.

The forward pass computes values. The backward pass computes how the final loss depends on those values.

Why The Backward Pass Starts With One

Every reverse pass begins at the final scalar output with:

Lˉ=LL=1.\bar L=\frac{\partial L}{\partial L}=1.

This is not an arbitrary initialization. A quantity changes one-for-one with itself. That unit sensitivity seeds the repeated chain-rule multiplications.

A Computation Graph Is A Factorization

Consider:

L(x,y)=(xy+1)2.L(x,y)=(xy+1)^2.

Factor it into named operations:

u=xy,v=u+1,L=v2.u=xy, \qquad v=u+1, \qquad L=v^2.

The graph is:

x --\
     multiply -> u -> add 1 -> v -> square -> L
y --/

At (x,y)=(2,3)(x,y)=(2,3), the forward pass gives:

u=6,v=7,L=49.u=6, \qquad v=7, \qquad L=49.

Now record only the local derivatives:

ux=y=3,uy=x=2,\frac{\partial u}{\partial x}=y=3, \qquad \frac{\partial u}{\partial y}=x=2, vu=1,Lv=2v=14.\frac{\partial v}{\partial u}=1, \qquad \frac{\partial L}{\partial v}=2v=14.

Propagate backward:

vˉ=14,uˉ=vˉvu=14,\bar v=14, \qquad \bar u=\bar v\frac{\partial v}{\partial u}=14, xˉ=uˉux=14(3)=42,yˉ=uˉuy=14(2)=28.\bar x=\bar u\frac{\partial u}{\partial x}=14(3)=42, \qquad \bar y=\bar u\frac{\partial u}{\partial y}=14(2)=28.

Therefore:

L(2,3)=[4228].\nabla L(2,3)= \begin{bmatrix} 42\\28 \end{bmatrix}.

The graph avoided expanding the whole expression. Each node needed only its own operation, stored forward values, and incoming sensitivity.

Branching Means Addition

Multiplication handles consecutive links along one path. Addition handles several paths from the same variable to the output.

Let:

u=x2,v=3x,L=u+v.u=x^2, \qquad v=3x, \qquad L=u+v.

The input xx influences LL along two paths:

       -> square -> u --\
x ---->              add -> L
       -> scale  -> v --/

The total derivative is the sum of both path contributions:

dLdx=Luux+Lvvx.\frac{dL}{dx} = \frac{\partial L}{\partial u}\frac{\partial u}{\partial x} + \frac{\partial L}{\partial v}\frac{\partial v}{\partial x}.

Since both addition-node derivatives are 11:

dLdx=1(2x)+1(3)=2x+3.\frac{dL}{dx}=1(2x)+1(3)=2x+3.

This yields the operational rule:

Multiply local derivatives along a path. Add contributions from different paths that meet at the same value.

Failing to add at a branch is one of the most common computation-graph mistakes.

Vector Composition

The same rule works when intermediate values are vectors.

Let:

F:R2R3,G:R3R.F:\mathbb R^2\to\mathbb R^3, \qquad G:\mathbb R^3\to\mathbb R.

Then:

JF(x)R3×2,JG(F(x))R1×3.J_F(x)\in\mathbb R^{3\times2}, \qquad J_G(F(x))\in\mathbb R^{1\times3}.

Their product is:

JGF(x)=JG(F(x))JF(x)R1×2.J_{G\circ F}(x) = J_G(F(x))J_F(x) \in\mathbb R^{1\times2}.

Because GFG\circ F is scalar-valued, this result is the transpose of its column gradient:

x(GF)(x)=JF(x)TG(F(x)).\nabla_x(G\circ F)(x) = J_F(x)^T\nabla G(F(x)).

This transposed form is important in machine learning. It says that an output gradient can be pulled backward through FF by multiplying with JFTJ_F^T.

A Concrete Vector Example

Define:

F(x,y)=[x+yxy],G(u,v)=u2+v.F(x,y)= \begin{bmatrix} x+y\\ xy \end{bmatrix}, \qquad G(u,v)=u^2+v.

The local Jacobians are:

JF(x,y)=[11yx],J_F(x,y)= \begin{bmatrix} 1 & 1\\ y & x \end{bmatrix},

and:

JG(u,v)=[2u1].J_G(u,v)= \begin{bmatrix} 2u & 1 \end{bmatrix}.

At (x,y)=(1,2)(x,y)=(1,2), the intermediate value is:

F(1,2)=[32].F(1,2)= \begin{bmatrix} 3\\2 \end{bmatrix}.

Therefore:

JF(1,2)=[1121],JG(3,2)=[61].J_F(1,2)= \begin{bmatrix} 1 & 1\\ 2 & 1 \end{bmatrix}, \qquad J_G(3,2)= \begin{bmatrix} 6 & 1 \end{bmatrix}.

Compose them:

JGF(1,2)=[61][1121]=[87].J_{G\circ F}(1,2) = \begin{bmatrix} 6 & 1 \end{bmatrix} \begin{bmatrix} 1 & 1\\ 2 & 1 \end{bmatrix} = \begin{bmatrix} 8 & 7 \end{bmatrix}.

Thus:

(GF)(1,2)=[87].\nabla(G\circ F)(1,2)= \begin{bmatrix} 8\\7 \end{bmatrix}.

The shapes are not decoration. They tell us which maps can be composed and in what order.

Forward Mode And Reverse Mode

There are two natural ways to apply the chain rule without constructing every full derivative matrix.

Forward Accumulation

Start with an input direction Δx\Delta x and push its effect forward:

Δu=JF(x)Δx,Δy=JG(F(x))Δu.\Delta u=J_F(x)\Delta x, \qquad \Delta y=J_G(F(x))\Delta u.

This computes a Jacobian-vector product:

JGF(x)Δx.J_{G\circ F}(x)\Delta x.

It efficiently answers: How does this chosen input direction affect every output?

Reverse Accumulation

Start with sensitivity at a scalar loss and pull it backward:

xL=JF(x)TuL.\nabla_x L=J_F(x)^T\nabla_u L.

This computes a vector-Jacobian product, usually represented with column gradients through the transpose.

It efficiently answers: How does the one final loss depend on every earlier input or parameter?

Machine learning commonly has millions of parameters but one scalar loss. That shape makes reverse accumulation especially valuable: one backward sweep can produce sensitivities for every parameter.

This Is The Foundation Of Backpropagation

Backpropagation is not a different derivative rule. It is reverse-mode chain-rule accumulation specialized to layered models and scalar losses.

This lesson focuses on the calculus and graph bookkeeping. Lesson 43 will apply the same mechanism to neural-network parameters, activations, and layers.

Connection To Programming

Here is the earlier branching example encoded as an explicit forward pass and backward pass:

type ForwardState = Readonly<{
  loss: number;
  scaled: number;
  squared: number;
  x: number;
}>;

function forward(x: number): ForwardState {
  const squared = x * x;
  const scaled = 3 * x;
  const loss = squared + scaled;

  return { loss, scaled, squared, x };
}

function backward(state: ForwardState): number {
  const lossSensitivity = 1;
  const squaredSensitivity = lossSensitivity * 1;
  const scaledSensitivity = lossSensitivity * 1;

  const fromSquared = squaredSensitivity * (2 * state.x);
  const fromScaled = scaledSensitivity * 3;

  return fromSquared + fromScaled;
}

const state = forward(2);
const derivative = backward(state);

console.assert(state.loss === 10);
console.assert(derivative === 7);

Notice the software structure:

  1. The forward pass stores values needed by local derivative formulas.
  2. The backward pass receives a sensitivity from each child.
  3. Each edge multiplies by one local derivative.
  4. Contributions are added when they reach a shared parent.

A full automatic-differentiation engine generalizes this pattern by storing operations and their local backward rules dynamically.

Common Mistakes

Reversing The Jacobian Product

For GFG\circ F, write the displacement flow:

ΔxJFΔuJGΔy.\Delta x \xrightarrow{J_F} \Delta u \xrightarrow{J_G} \Delta y.

Therefore JFJ_F is closest to Δx\Delta x on the right:

JGF=JGJF.J_{G\circ F}=J_GJ_F.

Evaluating A Local Derivative At The Wrong Value

JGJ_G must be evaluated at the intermediate value F(x)F(x), not at the original input xx unless those happen to be the same type and value.

Multiplying Across Branches Instead Of Adding

Consecutive edges multiply. Alternative paths add. A reused value can receive several valid sensitivity contributions.

Mixing Forward Values With Backward Sensitivities

vv is an intermediate value. vˉ=L/v\bar v=\partial L/\partial v is a sensitivity. They may have compatible shapes, but they represent different things.

Materializing A Full Jacobian Unnecessarily

If the goal is only a directional effect or scalar-loss gradient, Jacobian-vector and vector-Jacobian products can apply the local map without storing every entry of a large Jacobian.

Exercises

  1. In one sentence, explain why the chain rule for GFG\circ F has the order JG(F(x))JF(x)J_G(F(x))J_F(x) rather than JF(x)JG(F(x))J_F(x)J_G(F(x)).

  2. Let:

    u=2x1,L=u3.u=2x-1, \qquad L=u^3.

    Draw the two-operation computation graph, compute the forward values at x=2x=2, and use local derivatives to find dL/dxdL/dx.

  3. For:

    u=xy,v=u+2,L=v2,u=xy, \qquad v=u+2, \qquad L=v^2,

    run a forward and backward pass at (x,y)=(3,1)(x,y)=(3,-1) and report L/x\partial L/\partial x and L/y\partial L/\partial y.

  4. Let F:R4R3F:\mathbb R^4\to\mathbb R^3 and G:R3R2G:\mathbb R^3\to\mathbb R^2. State the shapes of JFJ_F, JGJ_G, and JGFJ_{G\circ F}. Explain how the dimensions type-check.

  5. A scalar xx is used in both:

    u=x2,v=sinx,L=u+v.u=x^2, \qquad v=\sin x, \qquad L=u+v.

    Explain why the backward contributions to xx must be added, then compute dL/dxdL/dx.

  6. For the vector composition:

    F(x,y)=[xyx+y],G(u,v)=u2+3v,F(x,y)= \begin{bmatrix} x-y\\ x+y \end{bmatrix}, \qquad G(u,v)=u^2+3v,

    compute JFJ_F, JGJ_G, and (GF)\nabla(G\circ F) at (x,y)=(2,1)(x,y)=(2,1) using Jacobian multiplication.

  7. Suppose an intermediate scalar vv feeds two children a(v)a(v) and b(v)b(v), and L=a+bL=a+b. Write vˉ\bar v in terms of aˉ\bar a, bˉ\bar b, da/dvda/dv, and db/dvdb/dv. State the general branch-accumulation rule in words.

  8. Compare forward and reverse accumulation for a function F:R1000RF:\mathbb R^{1000}\to\mathbb R. Which direction is naturally efficient for computing the full gradient of the scalar output, and why?

  9. Write TypeScript forward and backward functions for:

    L(x,y)=(xy+1)2.L(x,y)=(xy+1)^2.

    Store only the intermediate values needed by the backward pass. Check the result at (2,3)(2,3) against the analytic gradient [42,28][42,28].

  10. In your own words, explain why a computation graph does not change the function being differentiated. What does the graph add that the single expanded expression does not?

Practice 37.1: Local Derivatives And Branch Accumulation

This is a short correction checkpoint, not a new lesson. Work it on paper without expanding the full functions first. For every computation, write the forward values separately from the backward sensitivities.

1. Local Values Stay Local

Let:

u=3x2,L=u2.u=3x-2, \qquad L=u^2.

At x=1x=-1:

  1. Compute the forward values uu and LL.
  2. Write the local derivatives L/u\partial L/\partial u and u/x\partial u/\partial x.
  3. Compute dL/dxdL/dx using the stored value of uu.
  4. In one sentence, explain why replacing u2u^2 with x2x^2 would change the computation.

2. Follow The Actual Operations

For:

F(x,y)=[2xyx+3y],F(x,y)= \begin{bmatrix} 2x-y\\ x+3y \end{bmatrix},

write JF(x,y)J_F(x,y) by differentiating one output component at a time. Label rows by outputs and columns by inputs before filling in the entries.

Then compute:

JF(1,2)[11]J_F(1,2) \begin{bmatrix} 1\\-1 \end{bmatrix}

and explain what the resulting vector means.

3. Addition At A Branch

Let:

u=x2,v=cosx,L=u+v.u=x^2, \qquad v=\cos x, \qquad L=u+v.
  1. Draw the two branches from xx to LL.
  2. Write the local derivatives at the final addition node.
  3. Compute dL/dxdL/dx symbolically.
  4. Evaluate it at x=1x=1.
  5. Explain why neither branch’s forward value multiplies the other branch’s derivative.

4. Accumulate Child Contributions

An intermediate value zz feeds two children:

a=z2,b=4z,L=a+b.a=z^2, \qquad b=4z, \qquad L=a+b.

At z=3z=3, run the backward pass from Lˉ=1\bar L=1. Show aˉ\bar a, bˉ\bar b, the contribution from each child to zˉ\bar z, and their accumulated total.

Then write the general rule:

zˉ=contribution through a+contribution through b.\bar z=\text{contribution through }a+\text{contribution through }b.

using aˉ\bar a, bˉ\bar b, da/dzda/dz, and db/dzdb/dz.

5. One Complete Composition

Define:

F(x,y)=[xyx+2y],G(u,v)=u2+v.F(x,y)= \begin{bmatrix} x-y\\ x+2y \end{bmatrix}, \qquad G(u,v)=u^2+v.

At (x,y)=(2,1)(x,y)=(2,1):

  1. Compute the forward value F(2,1)F(2,1).
  2. Write JF(x,y)J_F(x,y) and JG(u,v)J_G(u,v) with shapes.
  3. Evaluate both Jacobians at the correct local values.
  4. Compute JGF(2,1)=JG(F(2,1))JF(2,1)J_{G\circ F}(2,1)=J_G(F(2,1))J_F(2,1).
  5. Convert the resulting scalar-output Jacobian into a column gradient.
  6. Check the result by expanding G(F(x,y))G(F(x,y)) only after completing the graph-based calculation.

Readiness Check

Lesson 37 is ready to close when the work consistently shows all four habits:

Summary

Next Lesson

Lesson 38 makes matrix-calculus layout conventions explicit. We will use shape checking to distinguish gradients with respect to vectors and matrices, translate between common notation conventions, and derive reusable identities without relying on memorized formula tables.