Code

Run it: rings and clothes

The tests pass. Now — two runs that answer the question this lesson exists for.

1. The rings — here the leap is real

This step creates circles.py: the rings generator and a run with two models — one layer and an MLP with 16 hidden neurons. It is not your task, so the file is complete.

$ python circles.py
--- linear: 6 parameters
epoch  1  loss 0.7084  train accuracy 44.4%
epoch  2  loss 0.6921  train accuracy 51.5%
...
epoch 19  loss 0.6894  train accuracy 52.8%
epoch 20  loss 0.6895  train accuracy 54.3%
linear final train accuracy: 54.3%
--- mlp: 82 parameters
epoch  1  loss 0.6181  train accuracy 77.8%
epoch  2  loss 0.5022  train accuracy 97.4%
epoch  3  loss 0.3604  train accuracy 99.5%
epoch  4  loss 0.2276  train accuracy 100.0%
...
epoch 20  loss 0.0065  train accuracy 100.0%
mlp final train accuracy: 100.0%

(... — lines I left out; the real output has them.)

54.3 % → 100.0 %. One layer — 6 numbers — gets stuck with a loss of 0.689, which is almost ln 2 = 0.693 — "guess by coin toss". An MLP with 82 numbers stops making mistakes after four epochs. No amount of noise explains this away.

2. FashionMNIST — here the leap is modest

$ python train.py --model linear
linear: 7,850 parameters
...
epoch 10  loss 0.4342  train accuracy 85.5%
done in 7.9s

$ python train.py --model mlp
mlp: 101,770 parameters
...
epoch 10  loss 0.3053  train accuracy 89.5%
done in 5.8s

$ python train.py --model mlp --hidden 128 64
mlp: 109,386 parameters
...
epoch 10  loss 0.2877  train accuracy 89.9%
done in 6.4s
model numbers training accuracy
linear 7 850 85.5 %
MLP (128) 101 770 89.5 %
MLP (128, 64) 109 386 89.9 %

What the numbers show — honestly

The rings and the clothes are two very different worlds. The rings are impossible without a hidden layer; the clothes — nearly not. One layer already gets 85.5 % there.

+4 points is real, but small. The run "same seed, same code" gives 85.5 → 89.5. But another pair of runs (different shuffling) gave 84.3 → 87.9: +3.6. That is why I say "about +4", not "+4.0".

A single run is noise. The same MLP(128) with the same settings but a different batch order gave 89.5, 87.9 and 86.3 %. A range of a few points from random shuffling alone. So a single "89.5 vs 85.5" is not very firm; the difference of matched pairs is firmer.

The other "improvement" here is smaller than the noise. (128, 64) gives 89.9 vs 89.5: less than the spread between runs of the same model. Do not say "deeper is better" from one run.

Broader context: I ran three times with different seeds and measured accuracy on images the model had not seen. The linear model averaged 81.6 %, MLP(128) 84.3 % — roughly +3 points. In lesson 7 you will learn to measure that yourself.

The panel now shows the filled-in version

As in the previous lesson: model.py and train.py in the panel are filled in. That is the reference to compare with; later lessons change exactly it.