Brown University crest
CPSY 1291 Computational Methods for Mind, Brain & Behavior
Lecture 9 · Theme 2: Learning representations: from neurons to deep networks

Hidden layers & backpropagation

Tuesday, October 13 · Fall 2026

Reader-friendly version — lecture content with figure descriptions

Last lecture: one neuron that learns

A model neuron with two inputs, x1 and x2, with weights w1 and w2, summed with a bias b into z, passed through the nonlinearity g, giving the output a = g(w1 x1 + w2 x2 + b)
  • Perceptron: y^=sign(z)\hat y = \mathrm{sign}(z), labels ±1\pm 1
  • Delta rule: y^=z\hat y = z, squared error
  • Logistic regression: y^=σ(z)\hat y = \sigma(z), cross-entropy
  • The model neuron: a weighted sum z=w⊤x+bz = \textcolor{#B5396B}{\mathbf{w}}^\top\textcolor{#3E6D8E}{\mathbf{x}} + \textcolor{#3F7A6B}{b}, then a nonlinearity a=g(z)a = \textcolor{#7A4FA3}{g}(z). Its weights set one decision boundary
  • Learning: the loss ℓ\ell measures the gap between the output y^=a\hat y = a and the target yy; the weights move against its gradient
  • All three rules of last lecture share one update: learning rate × error × input

Δw=η (y−y^) x\Delta \textcolor{#B5396B}{\mathbf{w}} = \eta\,(y-\hat y)\,\textcolor{#3E6D8E}{\mathbf{x}}

Learning the weights: start anywhere, walk downhill

Contours of the loss over the two weights w1 and w2, with the minimum marked by a star. At the start w(0), at the upper left, a dark arrow shows the gradient pointing uphill, with dashed arrows for its two components, the partial derivatives with respect to w1 and w2. A magenta arrow labelled minus the gradient points the other way, to w(1); eight dots w(0) to w(8) step down toward the minimum
  • Each pair (w1,w2)(w_1, w_2) has a loss ℓ\ell: the squared error 12(y−y^)2\tfrac12(y-\hat y)^2, averaged over a small training set; contours join equal losses
  • Start at small random weights w(0)\textcolor{#B5396B}{\mathbf{w}}^{(0)}. The gradient ∇ℓ=(∂ℓ/∂w1, ∂ℓ/∂w2)\nabla\ell = (\partial\ell/\partial w_1,\ \partial\ell/\partial w_2) points uphill, toward higher loss
  • Each step is a weight update against the gradient; the learning rate η\eta sets its size

w(t+1)=w(t)−η ∇ℓ\textcolor{#B5396B}{\mathbf{w}}^{(t+1)} = \textcolor{#B5396B}{\mathbf{w}}^{(t)} - \eta\,\nabla\ell

  • For this neuron the loss is convex, a bowl with a single minimum. From any start, small enough steps reach the bottom

You never see the whole landscape

  • The contour map was drawn by computing ℓ\ell for every pair (w1,w2)(w_1, w_2) on a grid: easy with only 2 weights
  • With 100 weights and only 10 values tried per weight, the grid has 1010010^{100} points. Real networks have millions of weights: the map can never be drawn
  • Gradient descent never needs the map. At the current weights it computes the gradient: for each weight, which way to move to lower ℓ\ell, and how strongly
  • Why that is cheap: the gradient is a formula, worked out once with calculus (next slides). Its cost grows in proportion to the number of weights, not exponentially as the grid does
  • Each small step lowers the loss. A step computed from one example, or from a small batch of examples (minibatches, next lecture), lowers it on average

The chain rule, one link at a time

  • The weights change the loss only through a chain: w  →  z=w⊤x+b  →  y^=g(z)  →  ℓ\textcolor{#B5396B}{\mathbf{w}} \;\to\; z = \textcolor{#B5396B}{\mathbf{w}}^\top \textcolor{#3E6D8E}{\mathbf{x}} + \textcolor{#3F7A6B}{b} \;\to\; \hat y = \textcolor{#7A4FA3}{g}(z) \;\to\; \ell
  • Chain rule of calculus: if ℓ=f(u)\ell = f(u) and u=h(w)u = h(w), then dℓdw=dℓdu dudw\dfrac{d\ell}{dw} = \dfrac{d\ell}{du}\,\dfrac{du}{dw}. A longer chain multiplies one slope per link. This gives the gradient of the loss with respect to each weight

∂ℓ∂w=∂ℓ∂y^  ∂y^∂z  ∂z∂w\frac{\partial\ell}{\partial \textcolor{#B5396B}{\mathbf{w}}}=\frac{\partial\ell}{\partial\hat y}\;\frac{\partial\hat y}{\partial z}\;\frac{\partial z}{\partial \textcolor{#B5396B}{\mathbf{w}}}

  • Link y^→ℓ\hat y \to \ell:   ∂ℓ/∂y^\;\partial\ell/\partial\hat y, set by the loss
  • Link z→y^z \to \hat y:   ∂y^/∂z=g′(z)\;\partial\hat y/\partial z = \textcolor{#7A4FA3}{g}'(z), the slope of the nonlinearity
  • Link w→z\textcolor{#B5396B}{\mathbf{w}} \to z:   ∂z/∂w=x\;\partial z/\partial \textcolor{#B5396B}{\mathbf{w}} = \textcolor{#3E6D8E}{\mathbf{x}}, because z=w1x1+w2x2+bz = w_1x_1 + w_2x_2 + b
  • Multiply the three slopes and you have the gradient

The three links, worked out: delta rule

Output y^=z\hat y = z (no nonlinearity), loss ℓ=12(y−y^)2\ell = \tfrac12(y-\hat y)^2

∂ℓ∂y^=12⋅2 (y−y^)⋅(−1)=−(y−y^)\frac{\partial\ell}{\partial\hat y} = \tfrac12\cdot 2\,(y-\hat y)\cdot(-1) = -(y-\hat y)

∂y^∂z=1∂z∂w=x\frac{\partial\hat y}{\partial z} = 1 \qquad\qquad \frac{\partial z}{\partial \textcolor{#B5396B}{\mathbf{w}}} = \textcolor{#3E6D8E}{\mathbf{x}}

∂ℓ∂w=−(y−y^)⋅1⋅x=−(y−y^) x\frac{\partial\ell}{\partial \textcolor{#B5396B}{\mathbf{w}}} = -(y-\hat y)\cdot 1\cdot \textcolor{#3E6D8E}{\mathbf{x}} = -(y-\hat y)\,\textcolor{#3E6D8E}{\mathbf{x}}

  • The error δ=y−y^\delta = y-\hat y gives the rule its name. Step against the gradient: Δw=η δ x\Delta \textcolor{#B5396B}{\mathbf{w}} = \eta\,\delta\,\textcolor{#3E6D8E}{\mathbf{x}}, the delta rule
  • Backpropagation, later, writes the error with the opposite sign: δ=∂ℓ/∂z=y^−y\delta = \partial\ell/\partial z = \hat y - y

The three links, worked out: logistic regression

Output y^=σ(z)=11+e−z\hat y = \sigma(z) = \dfrac{1}{1+e^{-z}}, loss ℓ=−[ ylog⁡y^+(1−y)log⁡(1−y^) ]\ell = -\big[\,y\log\hat y + (1-y)\log(1-\hat y)\,\big]

∂ℓ∂y^=−yy^+1−y1−y^=−y(1−y^)+(1−y) y^y^(1−y^)=−y−y^y^(1−y^)\frac{\partial\ell}{\partial\hat y} = -\frac{y}{\hat y}+\frac{1-y}{1-\hat y} = \frac{-y(1-\hat y)+(1-y)\,\hat y}{\hat y(1-\hat y)} = -\frac{y-\hat y}{\hat y(1-\hat y)}

∂y^∂z=σ(z)(1−σ(z))=y^(1−y^)∂z∂w=x\frac{\partial\hat y}{\partial z} = \sigma(z)\big(1-\sigma(z)\big) = \hat y(1-\hat y) \qquad\qquad \frac{\partial z}{\partial \textcolor{#B5396B}{\mathbf{w}}} = \textcolor{#3E6D8E}{\mathbf{x}}

∂ℓ∂w=−y−y^y^(1−y^)⋅y^(1−y^)⋅x=−(y−y^) x\frac{\partial\ell}{\partial \textcolor{#B5396B}{\mathbf{w}}} = -\frac{y-\hat y}{\hat y(1-\hat y)}\cdot\hat y(1-\hat y)\cdot \textcolor{#3E6D8E}{\mathbf{x}} = -(y-\hat y)\,\textcolor{#3E6D8E}{\mathbf{x}}

  • The sigmoid's slope cancels the loss's denominator: the same form as the delta rule

The perceptron is gradient descent after all

  • Last lecture: Rosenblatt's rule was a heuristic. On each mistake, add η y x\eta\,y\,\textcolor{#3E6D8E}{\mathbf{x}} (labels y=±1y=\pm1). Its threshold output has no slope, so the chain rule cannot derive it
  • Now treat the output as linear, y^=z\hat y = z, and score it with ℓ=max⁡(0, −y z)\ell = \max(0,\,-y\,z): 0 when the example is on the correct side, growing with how far a mistake is on the wrong side
  • The gradient is −y x-y\,\textcolor{#3E6D8E}{\mathbf{x}} on a mistake, 0 otherwise. Stepping against it gives exactly Rosenblatt's rule
  • The heuristic is gradient descent on this loss, the hinge loss with a margin of 0

Why more than one layer?

One line fails on XOR; simpler rules do not

  • XOR (first panel below): one neuron, one line, at best 3 of the 4 points right
  • But XOR is built from simpler rules, each one perceptron with one line (other panels):

x1 XOR x2=(x1∨x2)∧¬(x1∧x2)x_1 \,\text{XOR}\, x_2 = (x_1 \lor x_2) \land \lnot(x_1 \land x_2)

  • Stack them: OR and NOT-AND in a first layer, a neuron combining them in a second
Four small panels. XOR: the four inputs with the best single line, 3 of 4 right, the wrong point (1,1) circled. OR: the four inputs, with (0,1), (1,0) and (1,1) green and (0,0) blue, separated by the gold line x1 + x2 = 0.5. AND: only (1,1) green, separated by the line x1 + x2 = 1.5. NOT (x1 AND x2): the four inputs, green except (1,1) in blue, separated by the gold line x1 + x2 = 1.5, shaded below it

Stack them: two hidden units and one output

The four XOR points, blue at (0,0) and (1,1), green at (0,1) and (1,0). Two hidden units, then one output: two gold lines, x1 + x2 = 0.5 and x1 + x2 = 1.5, bound a band that is the output's green region, and all 4 points are right
  • Two hidden units, one like OR and one like AND; the output adds OR and subtracts AND (the NOT), so it fires in the band between their lines: all 4 right
  • A multilayer perceptron (MLP) stacks layers: each layer's outputs are the next layer's inputs, and every unit takes a weighted sum, then a nonlinearity. Stacked neurons draw boundaries that one line cannot

The hidden layer re-represents the input

The XOR network of the previous slide: inputs x1 and x2, weights of 1 into both ReLU hidden units, biases 0 and minus 1, output weights 1 and minus 2, output is a step unit with bias minus 0.5
  • aj[l]a^{[l]}_j: output of unit jj in layer ll (layer 1 is hidden). With ReLUs, unit 1 acts like OR, unit 2 like AND
  • In the plane of a1[1],a2[1]a^{[1]}_1, a^{[1]}_2, (0,1) and (1,0) land on one point: one line separates the classes
  • The hidden layer turns XOR into a linearly separable problem for the readout

The four XOR inputs in hidden-unit coordinates a1 and a2 of layer 1: blue (0,0) at the origin, green (0,1) and (1,0) together at (1,0), blue (1,1) at (2,1). One solid gold line separates the green point, on the shaded side, from the two blue points. The caption reads: in the hidden layer, one line suffices

Why the ReLU matters: linear layers collapse into one

  • Remove the ReLUs from the XOR network: a1[1]=x1+x2a^{[1]}_1 = x_1 + x_2 and a2[1]=x1+x2−1a^{[1]}_2 = x_1 + x_2 - 1
  • The output's sum becomes a1[1]−2a2[1]−0.5=−(x1+x2)+1.5a^{[1]}_1 - 2a^{[1]}_2 - 0.5 = -(x_1 + x_2) + 1.5: one weighted sum of the inputs, so one line again, and XOR is lost
  • A weighted sum of weighted sums is a weighted sum. Without a nonlinearity, stacking adds nothing
  • With the ReLU, unit 2 stays at 0 until x1+x2>1x_1 + x_2 > 1. That bend is what turns two lines into a band

With hidden layers, the landscape is no longer a bowl

A loss curve over one weight w with three valleys of different depths. Two starting points chosen at random; gradient descent from each follows the curve downhill to a different valley: one reaches the deepest valley, marked global minimum, the other stops in a shallower valley, marked local minimum
  • Once a network has hidden layers, the loss is not convex: it has many valleys, local minima
  • Gradient descent still goes down from wherever it starts. Different starts can end in different minima; none is guaranteed best
  • In practice, large networks usually reach a minimum that works well. That is an observation, not a guarantee

How can a hidden unit learn when nothing tells it what to output?

Backpropagation: a long and disputed history

  • 1958: Rosenblatt's perceptron learns its weights from examples, but only one layer of them
  • 1969: Minsky & Papert show that a perceptron cannot compute XOR. No widely known method trains hidden layers, and interest in neural networks fades
  • 1970–1974: Linnainmaa, studying rounding errors in computer programs, computes all the derivatives of a long calculation in one backward sweep. Werbos: general models in 1974, neural networks in 1982
  • 1986: Rumelhart, Hinton & Williams show that hidden units trained this way learn useful internal representations. Their Nature paper made backprop the standard method
  • Who deserves the credit is still argued. Hinton's 2024 Nobel Prize in Physics, shared with Hopfield, cited a different kind of network, the Boltzmann machine, not backprop. His 2018 Turing Award, shared with Bengio and LeCun, was for deep learning as a whole

Notation for a network with layers

  • Layers are numbered: the input is layer 0, a[0]=x\mathbf{a}^{[0]}=\mathbf{x}; the output is the last layer, LL, so y^=a[L]\hat y = a^{[L]} (LL = number of layers)
  • Unit jj of layer ll: weighted sum zj[l]z^{[l]}_j, output aj[l]=g(zj[l])a^{[l]}_j = g\big(z^{[l]}_j\big)
  • wjk[l]\textcolor{#B5396B}{w}^{[l]}_{jk}: one weight (a number), into unit jj of layer ll from unit kk of the layer below: zj[l]=∑kwjk[l] ak[l−1]+bj[l]z^{[l]}_j = \sum_k \textcolor{#B5396B}{w}^{[l]}_{jk}\,a^{[l-1]}_k + b^{[l]}_j, with bias bj[l]b^{[l]}_j. Layer ll's weights form the matrix W[l]\textcolor{#B5396B}{\mathbf{W}}^{[l]}
A fully connected network drawn left to right: inputs x1 to xD (a superscript 0 equals x), hidden layer 1 with units a superscript 1, hidden layer 2 with units a superscript 2, and an output layer y-hat. Every unit connects to every unit of the next layer; the weight matrices W superscript 1, 2 and 3 label the gaps

Nudge a hidden unit and follow the effect

How does the loss change if hidden unit jj's weighted sum zj[1]z^{[1]}_j grows by a small amount ε\varepsilon?

follows the chain in math
1 its output aj[1]=g(zj[1])a^{[1]}_j = g(z^{[1]}_j) moves by its slope × ε\varepsilon g′(zj[1]) εg'(z^{[1]}_j)\,\varepsilon
2 the output unit's sum z[2]z^{[2]} moves by the connecting weight × that wj[2] g′(zj[1]) ε\textcolor{#B5396B}{w}^{[2]}_j\,g'(z^{[1]}_j)\,\varepsilon
3 the loss moves by the output's error × that, as in logistic regression (y^−y) wj[2] g′(zj[1]) ε(\hat y - y)\,\textcolor{#B5396B}{w}^{[2]}_j\,g'(z^{[1]}_j)\,\varepsilon
  • The loss change per unit nudge is the hidden unit's error: δj[1]=(y^−y) wj[2] g′(zj[1])\delta^{[1]}_j = (\hat y - y)\,\textcolor{#B5396B}{w}^{[2]}_j\,g'(z^{[1]}_j), the output error sent back through the weight
  • It plays the role y^−y\hat y - y plays for the output. Each weight into the hidden unit changes by error × input: ∂ℓ/∂wjk[1]=δj[1] xk\partial\ell/\partial \textcolor{#B5396B}{w}^{[1]}_{jk} = \delta^{[1]}_j\,x_k

Backpropagation: the recipe, for any network

  1. Forward: run the input through and keep every weighted sum zz and output aa
  2. Output error: the output has a target, so its error is   δout=y^−y\;\delta_{\text{out}} = \hat y - y
  3. Backward: each hidden unit's error = the errors of the units it feeds, each × the weight to them, all × its own slope:   δj=g′(zj) ∑kwkj δk\;\delta_j = g'(z_j)\,\sum_k \textcolor{#B5396B}{w}_{kj}\,\delta_k
  4. Gradients: each weight's gradient = error of the unit it enters × its input: ∂ℓ/∂w=δ×input\partial\ell/\partial \textcolor{#B5396B}{w} = \delta \times \text{input}
  • Why backward: step 3 for one layer needs the errors of the layer above. Start at the output and work back, layer by layer

Where the recipe comes from: the chain rule

  • A unit's error is the slope of the loss with respect to its weighted sum:   δ=∂ℓ/∂z\;\delta = \partial\ell/\partial z
  • Output unit: chain through y^\hat y (logistic regression, earlier):

δout=∂ℓ∂y^ ∂y^∂zout=y^−y\delta_{\text{out}} = \frac{\partial\ell}{\partial\hat y}\,\frac{\partial\hat y}{\partial z_{\text{out}}} = \hat y - y

  • Hidden unit jj: zjz_j changes the loss through every unit kk it feeds, so the chains add up:

δj=∂ℓ∂zj=∑k∂ℓ∂zk⏟δk  ∂zk∂aj⏟wkj  ∂aj∂zj⏟g′(zj)∂ℓ∂wjk=∂ℓ∂zj⏟δj  ∂zj∂wjk⏟ak\delta_j = \frac{\partial\ell}{\partial z_j} = \sum_k \underbrace{\frac{\partial\ell}{\partial z_k}}_{\textstyle\delta_k}\;\underbrace{\frac{\partial z_k}{\partial a_j}}_{\textstyle \textcolor{#B5396B}{w}_{kj}}\;\underbrace{\frac{\partial a_j}{\partial z_j}}_{\textstyle g'(z_j)} \qquad\qquad \frac{\partial\ell}{\partial \textcolor{#B5396B}{w}_{jk}} = \underbrace{\frac{\partial\ell}{\partial z_j}}_{\textstyle\delta_j}\;\underbrace{\frac{\partial z_j}{\partial \textcolor{#B5396B}{w}_{jk}}}_{\textstyle a_k}

  • Each formula of the recipe is the chain rule, with the slopes we already know

Back to XOR: learn the weights from random ones

A 2-2-1 network drawn left to right. Inputs x1 = 1 and x2 = 0; six magenta weights; two hidden units marked with red question marks and the words target?; an output unit at 0.54; a box on the right reading target y = 1

  • Above: the XOR network before training, with small random weights instead of the hand-set ones. Hidden units ReLU. Output: a sigmoid with the cross-entropy, so y^\hat y is a probability (a linear output with squared error would also train; threshold only to read the class)
  • Input (1, 0), target 1: the output is y^=0.54\hat y = 0.54. Four steps compute every gradient

Step 1: the forward pass

The 2-2-1 network with its magenta weights 0.50, 0.30, minus 0.40, 0.80 into the hidden layer and 0.70, minus 0.60 into the output. Blue activations inside the units: inputs 1 and 0, hidden units 0.50 and 0.30, output 0.54; the box on the right reads target y = 1

  • Hidden: z1[1]=0.50⋅1−0.40⋅0+0=0.50z^{[1]}_1 = 0.50\cdot 1 - 0.40\cdot 0 + 0 = 0.50,   z2[1]=0.30⋅1+0.80⋅0+0=0.30\;z^{[1]}_2 = 0.30\cdot 1 + 0.80\cdot 0 + 0 = 0.30
  • Output: z[2]=0.70⋅0.50−0.60⋅0.30+0=0.17z^{[2]} = 0.70\cdot 0.50 - 0.60\cdot 0.30 + 0 = 0.17,   y^=σ(0.17)=0.54\;\hat y = \sigma(0.17) = 0.54

Step 1: the forward pass

The same network after the forward pass. The box on the right now reads target y = 1, loss 0.61, and underneath, equals minus log y hat

  • Hidden: z1[1]=0.50⋅1−0.40⋅0+0=0.50z^{[1]}_1 = 0.50\cdot 1 - 0.40\cdot 0 + 0 = 0.50,   z2[1]=0.30⋅1+0.80⋅0+0=0.30\;z^{[1]}_2 = 0.30\cdot 1 + 0.80\cdot 0 + 0 = 0.30
  • Output: z[2]=0.70⋅0.50−0.60⋅0.30+0=0.17z^{[2]} = 0.70\cdot 0.50 - 0.60\cdot 0.30 + 0 = 0.17,   y^=σ(0.17)=0.54\;\hat y = \sigma(0.17) = 0.54
  • Loss: ℓ=−[ylog⁡y^+(1−y)log⁡(1−y^)]=−[log⁡0.542+0]=0.61\ell = -\big[y\log\hat y + (1-y)\log(1-\hat y)\big] = -\big[\log 0.542 + 0\big] = 0.61

Step 2: the error at the output

The same network. A green arrow runs back from the loss box to the output unit, and a green tag under the output reads delta = minus 0.46

  • Sigmoid + cross-entropy: error = prediction − target: δ[2]=∂ℓ/∂z[2]=y^−y=−0.46\textcolor{#3F7A6B}{\delta^{[2]}} = \partial\ell/\partial z^{[2]} = \hat y - y = -0.46
  • Negative: the output was too low and should rise. Every later step builds on this output error

Step 3: send the error backward

The same network. Green arrows run back from the output to each hidden unit, labelled times 0.70 and times minus 0.60. Green tags read delta 1 = minus 0.32 next to a1 of layer 1 and delta 2 = 0.27 next to a2 of layer 1

  • A hidden unit's error = output error × the linking weight × its ReLU slope g′g' (1 if on, 0 if off)
  • δ1[1]=δ[2] w1[2] g′(z1[1])=−0.46×0.70×1=−0.32\textcolor{#3F7A6B}{\delta^{[1]}_1} = \textcolor{#3F7A6B}{\delta^{[2]}}\,\textcolor{#B5396B}{w^{[2]}_1}\,g'(z^{[1]}_1) = -0.46\times0.70\times1 = -0.32; δ2[1]=−0.46×(−0.60)×1≈0.27\textcolor{#3F7A6B}{\delta^{[1]}_2} = -0.46\times(-0.60)\times1 \approx 0.27
  • Each hidden unit gets its own error, even its own sign: a1[1]a^{[1]}_1 should have been higher, a2[1]a^{[1]}_2 lower

Step 4: every gradient is error × activity

The same network with the weights replaced by their gradients in green: minus 0.32 and 0.27 on the connections from x1, 0 on both connections from x2, minus 0.23 and minus 0.14 on the connections into the output. The error tags stay in place

  • gradient = error × activity: ∂ℓ/∂w1[2]=−0.46×0.50=−0.23\partial\ell/\partial \textcolor{#B5396B}{w^{[2]}_1} = \textcolor{#3F7A6B}{-0.46}\times\textcolor{#3E6D8E}{0.50} = -0.23
  • Weights from x2x_2 get 0, since x2=0x_2 = 0. Each bias gets its unit's error: −0.32-0.32, 0.270.27, −0.46-0.46
  • One step with η=1\eta = 1 on all weights and biases: y^\hat y rises from 0.54 to 0.82

Try it: train a small network on 2-D data

  • Compare one and two hidden units on XOR. Every weight is learned by the same four steps

Many classes: one output per class, then a softmax

Two panels stacked. Top, two classes: inputs x1 to xD, each with its weight, summed into z, passed through a sigmoid to give one probability y-hat (logistic regression). Bottom, K classes: the same inputs feed three output neurons, each with its own weight vector w1, w2, w3, giving logits z1 to z3; a softmax turns them into three probabilities p-hat 1 to 3 that sum to 1 (softmax regression)
  • Top: one output, one probability. Bottom, KK classes: KK output units with their own weights, one weighted sum zcz_c per class, the logits
  • Softmax: p^c=ezc/∑jezj\hat p_c = e^{z_c}/\sum_j e^{z_j}, which sum to 1
  • Loss ℓ=−log⁡p^true\ell = -\log \hat p_{\text{true}}; error δc=p^c−yc\delta_c = \hat p_c - y_c
  • Logits (2,1,0)(2,1,0): p^=(0.67,0.24,0.09)\hat{\mathbf p} = (0.67, 0.24, 0.09); ℓ=0.41\ell = 0.41 if class 1 is true
  • Right and confident, ℓ→0\ell \to 0; wrong and confident, ℓ\ell grows without bound

The training loop

model   = nn.Linear(D, K)                  # D inputs, one logit for each of K classes
loss_fn = nn.CrossEntropyLoss()            # softmax + cross-entropy, averaged
opt     = torch.optim.SGD(model.parameters(), lr=0.1)   # SGD: a plain gradient step
for epoch in range(num_epochs):            # one epoch = one pass over the training set
    opt.zero_grad()                        # 1. clear the old gradients
    logits = model(X_train)                # 2. forward: logits for every image
    loss = loss_fn(logits, y_train)        # 3. the average cross-entropy
    loss.backward()                        # 4. gradient of the loss for every weight
    opt.step()                             # 5. update: w <- w - lr * gradient
with torch.no_grad():                      # evaluate on held-out images
    acc = (model(X_test).argmax(1) == y_test).float().mean()
  • One step: a batch of examples forward, their average loss, its gradient, an update. One epoch: every training example once. The model line alone sets a readout or a hidden layer
  • backward() computes the gradients. opt, the optimizer, turns them into weight changes in step()
  • Last lecture's learning cycle, now as code: forward, loss, gradient, step, repeat

Autograd: you never write the backward pass

The worked example as PyTorch records it: x, a weighted sum with W1, z1, ReLU, a1, a weighted sum with W2, z2, and a sigmoid-plus-loss box giving ℓ. Forward values in blue above each quantity, gradients in green below, starting from 1 under ℓ; a long green arrow runs right to left, labelled loss.backward, one reverse sweep, the chain rule at each step. W1 and W2 carry their .grad values

  • PyTorch's automatic differentiation (autograd) records the forward pass as a computational graph: the operations that ran, and the values each one used
  • loss.backward() sweeps the graph in reverse: output error, hidden errors, then each parameter's gradient, stored in its .grad. opt.step() applies the update

Reuse a trained network: transfer learning

Two panels joined by an arrow labelled copy the weights. Left, 1, train on ImageNet: an image goes through a stack of layers, from early to late, to an output of 1,000 classes; 1.2 million labelled images, every weight learns. Right, 2, reuse for a new task: the same stack in grey with padlocks, frozen, weights fixed; the old output is replaced by a new readout for K classes, for example 51 objects; a few hundred labelled images, only the readout learns
  • Train once on a large dataset; freeze the layers and train only a new readout for the new task. A few hundred images can be enough

Train only part of a network

model = nn.Sequential(nn.Linear(D, 64), nn.ReLU(), nn.Linear(64, K))
model.load_state_dict(torch.load("trained.pt"))   # weights trained earlier
for p in model[0].parameters():            # the hidden layer
    p.requires_grad = False                # no gradients: these weights stay fixed
opt = torch.optim.Adam(model[2].parameters(), lr=1e-3)   # Adam: an optimizer, next lecture
  • model[0] is the first layer; .parameters() lists its weights and biases. The loop sets requires_grad = False on each: autograd computes no gradient for them, so they stay frozen
  • The optimizer is given only model[2], the readout: only its weights learn
  • Readout only: cheap. It shows what a trained readout can find in the hidden layer's fixed responses
  • Every weight: backpropagation also changes the hidden layer, so its responses to the images change too
  • Same data, same loss: only the set of weights allowed to move differs

Recap

  • One neuron: every learning rule moves the weights against the gradient of its loss, and the chain rule gives that gradient
  • Hidden layers: one neuron draws one line. Layers with a nonlinearity re-represent the inputs, so that a readout can separate classes no single line could
  • Backpropagation: forward pass, error at the output (y^−y\hat y - y), error sent backward through the weights, and every gradient is error × activity. Autograd runs these steps for you
  • The training loop: forward, loss, backward(), step(), repeated over epochs, with a softmax output for many classes. Freezing trained layers reuses them for a new task

Further reading for the research trail

Optional: a few research-trail entries over the semester. Any paper mentioned in any lecture qualifies, including those on the Going further slides that follow.

Minute paper

Submit on Canvas → Minute papers → Minute Paper 10 (access code read out in class).

Write three brief points in your own words:

  1. In plain words, no equations: why can a multilayer perceptron solve XOR when a single neuron cannot?
  2. Something you do not yet understand, or a question still open
  3. Another idea you found interesting, and why it matters for brains, behavior or AI

Credit for a thoughtful attempt, not for being correct.

Going further

Optional slides, beyond the core of the lecture

Weight transport: must feedback copy the weights?

Feedback alignment, from Lillicrap et al. 2016, Fig. 2: with fixed random feedback weights the hidden-unit updates come within 90 degrees of backprop's, and the MNIST test error of feedback alignment nearly matches backprop's

  • Backprop sends the error back through the forward weights W⊤\textcolor{#B5396B}{\mathbf{W}}^{\top}, so feedback synapses would have to copy them (weight transport)
  • With fixed random feedback weights B\mathbf{B} instead, the forward weights adapt until the hidden units' updates point within 90°90° of backprop's (panel b)
  • On MNIST (handwritten digits), 2.1% test error vs 2.4% for backprop

Error signals in dendrites, one per neuron

Three panels, each with two pyramidal neurons labelled P+ and P minus, with an apical dendrite rising to a tuft. No error in dendrites: no arrows. One error for all: the same green plus arrow onto both tufts, the same signal to every neuron, like dopamine. Each neuron its own error: a green plus arrow onto P+ and a red minus arrow onto P minus, sign set by what the neuron does to the output, like delta

  • Mice turned a grating with a brain–computer interface (BCI): a few layer-5 neurons (P+) rotated it toward the target, others (P−) away
  • Their apical dendrites carried error-related signals of opposite sign, matching each group's effect: each neuron its own error. Silencing them disrupted learning (caveat: a BCI task)

Do backprop's gradients follow the brain's hierarchy?

Two scatter plots, one point per brain region, horizontal axis distance from V1 in millimetres (0 to about 110), vertical axis the network layer that best predicts the region, as a fraction of network depth. Left, panel C, forward activations: V1, V2, V3 and V4 sit low near 0.7 to 0.77, regions farther from V1 are best predicted by deeper layers, and the fitted line rises (r = 0.35, p = 5e-03). Right, panel D, backpropagated gradients: V1 and V2 sit near 0.90 to 0.91, V4 near 0.95, and the fitted line falls with distance (r = -0.27, p = 4e-02)
  • Encoding models predicted fMRI from a network's activations and, separately, from its backpropagated gradients
  • Left, activations: regions farther from V1 match deeper layers. Right, gradients: the trend reverses
  • Shared representations, different ways of learning them?

- Today builds on the single neuron of last lecture, so this slide recalls it: what the neuron computes, how it learns, and the update rule all three learning rules share - The neuron computes a weighted sum of its inputs plus a bias, then passes it through a nonlinearity g. The output is ŷ - Learning compares ŷ with the target y. The loss ℓ measures how far apart they are, and each weight moves a little in the direction that lowers ℓ: against its gradient - The three rules of last lecture differ only in g and in the loss: a threshold for the perceptron, no nonlinearity and the squared error for the delta rule, a sigmoid and the cross-entropy for logistic regression. All three end with the same update, learning rate × error × input. For the perceptron, labels are ±1 and the error y − ŷ is 0 except on mistakes - One neuron draws one straight boundary. This lecture asks what to do when one boundary is not enough, and how to train networks with several layers

- The loss drawn here is the squared error averaged over the training set. This lecture writes ℓ for a loss throughout, whether of one example or averaged over several - The delta rule and logistic regression step against a gradient; a later slide shows the perceptron does too. This slide draws that walk for a neuron with two weights, where the whole loss can be plotted - ∂ℓ/∂w₁ is the slope of ℓ along w₁ with the other weight held fixed; the gradient ∇ℓ collects one such slope per weight - The figure: a linear neuron with two weights. The contours show its squared error, averaged over a small training set, as a function of the two weights. Each dot is one update of both weights - Here each update uses the gradient of the loss averaged over the whole training set. That gradient is exact, so the path has no noise: the same start always gives the same path. It is not a straight line either, because the steepest direction changes as the weights move - Updating after every example, as in the last lecture, makes the path zigzag, but each step still goes downhill on average. Noise appears whenever each step uses one example or a few (minibatches, next lecture) - Convex: curving up, like a bowl, so any local minimum is the global one. Concave is the opposite, a dome, which has a maximum. Minimizing a convex loss is the easy case - For one neuron, the squared error of a linear output, or the cross-entropy of a sigmoid output, is convex in its weights - Random rather than zero starting weights matter once there are hidden units: see the landscape slide once hidden layers are introduced

- The contour map on the previous slide exists only because the example has two weights. This slide explains why gradient descent does not need it - The forward pass that computes the loss visits each layer once; the backward pass that computes the gradient visits each layer once more, in reverse. Both grow with the number of layers, together, so the gradient costs a small, fixed multiple of the loss (two to three times in practice). Backpropagation, later today, is that backward pass - The step must be small: the gradient describes the slope only near the current weights. Too large a learning rate overshoots the valley (learning rates, next lecture) - "On average": one example's gradient points downhill for that example's loss. Averaged over the training set, these steps follow the gradient of the average loss ℓ - The next slides work out the gradient formula for one neuron with the chain rule

- The loss does not depend on a weight directly. A weight changes the weighted sum z, z changes the output ŷ, and ŷ changes the loss ℓ. To know how ℓ responds to a weight, we follow that chain one link at a time - The chain rule says the slopes multiply. Suppose raising w by 0.01 raises z by 0.02 (slope 2), and raising z by 0.01 raises ℓ by 0.03 (slope 3). Then raising w by 0.01 raises z by 0.02, which raises ℓ by 3 × 0.02 = 0.06: a slope of 6 = 2 × 3 - With several weights, each slope is a partial derivative. ∂ℓ/∂w₁ is the slope of ℓ along w₁ with every other weight held fixed, and the gradient collects one such slope per weight - Each link depends on one choice only. ∂ℓ/∂ŷ comes from the loss, ∂ŷ/∂z = g′(z) from the output function, and ∂z/∂w = x from the weighted sum, because z = w₁x₁ + w₂x₂ + b grows by x₁ for each unit increase of w₁ - This is why the gradient is a formula: every link is a simple slope we can write down once, and the gradient is their product. The next two slides fill in the links for the delta rule and for logistic regression - Backpropagation, later in this lecture, applies the same rule to a chain that runs through several layers

- The first worked case of the previous slide's three links: the delta rule, whose output has no nonlinearity. The result is last lecture's update, now derived - ∂ℓ/∂ŷ: the derivative of u² is 2u, and u = y − ŷ changes by −1 when ŷ grows by 1. The ½ in the loss cancels the 2 - ∂ŷ/∂z = 1 because the output is z itself - ∂z/∂w = x because raising w₁ by a little raises z by x₁ times that amount - Widrow and Hoff called the error δ = y − ŷ. Backpropagation, later in this lecture, uses δ for ∂ℓ/∂z, which is ŷ − y here: the same error with the opposite sign, so it is subtracted instead of added - Next: the same three links when a sigmoid sits between z and ŷ

- The same three links for logistic regression: a sigmoid output and the cross-entropy loss. Last lecture wrote this output as p̂; this lecture writes ŷ for the output of every rule. The point is that the gradient comes out identical to the delta rule's - ∂ℓ/∂ŷ: the derivative of log u is 1/u. So −y log ŷ gives −y/ŷ, and −(1 − y) log(1 − ŷ) gives +(1 − y)/(1 − ŷ), the minus sign coming from 1 − ŷ shrinking as ŷ grows. The numerator simplifies: −y + yŷ + ŷ − yŷ = ŷ − y - ∂ŷ/∂z: differentiating 1/(1 + e^(−z)) gives e^(−z)/(1 + e^(−z))², which equals σ(z)(1 − σ(z)). The backpropagation notes (course site, Recitations) show the algebra - You will not be asked to derive these. Following each line, and seeing which factor comes from which link, is what matters - This cancellation returns in backpropagation: with a sigmoid output and the cross-entropy loss, the error at the output is simply ŷ − y

- The chain rule just derived the delta rule and logistic regression. The third rule from last lecture, the perceptron, seemed out of reach because its threshold has no slope; this slide shows it is gradient descent too, on the right loss - This loss is the perceptron criterion. The plain count of mistakes is flat like the step, so it cannot be followed downhill; the criterion measures how wrong a mistake is, not only whether there is one - The hinge loss of support vector machines, max(0, 1 − y z), asks for a margin of 1 on the correct side; the perceptron criterion is the same loss with a margin of 0. The threshold is applied only to read out the class, not during learning - If a line through the origin separates the classes, this rule reaches zero training mistakes after finitely many updates (Novikoff 1962) - All three rules are now gradient descent on one neuron. The next section asks what one neuron cannot do

- This section asks what a network with hidden units can compute that one neuron cannot - Every rule so far trains one layer of weights, and one layer draws flat (linear) boundaries. XOR, from the geometry lecture, needs more: hidden units, and a way to train them - This section sets the hidden units' weights by hand; the next section trains them

- XOR is the standard problem that one line cannot solve. This slide splits it into rules that one neuron each can compute, which suggests stacking neurons - The first layer's two neurons each draw one line in the (x1, x2) plane. The second-layer neuron sees only their two outputs, never x1 and x2, and in those coordinates XOR is linearly separable. The next slides draw both - McCulloch and Pitts (1943) showed that networks of threshold units can compute any logical function this way. The hard part, solved in practice only in the 1980s, is learning the weights of the first layer instead of setting them by hand

- The previous slide proposed stacking; this slide shows the result on the same four points: two hidden units and one output, all four right - The figure is drawn from the network of the next slide, with weights set by hand: hidden unit 1 acts like OR, hidden unit 2 like AND, and the output fires in the band between x1 + x2 = 0.5 and x1 + x2 = 1.5 - The layers between the input and the output are hidden layers, and their units hidden units. No target tells them what to output - "Multilayer perceptron" is a historical name. The units are now ReLU or sigmoid units - The geometry lecture's fix: a third coordinate, x1·x2, lifts the four points into 3-D, where a plane separates them. Hidden units compute new coordinates like this one, and a network can learn them instead of being given them - Cortex is built this way too, with dozens of visual areas stacked into a hierarchy. Felleman & Van Essen (1991) mapped the connections between the visual areas of the macaque: a few dozen areas, hundreds of connections - The next slide looks at the same network from the hidden layer, to show why the output's single line now suffices

- The previous slide showed the network's boundary in the input plane. This slide shows why it works, by plotting the four inputs as the hidden layer sees them - Hidden unit 1 computes ReLU(x1 + x2) and is on if any input is on; hidden unit 2 computes ReLU(x1 + x2 − 1) and is on only if both are. Layer 1 is the hidden layer and layer 2 the output - The plot's axes are the two hidden outputs, written together as the vector a^[1]. The input (0,0) lands at (0,0), (0,1) and (1,0) both land at (1,0), and (1,1) lands at (2,1) - The output unit is a linear readout of this point: its rule, a1^[1] − 2a2^[1] − 0.5 > 0, is one line in this plane - This is untangling on a problem small enough to draw. Earlier lectures asked whether a good representation makes object manifolds linearly separable; here a hidden layer does it for XOR

- The hidden layer re-represented XOR on the previous slide because each hidden unit bends its weighted sum with a ReLU. This slide removes the ReLUs to show that the bend is essential - The same holds for any number of layers and units: a linear layer feeding a linear layer computes one linear map of the input, plus a constant. The next lecture writes this with weight matrices - Any nonlinearity works for this purpose, ReLU or sigmoid; what matters is that the unit's output is not a straight-line function of its weighted sum - The XOR weights so far were set by hand. The next section asks how a network finds them on its own

- Hidden layers buy the power to solve XOR, at a price. This slide returns to the loss landscape from the start of the lecture: with hidden layers it is no longer a bowl, so where gradient descent starts matters. The next section asks how to compute the gradient at all - Schematic: one weight and a made-up loss with three minima; two random starts, plain gradient descent from each - Real loss landscapes have millions of dimensions; besides local minima they have flat regions and saddle points, where the gradient is near zero in some directions - Why random starting weights: hidden units that start with identical weights get identical updates and stay identical forever. Small random weights break that symmetry - The noise of minibatches (next lecture) can help the weights leave shallow valleys

- This section answers the title's question: how to train hidden units, whose weights we have so far set by hand - Training one neuron needed a loss, its gradient, and a small step on each example. One neuron draws one line, and XOR needs two. A hidden unit has no target of its own, so its gradient has to come from the output error - The section starts with where the method came from, then works it through on the XOR network

- Before the method, its history: training hidden layers was the problem left open after the XOR result, and the solution was found several times, independently - Minsky & Papert (1969), Perceptrons. Their analysis applied to single-layer networks. They doubted that multilayer networks could be trained - Linnainmaa (1970) described reverse-mode automatic differentiation in his master's thesis, without neural networks in mind. Werbos (1974) derived it for general models and applied it to neural networks in 1982. Amari (1967) had already trained a small multilayer network by stochastic gradient descent. Parker (1985) and LeCun (1985) also derived it independently - Rumelhart et al. (1986), Learning representations by back-propagating errors. Its contribution was to show what hidden units learn, which made the method widely adopted - The 2024 Nobel Prize in Physics went to Hopfield and Hinton "for foundational discoveries and inventions that enable machine learning with artificial neural networks": the Hopfield network and Hinton's Boltzmann machine - The 2018 Turing Award (awarded in 2019) went to Bengio, Hinton and LeCun for deep learning. ACM's summary of Hinton's work lists the 1986 backprop paper alongside Boltzmann machines and his work on convolutional networks - Is backprop how the brain learns? Not literally. Crick (1989) argued that it is biologically implausible, since a hidden unit would need the weights downstream of it, and synapses pass signals one way. The success of backprop has since driven a lot of work on approximations a brain could compute. These approximations do not match backprop's performance, but may be good enough to be plausible learning mechanisms (Lillicrap et al. 2020, on the further-reading slide)

- The worked example that follows needs names for every weight and every unit's output, so this slide fixes them before the calculation starts - Earlier in the lecture, bold w was the weight vector of a single neuron. From here on, a plain w with a superscript and subscripts is one weight - z is the weighted sum before the nonlinearity and a the unit's output after it. The backward pass needs both, so the forward pass keeps both - The figure is a larger network with two hidden layers; the XOR network has one hidden layer of two units

- The output unit has a target, so its weights are trained as in logistic regression. A hidden unit has none, so this slide asks a question we can answer instead: if the unit's weighted sum were a little larger, would the loss go up or down, and by how much? - The answer follows the effect forward, one link at a time. A ReLU unit that is on passes the nudge unchanged (slope 1); one that is off passes nothing (slope 0) - The output's own error, ŷ − y, is the same number logistic regression used: with a sigmoid output and the cross-entropy, a nudge ε of the output's sum changes the loss by (ŷ − y)ε - Multiplying the slopes along a chain is the chain rule of calculus. The hidden error δ is the loss change per unit nudge of the hidden unit's sum, ∂ℓ/∂z_j^[1] - A positive δ means the unit's sum should have been lower; a negative δ, higher. The hidden unit now has an error to learn from, just like the output, and its weights change by error × input

- The previous slide found the error of one hidden unit feeding one output. This slide writes the same idea as a recipe for any network, in the four steps the XOR example will follow next - Step 3 with one output unit is exactly the previous slide: δ_j = g′(z_j) × w_j × (ŷ − y). With several units above, a hidden unit's effect on the loss passes through each of them, so their contributions add up: hence the sum over k - In layer notation, δ_j is δ_j^[l], the unit's layer is l, and the units k it feeds are in layer l + 1; the weight w_kj goes from unit j to unit k. The slides drop the layer superscripts here to keep the recipe readable - For a ReLU unit, g′ is 1 if the unit was on and 0 if it was off: a unit that was off passes no error back, and its incoming weights do not change on this example - Step 4 is the same error × input rule as the single-neuron learning rules at the start of the lecture

- The previous slide stated the recipe; this one shows that every line of it is the chain rule, applied to the definition of a unit's error, δ = ∂ℓ/∂z - Output unit: with a sigmoid output and the cross-entropy, ∂ℓ/∂ŷ = −(y − ŷ)/[ŷ(1 − ŷ)] and ∂ŷ/∂z = ŷ(1 − ŷ), as worked out for logistic regression earlier in the lecture. Their product is ŷ − y - Hidden unit: z_j changes a_j by g′(z_j); a_j enters the weighted sum z_k of every unit k above with weight w_kj, so ∂z_k/∂a_j = w_kj; and z_k changes the loss by δ_k. Multiply along each path, then add the paths, because a small change of z_j moves the loss along all of them at once - Weight: z_j = Σ_k w_jk a_k + b_j, so raising w_jk by a little raises z_j by a_k times that amount, and the loss by δ_j times that. Hence gradient = error × input - The nudge slide was the hidden-unit formula with a single unit above, the XOR network's output

- Why not keep the threshold and train a linear output instead? That works too: a linear output with the squared error is the delta rule, and the threshold is applied only afterwards, to read the class. Its output error is also ŷ − y, so the backward steps are the same. The sigmoid is used here because it is the standard output for two classes and gives a probability - The previous two slides stated backpropagation in general. This slide returns to the XOR network, which we wired by hand earlier, and asks it to find its own weights, starting from random ones. The four steps that follow compute every gradient on this one example. Biases start at 0 - Only the output changes from the hand-built network: a sigmoid instead of a threshold, because gradient descent needs a slope and a threshold has none. With a sigmoid output, the cross-entropy is the natural loss, as in logistic regression - The figure shows the starting weights, small and of both signs as at the start of any training, and the output they give for the input (1, 0). The question marks are the hidden units, whose correct outputs no one knows: that is credit assignment - The example is small enough to compute on paper, and every number on the next slides can be checked by hand

- The forward pass runs the input through the network and keeps every weighted sum z and every output a: the backward pass needs them all - ŷ = σ(0.17) = 1/(1 + e^(−0.17)) = 0.542 - The four steps start here, from the random starting weights of the previous slide. Step 1 runs the input (1, 0) forward and keeps every intermediate value, because the backward steps reuse them - Hidden layer: z1^[1] = 0.50·1 − 0.40·0 = 0.50 and z2^[1] = 0.30·1 + 0.80·0 = 0.30. Both are positive, so the ReLU passes them unchanged - Output: z^[2] = 0.70·0.50 − 0.60·0.30 = 0.35 − 0.18 = 0.17. The sigmoid gives ŷ = 0.54, the probability that XOR is 1. Numbers are rounded to two decimals

- This frame finishes the forward pass by scoring the output: one number now says how wrong the network is on this example - The loss is the cross-entropy of logistic regression. With the target y = 1, the second term vanishes and only −log ŷ is left; with y = 0 it would be −log(1 − ŷ). It would be 0 if ŷ were exactly the target - The next steps ask how each weight changes that number

- With the loss computed, the backward pass starts at the output: which way, and how strongly, should the output's weighted sum have moved? - δ^[2] is the gradient of the loss with respect to the output's weighted sum z^[2]: how much the loss would change if that sum were nudged - Last lecture, the logistic-regression update added η(y − ŷ)x. Backprop writes the error the other way round, ŷ − y, and subtracts it. Gradient descent subtracts η ∂ℓ/∂w, so subtracting η(ŷ − y)x and adding η(y − ŷ)x are the same change - δ is the backprop error of the general slide, ∂ℓ/∂z. It is positive when the unit's weighted sum should have been lower. The delta rule's δ = y − ŷ is the same error with the opposite sign - Step 3 sends this error back to the hidden units

- This is the step that solves credit assignment: each hidden unit gets an error of its own, computed from step 2's output error, as the general formula said - Each error goes back along the connection that carried activity forward, multiplied by that connection's weight - The numbers: δ1^[1] = −0.458 × 0.70 × 1 ≈ −0.32 and δ2^[1] = −0.458 × (−0.60) × 1 ≈ 0.27, using the unrounded output error (the rounded −0.46 gives 0.28) - a1^[1] excites the output (weight 0.70), so raising it would have raised ŷ toward its target. Its error is negative: its weighted sum should have been higher. a2^[1] inhibits the output (weight −0.60), so lowering it would have helped. Its error is positive - The ReLU slope g′ gates the error. A unit that was off for this input (z < 0) has slope 0, gets no error, and its incoming weights do not change on this example - With more hidden layers, the same step repeats, layer by layer, down to the first

- Every unit now has an error. Step 4 turns those errors into a gradient for every weight, then takes one step to check that the output moves toward its target - The product is local: a weight's gradient needs only the activity at its input end and the error of the unit it feeds - A negative gradient means the weight should grow, since the update subtracts it. Here every weight with a nonzero gradient moves in the direction that raises ŷ toward the target - The update: each weight and bias moves by −η times its gradient, here η = 1. Running the forward pass again gives ŷ = 0.82, and the loss falls from 0.61 to 0.20. Updating only the six weights gives ŷ = 0.68 and a loss of 0.39 - One step on one example. Training repeats this over all examples, many times. The same four steps, repeated layer by layer, train a network of any depth

- This demo runs the four steps on a small network, so you can watch hidden units learn the XOR boundary that we set by hand earlier - The code inside the page is the four steps, written out: forward pass, error at the output, error sent backward, gradient = error × activity, then a small step on every weight - One hidden unit draws one line. Add units and layers and the boundary bends. Try XOR with 1, 2 and 4 hidden units, then circles and spirals - Raise the learning rate until training becomes unstable. Add label noise, which randomly flips some class labels, to see the network fit the noise - An epoch, shown in the demo, presents every training example once - The demo is on the course site with the other demos. Play with it after class

- Backpropagation so far ended at a single sigmoid output. This slide widens the output layer to one unit per class, the readout used for the IT recordings - Each class has its own weight vector: one row of a K × D weight matrix, one row per output neuron. This is a layer of K units, the building block of the networks that follow - With two classes, the softmax over two logits is the sigmoid of their difference, so the top panel is the two-class case of the bottom one - The assignment reads the 51 object identities with a softmax readout. The next slide gives the softmax formula and its loss - The previous slide named the softmax. This slide gives its formula and the loss used with it, and shows that backprop's output error keeps the same form - The exponential makes every probability positive. Dividing by the sum makes them add up to 1. Adding the same number to every logit changes nothing - The example: e² = 7.39, e¹ = 2.72, e⁰ = 1, sum 11.11. The losses are −log 0.665 and −log 0.090, before rounding - The log is the natural log, as in PyTorch's CrossEntropyLoss and in scikit-learn. The name comes from information theory: the cross-entropy between the true label (all its probability on one class) and the predicted probabilities - Only the correct class's probability appears in the formula, but every logit appears in that probability (it is divided by the sum over all classes). So the gradient pushes the correct logit up and every other logit down. The gradient with respect to z_c is p̂_c − 1 for the correct class and p̂_c for each other class - This is the output error of step 2 again, prediction minus target, with one entry per class; the target is 1 for the correct class and 0 for the others. Backprop proceeds from there unchanged - The assignment trains its readouts with this loss

- Everything so far, written as the code that trains a softmax readout: the five numbered lines are the five steps of every training step - In the code, `loss` is the average of the examples' losses over the batch, so it is one number however many examples go in. A batch can be the whole training set (as here), a few dozen examples (minibatches, next lecture), or a single example (the perceptron and delta rule of last lecture) - X_train holds N examples with D inputs each, shape (N, D). y_train holds their N labels, integers from 0 to K − 1 (a torch.long tensor, or CrossEntropyLoss raises a dtype error) - SGD applies w ← w − lr × gradient. PyTorch calls any plain gradient step SGD (stochastic gradient descent), whatever the batch size. For Adam, an optimizer that adapts the step size for each weight, change only the line that builds opt. Adam comes next lecture - PyTorch adds new gradients to the old ones unless you clear them, which is why zero_grad() comes first - Here each epoch uses all training images at once (full-batch gradient descent), so one epoch is one step. Small batches come in the next lecture - To evaluate, predict the class with the largest logit; no_grad() skips recording gradients, which are not needed for a prediction - The five steps stay the same for any model. With one hidden layer of 64 ReLU units: model = nn.Sequential(nn.Linear(D, 64), nn.ReLU(), nn.Linear(64, K)). Nothing else in the loop changes, and backward() now runs backpropagation through the hidden layer - You write this loop in the assignment: you fit the same readout with scikit-learn and with this loop, using Adam, then add a hidden layer. scikit-learn's readout also uses weight decay, a penalty that pulls every weight a little toward zero at each step; the generalization lecture covers it

- The training loop called loss.backward() without saying where the gradients come from. This slide shows that it runs the four steps of backpropagation for you, on the same worked example - You write only the forward pass. The backward pass is derived for you - The figure is the worked example again, as the software sees it. The green numbers are the errors and gradients of steps 2 to 4, and the two `.grad` values are the gradients of step 4 - `.grad` is the stored derivative of the loss with respect to that parameter, one number per weight - The figure omits the bias branches. Each bias gets its own `.grad`, equal to the error of its unit: −0.32 and 0.27 for the two hidden biases, −0.46 for the output bias - Each operation only needs to know its own local derivative (for ReLU: 1 if the input was positive, 0 otherwise). The graph strings them together - Automatic differentiation is neither numerical differentiation (nudging each weight and measuring the change in the loss, one forward pass per weight) nor symbolic differentiation (deriving a formula for the gradient). It applies the chain rule, operation by operation, to the exact numbers computed on the forward pass - Backpropagation is reverse-mode automatic differentiation applied to a network. Every modern framework (PyTorch, TensorFlow, JAX) implements it. Baydin et al. (2018) gives further detail

- The training loop changes every weight. Often we do not want that: a network already trained on a large dataset, such as ImageNet with its 1.2 million labelled images, has layers whose responses are useful for many other tasks - Transfer learning copies those weights, keeps them fixed (frozen), and trains only a new last layer for the new task. Far fewer labelled examples are needed, because only the readout has to be learned - This is also how networks are compared with brains in this course: a readout trained on a frozen network's responses asks what those responses make available, as a readout trained on recorded neurons does - The next slide shows the few lines of PyTorch that do it

- Backpropagation computes a gradient for every weight, but you choose which weights move. This slide trains only the readout of a trained network, a comparison the assignment uses - model[0] is the hidden layer and model[2] the readout. model[1] is the ReLU, which has no weights - The second line loads weights saved after an earlier training run. Freezing a freshly built layer would freeze random weights, and the readout would then probe the responses of random units - Both lines matter. requires_grad = False stops PyTorch from computing those gradients. Leaving the frozen weights out of the optimizer makes sure step() never changes them - A readout trained on a frozen representation is a probe, as in earlier lectures: it tests what the representation contains - Training every weight lets the hidden units change what they respond to. To compare the two kinds of training, start both from copies of the same trained model; the difference shows what training changed in the hidden layer - The assignment compares readout-only training with training every weight, when the network learns new objects. It follows Sörensen et al. (2026), who compared IT in monkeys trained on new objects with untrained monkeys. The assignment's code writes requires_grad_(False), which has the same effect

- Next lecture: minibatches, learning-rate schedules and Adam; then what do trained units respond to? Tuning curves, Gabor fits and selectivity, in a monkey or in a network. Then when a trained network works on new data: overfitting, held-out data, weight penalties

- Crick (1989), The recent excitement about neural networks - Lillicrap et al. (2020), Backpropagation and the brain. The companion Lillicrap et al. (2016) shows that random feedback weights can replace the exact backward weights - Before posting, skim the existing entries on your paper. Your post must add something not already said

- Submitted on Canvas (Minute papers → Minute Paper 10). Credit for a thoughtful attempt

- These optional slides connect today's methods to current research on how brains might learn

- The history slide raised Crick's objection: a brain cannot send errors back through its forward weights. This slide tests one answer, sending them back through random weights instead - In step 3, a hidden unit's error was the output error times the forward weight from that unit to the output. In a brain, the synapse from neuron A to neuron B cannot be read by the feedback pathway from B back to A - Lillicrap et al. (2016) sent the errors back through fixed random weights instead (feedback alignment). Learning still worked: the forward weights changed until the random feedback gave useful directions. Exact weight symmetry is not needed for credit assignment - The figure is reproduced from their Fig. 2: panel b is the angle between the feedback-alignment update and the backprop update during training - Predictive coding (Whittington & Bogacz 2017) is another family of proposals: local error units and local learning rules that approximate backprop's updates - Lillicrap et al. (2020) review the proposals. Their common idea: feedback connections change neural activity, and differences in activity stand in for the error

- The previous slide asked how the error could travel backward. This one asks whether each neuron gets an error of its own - In backprop, each unit gets its own error, and its sign depends on what the unit does to the output. A reward signal such as dopamine is closer to the opposite: roughly one number, broadcast to many neurons (dopamine signals are not perfectly uniform, but they are not tailored to each neuron's role) - Francioni et al. (2026) chose 4 or 5 neurons for each group in mouse retrosplenial cortex and imaged their cell bodies and their distal apical dendrites (calcium imaging) while the mice learned the task. The apical dendrites receive most of the feedback input from other areas - The figure is our redraw of their Fig. 5b (the original is CC BY-NC-ND). As the error fell, P+ dendrites were amplified relative to their cell bodies and P− dendrites attenuated; as it rose, the reverse. This was seen in all six mice - Activating layer-1 inhibitory interneurons with light suppressed the dendritic signals, and the mice no longer improved at the task - Caveat: a brain–computer interface task with a handful of chosen neurons, far from natural learning. How closely the signal matches backprop's error is still being worked out

- Another test of whether brains run backprop, this time with brain imaging: do a network's gradients, not only its activations, predict brain responses, and in the order backprop would produce them? - Setup: the network is DINOv3-S, a vision transformer trained without labels, trained from scratch for 500,000 steps. For each image, the authors ran the forward pass, then the backward pass on the network's own self-supervised loss, and kept each layer's gradient as a second set of features - Brain data: fMRI (7 tesla) from the Natural Scenes Dataset for where, and THINGS-MEG for when. MEG: magnetoencephalography, magnetic fields from the scalp measured every millisecond - Vertical axis: the layer whose features best predict a region, as a fraction of network depth (0 = input, 1 = last layer). Each point is one region among the best-predicted third - A brain that ran backprop should show the reverse of the forward sweep: gradients for deep layers first and in high-level regions, gradients for early layers later and in early regions - Key numbers: activations r = 0.35 (p = 0.005) with distance from V1; gradients r = −0.27 (p = 0.04). In MEG, activation layers peak one after another; gradient layers all peak together, at the time of the last forward layer - Gradients still predict brain responses that activations do not, mostly late (0.5 to 1.7 s after the image) and in high-level regions. Gradients also predict brain responses in all eight networks tested, convolutional and transformer; the panels shown are for DINOv3 - Caveat: a preprint, and the correlations are modest. A brain could approximate backprop in a way that does not produce these signatures; the study tests one family of plausible implementations