Training a Simple Neural Network with a Framework
Learning Objectives: By the end of this lesson, you will be able to:
- Load and preprocess a basic dataset (e.g., MNIST or Iris)
- Train a neural network model using
.fit()in Keras or a manual loop in PyTorch- Monitor training progress and evaluate performance
1. Welcome and Introduction (5 minutes)
Icebreaker Activity
- Think back to your first experience training a model: was it exciting or intimidating?
Lesson Overview
- Duration: 45 minutes
- Prerequisites: Lesson on framework setup and basic model definition
- Materials Needed: Python environment, Jupyter Notebook or script
2. Learning Objectives and Session Outline (5 minutes)
What We’ll Cover Today:
- Dataset loading and preprocessing
- Training with
.fit()or manual loop - Monitoring loss and accuracy
- Evaluating on test data
- Visualizing training curves
Success Criteria:
- Ability to load data and train a model end-to-end with a deep learning framework
3. Foundation Knowledge (15-20 minutes)
Core Concepts
Data Pipelines
- Keras:
tf.keras.datasets.mnist.load_data()returns training and test arrays. - PyTorch:
torchvision.datasets.MNISTloads each image and label; aDataLoaderbatches the samples and can shuffle the training set.
Both examples scale pixel values to [0, 1]. Training loss and validation metrics monitor learning during training; evaluate on the held-out test set only after training and tuning are complete.
Key Terminology
- Batch Size: Number of samples per gradient update
- Epoch: One pass through the full training dataset
- Validation Split: Fraction of data for validation during training
4. Detailed Explanation and Examples (25-30 minutes)
Understanding Training APIs
Keras Example:
from tensorflow.keras import Sequential
from tensorflow.keras.datasets import mnist
from tensorflow.keras.layers import Dense, Flatten, Input
# Load images and integer digit labels
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
model = Sequential([
Input(shape=(28, 28)),
Flatten(),
Dense(128, activation="relu"),
Dense(10, activation="softmax"),
])
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)
history = model.fit(
x_train, y_train,
epochs=5,
batch_size=32,
validation_split=0.1,
)
test_loss, test_accuracy = model.evaluate(x_test, y_test, verbose=0)
print(f"Test loss: {test_loss:.4f}; test accuracy: {test_accuracy:.4f}")
PyTorch Example:
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
transform = transforms.ToTensor() # MNIST pixels are converted to float values in [0, 1]
train_dataset = datasets.MNIST("data", train=True, download=True, transform=transform)
test_dataset = datasets.MNIST("data", train=False, download=True, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=256, shuffle=False)
class Net(nn.Module):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.hidden = nn.Linear(28 * 28, 128)
self.relu = nn.ReLU()
self.output = nn.Linear(128, 10)
def forward(self, x):
x = self.flatten(x)
x = self.relu(self.hidden(x))
return self.output(x) # raw logits for CrossEntropyLoss
model = Net()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
for epoch in range(5):
model.train()
running_loss = 0.0
examples_seen = 0
for images, labels in train_loader:
optimizer.zero_grad()
logits = model(images)
loss = criterion(logits, labels)
loss.backward()
optimizer.step()
running_loss += loss.item() * labels.size(0)
examples_seen += labels.size(0)
print(f"Epoch {epoch + 1}: train loss={running_loss / examples_seen:.4f}")
# Evaluate once on the held-out test set after training
model.eval()
correct = 0
examples_seen = 0
with torch.no_grad():
for images, labels in test_loader:
logits = model(images)
predictions = logits.argmax(dim=1)
correct += (predictions == labels).sum().item()
examples_seen += labels.size(0)
test_accuracy = correct / examples_seen
print(f"Test accuracy: {test_accuracy:.4f}")
Common Misconceptions:
- Misconception: More epochs always mean better model Reality: After a point, the model may overfit
- Misconception: Validation split is test accuracy Reality: Validation is for tuning; test set remains unseen
5. Live Coding Demonstration (20-25 minutes)
Example 1: Training Curve Visualization
import matplotlib.pyplot as plt
plt.plot(history.history['loss'], label='train loss')
plt.plot(history.history['val_loss'], label='val loss')
plt.legend(); plt.show()
Debugging Demonstration
# Common mistake: not shuffling data
data_loader = DataLoader(dataset, batch_size=32, shuffle=False)
# You may see poor convergence
# Correct: shuffle=True
6. Hands-On Practice (30-40 minutes)
Exercise 1: Basic Practice (10 minutes)
Objective: Train a model on Iris using Keras.
Exercise 2: Intermediate Challenge (15 minutes)
Objective: Implement manual training loop in PyTorch.
Exercise 3: Creative Application (15 minutes)
Objective: Compare SGD vs. Adam on the same dataset.