An end-to-end deep learning portfolio project that trains, evaluates, and compares multiple architectures on the CIFAR-10 dataset, demonstrating the practical impact of transfer learning over a custom CNN baseline — and packaging the results into a live interactive demo.
This project goes beyond model training. It includes augmentation pipelines, cosine annealing scheduling, progressive unfreezing, INT8 quantisation experiments (notebook), Grad-CAM interpretability visualisations (CLI + notebook), CLI inference tools, and a Gradio demo deployed on Hugging Face Spaces — all documented in a structured Jupyter notebook.
📓 Explore the Notebook · 🚀 Live Demo · 📊 Key Results
How much does a pretrained backbone actually help compared to training from scratch when both models share the same training setup?
A common assumption in deep learning is that transfer learning always wins — but by how much, and under what conditions? This project answers that question with a controlled comparison: the same dataset, optimiser, learning-rate schedule, epoch budget, and augmentation pipeline across all models, with architecture and pretraining strategy as the only variables.
The results are relevant to:
- Model selection in resource-constrained and edge-deployment environments
- Training efficiency when labelled data or compute budget is limited
- Deployment strategy when balancing latency, model size, and accuracy
This isn't just a training script — it's an end-to-end applied ML workflow:
- Controlled experimentation — one dataset, optimiser, schedule, and augmentation pipeline held constant across five architectures, isolating architecture and pretraining as the only variables.
- Transfer learning impact, quantified — a from-scratch CNN vs. two frozen-backbone ImageNet models, with the accuracy/parameter trade-off measured, not asserted.
- Evaluation beyond top-1 accuracy — confusion-pair analysis, per-class breakdowns, and confidence calibration on the full 10,000-image test set.
- Interpretability — Grad-CAM visualisations (CLI + notebook) showing where each model is looking when it makes a prediction.
- Deployment — a working Gradio app on Hugging Face Spaces that loads weights from the Hub at runtime, with a custom domain in front of it.
- Engineering hygiene — a 79-test Pytest suite, a single source-of-truth benchmark module (
benchmark_data.py), and CLI tooling for reproducible inference.
╔══════════════════════════════════════════════════════════════════════════════╗
║ 🧠 3 deployed models in live demo · 5 architectures explored in notebook ║
║ 📈 Full training pipeline with cosine annealing and progressive unfreezing ║
║ 🎲 Advanced augmentation: RandomCrop, CutOut, MixUp, CutMix ║
║ 🔬 Grad-CAM interpretability via CLI + notebook (not in the live app UI) ║
║ ⚡ INT8 dynamic quantisation experiments (notebook only) ║
║ 📊 Confusion matrices, training curves, and efficiency benchmarks ║
║ 🖥️ Gradio demo on HF Spaces · weights served from HF Hub at runtime ║
║ 🛠️ CLI inference for single image, batch, and full test-set evaluation ║
╚══════════════════════════════════════════════════════════════════════════════╝
| Metric | Custom CNN | MobileNetV2 | ResNet-18 | Winner |
|---|---|---|---|---|
| Test Accuracy | 48.40% | 86.91% | 87.48% | 🏆 ResNet-18 |
| Trainable Params | 2,462,282 | 12,810 | 5,130 | 🏆 ResNet-18 |
| Model Size | 9.42 MB | 8.76 MB | 44.80 MB | 🏆 MobileNetV2 |
| CPU Latency (batch 1) | 1.38 ms | 17.22 ms | 9.80 ms | 🏆 Custom CNN |
| Throughput | ~724 FPS | ~58 FPS | ~102 FPS | 🏆 Custom CNN |
Accuracy results were evaluated on the 10,000-image CIFAR-10 test set. Latency and throughput figures are hardware-dependent and should be interpreted as project benchmark results rather than universal model performance. ResNet-18 retrained and verified 2026-04-18 via cached-features linear probe.
Key finding: In this experiment, ResNet-18 achieved 87.48% accuracy with just 0.2% of the Custom CNN's trainable parameters — a +39.1 percentage-point lift for a 480× reduction in trainable weights. MobileNetV2 landed within a fraction of a point at 86.91% with a different parameter/latency trade-off.
Epoch Custom CNN (Val Acc) MobileNetV2 (Val Acc) ResNet-18 (Val Acc)
───── ──────────────────── ───────────────────── ───────────────────
1 21.0% 85.88% 84.21%
2 27.8% 86.80% 85.64%
3 32.4% 86.91% 86.27%
… … … …
15 48.40% 86.91% 87.16%
30 — — 87.48%
Both transfer-learning models reach strong accuracy within 1–3 epochs because their frozen backbones already encode powerful ImageNet features. The Custom CNN is still improving across the full 15-epoch budget — highlighting the data efficiency of pretrained representations.
| Layer | Technology |
|---|---|
| Framework | PyTorch 2.1+ |
| Deployed Models | torchvision (MobileNetV2, ResNet-18) + Custom CNN |
| Notebook-only Models | EfficientNet-B0, ViT (Small, custom implementation) — explored in notebook, not deployed |
| Dataset | CIFAR-10 — 60K images, 10 classes |
| Evaluation | scikit-learn (classification reports, confusion matrices) |
| Visualization | Matplotlib (deployed) · Seaborn (notebook) |
| Interpretability | Grad-CAM with PyTorch hooks — CLI (gradcam.py) + notebook only |
| Demo App | Gradio ≥5.29 on Hugging Face Spaces |
| Model Weights | Hugging Face Hub (mrpouyaalavi/cifar10-models) |
| Hardware | Auto-detected: CUDA / Apple Silicon MPS / CPU |
| Feature | Status |
|---|---|
| Custom CNN, MobileNetV2, ResNet-18 training & inference | ✅ Deployed (live demo + CLI) |
| EfficientNet-B0, ViT-Small | 📓 Notebook-only (not deployed) |
| RandomCrop, HFlip, CutOut, MixUp, CutMix augmentation | 📓 Notebook-only training pipeline |
| Cosine annealing LR schedule | 📓 Notebook-only |
| Progressive unfreezing (MobileNetV2) | 🧪 Experiment (notebook, Section 6) |
| AMP (mixed precision) support | 📓 Notebook-only |
| Grad-CAM interpretability | 🛠️ CLI + notebook (gradcam.py) — not in the Gradio app UI |
| INT8 dynamic quantisation | 🧪 Experiment (notebook, Section 13) |
| CLI single-image / batch / full test-set inference | ✅ Deployed (predict.py) |
| Hugging Face Hub runtime weight loading | ✅ Deployed (app + CLI) |
Optimiser : Adam
Learning Rate : 0.001 (with Cosine Annealing decay)
Weight Decay : 1e-4
Batch Size : 128
Epochs : 15 (ResNet-18 linear probe: 30)
Loss Function : CrossEntropyLoss
Training Set : 50,000 images
Test Set : 10,000 images
Augmentation : RandomCrop(32,4), HFlip, CutOut(16), MixUp, CutMix
Random Seed : 42Custom CNN — 4-Block Design (trained from scratch)
Input (3 × 32 × 32)
├── Block 1: Conv(3→64)×2 → BN → ReLU → MaxPool → Dropout(0.25)
├── Block 2: Conv(64→128)×2 → BN → ReLU → MaxPool → Dropout(0.25)
├── Block 3: Conv(128→256)×2 → BN → ReLU → MaxPool → Dropout(0.25)
├── Block 4: Conv(256→512) → BN → ReLU → AdaptiveAvgPool
└── Flatten → Dropout(0.5) → FC(512→256) → ReLU → Dropout(0.5) → FC(256→10)
MobileNetV2 — frozen ImageNet backbone + Dropout(0.2) → Linear(1280→10)
ResNet-18 — frozen ImageNet backbone + Linear(512→10) (5,130 trainable params)
| Confusion Pair | Custom CNN | MobileNetV2 | Reduction | Root Cause |
|---|---|---|---|---|
| 🚚 Truck ↔ 🚗 Automobile | 432 | 97 | 78% | Similar vehicle structure at 32×32 |
| 🚢 Ship ↔ |
375 | 83 | 78% | Shared background cues |
| 🐱 Cat ↔ 🐕 Dog | 333 | 243 | 27% | Fine-grained mammal similarity |
| 🐴 Horse ↔ 🐕 Dog | 293 | 68 | 77% | Quadruped shape overlap |
| 🐦 Bird ↔ 🦌 Deer | 180 | 78 | 57% | Challenging low-resolution silhouettes |
| # | Section | Description |
|---|---|---|
| 1 | Environment & Configuration | Seed setup, device detection, hyperparameter config |
| 2 | Data Preparation & Augmentation | Dataset loading, RandomCrop/HFlip/CutOut, MixUp & CutMix |
| 3 | Model Architectures | Custom CNN, MobileNetV2, ResNet-18, EfficientNet-B0, ViT (Small) |
| 4 | Training Pipeline | Unified loop with cosine annealing and AMP support |
| 5 | Train All Models | Controlled comparisons across all five architectures |
| 6 | Progressive Unfreezing | MobileNetV2 backbone fine-tuning schedule |
| 7 | Test Set Evaluation | Full test-set accuracy and class-level metrics |
| 8 | Confusion Matrices | Side-by-side error analysis |
| 9 | Training Curves & LR Schedule | Loss, accuracy, and LR schedule visualisation |
| 10 | Error Analysis | Misclassification deep-dive |
| 11 | Efficiency & Deployment Analysis | Parameters, size, latency, and throughput |
| 12 | Model Quantization (INT8) | Dynamic quantisation experiments |
| 13 | Save Experiment Artifacts | Export config, results, and metadata |
| 14 | Final Summary & Conclusions | Consolidated findings across all models |
Released under the MIT License — see LICENSE for details.
| Name | Role |
|---|---|
| Pouya Alavi Naeini | Lead — ML pipeline, deployment, Gradio app |
app.py Gradio demo — HF Spaces entry point
model_utils.py Shared model architectures & inference
benchmark_data.py Canonical benchmark metrics (single source of truth)
predict.py CLI inference tools
gradcam.py Grad-CAM visualisations (CLI only)
cifar10 image classification.ipynb Main 14-section notebook
scripts/ Retraining & measurement scripts
retrain_custom_cnn.py
retrain_mobilenetv2.py
retrain_resnet18.py
retrain_resnet18_fast.py Cached-features linear probe (fast retraining)
measure_model.py
tests/ Pytest unit & integration tests (79 tests)
conftest.py test_models.py test_inference.py test_preprocessing.py
test_gradcam.py test_benchmark_data.py test_checkpoint_remap.py test_device.py
results/ Training results, confusion matrices, metadata
assets/ README screenshots and favicon
examples/ Example CIFAR-10 images for the live demo
artifacts/ Saved run configuration (run_config.json)
requirements.txt HF Spaces / Gradio dependencies
requirements-dev.txt Development dependencies (adds pytest on top of requirements.txt)
runtime.txt Python version pin
pytest.ini Pytest configuration
data/(CIFAR-10 raw files) andcheckpoints/(local.pthfiles) are git-ignored — the dataset auto-downloads via torchvision on first run, and deployed model weights are hosted on Hugging Face Hub and downloaded automatically at runtime. No binaries are committed to this repo.
- Python
3.11(as specified inruntime.txt) - pip or conda
- GPU recommended but not required — CPU works fine for inference
# Clone and install
git clone https://github.com/mrpouyaalavi/CIFAR-10-Image-Classification.git
cd CIFAR-10-Image-Classification
python -m venv .venv
source .venv/bin/activate # macOS / Linux
# .venv\Scripts\activate # Windows
pip install -r requirements.txtjupyter notebook "cifar10 image classification.ipynb"
# CIFAR-10 dataset downloads automatically on first run via torchvisionpython predict.py --test-samples 10 --model all
python predict.py --image path/to/image.png --model mobilenet
python predict.py --image-dir path/to/images/ --model all --save results/predictions.pngCLI-only (gradcam.py supports custom_cnn, mobilenet, or both — ResNet-18 is not currently wired up in this script). Not available inside the Gradio app UI.
python gradcam.py --model both --num-images 6
python gradcam.py --model both --image-index 0 42 100 --save results/gradcam/pip install -r requirements-dev.txt
pytest -q # 79 tests| Document | Path |
|---|---|
| Benchmark metrics (single source of truth) | benchmark_data.py |
| Training metadata & retrain history | results/training_metadata.json |
| ResNet-18 training history | results/resnet18_training_history.json |
| Main notebook | cifar10 image classification.ipynb |
| Live demo | Hugging Face Spaces |
| Model weights | HF Hub — mrpouyaalavi/cifar10-models |
- CIFAR-10 is low-resolution (32×32) and dataset-specific. Results here don't generalise to arbitrary real-world computer vision tasks, higher-resolution imagery, or open-set classification.
- Latency and throughput are hardware-dependent. All CPU timings were measured on Apple Silicon (M-series); numbers will differ on other CPUs/GPUs and should be read as project benchmarks, not universal figures.
- Transfer learning relies on ImageNet pretraining. MobileNetV2 and ResNet-18 inherit whatever biases and coverage gaps exist in ImageNet-1K; the accuracy gains reported here are conditional on that pretraining being available.
- The Gradio demo is a portfolio/educational artifact, not a production computer-vision deployment — there's no batching, rate limiting, monitoring, or adversarial-input handling.
- The custom domain (
cifar10.pouyaalavi.dev) is a DNS alias for the Hugging Face Space and depends on the Space container staying awake; if the Space is asleep or down, the custom domain will be unavailable too. - Grad-CAM and INT8 quantisation are not part of the deployed app — they're available via CLI (
gradcam.py) or in the notebook only.
Built with the support of the open-source community. This project benefits from:
- PyTorch — Deep learning framework and pretrained model weights.
- Hugging Face — Model hosting and Spaces deployment infrastructure.
- Gradio — Interactive demo framework.
> Target : Pouya Alavi Naeini — Software Engineer | Applied AI/ML
> University : Macquarie University, Sydney, NSW
> Major : B.IT — Artificial Intelligence & Web/App Development
> Status : [●] ONLINE — open to grad & junior opportunities
CIFAR-10 Image Classification is an independent, open-source portfolio project.

