Launch the interactive walkthrough to discover each component, including the 3D Q-Sphere Lab & Python in Colab.
Synthesize Module 3: construct, train, validate, and evaluate a multi-layer deep neural network on handwritten digits (MNIST).
| Symbol / Term | Meaning | Beginner Interpretation |
|---|---|---|
| Flattened 784-pixel image | Input vector | |
| Predicted digit (0-9) | Final model decision |
Image of digit "7" generates highest probability at index 7: P(7) = 0.96.
Result: Classified as Digit 7
28x28 pixel images are unrolled into 784-element vectors.
Vectors pass through Layer 1 (784->128, ReLU), Layer 2 (128->64, ReLU), and Output (64->10).
Cross-Entropy compares output logits against target digit labels and computes gradients.
Accuracy is audited on unseen test images.
Problem: Sorting millions of handwritten envelope zip codes per hour in postal centers.
Solution: Deep MLPs and CNNs read handwritten numbers directly on conveyor belts.
Problem: Reading check dollar amounts from mobile camera photos.
Solution: Digit recognition networks parse handwriting on mobile banking applications.
Interactive activity component
Build, train, and evaluate a Convolutional Neural Network (CNN) with Conv2d, MaxPool2d, and Linear layers on the MNIST dataset using PyTorch.
For Google Colab or Jupyter notebooks, run this shell command to install the required dependencies:
!pip install torch torchvision matplotlib1 import torch 2 import torch.nn as nn 3 import torchvision.transforms as transforms 4 import torchvision.datasets as datasets 5 from torch.utils.data import DataLoader 6 import matplotlib.pyplot as plt
import torch → Core PyTorch tensor and autograd library
import torch.nn as nn → Neural network layers (Conv2d, MaxPool2d, Linear)
import torchvision.transforms as transforms → Image transformations and normalization
import torchvision.datasets as datasets → MNIST benchmark dataset loader
from torch.utils.data import DataLoader → Mini-batch generator
import matplotlib.pyplot as plt → Plotting utility
1 # Transform: Convert image to Tensor and normalize pixels to [-1, 1] 2 transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))]) 3 4 # Download and prepare MNIST training and test datasets 5 train_data = datasets.MNIST(root='./data', train=True, download=True, transform=transform) 6 test_data = datasets.MNIST(root='./data', train=False, download=True, transform=transform) 7 8 # Create mini-batch DataLoaders (batch size = 64) 9 train_loader = DataLoader(train_data, batch_size=64, shuffle=True) 10 test_loader = DataLoader(test_data, batch_size=64, shuffle=False) 11 12 # Define Convolutional Neural Network (CNN) Architecture 13 class CNN(nn.Module): 14 def __init__(self): 15 super(CNN, self).__init__() 16 self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1) 17 self.pool = nn.MaxPool2d(2, 2) 18 self.fc1 = nn.Linear(32 * 14 * 14, 10) 19 20 def forward(self, x): 21 x = self.pool(torch.relu(self.conv1(x))) 22 x = x.view(-1, 32 * 14 * 14) 23 x = self.fc1(x) 24 return x 25 26 model = CNN() 27 criterion = nn.CrossEntropyLoss() 28 optimizer = torch.optim.Adam(model.parameters(), lr=0.001) 29 30 # Train for 5 epochs over the MNIST dataset 31 for epoch in range(5): 32 for images, labels in train_loader: 33 optimizer.zero_grad() 34 outputs = model(images) 35 loss = criterion(outputs, labels) 36 loss.backward() 37 optimizer.step() 38 print(f"Epoch {epoch+1}, Loss: {loss.item():.4f}") 39 40 # Evaluate model accuracy on unseen test set (10,000 images) 41 correct = 0 42 total = 0 43 with torch.no_grad(): 44 for images, labels in test_loader: 45 outputs = model(images) 46 _, predicted = torch.max(outputs.data, 1) 47 total += labels.size(0) 48 correct += (predicted == labels).sum().item() 49 50 print(f"Test Accuracy: {100 * correct / total:.2f}%")
# Transform: Convert image to Tensor and normalize pixels to [-1, 1]
Normalization pipeline
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
Normalize with mean 0.5 and std 0.5
# Download and prepare MNIST training and test datasets
Data loading
train_data = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
Load 60,000 training images
test_data = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
Load 10,000 test images
# Create mini-batch DataLoaders (batch size = 64)
DataLoaders
train_loader = DataLoader(train_data, batch_size=64, shuffle=True)
Shuffle training batches
test_loader = DataLoader(test_data, batch_size=64, shuffle=False)
Test batches
# Define Convolutional Neural Network (CNN) Architecture
CNN definition
class CNN(nn.Module):
Subclass nn.Module
def __init__(self):
Constructor
super(CNN, self).__init__()
Initialize parent
self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)
32 feature filters (3x3)
self.pool = nn.MaxPool2d(2, 2)
2x2 max-pooling (downsamples 28x28 to 14x14)
self.fc1 = nn.Linear(32 * 14 * 14, 10)
Dense output layer mapping to 10 classes
def forward(self, x):
Forward computation
x = self.pool(torch.relu(self.conv1(x)))
Conv -> ReLU -> MaxPool
x = x.view(-1, 32 * 14 * 14)
Flatten feature maps
x = self.fc1(x)
Linear output logits
return x
Return predictions
model = CNN()
Instantiate CNN model
criterion = nn.CrossEntropyLoss()
Cross-entropy loss function
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
Adam optimizer with lr=0.001
# Train for 5 epochs over the MNIST dataset
Training loop
for epoch in range(5):
Loop through epochs
for images, labels in train_loader:
Iterate mini-batches
optimizer.zero_grad()
Clear previous gradients
outputs = model(images)
Forward pass
loss = criterion(outputs, labels)
Compute batch loss
loss.backward()
Backpropagate error
optimizer.step()
Update weights
print(f"Epoch {epoch+1}, Loss: {loss.item():.4f}")
Log epoch progress
# Evaluate model accuracy on unseen test set (10,000 images)
Testing loop
correct = 0
Counter for correct predictions
total = 0
Total test samples
with torch.no_grad():
Disable gradient tracking for inference
for images, labels in test_loader:
Loop over test batches
outputs = model(images)
Predict on test images
_, predicted = torch.max(outputs.data, 1)
Select highest logit index
total += labels.size(0)
Tally batch size
correct += (predicted == labels).sum().item()
Count correct matches
print(f"Test Accuracy: {100 * correct / total:.2f}%")
Display final test accuracy
Click "Copy for Colab", open Google Colab, paste into a single cell, and run.
1 # ========================================================= 2 # PyTorch CNN Handwritten Digit Classifier (MNIST) 3 # Prepared for Google Colab (Run with Shift + Enter) 4 # ========================================================= 5 6 # Step 1: Install required packages 7 !pip install torch torchvision matplotlib 8 9 # Step 2: Import libraries 10 import torch 11 import torch.nn as nn 12 import torchvision.transforms as transforms 13 import torchvision.datasets as datasets 14 from torch.utils.data import DataLoader 15 import matplotlib.pyplot as plt 16 17 # Step 3: Run Demonstration 18 # Transform: Convert image to Tensor and normalize pixels to [-1, 1] 19 transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))]) 20 21 # Download and prepare MNIST training and test datasets 22 train_data = datasets.MNIST(root='./data', train=True, download=True, transform=transform) 23 test_data = datasets.MNIST(root='./data', train=False, download=True, transform=transform) 24 25 # Create mini-batch DataLoaders (batch size = 64) 26 train_loader = DataLoader(train_data, batch_size=64, shuffle=True) 27 test_loader = DataLoader(test_data, batch_size=64, shuffle=False) 28 29 # Define Convolutional Neural Network (CNN) Architecture 30 class CNN(nn.Module): 31 def __init__(self): 32 super(CNN, self).__init__() 33 self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1) 34 self.pool = nn.MaxPool2d(2, 2) 35 self.fc1 = nn.Linear(32 * 14 * 14, 10) 36 37 def forward(self, x): 38 x = self.pool(torch.relu(self.conv1(x))) 39 x = x.view(-1, 32 * 14 * 14) 40 x = self.fc1(x) 41 return x 42 43 model = CNN() 44 criterion = nn.CrossEntropyLoss() 45 optimizer = torch.optim.Adam(model.parameters(), lr=0.001) 46 47 # Train for 5 epochs over the MNIST dataset 48 for epoch in range(5): 49 for images, labels in train_loader: 50 optimizer.zero_grad() 51 outputs = model(images) 52 loss = criterion(outputs, labels) 53 loss.backward() 54 optimizer.step() 55 print(f"Epoch {epoch+1}, Loss: {loss.item():.4f}") 56 57 # Evaluate model accuracy on unseen test set (10,000 images) 58 correct = 0 59 total = 0 60 with torch.no_grad(): 61 for images, labels in test_loader: 62 outputs = model(images) 63 _, predicted = torch.max(outputs.data, 1) 64 total += labels.size(0) 65 correct += (predicted == labels).sum().item() 66 67 print(f"Test Accuracy: {100 * correct / total:.2f}%")
Downloads 70,000 MNIST images and scales grayscale pixels to [-1, 1] range.
Conv2d layer extracts 32 feature maps, followed by ReLU and 2x2 max-pooling to downsample spatial dimensions.
Adam optimizer minimizes CrossEntropyLoss across mini-batches of 64 images.
Evaluates on 10,000 held-out test images, achieving >98% test accuracy.
60,000 training and 10,000 test handwritten digit images (28x28 grayscale pixels)
Epoch 1, Loss: 0.0842 Epoch 2, Loss: 0.0511 Epoch 3, Loss: 0.0324 Epoch 4, Loss: 0.0195 Epoch 5, Loss: 0.0128 Test Accuracy: 98.65%
The convolutional neural network effectively captures 2D spatial stroke geometries, correctly classifying unseen handwritten digits with over 98% accuracy.
Convolutional Neural Networks, MNIST dataset, backpropagation, loss functions, and optimization.
Test your understanding with these questions. Remember, this is for learning, not examination!