TP1 : CNN Challenge, deliver the best model!
Your goal is to optimize via transfer learning a deep learning model to achieve the best possible training and validation accuracy on the CIFAR-10 dataset, while minimizing both training and validation loss.
Dataset
- Dataset: CIFAR-10 URL: https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz Description: The CIFAR-10 dataset consists of 60,000 color images of size 32×32 pixels, divided into 10 classes (e.g., airplane, car, bird, cat, etc.), with 50,000 training images and 10,000 test images.
Task Description
You are asked to design and train a Convolutional Neural Network (CNN) for image classification using transfer learning. You may use one of the following pretrained models:
- VGG19
- ResNet
- MobileNet
- Inception
- Or any other relevant model
Your choice must be justified .
Model Design
Use transfer learning: load a pretrained model and adapt it to CIFAR-10.
You may:
- Freeze or unfreeze layers as needed.
- Add or replace fully connected layers (classifier head).
- Experiment with different dropout rates.
Training Strategy
Experiment with different hyperparameters, including:
- Learning rate and optimizer (Adam, SGD, RMSProp…)
- Batch size and number of epochs
- Use early stopping or learning rate scheduling to improve convergence.
Evaluation
Compare:
- Training Accuracy and Validation Accuracy
- Training Loss and Validation Loss
- Test accuracy.
Analysis
Discuss your results:
- Which model and configuration performed best?
Your starter Notebook
Please copy/paste your starter Notebook:
# ==============================
# 0. Install & Imports
# ==============================
!pip install --quiet gdown
from tqdm import tqdm, trange
import os
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, random_split, TensorDataset
from torchvision import datasets, transforms, models
import pandas as pd
import gdown
# ==============================
# 1. Hyperparameters & Device
# ==============================
BATCH_SIZE = 64
LR = 1e-3
EPOCHS = 10
N_CLASSES = 10
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
DATA_DIR = "./CIFAR10_data"
os.makedirs(DATA_DIR, exist_ok=True)
# ==============================
# 2. Transforms
# ==============================
transform_train = transforms.Compose([
transforms.RandomHorizontalFlip(),
transforms.RandomCrop(32, padding=4),
transforms.ToTensor()
])
transform_test = transforms.Compose([
transforms.ToTensor()
])
# ==============================
# 3. Load Train/Validation (Public CIFAR-10)
# ==============================
full_train_dataset = datasets.CIFAR10(root=DATA_DIR, train=True, download=True, transform=transform_train)
train_size = int(0.8 * len(full_train_dataset))
val_size = len(full_train_dataset) - train_size
train_dataset, val_dataset = random_split(full_train_dataset, [train_size, val_size])
train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False)
# ==============================
# 4. Download Test Dataset
# ==============================
# Students download this version only (images, no labels)
FILE_ID = "1cXUWjw-WiJqXb5gfjtqGFDMDDOGi2N56"
DEST_PATH = "cifar10_test.pt"
gdown.download(f"https://drive.google.com/uc?id={FILE_ID}", DEST_PATH, quiet=False)
# Load images only
test_images = torch.load(DEST_PATH) # shape [N, 3, 32, 32]
# Dummy labels for DataLoader
test_labels = torch.zeros(len(test_images), dtype=torch.long)
test_dataset = TensorDataset(test_images, test_labels)
test_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False)
print(f"Train: {len(train_dataset)}, Val: {len(val_dataset)}, Test: {len(test_dataset)}")
# ==============================
# 5. Define Models
# ==============================
# VGG16 Transfer Learning
vgg_model = models.vgg16(weights=models.VGG16_Weights.DEFAULT)
for param in vgg_model.features.parameters():
param.requires_grad = False
num_features = vgg_model.classifier[0].in_features
vgg_model.classifier = nn.Sequential(
nn.Linear(num_features, 512),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(512, N_CLASSES)
)
models_dict = {
"VGG16": vgg_model.to(DEVICE)
}
# ==============================
# 6. Training & Evaluation Functions
# ==============================
def train_one_epoch(model, loader, criterion, optimizer):
model.train()
total_loss, correct, total = 0, 0, 0
for x, y in loader:
x, y = x.to(DEVICE), y.to(DEVICE)
optimizer.zero_grad()
out = model(x)
loss = criterion(out, y)
loss.backward()
optimizer.step()
total_loss += loss.item() * x.size(0)
correct += (out.argmax(1) == y).sum().item()
total += y.size(0)
return total_loss / total, correct / total
def evaluate(model, loader, criterion=None, show_progress=False):
model.eval()
total_loss, correct, total = 0, 0, 0
y_pred = []
iterator = loader
if show_progress:
iterator = tqdm(loader, desc="Evaluating", unit="batch")
with torch.no_grad():
for x, y in iterator:
x, y = x.to(DEVICE), y.to(DEVICE)
out = model(x)
if criterion is not None:
total_loss += criterion(out, y).item() * x.size(0)
preds = out.argmax(1)
y_pred.extend(preds.cpu().numpy())
correct += (preds == y).sum().item()
total += y.size(0)
avg_loss = None if criterion is None else total_loss / total
acc = correct / total
return avg_loss, acc, y_pred
# ==============================
# 7. Training Loop + Save Test Predictions
# ==============================
criterion = nn.CrossEntropyLoss()
for name, model in models_dict.items():
optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=LR)
print(f"\nTraining {name} ...")
# Epoch loop with progress bar
for epoch in trange(1, EPOCHS + 1, desc="Epochs", unit="epoch"):
train_loss, train_acc = train_one_epoch(model, train_loader, criterion, optimizer)
val_loss, val_acc, _ = evaluate(model, val_loader, criterion)
tqdm.write(f"Epoch [{epoch}/{EPOCHS}] | "
f"Train Loss: {train_loss:.4f} | Train Acc: {train_acc:.3f} | "
f"Val Loss: {val_loss:.4f} | Val Acc: {val_acc:.3f}")
# Evaluate on test set with progress bar
_, _, test_preds = evaluate(model, test_loader, show_progress=True)
submission = pd.DataFrame({
"Id": list(range(len(test_preds))),
"Predicted": test_preds
})
submission_file = f"{name}_CIFAR10_test_predictions.csv"
submission.to_csv(submission_file, index=False)
print(f"Test predictions saved to {submission_file}")