All projects

AI & ML / UCT · CSC3022 / 2024

Handwritten digit recognition

From image preprocessing to held-out prediction: a PyTorch digit classifier with inspectable training curves and class-level errors.

PythonPyTorchNeural networks

UCT / COURSE CONTEXT / 2024

CSC3022F · C++ and Machine Learning

C++ language and memory-model foundations followed by Python-based machine-learning implementation.

Science handbook · 2024

ENGINEERING PERSPECTIVE

Inside the work

A complete small-scale classification workflow: turn image data into a trained decision function, then check predictions on unseen digits. The engineering challenge is consistency between data preparation, tensor shapes, optimisation and evaluation.

PyTorch
Tensor operations, automatic differentiation, fully connected layers and Adam optimisation.
MNIST / torchvision
Labelled 28-by-28 digit images and a consistent loading/normalisation path.
STEP 1 / 3

Prepare pixels

Load MNIST, convert images to tensors and apply grayscale normalisation.

Source-derived walkthrough

What it is

Built a feedforward classifier for handwritten digits, including data loading, minibatch training, test evaluation and prediction for a local image.

Why it was built

An introductory learning problem with a complete path from image pixels to training and held-out predictions: recognise ten handwritten digit classes.

My contribution

Individual submitted classifier, training loop, evaluation and local-image prediction, supported by the source and named submission. PyTorch and MNIST are external frameworks/data, not original inventions.

How it works

Flatten 28 × 28 images into 784 inputs, then use 128- and 64-unit ReLU hidden layers and a 10-class output. The original uses Adam at 0.001, batches of 32 and seven epochs.

  1. 01MNIST
  2. 02Normalise
  3. 03784 → 128 → 64 → 10
  4. 04Train with Adam
  5. 05Evaluate / predict

Technical implementation

  • ToTensor and grayscale normalisation prepare 28x28 input; flattening produces 784 features.
  • Two fully connected hidden layers use ReLU, followed by a ten-class softmax. Adam, a 0.001 learning rate and batches of 32 drive seven original training epochs.
  • CrossEntropyLoss already expects logits. The retained extra softmax is a documented design limitation, not silently rewritten historical work.
  • Cleanup adds explicit dataset paths, subset/epoch controls, non-interactive prediction and bounded CPU smoke verification.

Controlled enhancement experiments

NEW / PORTFOLIO REPRODUCIBILITY EXPERIMENTS

Same architecture and initial seed. Fixed 10,000 training, 2,000 validation and 2,000 official held-out test examples. Three epochs; Adam at 0.001. Validation is disjoint from training. These are not the original full-data results.

HELD-OUT ACCURACY / IDENTICAL TEST SUBSET
Original softmax / batch 3289.8%
Logits / batch 3291.3%
Logits / batch 12890.1%
ConfigurationBatchTest accuracyTrain + validation
Original softmaxoriginal-softmax-323289.80%10.9s
Logitslogits-323291.30%7.9s
Logitslogits-12812890.10%8.4s
0.000.340.69Epoch 1Epoch 2Epoch 3Epoch 1: train loss 0.689Epoch 1: validation loss 0.365Epoch 2: train loss 0.357Epoch 2: validation loss 0.332Epoch 3: train loss 0.289Epoch 3: validation loss 0.272
Cross-entropy: solid training, dashed validation. Scale per selected configuration; softmax/logits objectives differ.
EpochTrain lossValidation
10.6890.365
20.3570.332
30.2890.272
True 0, predicted 0: 161 examples161True 0, predicted 1: 0 examples0True 0, predicted 2: 1 examples1True 0, predicted 3: 0 examples0True 0, predicted 4: 0 examples0True 0, predicted 5: 3 examples3True 0, predicted 6: 5 examples5True 0, predicted 7: 0 examples0True 0, predicted 8: 4 examples4True 0, predicted 9: 0 examples0True 1, predicted 0: 0 examples0True 1, predicted 1: 223 examples223True 1, predicted 2: 1 examples1True 1, predicted 3: 1 examples1True 1, predicted 4: 0 examples0True 1, predicted 5: 0 examples0True 1, predicted 6: 0 examples0True 1, predicted 7: 0 examples0True 1, predicted 8: 0 examples0True 1, predicted 9: 0 examples0True 2, predicted 0: 0 examples0True 2, predicted 1: 2 examples2True 2, predicted 2: 192 examples192True 2, predicted 3: 3 examples3True 2, predicted 4: 1 examples1True 2, predicted 5: 0 examples0True 2, predicted 6: 2 examples2True 2, predicted 7: 2 examples2True 2, predicted 8: 6 examples6True 2, predicted 9: 0 examples0True 3, predicted 0: 0 examples0True 3, predicted 1: 1 examples1True 3, predicted 2: 4 examples4True 3, predicted 3: 192 examples192True 3, predicted 4: 0 examples0True 3, predicted 5: 0 examples0True 3, predicted 6: 1 examples1True 3, predicted 7: 2 examples2True 3, predicted 8: 4 examples4True 3, predicted 9: 1 examples1True 4, predicted 0: 1 examples1True 4, predicted 1: 2 examples2True 4, predicted 2: 3 examples3True 4, predicted 3: 0 examples0True 4, predicted 4: 194 examples194True 4, predicted 5: 0 examples0True 4, predicted 6: 2 examples2True 4, predicted 7: 0 examples0True 4, predicted 8: 1 examples1True 4, predicted 9: 2 examples2True 5, predicted 0: 3 examples3True 5, predicted 1: 1 examples1True 5, predicted 2: 1 examples1True 5, predicted 3: 15 examples15True 5, predicted 4: 5 examples5True 5, predicted 5: 151 examples151True 5, predicted 6: 1 examples1True 5, predicted 7: 0 examples0True 5, predicted 8: 6 examples6True 5, predicted 9: 2 examples2True 6, predicted 0: 0 examples0True 6, predicted 1: 2 examples2True 6, predicted 2: 2 examples2True 6, predicted 3: 0 examples0True 6, predicted 4: 4 examples4True 6, predicted 5: 5 examples5True 6, predicted 6: 186 examples186True 6, predicted 7: 0 examples0True 6, predicted 8: 3 examples3True 6, predicted 9: 0 examples0True 7, predicted 0: 0 examples0True 7, predicted 1: 9 examples9True 7, predicted 2: 10 examples10True 7, predicted 3: 1 examples1True 7, predicted 4: 7 examples7True 7, predicted 5: 0 examples0True 7, predicted 6: 0 examples0True 7, predicted 7: 185 examples185True 7, predicted 8: 1 examples1True 7, predicted 9: 9 examples9True 8, predicted 0: 0 examples0True 8, predicted 1: 1 examples1True 8, predicted 2: 2 examples2True 8, predicted 3: 4 examples4True 8, predicted 4: 0 examples0True 8, predicted 5: 1 examples1True 8, predicted 6: 2 examples2True 8, predicted 7: 1 examples1True 8, predicted 8: 170 examples170True 8, predicted 9: 0 examples0True 9, predicted 0: 0 examples0True 9, predicted 1: 1 examples1True 9, predicted 2: 0 examples0True 9, predicted 3: 0 examples0True 9, predicted 4: 15 examples15True 9, predicted 5: 1 examples1True 9, predicted 6: 0 examples0True 9, predicted 7: 2 examples2True 9, predicted 8: 2 examples2True 9, predicted 9: 172 examples17200112233445566778899
Rows: true digit. Columns: predicted digit. All 2,000 test predictions are counted.
Actual held-out predictions: four correct examples followed by four mistakes from the new logits batch32 experiment

First four correct and first four wrong predictions in fixed test order, logits/batch32. Not selected for visual quality. Confidence was not retained and is not inferred. One seed, limited subsets and no test-driven tuning; timings are machine-specific and include validation.

Removing softmax before CrossEntropyLoss changes the objective to its intended logits convention. Batch128 makes fewer optimiser updates per epoch: it ran faster here but had lower accuracy than batch32. This is a small controlled comparison, not a universal ranking.

Results & evidence

  • The original training log records 95.71% MNIST test accuracy.
  • The cleaned entry point supports explicit dataset paths and a bounded, non-interactive smoke run.

Engineering challenges

Image shape, normalisation and label interpretation must agree across training and single-image prediction. Historical test accuracy and a tiny smoke run answer different questions.

Scope & limitations

The 95.71% result is historical. The submitted softmax-before-cross-entropy design is retained and documented; no saved checkpoint or seeded repeatability evidence was supplied.

What I learned

How preprocessing, tensor dimensions, minibatch optimisation and evaluation fit together; why loss/output conventions and reproducibility matter.

What I would improve now

The new controlled experiments above add logits, fixed seeds and per-class confusion counts. Next: repeat across seeds, save checkpoints and compare a convolutional baseline on a predeclared evaluation protocol.

NEXT PROJECTFinding patterns in student performance