Machine learning from zero · Lesson 3.3 · 16 of 33 lessons ready · 12 min
Learning curves: more data or a better model?
In short
Learning curves show the training and validation score as the data grow. Their shape tells you whether to collect more data or switch to a richer model.
Warm-up Two questions from earlier lessons. A minute, and it never blocks the lesson.
In lesson 3.1 the model was too simple or too complex, while the amount of data stayed the same. Today you change the amount of data. It is a practitioner’s everyday question: the model is so-so, so do you collect more examples or change the model? The answer comes from a learning curve: the score on training and on validation, drawn for a larger and larger training set.
Choose an answer and how sure you are.
Answer to unlock the lab.
Interactive lab
This interactive lab runs in a browser with JavaScript enabled. The text around it describes what the lab shows.
Show the answer
Correct answer: About 82%, more than ten points lower than on its training images
Validation is 82.3% (the mean of 5 draws of 50 images), so the gap is 17.7 points. On the full training set, 1438 images, validation rises to 95.8% and the gap shrinks to 2.2 points. With little data, 100% on training is largely memory.
Try this
- With the detailed model, move the slider from 50 to 1438 images. Which curve changes more: training or validation?
- Switch to the model of blurred digits. Where do its curves meet, and how high?
- Compare the detailed model with 100 images and the blurred one with 1438. Which wins?
Once you have checked it in the lab, let us name what you see.
The idea in plain words
A learning curve is two lines: accuracy on the training data and on validation, against the number of training examples. With a few dozen images the model memorises each of them: training is 100% and validation 82.3%. The more data, the harder it is to memorise everything, so training falls (to 98.0%) and validation rises (to 95.8%). The gap between them shrinks from 17.7 to 2.2 points.
You read the decision off the shape of those lines:
- A big gap, validation still rising (high variance): the model knows its training data far better than new data. More data will help, and so will regularisation.
- A small gap, both lines low (high bias): the model is too simple. The curves have met and more data will barely help. A richer model or better features will.
The model of blurred digits sees each digit as a 4 × 4 picture, 16 pixels instead of 64. With 1438 images it scores 86.9% on training and 85.0% on validation, a gap of only 1.9 points. Validation usually does not rise above training, and that is only 86.9%. The detailed model already reaches 87.6% with just 100 images.
Jak to policzono
- Digits: Optical Recognition of Handwritten Digits, UCI, licence CC BY 4.0. 1797 images of 8 × 8 pixels, 10 digits.
- A stratified 80/20 split, the same as in the Atlas widget: 1438 images for learning, 359 for validation. For each size the mean of 5 draws of which images are used for learning.
- Model: logistic (softmax) regression with a penalty of 0.001 on large weights. The blurred model sees the means of 2 × 2 pixel blocks.
Why it works
On training the model sees the answers, so with little data it can memorise them. Every new example makes memorising harder and finding a rule that also works outside training easier. That is why the lines move towards each other: training down, validation up. They meet at the level this model can reach at all.
That level depends on the model, not on the data. A blurred picture loses the details that tell, for example, a 3 from an 8, and no number of examples brings them back. In the code below the same experiment runs on 50 different splits: with all the data the blurred model scores 86.4% on training and 85.1% on validation, while the detailed one reaches 96.6% on validation. The detailed model from 100 images beats the blurred one from 1437 images in 49 splits out of 50.
Common mistake
True or false: “more data always helps”. False. More data helps when the model is too powerful for the amount of data: then the gap is big and validation keeps rising. When the model is too simple, the curves meet early and stay flat. In the lab the blurred model has 83.6% on validation with 400 images, and 85.0% with a set almost four times larger. The detailed model has 95.8% with the same data. Before you pay for collecting data, draw a learning curve: if the training score itself is low, data will not help.
Note: draw the curves on validation or in cross-validation, not on the test set. The test is kept for the final evaluation only.
Quiz
Three questions to check yourself. Pick an answer, or open the answer under a question. Keyboard: arrow keys choose, Enter or Space confirms.
Key takeaways
- A learning curve is the training and validation score for a growing training set.
- A big gap and rising validation: the model memorises, more data will help.
- A small gap at a low score: the model is too simple; a richer model or better features will help, not more data.
- Draw the curve before you pay for data; draw it on validation and keep the test for the end.
Going further: formula, code, practice
The math
Let A_tr(n) and A_val(n) be the accuracy on n training examples and on validation. The learning curve is both functions of n. Usually A_tr(n) falls, A_val(n) rises, and both approach the same level A*, the best accuracy this family of models can reach.
The gap A_tr(n) − A_val(n) measures variance: how much the score depends on which examples were used for learning. The distance 1 − A is the bias of this model family together with noise that no model removes (digits unreadable even for a human): no data removes it. More data shrinks the gap; only a change of model raises A.
The logistic regression in the lab minimises L = mean loss + (λ / 2) · ‖W‖² with λ = 0.001. In scikit-learn the same penalty is C = 1 / (λ · n) = 1000 / n.
In code (Python)
The same experiment in scikit-learn on 50 different splits: a model on 64 pixels and on the digit blurred to 16 pixels, with a growing number of training images.
import numpy as np
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
X, y = load_digits(return_X_y=True)
X = X / 16 # 8 × 8 = 64 pixels from 0 to 1, as in the lab
X16 = X.reshape(-1, 4, 2, 4, 2).mean(axis=(2, 4)).reshape(len(X), -1) # the same digit blurred to 4 × 4 = 16 pixels
def run(Z, n, seed):
Xtr, Xva, ytr, yva = train_test_split(Z, y, test_size=0.2, stratify=y, random_state=seed)
i = np.random.default_rng(seed).permutation(len(ytr))[:n] # the first n training images of a shuffle
m = LogisticRegression(C=1000 / n, max_iter=5000).fit(Xtr[i], ytr[i]) # C = 1000 / n is the lab's penalty 0.001
return m.score(Xtr[i], ytr[i]), m.score(Xva, yva)
for name, Z in (("64 pixels", X), ("16 pixels", X16)):
for n in (50, 100, 400, 800, 1437):
tr, va = np.mean([run(Z, n, s) for s in range(50)], axis=0) # mean of 50 different splits
print(f"{name}, {n} images: training {tr:.1%}, validation {va:.1%}, gap {(tr - va) * 100:.1f} points")
wins = sum(run(X, 100, s)[1] > run(X16, 1437, s)[1] for s in range(50))
print(f"64 pixels from 100 images beat 16 pixels from 1437 images in {wins} of 50 splits")
Output
64 pixels, 50 images: training 100.0%, validation 81.2%, gap 18.8 points
64 pixels, 100 images: training 100.0%, validation 89.5%, gap 10.5 points
64 pixels, 400 images: training 99.7%, validation 94.9%, gap 4.8 points
64 pixels, 800 images: training 99.0%, validation 96.0%, gap 2.9 points
64 pixels, 1437 images: training 98.2%, validation 96.6%, gap 1.6 points
16 pixels, 50 images: training 98.5%, validation 72.6%, gap 25.9 points
16 pixels, 100 images: training 94.1%, validation 79.8%, gap 14.4 points
16 pixels, 400 images: training 87.7%, validation 83.8%, gap 3.8 points
16 pixels, 800 images: training 86.9%, validation 84.6%, gap 2.3 points
16 pixels, 1437 images: training 86.4%, validation 85.1%, gap 1.3 points
64 pixels from 100 images beat 16 pixels from 1437 images in 49 of 50 splits
The lab shows one split and 5 draws, the code 50 splits, so the numbers differ a little: with 50 images validation is 82.3% in the lab and 81.2% on average. The shape of the curves and the conclusion are the same.
Download the notebook (.ipynb). Open it in Jupyter or upload it to Google Colab; it fetches any missing data itself.
For practitioners
- In scikit-learn the curves come from
learning_curve(with cross-validation) andLearningCurveDisplay. For classification useStratifiedKFold, so every size has all the classes. - Draw the number of examples on a log scale: the progress per doubling of the data is easier to see.
- A validation curve (
validation_curve) is something else: the score against a model setting, such as the strength of regularisation, with the data fixed. - Before you collect data, estimate what a doubling will bring: if the last doubling gave a fraction of a point, the next one will give even less.
Was this helpful?
Thanks! This helps us improve the Atlas.
Go deeper in the Atlas
Encyclopedia entries on the ideas in this lesson: