We can specify a neural network; now we need to learn its parameters. A loss measures prediction error, an optimization rule uses gradients to improve the parameters, and the chain rule connects derivatives through the network. This handout develops the foundations for analytical backpropagation in Handout #5.
- Reading for Thursday, Sept 10
- Slides 55–89 of Feedforward Nets: optimization in slides 56–75, algebra and calculus in slides 76–89. Analytical backpropagation in slides 90–109 is covered in Handout #5.
- Where we left off
- Tuesday's lecture reached slide 54. Handout #3 covers that material. Loss functions and gradients begin here.
- Time
- About 50–70 minutes including exercises.
- By the end
- Choose a loss; distinguish training from evaluation; explain a gradient step; track derivative shapes; apply the chain rule with Jacobians.
- Assumes
- MLP architecture and parameter shapes, basic derivatives, and cross-entropy and perplexity.
- How to use it
- Pause at each question before opening its answer. Code blocks are independent, runnable examples using Python and PyTorch.
1Learning as optimization
Slides 56–75
1.1 Data, model, loss, objective
Let $D=\{(x_i,y_i)\}_{i=1}^{N}$ be training examples, $f_\theta$ the predictive function, and $\ell(f_\theta(x_i),y_i)$ the loss for one example. The empirical risk is
$$J(\theta)=\frac1N\sum_{i=1}^{N}\ell(f_\theta(x_i),y_i),\qquad \theta^*\in\operatorname*{argmin}_\theta J(\theta).$$The loss is a scalar penalty; the objective averages it over the training data. The notation $\arg\min$ describes the desired parameters, not an algorithm or a promise that we can find a global minimum. During an update, the data and targets are fixed and the parameters change.
| Task | Per-example loss | What it penalizes |
|---|---|---|
| Scalar regression | Squared error $(\hat y-y)^2$ | Large residuals quadratically; smooth in the prediction. |
| Scalar regression | Absolute error $|\hat y-y|$ | Residual magnitude linearly; has a kink at zero. |
| Classification | Cross-entropy $-\sum_j y_j\log p_j$ | Low probability on the correct class (one-hot $y$). |
Compare residuals of 1 and 10. How much does each loss increase? Does the kink in absolute error make optimization impossible?
Work it out, then reveal the answer
You predict a real-valued temperature in one task and one of ten class labels in another. Which is a natural loss for each: squared error or cross-entropy? Is this a mathematical ban on using other losses?
Work it out, then reveal the answer
Squared error is a natural regression loss; cross-entropy is a natural loss for a categorical probability model. The choice expresses what errors we penalize and how we model the target. This is a modeling convention, not a theorem that squared error can never be used with class probabilities.
1.2 Cross-entropy connects back to language modeling
If class $t$ is correct, its one-hot vector has $y_t=1$ and all other entries zero. Therefore
$$\ell=-\sum_j y_j\log p_j=-\log p_t.$$Cross-entropy is the negative log of the correct-class probability, not that probability itself. The minus sign turns maximizing probability into minimizing loss. We use natural logs here: loss is in nats. At $p_t=1$ the loss is 0, and as $p_t\to0$ the loss tends to infinity.
Two models assign the target probabilities $0.8$ and $0.2$. What losses do they get? If their top-ranked class is the same, must their cross-entropies be equal?
Work it out, then reveal the answer
import torch
import torch.nn.functional as F
# Rows are examples; columns are classes. Targets are class indices.
logits = torch.tensor([[2., 1., 0.], [0., 1., 2.]], dtype=torch.float64)
target = torch.tensor([0, 2])
log_probs = logits.log_softmax(dim=-1)
per_example = -log_probs[torch.arange(2), target]
loss = F.cross_entropy(logits, target)
assert torch.allclose(loss, per_example.mean())
print(per_example.tolist(), loss.item()) # both about 0.407606
# Try target = torch.tensor([2, 0]): both losses become about 2.407606.
Pass logits to F.cross_entropy; it computes the log-softmax internally.
Taking softmax first gives it different inputs and a different loss. The stable calculation uses
$\log p_t=s_t-\log\sum_j e^{s_j}$, evaluating the log-sum-exp after subtracting the maximum logit.
This avoids overflowing exponentials. Mathematical softmax positivity does not prevent numerical
underflow in a naive implementation.
A classifier assigns probability $0.1$ to each of ten classes on each of 20 labeled examples. Find the mean cross-entropy in nats and the summed loss. Does changing the number of examples change the mean?
Work it out, then reveal the answer
Each example contributes $-\ln(0.1)=\ln10\approx2.302585$. The mean is the same value; the sum is $20\ln10\approx46.051702$. For these identical per-example losses, changing the number of examples changes the sum, not the mean. More generally, class count alone does not determine the starting loss unless predictions are uniform.
1.3 Why step against the gradient?
The gradient collects the sensitivities to all parameters. For a small change $\Delta\theta$, the first-order approximation is
$$J(\theta+\Delta\theta)\approx J(\theta)+\nabla J(\theta)^\top\Delta\theta.$$Choosing $\Delta\theta=-\eta\nabla J(\theta)$ with $\eta>0$ makes the predicted change $-\eta\|\nabla J(\theta)\|^2$. For a differentiable objective with nonzero gradient, a sufficiently small step decreases the loss. The negative gradient is the steepest local direction under a fixed Euclidean step length; a large finite step can still overshoot.
$$\theta_{k+1}=\theta_k-\eta\nabla J(\theta_k).$$On the convex bowl $J(\theta)=\tfrac12\theta^2$, try learning rates $0.04$, $1$, $1.5$, $2$, and $2.2$ (reset between runs). Derive the behavior before using Run 25.
Work it out, then reveal the answer
Switch the widget to Two minima to see why local progress need not find the best possible value. Neural-network objectives are generally nonconvex; the convex bowl explains step size, not a global convergence guarantee for a network.
For $J(w)=(w-3)^2+4$, start at $w_0=6$ with learning rate $0.1$. Compute $J\prime(w_0)$, $w_1$, and the loss before and after the update. Why does the constant 4 disappear from the derivative?
Work it out, then reveal the answer
$J\prime(w)=2(w-3)$, so $J\prime(6)=6$ and $w_1=6-0.1(6)=5.4$. The loss changes from 13 to $2.4^2+4=9.76$. A constant shifts all objective values equally and has derivative zero; it changes neither the minimizing weight nor the update.
1.4 Minibatches: estimating the direction
$$\widehat J_B(\theta)=\frac1B\sum_{i\in\mathcal B}\ell_i(\theta),\qquad \widehat g_B=\frac1B\sum_{i\in\mathcal B}\nabla_\theta\ell_i(\theta).$$Full-batch gradient descent uses all $N$ examples per update. A minibatch uses $B$ examples; strictly, stochastic gradient descent uses one, though the name commonly includes minibatches. For uniformly sampled examples at fixed $\theta$, the batch-average gradient is an unbiased estimate of the full-data average gradient. One batch can point in a poor direction; unbiased means correct in expectation, not correct on every step.
Smaller batches permit frequent updates with less activation memory, but introduce more noise. Bigger batches often use hardware efficiently. An epoch is one pass over the training set; with $N$ examples, batches of size $B$, and a retained final partial batch, it has $\lceil N/B\rceil$ updates. Noisy updates need not decrease the full-data loss at every step.
At the current parameter, four example-gradients are $2,4,-2,0$. What is the full gradient? Is a one-example gradient of $-2$ a contradiction of unbiasedness?
Work it out, then reveal the answer
1.5 Fitting is not evaluation
Use the training set to update weights, a held-out validation set to choose architecture, learning rate, and stopping point, and a held-out test set for final evaluation after those choices. Repeatedly selecting models by their test scores turns the test set into another validation set.
Low training loss with high validation loss suggests overfitting. High loss on both can reflect insufficient capacity, unsuccessful optimization, or a data/implementation problem. Split text at an appropriate document or source boundary before creating overlapping windows so near-duplicate contexts do not leak across splits.
You try ten learning rates and keep the one with the lowest test loss. What went wrong?
Work it out, then reveal the answer
2Algebra and calculus for backpropagation
Slides 76–89 · Shape bridge to the network equations
2.1 Forward shapes before derivative shapes
Our mathematical input $x$ is a column vector, so one layer computes $Wx+b$. In code we stack examples as rows of $X\in\mathbb R^{B\times d}$:
$$H=\sigma(XW^\top+b),\qquad W\in\mathbb R^{h\times d},\quad H\in\mathbb R^{B\times h}.$$The bias $b\in\mathbb R^h$ is broadcast to every row. These are two conventions for the same operation, not different models. Each row uses the same parameters.
import torch
import torch.nn as nn
torch.manual_seed(0)
B, d, h, m = 5, 4, 6, 3
x = torch.randn(B, d)
first, second = nn.Linear(d, h), nn.Linear(h, m)
hidden = torch.relu(first(x))
logits = second(hidden)
assert torch.allclose(first(x), x @ first.weight.T + first.bias)
assert hidden.shape == (B, h) and logits.shape == (B, m)
assert sum(p.numel() for layer in (first, second)
for p in layer.parameters()) == 51
print(hidden.shape, logits.shape) # (5, 6), (5, 3)
For $X$ of shape $(B,T,d)$, nn.Linear(d,h) maps the last dimension and produces
$(B,T,h)$. The matrix work costs $BTdh$ multiply-accumulates. Broadcasting checks compatible
sizes, not the intended meaning of an axis: write down and assert shapes.
2.2 Partial derivatives and gradients
A partial derivative changes one argument while holding the others fixed. For the example in slides 78–80, $z(x,y)=y^4x^5$:
$$\frac{\partial z}{\partial x}=5y^4x^4,\qquad \frac{\partial z}{\partial y}=4y^3x^5,\qquad \nabla z=\begin{bmatrix}5y^4x^4\\4y^3x^5\end{bmatrix}.$$The gradient is a column vector in the declared input order $(x,y)$. A derivative is itself a function until we evaluate it at a point.
Evaluate $\nabla z$ at $(x,y)=(1,2)$. Use it to predict the change from increasing only $y$ by $0.001$.
Work it out, then reveal the answer
2.3 A Jacobian records every output–input sensitivity
For $f:\mathbb R^n\to\mathbb R^m$, the Jacobian has outputs as rows and inputs as columns:
$$[J_f(x)]_{ij}=\frac{\partial f_i}{\partial x_j},\qquad J_f(x)\in\mathbb R^{m\times n}, \qquad f(x+\Delta x)\approx f(x)+J_f(x)\Delta x.$$For $f(x_1,x_2)=(x_1^2+x_2,\ x_1x_2,\ 3x_2)^\top$,
$$J_f(x)=\begin{bmatrix}2x_1&1\\x_2&x_1\\0&3\end{bmatrix},\qquad J_f(1,2)=\begin{bmatrix}2&1\\2&1\\0&3\end{bmatrix}.$$If $m=1$, the Jacobian is the row $\nabla f^\top$, not the gradient column itself. If $m=n=1$, it is the ordinary scalar derivative. This transpose convention matters in the chain rule.
If $f:\mathbb R^4\to\mathbb R^3$, what is the shape of $J_f$? If a scalar loss depends on a parameter matrix $W\in\mathbb R^{3\times4}$, what shape should its stored gradient have?
Work it out, then reveal the answer
For a vector output $f(W)\in\mathbb R^m$ and a matrix input $W\in\mathbb R^{n\times p}$, the unflattened derivative has shape $(m,n,p)$ and entries $\partial f_i/\partial W_{jk}$. Flattening $W$ in a fixed order gives the equivalent $m\times(np)$ Jacobian. For a scalar loss, we conventionally store the derivatives with the original parameter shape $(n,p)$.
For $f(x,y,z)=(x^2+y,xy,z^2/y)^\top$, with $y\ne0$, compute $J_f(x,y,z)$ and evaluate it at $(1,1/2,-1)$. Label its row and column meanings.
Work it out, then reveal the answer
Rows correspond to the three output coordinates; columns correspond to inputs $(x,y,z)$. Substitute only after taking derivatives.
2.4 Composition: multiply along a path, add across paths
For a scalar chain $x\mapsto y(x)\mapsto z(y)$,
$$\frac{dz}{dx}=\frac{dz}{dy}\frac{dy}{dx}.$$If $y=x^2$ and $z=3y+1$, then $dz/dx=3(2x)=6x$. The local derivative of the outer function is evaluated at the inner function's value.
For $g:\mathbb R^d\to\mathbb R^n$ followed by $f:\mathbb R^n\to\mathbb R^m$, the same rule becomes a matrix product:
$$J_{f\circ g}(x)=\underbrace{J_f(g(x))}_{m\times n} \underbrace{J_g(x)}_{n\times d}\in\mathbb R^{m\times d}.$$The order follows the dependencies and the shapes. Matrix multiplication automatically sums over the intermediate coordinates. In particular, if one scalar $x$ affects several intermediates $y_i$, which all affect a scalar $z$,
$$\frac{dz}{dx}=\sum_i\frac{\partial z}{\partial y_i}\frac{dy_i}{dx}.$$Let $y_1=x^2$, $y_2=3x$, and $z=y_1y_2$. Compute $dz/dx$ through both paths, then check by substitution.
Work it out, then reveal the answer
2.5 Code lab: check the chain rule numerically
Finite differences estimate the effect of perturbing an input. The following uses only Python's standard library. Predict the row and column shapes before running it.
from math import isclose
def g(x):
return [x * x, 3 * x] # R -> R^2
def f(y):
return y[0] * y[1] # R^2 -> R
x = 2.0
y = g(x)
J_f = [y[1], y[0]] # 1 x 2: [dz/dy1, dz/dy2]
J_g = [2 * x, 3.0] # 2 x 1: [dy1/dx, dy2/dx]^T
contributions = [a * b for a, b in zip(J_f, J_g)]
chain = sum(contributions)
eps = 1e-5
numeric = (f(g(x + eps)) - f(g(x - eps))) / (2 * eps)
assert contributions == [24.0, 12.0]
assert isclose(chain, numeric, rel_tol=1e-7)
print(chain, numeric) # both approximately 36
# Try eps = 1.0, then 1e-14. Why can either hurt the comparison?
Why not make the perturbation arbitrarily small?
One could perturb every parameter to estimate its derivative, but a central-difference gradient for $P$ parameters costs $2P$ loss evaluations. It is useful for checking tiny examples, not for training a large network. The chain rule gives the mathematical alternative; backprop will organize it so intermediate computations are reused.
3Ready for analytical backprop?
Slide 89 recap · Slide 90 transition
We can now specify the forward computation and the scalar objective. For one labeled example:
$$x\longrightarrow z_1=W_1x+b_1\longrightarrow h=\sigma(z_1) \longrightarrow s=W_2h+b_2\longrightarrow \ell(s,t).$$Training needs $\nabla_{W_1}\ell$, $\nabla_{b_1}\ell$, $\nabla_{W_2}\ell$, and $\nabla_{b_2}\ell$. Backpropagation computes these gradients using the chain rule; gradient descent uses them to update the parameters. They are distinct jobs.
For $x\in\mathbb R^4$, hidden width 6, and three output classes, list the parameter shapes, logit shape, and total parameter count.
Work it out, then reveal the answer
The network gives the correct class probability $0.25$. What is the per-example loss? What changes when computing empirical risk over 20 examples?
Work it out, then reveal the answer
For $h:\mathbb R^4\to\mathbb R^6$ and a scalar $\ell(h)$, what are the shapes in $J_{\ell\circ h}=J_\ell J_h$? What is the corresponding gradient-column expression?
Work it out, then reveal the answer
If we already know the gradient-descent update and the chain rule, what remains to derive?
Work it out, then reveal the answer
4Review route
If one part felt unfamiliar, revisit the relevant worked example rather than memorizing all the notation at once:
- For dimensions and matrix multiplication, revisit Handout #1's linear algebra review, then redo §2.1 here.
- For log probabilities, revisit Handout #2's cross-entropy and perplexity discussion, then redo §1.2 here.
- For derivative notation, revisit Handout #1's calculus review, then redo the two-path example in §2.4.