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()
model line alone sets a readout or a hidden layerbackward() computes the gradients. opt, the optimizer, turns them into weight changes in step()loss.backward() sweeps the graph in reverse: output error, hidden errors, then each parameter's gradient, stored in its .grad. opt.step() applies the updatemodel = 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 frozenmodel[2], the readout: only its weights learnbackward(), step(), repeated over epochs, with a softmax output for many classes. Freezing trained layers reuses them for a new taskOptional: a few research-trail entries over the semester. Any paper mentioned in any lecture qualifies, including those on the Going further slides that follow.
Submit on Canvas → Minute papers → Minute Paper 10 (access code read out in class).
Write three brief points in your own words:
Credit for a thoughtful attempt, not for being correct.

- 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