Stop 07 · Deep Learning FoundationsProjects · 1/2

Digit Classifier (MNIST)

Part of the AI Engineer Roadmap

In short

MNIST is the 'Hello, World' of deep learning: 70,000 small handwritten digits. Building a classifier for it end to end teaches you the whole PyTorch workflow in one sitting.

The 'hello world' of deep learning: classify handwritten digits — a small, fast project that exercises the full PyTorch/TensorFlow training loop end to end.

The blob in a post office sorts a pile of envelopes into a wall of pigeonhole slots.

Think of it like this

The post office PIN code reader

At a busy sorting office, someone reads thousands of handwritten PIN codes a day, scrawled in every style. After enough envelopes, they barely need to think. Your model sees 60,000 handwritten digits and learns to read them the same way.

Watch it happen

Your build plan

Load MNIST
Normalise
Model
Train
Test
Your digit

1/6torchvision downloads 60,000 training and 10,000 test images, each 28 × 28 pixels in greyscale.

The big ideas

What you need to know

Images are grids of numbers

Each image is a 28 × 28 grid of brightness values. Flattened, that's 784 inputs per example.

Ten outputs, one per digit

The last layer gives 10 scores. The highest one is the prediction. Cross-entropy trains them.

Upgrade to a CNN

An MLP gets you a good score. A small CNN, which looks at nearby pixels together, does noticeably better.

Study the mistakes

Plot misclassified digits. Many are 4s that look like 9s, or messy 7s. It tells you what the model finds hard.

See it in code

Walk through the code

python
1import torch, torch.nn as nn2from torchvision import datasets, transforms3from torch.utils.data import DataLoader4 5tf = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])6train = DataLoader(datasets.MNIST("data", train=True, download=True, transform=tf), batch_size=64, shuffle=True)7 8model = nn.Sequential(nn.Flatten(), nn.Linear(28 * 28, 128), nn.ReLU(), nn.Linear(128, 10))9opt = torch.optim.Adam(model.parameters(), lr=1e-3)10 11for images, labels in train:          # one epoch12    opt.zero_grad()13    loss = nn.functional.cross_entropy(model(images), labels)14    loss.backward()15    opt.step()16print("last batch loss:", loss.item())

1/3Load MNIST as tensors, normalised with its usual mean and std, in shuffled batches of 64.

One epoch of a simple MLP. Add a test loop with torch.no_grad() next and count correct predictions.

Save yourself the pain

Common mistakes

Oops

Checking accuracy on the training batches and calling it done.

Do this instead

Load the test split with train=False and report accuracy there, inside torch.no_grad().

Oops

Testing your own drawing as black ink on white paper.

Do this instead

MNIST digits are white on black and centred. Invert and centre your image first, or the model will be confused.

Your mission

Milestone 1: beat 95% on the test set

~45 min

Quick check

Your MNIST model outputs 10 numbers for an image. How do you get the predicted digit?

Go deeper

  1. 1Build and train a small feedforward or CNN model on MNIST from scratch.
  2. 2Plot training/validation loss curves to check for overfitting.
  3. 3Push accuracy above 98% and explain what architecture changes got you there.

More projects at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge