Before this lesson:lesson 01 (the 1-D chain rule and
linear approximation), lesson 02 (partial derivatives,
the gradient), lesson 03 (the derivative as a linear map,
the Jacobian and its shape), and linear algebra lesson 01
(the product AB is the map "first B, then A").
Time: about 70 minutes, plus the notebook.
Backpropagation is the chain rule, applied in a clever order. Every deep-learning framework
(PyTorch, JAX, TensorFlow) stores your model as a computational graph and runs the chain rule on
it. When you understand the chain rule as a product of Jacobians, you can:
derive the gradient of any new layer, loss or custom operation by hand (and check it);
see why a residual connectiony=x+F(x) helps the gradient reach early layers: the two
paths add, and the identity path passes the gradient unchanged;
see why a weight used in many places (an RNN cell, tied input and output embeddings) gets the
sum of the gradients of all its uses;
understand the adjoint models of science (weather data assimilation, seismic imaging): they
are the same backward sweep, run through a simulator.
One variable first: rates multiply. Take y=(3x+1)2. Write it as two steps: u=3x+1
and y=u2. At x=1:u=4,du/dx=3, and dy/du=2u=8. A small step Δx
gives Δu≈3Δx, and this step in u gives Δy≈8Δu. So
Δy≈8⋅3Δx=24Δx,dxdy=dudydxdu=24.
Check: y=9x2+6x+1 gives dy/dx=18x+6=24 at x=1.
Interactive figure: loading…
Move the Δx slider toward 0. A small step on the x line becomes a step on the u line and then
on the y line. The violet bars are the true changes; the dashed
blue bars are the linear predictions u′(x)Δx and y′(u)u′(x)Δx.
The magenta gap shrinks faster than Δx, so Δy/Δx tends to
the product y′(u)u′(x). Try the other presets: the rates are now different at every point.
Many variables: linear maps compose. Near a point x, a differentiable map f acts on a
small step h like its Jacobian (lesson 03):
f(x+h)≈f(x)+Df(x)h. Near u=f(x), the map g acts like Dg(u). So the step h
goes through two matrices:
hDf(x)Df(x)hDg(f(x))Dg(f(x))Df(x)h.
Composing two linear maps multiplies their matrices (linear algebra lesson 01).
The map applied first stands on the right. The figure shows this for two maps of the plane.
Interactive figure: loading…
Make the square smaller with the ε slider. The violet square around x is
mapped by f (a rotation and scaling near each point) and then by g (a shear). The true images
are slightly curved. The dashed blue parallelograms are the Jacobian
predictions Df⋅square and DgDf⋅square; for small ε they match
the true images. Press show wrong order: the magenta parallelogram
DfDg⋅square does not match, even for tiny squares. Each panel is zoomed around its point.
Quick check
f:R4→R3 and g:R3→R2. What is the shape of D(g∘f)(x)?
Why.
A Jacobian has one row per output and one column per input. g∘f maps R4 to R2, so its Jacobian is 2×4. The product Dg(f(x))Df(x) is (2×3)(3×4)=2×4. The answer 2×3 is the shape of Dg alone.
A program is a graph. A formula like f(x1,x2)=lnx1+x1x2−sinx2 is computed in
small steps. Give each step a name: v1=lnx1,v2=x1x2,v3=sinx2,v4=v1+v2,v5=v4−v3. Draw one node per step and an arrow from each value to the
steps that use it. This is the computational graph of f (the example is from Baydin et al. 2018).
To get the derivatives, sweep the graph twice. The forward run computes all values from the
inputs to the output. The backward run starts at the output with the number 1 and walks back.
At each node it multiplies by the local derivative on the edge (the derivative of one small step).
Where a value feeds two nodes, the two contributions add.
Interactive figure: loading…
Press Next step and predict each number before it appears. The first 7 steps compute the
values (first number under each node). Then the backward run fills the
orange adjointsvˉi=∂f/∂vi from right to left.
Watch x2 and x1: each is used twice, so it receives two contributions, and the second one is
added (magenta). At the end, xˉ1=5.5 and xˉ2=1.716 are the two
partial derivatives. Switch to forward (tangents) to get one directional derivative instead.
Quick check
For f and g as above, which expression is the Jacobian of g∘f at x?
Why.
The step h first goes through Df(x), so Df(x) stands on the right. The outer map g acts near the point f(x), not near x, so its Jacobian is evaluated at f(x). The option Dg(x)Df(x) has the right order but the wrong point (and g may not even be defined at x). The transposed product is the transpose of the right answer, D(g∘f)⊤.
We use the notation of lesson 03. Vectors are columns.
For f:Rn→Rm, the JacobianDf(x)∈Rm×n has entries [Df(x)]ij=∂fi/∂xj
(outputs × inputs). f is differentiable at x if
f(x+h)=f(x)+Df(x)h+r(h),∥h∥∥r(h)∥→0 as h→0.
In words: the error r(h) of the linear approximation is small even compared with the step h.
We write this as r(h)=o(∥h∥).
Let f:Rn→Rm be differentiable at x, and g:Rm→Rp differentiable at u=f(x).
Then g∘f is differentiable at x, and
D(g∘f)(x)=Dg(f(x))Df(x),(p×m)⋅(m×n)=p×n.
Why it is true. Write A=Df(x) and B=Dg(u). A step h moves f by k=Ah+rf(h).
This step k moves g by Bk+rg(k)=BAh+(Brf(h)+rg(k)). The main part is BAh,
a linear function of h. The rest is a sum of two errors, and both are o(∥h∥):Brf(h) because B is a fixed matrix, and rg(k) because k is at most a constant times ∥h∥.
So BA is the derivative. The full proof makes "the rest is small" precise.
Full proof (six steps)
Let ∥⋅∥ be the Euclidean norm, and for a matrix the induced operator norm
∥A∥=maxh=0∥Ah∥/∥h∥ (linear algebra lesson 11), so that
∥Ah∥≤∥A∥∥h∥.
By the definition of the derivative, f(x+h)=u+Ah+rf(h) with ∥rf(h)∥/∥h∥→0,
and g(u+k)=g(u)+Bk+rg(k) with ∥rg(k)∥/∥k∥→0.
Set ρ(k)=∥rg(k)∥/∥k∥ for k=0 and ρ(0)=0. Then ∥rg(k)∥=ρ(k)∥k∥
for every k (also for k=0, because rg(0)=0), and ρ(k)→0 as k→0.
This trick avoids dividing by ∥k∥, which can be 0 even when h=0.
Put k(h)=f(x+h)−u=Ah+rf(h). Then
g(f(x+h))=g(u)+BAh+R(h) with R(h)=Brf(h)+rg(k(h)).
First part: ∥Brf(h)∥≤∥B∥∥rf(h)∥, so ∥Brf(h)∥/∥h∥→0.
Second part: for small h,∥rf(h)∥≤∥h∥, so ∥k(h)∥≤(∥A∥+1)∥h∥. Hence k(h)→0
and ∥rg(k(h))∥/∥h∥=ρ(k(h))∥k(h)∥/∥h∥≤ρ(k(h))(∥A∥+1)→0.
So R(h)=o(∥h∥). By the definition (and the uniqueness) of the derivative,
D(g∘f)(x)=BA.■
Shape check. Always check (p×m)(m×n): the inner sizes must agree, and the result
has the outer sizes. If the shapes do not fit, the order is wrong. If the shapes fit by accident
(square matrices), the order can still be wrong: matrix products do not commute.
Longer chains. For F=fL∘⋯∘f1 with x0=x,xk=fk(xk−1) and
Jk=Dfk(xk−1), induction on L gives DF(x)=JLJL−1⋯J1. Each Jk is evaluated
at the input of its own step.
Read the product DgDf entry by entry. Entry (i,j) is row i of Dg times column j of Df:
∂xj∂(g∘f)i=k=1∑m∂uk∂gi∂xj∂fk.
In words: sum over every intermediate variableuk through which xj can change gi.
Each term is the product of the rates along one path xj→uk→gi.
The case most people learn first. Let f(x,y) be a function of two variables, and let x(t),y(t) be functions of time. Then t↦(x(t),y(t)) has the 2×1 Jacobian (x′(t),y′(t))⊤,
and f has the 1×2 Jacobian (∂xf,∂yf). Their product is
dtdf(x(t),y(t))=∂x∂fx′(t)+∂y∂fy′(t).
Example.f(x,y)=x2y with x(t)=cost,y(t)=sint, at t=0:x=1,y=0,x′=−sin0=0,y′=cos0=1. So dtdf=2xy⋅0+x2⋅1=1. Check:
f(x(t),y(t))=cos2tsint has derivative −2costsin2t+cos3t, which is 1 at t=0.
A gradient through a map is a vector-Jacobian product #
In ML the last function is almost always a scalar loss ℓ:Rm→R. Its Jacobian is the row
∇ℓ⊤ (lesson 02). The chain rule gives the
1×n row ∇ℓ(f(x))⊤Df(x). Transpose it to get a column:
∇(ℓ∘f)(x)=Df(x)⊤∇ℓ(f(x)).
This is a vector-Jacobian product (VJP): a vector times the Jacobian, written as Df⊤u
(or u⊤Df as a row). We write the gradient of the loss with respect to any intermediate value
u as uˉ=∂ℓ/∂u. It has the same shape as u and is called the
adjoint of u. The formula above says:
xˉ=Df(x)⊤uˉfor u=f(x).
The adjoint of the output, multiplied by the transposed local Jacobian, gives the adjoint of the input.
Three VJPs appear in every network.
(a) Linear map, z=Wx with W∈Rm×n. The Jacobian with respect to x is W itself, so
xˉ=W⊤zˉ.
(b) Elementwise map, a=φ(z) (for example tanh or ReLU applied to each entry). The
Jacobian is diag(φ′(z)) (lesson 03), a
diagonal matrix, so zˉ=φ′(z)⊙aˉ. Here ⊙ is the elementwise product. Never
build the diagonal matrix in code: it has m2 entries, and only m of them are nonzero.
(c) The weights, z=Wx as a function of W. Now W is the variable and x is fixed.
Proposition. If z=Wx and zˉ=∂ℓ/∂z, then Wˉ=∂ℓ/∂W=zˉx⊤,
an m×n matrix (the shape of W).
Proof.
zk=∑jWkjxj, so ∂zk/∂Wij=xj if k=i, and 0 otherwise.
By the entry form of the chain rule, ∂ℓ/∂Wij=∑kzˉk∂zk/∂Wij=zˉixj.
The matrix with entries zˉixj is the outer product zˉx⊤.■
An outer product of two vectors has rank at most 1. So for one sample, the gradient of a linear
layer is a rank-1 matrix. Lesson 05 returns to this fact.
Quick check
z=Wx with W∈R3×5, and the upstream gradient is zˉ∈R3. What is xˉ=∂ℓ/∂x?
Why.
The gradient through a map is Df⊤zˉ, and Df=W. So xˉ=W⊤zˉ, a vector in R5 like x.Wzˉ is not even defined (W needs a vector in R5).zˉx⊤ is the gradient with respect to W, not x.
A value fans out when it is used by more than one later step. For example, x feeds two maps,
u=f(x) and w=g(x), and the loss is ℓ=F(u,w).
Theorem (paths add). With uˉ=∇uF and wˉ=∇wF,
xˉ=Df(x)⊤uˉ+Dg(x)⊤wˉ.
Proof.
Stack the two maps into one: s(x)=(f(x),g(x)). Its Jacobian is the stacked block matrix
Ds=(DfDg), because the rows of Ds are the rows of Df and then
the rows of Dg.
ℓ=F(s(x)), so the VJP rule gives xˉ=Ds⊤∇F=(Df⊤Dg⊤)(uˉwˉ).
Multiply the blocks: xˉ=Df⊤uˉ+Dg⊤wˉ.■
So the gradient through each path is computed as if the other path did not exist, and then the
results are added. The same is true for any number of paths.
Interactive figure: loading…
Drag the violet point along the curve. Here x feeds two branches, and y depends on both.
The bars show the path-1 and path-2 products and their
sum. Only the tangent with the summed slope touches the curve; the
magenta lines use one path only. Try residual: the identity path always
contributes 1. Try shared weight: one parameter θ is used in two places.
Three places where fan-out matters:
Residual connections.y=x+F(x). The identity path and the F path add:
xˉ=yˉ+DF(x)⊤yˉ. Even if DF⊤yˉ is tiny, the gradient yˉ still
reaches x through the identity path.
Shared weights. A parameter used in several places (the same RNN weight at every time step,
tied input and output embeddings) gets the sum of the gradients of all its uses.
A variable used twice in a formula. In y=x2sinx, the product rule
2xsinx+x2cosx is exactly "path through x2" plus "path through sinx".
Quick check
y=uw with u=x2 and w=sinx. What is dy/dx at x=π?
Why.
Two paths. Through u:∂u∂ydxdu=w⋅2x=sinπ⋅2π=0. Through w:∂w∂ydxdw=ucosx=π2⋅(−1). They add: 0−π2. The answer 0 counts only the first path. −2π3 multiplies the paths instead of adding them.
A primitive operation is a small function whose derivative we know in closed form: +,−,×,/,exp,ln,sin,tanh, a matrix product, a sum over an axis.
A program computes intermediate variablesvi, one per primitive operation. We number the
n inputs v1−n,…,v0 and the later variables v1,v2,… in the order they are
computed. This order is a topological order: every vi uses only variables with smaller index.
The computational graph has one node per variable and an edge j→i when the operation that
makes vi uses vj directly. Then j is a parent of i, and i is a child of j.
The graph has no cycles: it is a directed acyclic graph (DAG).
The local derivative on edge j→i is ∂vi/∂vj: the derivative of the one
operation that makes vi, with respect to one of its arguments, the others fixed.
The example. For f(x1,x2)=lnx1+x1x2−sinx2:
variable
operation
parents
local derivatives
v−1=x1
input
v0=x2
input
v1=lnv−1
ln
v−1
∂v1/∂v−1=1/v−1
v2=v−1v0
×
v−1,v0
∂v2/∂v−1=v0,∂v2/∂v0=v−1
v3=sinv0
sin
v0
∂v3/∂v0=cosv0
v4=v1+v2
+
v1,v2
1,1
v5=v4−v3
−
v4,v3
1,−1
x1 has two children (v1 and v2) and x2 has two children (v2 and v3): both fan out.
Adjoints and tangents. Let y be the output. For every node:
the adjointvˉj=∂y/∂vj says how much y changes when vj changes and
everything computed from vj is computed again;
the tangentv˙i=dtdvi(x+tx˙)t=0 says how fast vi changes when
the inputs move in a chosen direction x˙.
Theorem (the two sweeps).
Backward sweep. Set yˉ=1. Then, for j in reverse topological order,
vˉj=i∈children(j)∑vˉi∂vj∂vi.
At the end, vˉ1−n,…,vˉ0 are the partial derivatives ∂y/∂x1,…,∂y/∂xn.
2. Forward sweep. Set the input tangents to x˙. Then, for i in topological order,
v˙i=j∈parents(i)∑∂vj∂viv˙j.
At the end, y˙=∇y⊤x˙, the directional derivative of y along x˙.
Proof of the backward sweep.
vj enters the rest of the program only through its children. Give each use its own copy:
child i uses a copy ci, and all copies equal vj. Then y is a function H of the copies
(all other earlier variables stay fixed), and y(vj)=H(vj,…,vj).
By the fan-out rule (or the entry form with one input and several paths),
∂y/∂vj=∑i∂H/∂ci.
The copy ci changes y only through vi. By the 1-D chain rule,
∂H/∂ci=(∂y/∂vi)(∂vi/∂ci)=vˉi∂vi/∂vj.
Children come later in the topological order. In reverse order, all vˉi of the children are
known when we reach j. Induction from the output (where yˉ=1) to the inputs gives the claim. ■
Proof of the forward sweep. Move the inputs along x(t)=x+tx˙. Each vi is a function of
its parents, so the entry form of the chain rule gives dtdvi=∑j∂vj∂vidtdvj.
The parents come earlier, so their tangents are known. At the output, the chain rule gives
y˙=Dyx˙=∇y⊤x˙.■
Graph and sweep are different things. The graph says what is computed. A sweep says in which
order the local derivatives are combined. One backward sweep gives the derivatives of one output
with respect to all inputs. One forward sweep gives the derivatives of all outputs along
one input direction.
Quick check
In the backward sweep, a node vj has two children, va and vb. What is vˉj?
Why.
Each child gives one path from vj to the output, and the contributions of all paths add (fan-out rule). Each contribution is the adjoint of the child times the local derivative on the edge. vˉa+vˉb forgets the local derivatives; the product of adjoints has no meaning here.
For a chain F=fL∘⋯∘f1, the Jacobian is JL⋯J1. Matrix multiplication is
associative, so every way of placing the brackets gives the same matrix. But the costs differ a lot:
Forward: push an input direction v through the chain, JL(⋯(J2(J1v))). Every step
is a matrix-vector product. The result is DFv, a Jacobian-vector product (JVP).
Backward: pull an output weight u back, (⋯((u⊤JL)JL−1)⋯)J1. Every step is
again a matrix-vector product. The result is u⊤DF, a VJP.
For a scalar loss, the last Jacobian JL is a single row. Starting there, every intermediate result
stays a single row, and one backward sweep gives the whole gradient. This is why training uses the
backward order. Lesson 05 turns the two sweeps into the
forward and reverse modes of automatic differentiation and counts their costs.
Linear algebra lesson 15 gives a short first view of JVPs and VJPs.
Answers to section 1. (1) 2×4, and DgDf is the right product:
(2×3)(3×4). The other order DfDg would be (3×4)(2×3), which is not defined.
(2) Add. x1 reaches f along two paths, through lnx1 and through x1x2, and the two
contributions add: ∂f/∂x1=1/x1+x2. At (2,5) this is 0.5+5=5.5.
Check directly: g(f(x))=x1x2(x1+x2)+x22=x12x2+x1x22+x22. Then
∂1=2x1x2+x22=4+4=8 and ∂2=x12+2x1x2+2x2=1+4+4=9. ✓
(b) The graph of f(x1,x2)=lnx1+x1x2−sinx2 at (2,5).
Forward run (values).
step
value
v−1=x1
2
v0=x2
5
v1=lnv−1
ln2=0.693
v2=v−1v0
10
v3=sinv0
sin5=−0.959
v4=v1+v2
10.693
v5=v4−v3
11.652=f(2,5)
Backward run (adjoints), in reverse order. Each node sends vˉi times the local derivative
to each parent.
Seed: vˉ5=1.
Node v5=v4−v3:vˉ4=vˉ5⋅1=1 and vˉ3=vˉ5⋅(−1)=−1.
Node v4=v1+v2:vˉ1=vˉ4⋅1=1 and vˉ2=vˉ4⋅1=1.
Node v3=sinv0:vˉ0=vˉ3cosv0=−cos5=−0.284.
Node v2=v−1v0:vˉ−1=vˉ2⋅v0=5, and add to vˉ0:vˉ0=−0.284+vˉ2⋅v−1=−0.284+2=1.716.
Node v1=lnv−1:add to vˉ−1:vˉ−1=5+vˉ1/v−1=5+0.5=5.5.
So ∂f/∂x1=5.5 and ∂f/∂x2=1.716. Check with the formulas:
∂f/∂x1=1/x1+x2=0.5+5=5.5 and ∂f/∂x2=x1−cosx2=2−0.284=1.716. ✓
The two "add" steps are the fan-outs of x2 (step 5) and x1 (step 6).
Forward sweep (tangents) with x˙=(1,0).v˙−1=1,v˙0=0;v˙1=v˙−1/v−1=0.5;v˙2=v˙−1v0+v−1v˙0=5;v˙3=cos(v0)v˙0=0;v˙4=0.5+5=5.5;v˙5=5.5−0=5.5. One forward sweep gives one number,
∂f/∂x1=5.5. For ∂f/∂x2 you need a second sweep with x˙=(0,1).
The backward sweep gave both at once.
(c) One neuron with a squared loss.z=w⊤x+b,a=σ(z),ℓ=21(a−t)2,
with the sigmoid σ(z)=1/(1+e−z) and σ′=σ(1−σ). Take
x=(1,2),w=(0.5,−0.5),b=0.5,t=1.
NumPy checks the three hand computations with central differences
(f(x+ηei)−f(x−ηei))/(2η) (lesson 07
explains this check).
importnumpyasnpdefnum_grad(f,x,eta=1e-6):"""Central differences, one input at a time."""g=np.zeros_like(x)foriinrange(x.size):e=np.zeros_like(x);e[i]=etag[i]=(f(x+e)-f(x-e))/(2*eta)returng# (a) gradient through a map is a VJP: Df^T grad gx=np.array([1.0,2.0])f=lambdax:np.array([x[0]*x[1],x[0]+x[1],x[1]**2])g=lambdau:u[0]*u[1]+u[2]Df=np.array([[x[1],x[0]],[1.0,1.0],[0.0,2*x[1]]])u=f(x)print(Df.T@np.array([u[1],u[0],1.0]))# [8. 9.]print(num_grad(lambdax:g(f(x)),x))# [8. 9.] (up to ~1e-9)# (b) backward sweep on the graph of ln x1 + x1 x2 - sin x2 at (2, 5)x1,x2=2.0,5.0v1,v2,v3=np.log(x1),x1*x2,np.sin(x2)v4=v1+v2;v5=v4-v3b5=1.0b4,b3=b5*1.0,b5*-1.0b1,b2=b4*1.0,b4*1.0b0=b3*np.cos(x2)# from v3bm1=b2*x2# from v2b0+=b2*x1# from v2: fan-out of x2, addbm1+=b1/x1# from v1: fan-out of x1, addprint(round(v5,3),round(bm1,3),round(b0,3))# 11.652 5.5 1.716F=lambdax:np.log(x[0])+x[0]*x[1]-np.sin(x[1])print(num_grad(F,np.array([2.0,5.0])).round(3))# [5.5 1.716]# (c) one neuron, squared lossxn,w,b,t=np.array([1.0,2.0]),np.array([0.5,-0.5]),0.5,1.0sig=lambdaz:1/(1+np.exp(-z))z=w@xn+b;a=sig(z)zbar=(a-t)*a*(1-a)print(zbar*xn,zbar,zbar*w)# [-0.125 -0.25 ] -0.125 [-0.0625 0.0625]loss_w=lambdaw:0.5*(sig(w@xn+b)-t)**2print(num_grad(loss_w,w).round(6))# [-0.125 -0.25 ]
Backpropagation. A neural network is a long chain of layers. Its gradient is the product of
the transposed layer Jacobians, applied to ℓˉ=1 from the loss backward. Lesson 06 and
deep learning lesson 03 derive the full backward pass of an MLP.
Every autodiff framework. PyTorch, JAX and TensorFlow record the computational graph of your
code. Each primitive operation comes with a VJP rule (its "backward" function), and
loss.backward() runs the backward sweep of section 3.
Residual networks (He et al., 2016). In y=x+F(x) the gradient is yˉ+DF⊤yˉ.
The identity path lets the gradient reach early layers of very deep networks. Transformers use a
residual connection around every attention and MLP block.
Shared parameters. Recurrent networks use the same weights at every time step; convolutions
use the same kernel at every position; many language models tie the input embedding and the
output projection. In each case the gradient is the sum over all uses.
ML for science. In weather prediction, the backward sweep through a forecast model is the
adjoint model; 4D-Var data assimilation gets the gradient of the misfit with respect to the
initial state from one adjoint run. Seismic full-waveform inversion does the same through a wave
simulation. See the ML for science track.
Wrong order.D(g∘f)=DgDf, not DfDg. The map applied first stands on the right.
The shape check catches this unless the matrices are square.
Wrong point. The outer Jacobian is evaluated at f(x), not at x:Dg(f(x)). In a network,
each layer's Jacobian uses that layer's own input, stored from the forward run.
Missing transpose. The gradient through z=Wx is W⊤zˉ, not Wzˉ. The gradient for
the weights is zˉx⊤, with the shape of W. Check shapes after every step.
Not adding at a fan-out. When a value is used twice (a residual, a shared weight, x in
x2sinx), its adjoint is the sum of the contributions. Overwriting instead of adding (=
instead of +=) is a classic bug in hand-written backward passes.
Mixing up the local and the total derivative. On the edge x1→v2=x1x2, the local
derivative is x2=5. The total derivative ∂f/∂x1=5.5 also includes the path
through lnx1.
Building diagonal Jacobians. For an elementwise map, use φ′(z)⊙aˉ. A
diag matrix of size m×m wastes memory and time.
f:R5→R2 and g:R2→R3. Give the shapes of Df(x),Dg(f(x)) and D(g∘f)(x).AnswerDf is 2×5,Dg is 3×2, and D(g∘f)=DgDf is (3×2)(2×5)=3×5.
f(x,y)=exy,x(t)=t2,y(t)=3t. Compute dtdf(x(t),y(t)) at t=1 with the
entry form, then check by substitution.AnswerAt t=1:x=1,y=3,x′=2t=2,y′=3.∂xf=exy=3e and ∂yf=ex=e. So dtdf=3e⋅2+e⋅3=9e≈24.46. Check: f=3tet2, derivative 3et2+6t2et2=9e at t=1. ✓
a=tanh(z) elementwise, with z∈R4. Write zˉ in terms of aˉ and a. Why is it
enough to store a from the forward run?Answerzˉ=(1−a⊙a)⊙aˉ, because tanh′=1−tanh2. The derivative is a function of the output a, so z is not needed.
A residual block computes y=x+Wx with a square matrix W. Given yˉ, what is xˉ?AnswerTwo paths add: xˉ=yˉ+W⊤yˉ=(I+W)⊤yˉ. The identity path passes yˉ unchanged.
Draw the computational graph of f(x,y)=(x+y)ex and run the backward sweep at (1,0).Answerv1=x+y=1,v2=ex=e,v3=v1v2=e. Backward: vˉ3=1;vˉ1=v2=e,vˉ2=v1=1;yˉ=vˉ1⋅1=e;xˉ=vˉ1⋅1+vˉ2⋅ex=e+e=2e≈5.437(x fans out to v1 and v2). Check: ∂xf=ex+(x+y)ex=2e and ∂yf=ex=e at (1,0). ✓
For one sample, why does ∂ℓ/∂W of a linear layer z=Wx have rank at most 1?AnswerIt equals zˉx⊤, an outer product. Every column j is xjzˉ, a multiple of the same vector zˉ.
Recall cardsAnswer in your head first, then reveal. Add the cards to your review deck to see them again just before you would forget.
State the chain rule for g∘f with Jacobians.
D(g∘f)(x)=Dg(f(x))Df(x): the outer Jacobian (evaluated at f(x)) on the left, the inner one on the right.
f:R4→R3,g:R3→R2. What is the shape of D(g∘f)?
2×4, from (2×3)(3×4).
Write the entry form of the chain rule.
∂(g∘f)i/∂xj=∑k(∂gi/∂uk)(∂fk/∂xj): a sum over the intermediate variables uk.
What is a vector-Jacobian product (VJP), and where does it appear?
Df⊤u (or u⊤Df). The gradient of a scalar loss through u=f(x) is the VJP xˉ=Df(x)⊤uˉ.
For z=Wx, give xˉ and Wˉ in terms of zˉ.
xˉ=W⊤zˉ and Wˉ=zˉx⊤ (an outer product with the shape of W).
For an elementwise map a=φ(z), what is zˉ?
zˉ=φ′(z)⊙aˉ. The Jacobian is diagonal, so never build it.
Why do gradients add when a value is used twice?
Stack the two uses into one map with Jacobian (DfDg); its transpose times (uˉ,wˉ) is Df⊤uˉ+Dg⊤wˉ.
What is the adjoint vˉj of a node in a computational graph, and how is it computed?
vˉj=∂y/∂vj. In reverse topological order, vˉj=∑children ivˉi∂vi/∂vj, with yˉ=1.
For f(x1,x2)=lnx1+x1x2−sinx2, what is ∂f/∂x1 at (2,5), and which two paths give it?
5.5=1/x1+x2: the path through lnx1 gives 0.5, the path through x1x2 gives 5.
What does one forward sweep give, and what does one backward sweep give?
Forward: one directional derivative ∇y⊤x˙ (a JVP). Backward: the derivatives of one output with respect to all inputs (a VJP).
"Explain the chain rule for vector functions." — D(g∘f)=Dg(f(x))Df(x); show the shapes;
the first map stands on the right because composition of linear maps is the matrix product.
"What is the gradient of ℓ(Wx) with respect to x and with respect to W?" — W⊤zˉ and
zˉx⊤ with zˉ=∇ℓ(Wx). Mention the rank-1 structure of the weight gradient.
"Why do residual connections help training?" — fan-out: xˉ=yˉ+DF⊤yˉ; the identity
path carries the gradient back even when DF is small.
"Backprop through this small expression on the whiteboard." — draw the graph, compute the values,
seed yˉ=1, go backward, multiply by local derivatives, add at fan-outs, then check one
partial derivative by hand or with finite differences.