data.py — fill in two holes
Now what you saw in step 2 is written down as data.py — and you fill in two
missing pieces. These are exactly the two places where data mistakes are the
quietest.
What is in the file
class_counts— how many pictures in each class. Ready.build_transform— how aPILpicture becomes a tensor: gray →[1, 28, 28]→ normalised. Ready.split_indices— a stratified split: every class givesval_fracof its pictures to validation. The loop is written, one line is missing.mean_std— pixel mean and std over the indices you name. Ready.make_loaders— ties it together and returns(train_loader, val_loader, classes). One line is missing.
Your job
Create data.py and test_data.py (see the right panel). data.py runs
without crashing but is wrong — two places are marked HOLE 1 and HOLE 2:
- HOLE 1 — how many pictures of a class go to validation?
val_fracof them, rounded, but never fewer than one. Right now it is0. - HOLE 2 — the normalisation mean and std.
mean_std(plain, ...)takes a list of picture indices — which ones? Right now it is0.0, 1.0(changes nothing).
Nothing else needs to change.
test_data.py is the verdict. It builds a tiny folder of pictures in a
temporary directory itself (three classes of 30 pictures, each with its own
average brightness), so it needs neither your photographs nor FashionMNIST.
Run it before filling anything in
$ python -m unittest test_data
FF..FF
======================================================================
FAIL: test_a_tiny_class_still_gets_a_validation_image (test_data.DataTest.test_a_tiny_class_still_gets_a_validation_image)
...
AssertionError: Lists differ: [] != [0, 1]
======================================================================
FAIL: test_batches_have_the_shape_the_cnn_expects (test_data.DataTest.test_batches_have_the_shape_the_cnn_expects)
...
AssertionError: 90 != 72
======================================================================
FAIL: test_split_is_stratified_and_disjoint (test_data.DataTest.test_split_is_stratified_and_disjoint)
...
AssertionError: 0 != 18 : 20 % of 90 images
======================================================================
FAIL: test_training_pixels_are_normalised_with_training_statistics (test_data.DataTest.test_training_pixels_are_normalised_with_training_statistics)
...
AssertionError: 0.4701877236366272 != 0.0 within 4 places (0.4701877236366272 difference)
----------------------------------------------------------------------
Ran 6 tests in 0.6s
FAILED (failures=4)
(Shortened: the Traceback bodies are cut. The first run can take longer — that
is the torchvision import.)
Read the messages from the top; they tell a story: AssertionError: 90 != 72 —
the training set holds all 90 pictures because nothing was given to
validation; 0 != 18 — validation is empty; 0.47 != 0.0 — the training pixel
mean is 0.47 because normalisation does nothing.
The two . — class_counts and the repeatability test — already pass because
they do not depend on these holes.
When it does not pass
- Only
test_a_tiny_class_still_gets_a_validation_imagefails, the rest pass — you wroteround(len(idx) * val_frac)orint(...). For a class of three pictures 10 % rounds to 0 and the class is left without validation. You needmax(1, ...). test_training_pixels_are_normalised…fails by a tiny amount (e.g.0.0007 != 0.0) — HOLE 2 uses more than the training pictures. With all pictures the difference is 0.0007; with the validation ones, 0.0036. That does not look like much — but the test is strict on purpose: validation pictures must not influence a single training number.AssertionError: 72 != 18— you flipped it:val_fractaken for training rather than validation.