Overfitting, Underfitting and the Bias-Variance Trade-off
4 min read · updated August 3, 2026
Overfitting is usually explained with a picture of a wiggly line through some dots. The picture is fine and it does not tell you what to do on a Tuesday. What tells you what to do is the decomposition underneath it, which is four lines of algebra, and the two curve shapes it predicts.
It is two numbers, not one
A model has a training error and a held-out error, and every diagnosis starts by putting them side by side.
- Both high. Underfitting. The model class cannot represent the pattern, or optimisation has not finished. More data will not help.
- Training low, held-out high. Overfitting. The model has capacity to spare and has spent it memorising noise.
- Both low. Either you are done, or your split leaks — check the leakage list before celebrating.
A single accuracy number cannot distinguish any of these, which is why reporting one number is the most common self-inflicted wound in applied machine learning.
Deriving the decomposition
Assumptions first, because the result is only true under them. Suppose the world generates y = f(x) + ε with E[ε] = 0 and Var(ε) = σ². Fix a single input x. Your fitted model f̂ is random, because it depends on which training set you happened to draw, so take expectations over training sets and write f̄ = E[f̂(x)] — the average prediction across all the training sets you might have had.
Now expand the expected squared error at that point, adding and subtracting f̄:
E[(y − f̂)²] = E[(f + ε − f̂)²]
= E[((f − f̄) + (f̄ − f̂) + ε)²]
The three cross terms vanish:
E[f̄ − f̂] = 0 by definition of f̄
E[ε] = 0, and ε is independent of the training set
leaving
E[(y − f̂)²] = (f − f̄)² + E[(f̂ − f̄)²] + σ²
= Bias² + Variance + irreducibleRead what each term is. Bias is how far the average model is from the truth — a property of the model class, not of any particular fit. Variance is how far a typical fit is from that average — how much your answer depends on which data you happened to get. Irreducible error is the noise; no model and no amount of data removes it, and a project that has not estimated it is a project that can waste a quarter chasing it.
The trade-off falls out immediately. Restricting the model class — a shallower tree, fewer features, stronger regularisation — reduces variance because there are fewer ways for the fit to move, and raises bias because the average model is further from the truth. Every knob in this cluster is somewhere on that line.
Reading learning curves
A learning curve plots training and held-out error against training set size. Two shapes carry almost all the diagnostic value:
- The curves meet, high. Training error rises to meet held-out error and both flatten well above the acceptable level. That is bias. Adding rows will not help — the flat line is the answer that more data gives. Add capacity, add features, weaken regularisation.
- The curves have not met. Training error is low, held-out error is falling but still clearly above it, and the gap is narrowing as data is added. That is variance, and it is the one case where more data is genuinely the fix. Extrapolate the gap to decide whether the data you can afford closes it.
The distinction is worth money, because “get more data” is the most expensive intervention available and the curve tells you in advance whether it will do anything.
from sklearn.model_selection import learning_curve
import numpy as np
sizes, train, val = learning_curve(
estimator, X, y,
train_sizes=np.linspace(0.1, 1.0, 8),
cv=5, scoring="neg_mean_squared_error",
)
for n, tr, va in zip(sizes, -train.mean(1), -val.mean(1)):
print(f"{int(n):6d} train {tr:.4f} val {va:.4f} gap {va - tr:.4f}")Print the gap column, not just the two errors. The gap is the variance term made visible, and watching it shrink (or refuse to) is the decision you came for.
Where the U-curve stops being true
The classical picture says held-out error falls, bottoms out, and rises again as capacity grows past the sweet spot. That picture is correct in the regime it was drawn for and incomplete for very large models.
Belkin, Hsu, Ma and Mandal (PNAS, 2019) described double descent: past the interpolation threshold — where the model has just enough capacity to fit the training set exactly — test error can start falling again, sometimes below the classical minimum. Nakkiran and colleagues (ICLR, 2020) reported the same shape in deep networks and observed it as a function of training time and dataset size as well as model size. Report those as the published claims they are; the mechanism is still argued about.
The practical consequence is narrow but real: “the model is bigger than the dataset, therefore it will overfit” is not a sound inference for modern architectures. Measure it. The decomposition above is still exactly true — it is an identity, not an empirical claim — but the way variance behaves as capacity grows is not the monotone story the U-curve implies.
What it looks like in LLM work
You will rarely train a model from scratch, and overfitting shows up anyway, wearing three disguises:
- Fine-tuning past the point of use. Three epochs on a small instruction set and the model reproduces your examples beautifully and has lost range elsewhere — the specific form is catastrophic forgetting, and the guard is a held-out set that includes the general behaviour you do not want to lose.
- Overfitting a prompt. Iterating a system prompt against the same twenty examples is fitting parameters by hand, with you as the optimiser and no validation set. It has all the statistical properties of overfitting and none of the tooling, which is why a held-out eval set matters more for prompts than for models.
- Overfitting the benchmark. When a whole field selects on one leaderboard, the field is the optimiser and the leaderboard is the training set. That is why benchmark gains stop transferring.