A deep learning image classification application that identifies 102 species of flowers using transfer learning with a fine-tuned ResNet50 backbone. Built as part of the Udacity AI Programming with Python Nanodegree.
This project trains a convolutional neural network to classify flower images into 102 categories. It leverages a pretrained ResNet50 model from torchvision, replaces its fully connected head with a custom classifier, and fine-tunes it on the Oxford 102 Flower Dataset.
The project is split into two parts:
- Jupyter Notebook — interactive development, training, and sanity checks
- Command-line scripts (
train.py/predict.py) — production-ready training and inference pipelines
├── Image Classifier Project.ipynb # Interactive notebook (development)
├── train.py # CLI training script
├── predict.py # CLI inference script
├── cat_to_name.json # Mapping of class labels → flower names (102 classes)
├── Flowers.png # Sample output visualization
└── README.md
Oxford 102 Flower Dataset — 102 flower categories with train, validation, and test splits.
Download via:
wget 'https://s3.amazonaws.com/content.udacity-data.com/nd089/flower_data.tar.gz'
mkdir flowers && tar -xzf flower_data.tar.gz -C flowersExpected directory structure:
flowers/
├── train/
├── valid/
└── test/
| Component | Detail |
|---|---|
| Base model | ResNet50 (pretrained on ImageNet) |
| Frozen layers | All convolutional layers |
| Custom head | Linear(2048→512) → ReLU → Dropout(0.2) → Linear(512→102) → LogSoftmax |
| Output classes | 102 flower species |
| Split | Transforms Applied |
|---|---|
| Train | RandomRotation(30°), RandomResizedCrop(224), RandomHorizontalFlip, Normalize |
| Validation | Resize(255), CenterCrop(224), Normalize |
| Test | Resize(255), CenterCrop(224), Normalize |
Normalization uses ImageNet mean [0.485, 0.456, 0.406] and std [0.229, 0.224, 0.225].
pip install torch torchvision pillow numpy matplotlib pandaspython train.py \
--data_dir flowers \
--arch resnet50 \
--epochs 4 \
--lr 0.003 \
--hidden_units 512 \
--dropout 0.2 \
--gpu \
--checkpoint_final checkpoint_final.pth| Argument | Default | Description |
|---|---|---|
--data_dir |
flowers |
Path to dataset |
--arch |
resnet50 |
Model architecture |
--epochs |
4 |
Number of training epochs |
--lr |
0.003 |
Learning rate |
--hidden_units |
512 |
Hidden layer size |
--dropout |
0.2 |
Dropout probability |
--gpu |
enabled | Use GPU if available |
--checkpoint_final |
./checkpoint_final.pth |
Path to save checkpoint |
python predict.py \
--input_img flowers/test/1/image_04938.jpg \
--checkpoint_final checkpoint_final.pth \
--top_k 5 \
--cat_names cat_to_name.json \
--gpu| Argument | Default | Description |
|---|---|---|
--input_img |
sample test image | Path to input image |
--checkpoint_final |
./checkpoint_final.pth |
Saved model checkpoint |
--top_k |
5 |
Number of top predictions to return |
--cat_names |
cat_to_name.json |
Label-to-name mapping file |
--gpu |
enabled | Use GPU if available |
- Load and transform dataset using
torchvision.datasets.ImageFolder - Freeze all ResNet50 convolutional weights
- Attach custom fully connected classifier head
- Train with Adam optimizer and NLLLoss criterion
- Log training loss, validation loss, and validation accuracy every 10 steps
- Evaluate final accuracy on held-out test set
- Save full model checkpoint (architecture + weights + class mapping)
The saved checkpoint contains:
{
'input_size': 2048,
'output_size': 102,
'arch': model,
'fc': classifier,
'state_dict': model.state_dict(),
'class_to_idx': model.class_to_idx
}Load it back with:
checkpoint = torch.load('checkpoint_final.pth')
model = checkpoint['arch']
model.fc = checkpoint['fc']
model.load_state_dict(checkpoint['state_dict'])
model.class_to_idx = checkpoint['class_to_idx']process_image()— resizes, center-crops to 224×224, normalizes to ImageNet stats, returns a NumPy arraypredict()— runs the model in eval mode, returns top-K class probabilities and labels- Sanity check — bar chart of top-5 predictions displayed alongside the input flower image
| Tool | Purpose |
|---|---|
PyTorch |
Model training and inference |
torchvision |
Pretrained ResNet50, transforms, ImageFolder |
PIL / Pillow |
Image loading and preprocessing |
NumPy |
Array operations |
matplotlib |
Visualization of predictions |
argparse |
CLI argument parsing |
- Only
resnet50is wired up intrain.py;resnet101/resnet152were tested but excluded due to longer training time - GPU acceleration (CUDA) is automatically used when available and falls back to CPU
- The full model object is saved in the checkpoint (not just
state_dict), which makes it portable but ties it to the original class structure - For production use, consider exporting with
torch.jit.scriptor ONNX for framework-agnostic deployment
Built as a submission for the Udacity AI Programming with Python Nanodegree — Neural Networks & PyTorch module.
