Module 04 · Part I · Foundations
How a Model Learns From Data
Self-Supervision, Neurons and MLPs, Softmax and Cross-Entropy, Overfitting, Hyperparameters, and How to Read an Experiment
By the end you can train a tiny MLP end to end, diagnose overfitting, and read an experiment's result critically.
Check yourself ▸
Before you start, can you already…
- ☐use the rules for expectation and variance, read conditional probability notation, and explain cross-entropy, perplexity and KL divergence. (Module 3)
If any is shaky, the linked module teaches it.
Modules 2 and 3 supplied the two halves of learning: a loss that measures how wrong a model is, and gradient descent to make it less wrong. This module puts them together on a small neural network, then adds what makes training a science: why fitting the training data is not the goal, which knobs you choose by hand, and how to tell a real improvement from luck.
4.1 Supervised and Self-Supervised Learning
Most machine learning is supervised: each example pairs an input with the wanted answer, its label (an image labelled cat, an email labelled spam), and the loss compares the model's output with the label.
Labels are expensive, so labelled datasets hold millions of examples, not trillions. Language models make labels from the data itself: hide the next token and predict it from the tokens before. A 20-token sentence is 20 training examples, and the whole internet becomes a labelled dataset. This is , and it is why language models could grow so large: the training signal grows with the supply of text. Section 8.4 writes the objective out, and section 8.2 shows a second self-supervised task, filling in blanks.
A third kind, reinforcement learning, has no labels, only a score for how good an output was. Module 21 uses it to tune assistants to people's preferences.
4.2 Neurons, Layers, and the MLPRun this section
A is the smallest unit of a neural network. It takes a vector of inputs, computes a weighted sum plus a constant, and passes the result through a fixed nonlinear function:
The weights and bias are learned. is the : ReLU, , zeroes negative values; squashes into ; GELU is a smooth ReLU used in transformers (section 7.4).
A layer is many neurons reading the same input. With their weight vectors as the columns of , a layer is one matrix multiplication followed by entry by entry: . A (MLP) chains such layers. The layers between input and output are hidden layers, and their size is the network's width.
Why the Nonlinearity Matters
Without , two layers give : one linear layer again. Any stack of linear layers can only draw straight boundaries; the nonlinearity is what lets depth add power. With enough hidden neurons, one hidden layer can approximate any reasonable function (the universal approximation theorem), but depth makes many functions far cheaper to represent.
Every transformer block contains an MLP, the feed-forward network (section 7.4), which holds most of the model's parameters.
4.3 Logits, Softmax, and Cross-EntropyRun this section
A model produces raw scores called , , any real numbers. Softmax turns them into probabilities: positive, and summing to 1.
Numerical Catastrophe: Floating-Point Overflow
Floating-point formats have a largest value; anything bigger becomes infinity (inf). Because grows so fast, ordinary logits can overflow:
- In 32-bit floats (
fp32) the largest value is about , so overflows once . - In 16-bit half precision (
fp16) the largest value is , so overflows once . bf16keeps fp32's exponent range and gives up precision instead, so it overflows near the same point as fp32.
Once any is inf, softmax computes = NaN ("not a number"). Backpropagation carries it into the gradients and then the weights, and any arithmetic with NaN gives NaN.
Shift-Invariance & Safe Softmax
Subtracting the same number from every logit leaves the softmax unchanged:
The factor cancels top and bottom. Standard implementations (PyTorch, FlashAttention, TensorRT-LLM) use :
Every exponent is now zero or negative, so every exponential lies in and nothing can overflow.
In words. Subtract the largest logit from every logit, then exponentiate and divide by the sum. The answer is unchanged; only overflow is prevented.
Temperature Scaling Regimes
When sampling text, the logits are often divided by a first:
- : the model's own probabilities.
- (greedy decoding, always picking the most likely token): every gap grows without bound, so all probability lands on the largest logit, a distribution. is the position of the largest logit:
introduces 2 notations
- (uniform): every goes to , so every token gets the same weight:
Three logits give three probabilities that add to 1, so every softmax output is a point in this triangle. Lower T slides it to the top corner (greedy); higher T slides it to the center (uniform).
Before moving the slider, decide where the point must end up as the temperature grows very large, and why the answer does not depend on the logits at all.
In words. With three logits, every softmax output is a point in a triangle whose corners are the one-hot distributions. Lowering the temperature slides the point toward the largest logit's corner (greedy decoding); raising it slides it to the center, where each probability is a third.
Softmax Jacobian and Gradient Dynamics
How does each probability change when logit changes?
is when and otherwise. This Jacobian is not diagonal: raising one logit lowers every other probability, since they must still sum to 1. Both cases follow from the quotient rule with : for , ; for , .
If one logit dominates, and every other , so every entry of the Jacobian is nearly zero and almost no gradient flows back. The softmax is saturated, and learning through it stalls. This is one reason attention divides its scores by .
Measured (lab 1b,
experiments/softmax_overflow.py). The size of the Jacobian (its Frobenius norm) drops from for equal logits to for saturated ones, a factor of , as the largest probability goes from to . Only the two ends are compared: along some paths between them the norm rises before it falls, which is why section 6.3 tracks the top class's instead.
Measured (lab 1b). exp() overflows fp32 at and fp16 at , matching the values quoted in the overflow section. Passing to the plain softmax formula returns
nan, while the safe version gives the exact answer. Note which code is at risk:torch.softmaxalready subtracts the row maximum internally, so the model code shipped with this course never overflows. The danger is in writing the formula out by hand, not in calling the library.
Softmax With Cross-Entropy: The Gradient That Trains Every LLM
Saturation matters when the softmax output feeds further computation, as in attention. At a model's output, the softmax feeds the cross-entropy loss for the correct class (section 3.5), and differentiating through both at once gives something much simpler:
is for the correct class and otherwise. In one line: , and the second term's derivative is .
The gradient is "what the model predicted, minus what was right". When the model is confidently wrong (), the correct class gets a gradient near , the strongest push; it vanishes only when the model is confidently right. The log cancels the exponential, which is why a saturated output layer is no problem while a saturated softmax inside attention is.
4.4 Generalization, Overfitting, and RegularizationRun this section
The goal is not a low loss on the training data but on data the model has never seen: . A model that memorized its examples would be useless on anything else.
Three Splits
To measure generalization honestly, the data is divided before training:
- The training set is what gradient descent sees.
- The validation set is held out and used for decisions: learning rate, model size, when to stop. Its loss is the validation loss.
- The test set is touched once, at the end, to report the final number.
Making decisions on the test set turns it into a second validation set, and the reported number becomes optimistic. Section 13.3 shows the same failure with public benchmarks.
Overfitting and Underfitting
Watch the training and validation losses together:
- Underfitting. Both are high, still falling or stalled. The model is too small or undertrained.
- A good fit. Both fall, and stay close.
- Overfitting. Training loss keeps falling while validation loss turns and rises: the model is fitting noise in its particular examples.
Overfitting needs a model big enough to memorize and data small enough to be memorized. Large language models see almost every example once and rarely overfit; small models trained for many passes over small datasets overfit readily.
Regularization
A regularizer discourages memorization at a small cost to the training loss:
- More data, the most effective of all.
- Weight decay pulls every weight slightly toward zero each step, discouraging the large, finely tuned weights memorization needs (section 10.2).
- Dropout zeroes a random fraction of activations at each training step, so the model cannot rely on any single feature (Srivastava et al., 2014). GPT-2 used ; most modern pretraining uses zero, since it rarely overfits.
- Early stopping keeps the weights from the step with the lowest validation loss.
4.5 Hyperparameters, Batches, Steps, and Epochs
are what gradient descent learns. Everything chosen by hand is a : learning rate, number and width of layers, batch size, weight decay, dropout, training length. They are chosen by comparing validation loss across several values.
- A batch is the set of examples for one gradient computation. Larger batches give a less noisy gradient (section 3.2) at a higher cost per step.
- A step is one weight update: loss on one batch, backpropagate, gradient descent.
- An epoch is one full pass over the training set: steps for examples and batch size .
Small models train for many epochs. Large language models train for about one epoch or less, so progress is counted in tokens seen instead (section 10.5).
Reading a Loss Curve
A loss curve plots loss against step. A healthy one falls fast, then flattens. A flat curve suggests a learning rate too small, or a bug disconnecting loss from weights. Sudden spikes suggest a learning rate too large or overflow (section 4.3); section 10.4 lists the defences.
4.6 Reading an ExperimentRun this section
Rerun any experiment and its numbers come out slightly different. Reading results well means knowing why.
Seeds and Run-to-Run Noise
Initial weights, batch order and dropout are drawn from a pseudo-random generator, which repeats exactly from the same seed. A different seed gives a different but equally valid run, and the final loss moves a little: run-to-run noise.
A difference between methods means something only if it is clearly larger than the noise. If changing the seed moves validation loss by , a single-run improvement of shows nothing yet. Run each method with several seeds and compare the spread.
Ablations
An ablation changes one component and keeps everything else (data, seed, steps) identical, isolating that component's effect. Most comparisons in this course are ablations: sinusoidal against learned positions (section 7.1), Post-LN against Pre-LN (section 8.5).
Reading a Measured Box
When you read a Measured box, ask four questions:
- What was measured? A derivation checked to floating-point precision (such as an identity holding to ) is a different kind of claim from a training comparison.
- At what scale? A result on a model with 100,000 parameters may not hold at a billion. The boxes say when this matters.
- How many seeds? One seed shows that something can happen, not how reliably.
- Compared with what noise? A difference smaller than the run-to-run noise is not a result.
The Caveat boxes exist to answer these questions in advance.
4.7 Worked Example: Training a Tiny MLPRun this section
The figure trains an MLP in your browser to separate two classes of points in a plane: two coordinates in, two logits out, softmax and cross-entropy, then backpropagation and gradient descent on each batch.
The network sees the training points (solid). The validation points are never trained on; their loss is the dashed curve. Shading shows the class the network predicts.
Set the training set to its smallest size and the hidden layer to its largest width, then train. Before you press play, predict what the two loss curves will do.
In words. A plane of two-coloured points, shaded by the network's current prediction, beside a chart of training and validation loss. Controls set the number of points, network width and depth, activation, learning rate and weight decay. As training runs, the shading reshapes around the data and the curves show underfitting, fitting or overfitting.
Try, in order: with ReLU and moderate width, the boundary bends to follow the data. Switch the activation to none and it stays a straight line however many layers you add (section 4.2). Raise the learning rate and the loss curve jumps around (section 2.4). Finally, make it overfit with the smallest training set and widest network, then cure it.
The same network, two training-set sizes
Each run uses a new seed. Run it a few times: the exact numbers move, which is run-to-run noise (section 4.6), but whether the gap is large or small does not.
Exercises
Why is next-token prediction called self-supervised rather than supervised?
Show that two linear layers with no activation between them, with and , are equivalent to one linear layer. What is that layer's shape, and what is the largest rank it can have?
A model's logits are and the correct class is the first. Compute the gradient of the cross-entropy loss with respect to the first logit.
A training set has 60,000 examples and the batch size is 128. How many steps is 3 epochs, rounding each epoch up to a whole number of steps?
Describe what the training and validation loss curves look like when a model overfits, and name two ways to reduce it.
Two methods are compared with one seed each. Method B's validation loss is lower than method A's. Three more seeds of method A give losses spread over a range of . What can you conclude, and what would you do next?
Why does a saturated softmax stall learning inside attention but not at the output layer of a classifier trained with cross-entropy?
Core Academic References
- Goodfellow, Bengio & Courville (2016): Deep Learning, chapters 5–7 (Machine Learning Basics, Deep Feedforward Networks, Regularization). MIT Press.
- Srivastava et al. (2014): Dropout: A Simple Way to Prevent Neural Networks from Overfitting. JMLR 15: 1929–1958.
- Hornik, Stinchcombe & White (1989): Multilayer Feedforward Networks are Universal Approximators. Neural Networks, 2(5): 359–366.
- Bouthillier et al. (2021): Accounting for Variance in Machine Learning Benchmarks. MLSys 2021. arXiv:2103.03098
Measured labs
These labs test what this module says by running real code. Each card states the idea, what the experiment found, and what it does not prove. The numbers come from experiments/results.json, the output of running experiments/run_all.sh on the tiny-transformers reference code at version 137f7ef. The project checks fail if a measured number in the module text stops matching that file.
Lab 1b — softmax overflow, reproduced and then fixed
What the module says
Section 4.3 says that computing directly overflows to infinity once passes 88.72 in fp32 or 11.09 in fp16. It says standard implementations avoid this by subtracting the largest score, , first. It also says that when softmax puts almost all probability on one class, its gradient shrinks toward zero, so learning stalls.
What the experiment found
Both overflow points reproduce: in fp32 and in fp16, the values the module quotes. The plain softmax from the module returns NaN (not a number) on scores as large as , while the version that subtracts the maximum gives the exact answer. When the scores are extreme enough that one probability is 1, the gradient term is exactly 0: the stalled-learning effect the module describes.
- fp32 overflow point
- 88.7228
- fp16 overflow point
- 11.0899
- plain softmax gives a finite answer at ?
- false
- gradient term for the top class, scores
- 0
- size of the whole gradient matrix, spread-out peaked scores
- 0.433013 → 0.000193
above this , is too large for a 32-bit float
above this , is too large for a 16-bit float
torch.softmax does: it subtracts the row maximum for you
the term the module says goes to zero, measured at zero
context only: this is the Frobenius norm , not the term
What this does not prove
The model in this repository never overflows, because it calls torch.softmax, which already subtracts the row maximum. The risk is in the plain formula, not in this code. You only see that by running the experiment: reading the module alone could leave you thinking this code base is at risk.
Run it yourself
cd tiny-transformers && .venv/bin/python experiments/softmax_overflow.pyThe code being tested