CIFAR-100 Image Classification — CNN & ResNet18
This repository contains two image classification models trained on the CIFAR-100 dataset: a Custom CNN built from scratch, and a ResNet18 model adapted via transfer learning.
📊 Model Results
| Model | Top-1 Accuracy | Top-5 Accuracy | Parameters | File Size |
|---|---|---|---|---|
| Custom CNN | 55.21% | 84.12% | ~2.1M | 5.57 MB |
| ResNet18 (Transfer Learning) | 71.13% | — | ~11.2M | 45 MB |
Independently verified: on the full CIFAR-100 test set (10,000 images), the ResNet18 model achieved 70.53% accuracy.
🗂️ About the Dataset
CIFAR-100 consists of 60,000 color images (32x32 pixels) across 100 classes: 50,000 training images and 10,000 test images, with 600 images per class.
🏗️ Model Architecture
Custom CNN
Input (3x32x32)
→ [Conv2D(32) + BatchNorm + ReLU] x2 → MaxPool → Dropout(0.25)
→ [Conv2D(64) + BatchNorm + ReLU] x2 → MaxPool → Dropout(0.3)
→ [Conv2D(128) + BatchNorm + ReLU] x2 → MaxPool → Dropout(0.4)
→ Flatten → Dense(512) → Dropout(0.5) → Dense(100)
ResNet18 (Adapted)
Based on a ResNet18 pretrained on ImageNet, adapted for small (32x32) images as follows:
- First convolutional layer changed from
7x7, stride=2to3x3, stride=1 - Initial
MaxPoollayer removed (replaced withnn.Identity()) - Final fully connected layer resized for 100 output classes
🚀 Usage (Inference)
import torch
import torch.nn as nn
from torchvision.models import resnet18
from huggingface_hub import hf_hub_download
# Download the model from Hugging Face
resnet_path = hf_hub_download(
repo_id="maqsudxo1ja/cifar100-cnn-resnet18",
filename="resnet18_cifar100.pth"
)
# Rebuild the architecture
model = resnet18(weights=None)
model.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
model.maxpool = nn.Identity()
model.fc = nn.Linear(model.fc.in_features, 100)
# Load the weights
model.load_state_dict(torch.load(resnet_path, map_location="cpu"))
model.eval()
Preprocessing
import torchvision.transforms as transforms
transform = transforms.Compose([
transforms.Resize((32, 32)),
transforms.ToTensor(),
transforms.Normalize((0.5071, 0.4865, 0.4409), (0.2673, 0.2564, 0.2762))
])
Full Inference Example
from PIL import Image
import torch
image = Image.open("image.jpg").convert("RGB")
input_tensor = transform(image).unsqueeze(0)
with torch.no_grad():
output = model(input_tensor)
probs = torch.softmax(output, dim=1)[0]
top5_prob, top5_idx = torch.topk(probs, 5)
# class names can be obtained via torchvision.datasets.CIFAR100(...).classes
for i in range(5):
print(f"{classes[top5_idx[i]]}: {top5_prob[i]*100:.2f}%")
🎯 Training Details
| Parameter | Value |
|---|---|
| Optimizer | Adam (weight_decay=1e-4) |
| Learning rate | 0.001 (with ReduceLROnPlateau) |
| Loss function | CrossEntropyLoss |
| Batch size | 128 |
| Data augmentation | RandomCrop, RandomHorizontalFlip |
| Early stopping | Patience = 5 epochs |
| Environment | Kaggle, GPU T4 x2 |
📁 Files in this Repository
cnn_cifar100.pth— weights of the Custom CNN trained from scratchresnet18_cifar100.pth— weights of the fine-tuned ResNet18 (transfer learning)
⚠️ Limitations
- The model only recognizes CIFAR-100's 100 classes (not general real-world objects)
- Optimized for small (32x32) images — higher-resolution images must be resized to 32x32 first
- Higher confusion is likely between visually similar classes (e.g., different animal species)
📄 License
MIT License