transfer-learning-resnet / project_problem.md
Ashutosh
Upload folder using huggingface_hub
e980ac5 verified
|
Raw
History Blame Contribute Delete
9.43 kB

Project 09 β€” Transfer Learning & Fine-tuning

Level: Intermediate | Dataset: Oxford Flowers102 (torchvision) | Framework: PyTorch


Objective

Fine-tune a pretrained ResNet-50 on a 102-class flower dataset. Cover: feature extraction vs fine-tuning, layer freezing, differential LR, Optuna HPT, ONNX export.


Project Structure

09_transfer_learning/
β”œβ”€β”€ notebooks/
β”‚   β”œβ”€β”€ 01_data_setup.ipynb
β”‚   β”œβ”€β”€ 02_feature_extraction.ipynb
β”‚   β”œβ”€β”€ 03_finetuning.ipynb
β”‚   └── 04_optuna_hpt.ipynb
β”œβ”€β”€ data/
β”œβ”€β”€ models/
β”‚   β”œβ”€β”€ feature_extract.pkl
β”‚   β”œβ”€β”€ finetuned.pkl
β”‚   └── best_optuna.pkl
β”œβ”€β”€ charts/
β”œβ”€β”€ path_utils.py
β”œβ”€β”€ dashboard_core.py
└── app.py

Notebook 01 β€” Data Setup (01_data_setup.ipynb)

STOP 1 β€” Load Flowers102

  • torchvision.datasets.Flowers102(download=True)
  • 102 categories, 8189 total images, ~80 per class
  • Visualize 3 images per class for 6 classes
  • Agent stops here. Explain:
    • Why Flowers102 is a good transfer learning benchmark (small dataset, many classes)
    • The fundamental premise of transfer learning: ImageNet features generalize
    • Why building a CNN from scratch on 8189 images would fail (not enough data)
    • What ImageNet is: 1.2M images, 1000 classes β€” what ResNet was trained on
  • Wait for user confirmation before continuing

STOP 2 β€” ImageNet Normalization

  • Always use ImageNet mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225]
  • Resize to 224Γ—224 (ResNet input requirement)
  • Train augmentations: RandomResizedCrop(224), RandomHorizontalFlip, ColorJitter
  • Val/Test: Resize(256), CenterCrop(224)
  • Agent stops here. Explain:
    • Why we MUST use ImageNet normalization with pretrained models
    • What happens if we use different normalization: activations are in wrong range, pretrained features break
    • Why 224Γ—224: ResNet was designed for this input size
    • What RandomResizedCrop does vs CenterCrop
  • Wait for confirmation

STOP 3 β€” DataLoader Setup

  • batch_size=32, num_workers=4, pin_memory=True
  • Check class balance: Flowers102 is roughly balanced
  • Agent stops here. Explain:
    • Why balanced datasets are rare in practice
    • What to do when class counts vary in a 102-class problem
  • Wait for confirmation

Notebook 02 β€” Feature Extraction (02_feature_extraction.ipynb)

STOP 4 β€” Load Pretrained ResNet-50

import torchvision.models as models
model = models.resnet50(weights='IMAGENET1K_V1')
print(model)  # understand the architecture
  • Print total parameters
  • Agent stops here. Explain:
    • ResNet-50 architecture overview: stem, 4 layer groups, global avg pool, FC
    • What residual connections are: skip connections that allow gradients to flow directly
    • Why ResNet solved the vanishing gradient problem for deep nets (50+ layers)
    • What IMAGENET1K_V1 weights are: trained on 1.2M ImageNet images
    • Total params: ~25M β€” why we don't want to train all of them on 8k images
  • Wait for confirmation

STOP 5 β€” Freeze All Layers

for param in model.parameters():
    param.requires_grad = False
model.fc = nn.Linear(2048, 102)  # replace final FC only
  • Verify: only model.fc params are trainable
  • Print trainable vs frozen parameter counts
  • Agent stops here. Explain:
    • What requires_grad=False does: no gradient computed, no weight update
    • Why we freeze: use ResNet as a fixed feature extractor
    • Why only replace model.fc: all other layers produce ImageNet features we reuse
    • What 2048 is: ResNet-50's global avg pool output dimension
    • Feature extraction: fast (only FC trains), lower accuracy
  • Wait for confirmation

STOP 6 β€” Feature Extraction Training

  • Train ONLY the new FC layer
  • 20 epochs, Adam lr=0.001
  • Expected accuracy: ~70-75% (fast to converge)
  • Agent stops here. Explain:
    • Why feature extraction trains so fast (only 102*2048 + 102 = 210k params update)
    • Why accuracy plateaus quickly (backbone frozen, can't adapt to flowers)
    • When feature extraction is enough vs when fine-tuning is needed
  • Wait for confirmation

Notebook 03 β€” Fine-tuning (03_finetuning.ipynb)

STOP 7 β€” Selective Layer Unfreezing

# Unfreeze only last 2 ResNet layer groups + FC
for param in model.layer3.parameters():
    param.requires_grad = True
for param in model.layer4.parameters():
    param.requires_grad = True
  • Agent stops here. Explain:
    • Why we don't unfreeze ALL layers: early layers (edges, textures) are universal β†’ don't need updating
    • Why we unfreeze later layers: they encode high-level features that are ImageNet-specific
    • The general rule: the more domain-specific your data, the more layers to unfreeze
    • Risk of unfreezing too many layers on small data: catastrophic forgetting
  • Wait for confirmation

STOP 8 β€” Differential Learning Rates

optimizer = Adam([
    {'params': model.layer3.parameters(), 'lr': 1e-5},
    {'params': model.layer4.parameters(), 'lr': 1e-4},
    {'params': model.fc.parameters(),     'lr': 1e-3},
])
  • Agent stops here. Explain:
    • Why differential LR: pretrained layers need tiny updates (they're already good)
    • New FC needs larger LR (random initialization, needs to train fast)
    • The 10Γ— rule: each layer group gets ~10Γ— smaller LR than the one above it
    • This is the same trick used in ULMFiT (NLP) and discriminative fine-tuning
  • Wait for confirmation

STOP 9 β€” Fine-tuning Training Loop

  • 30 epochs, CosineAnnealingLR
  • Compare accuracy: feature extraction vs fine-tuning
  • Expected improvement: ~5-10% accuracy gain from fine-tuning
  • Agent stops here. Explain:
    • Why fine-tuning outperforms feature extraction: domain adaptation
    • The risk of fine-tuning without careful LR: destroying pretrained knowledge
    • What "catastrophic forgetting" looks like: accuracy spikes then crashes
    • How CosineAnnealing helps: prevents large late-epoch gradient updates on pretrained layers
  • Wait for confirmation

Notebook 04 β€” Optuna HPT (04_optuna_hpt.ipynb)

STOP 10 β€” Optuna Setup

import optuna

def objective(trial):
    lr_fc = trial.suggest_float('lr_fc', 1e-4, 1e-2, log=True)
    lr_backbone = trial.suggest_float('lr_backbone', 1e-6, 1e-4, log=True)
    dropout = trial.suggest_float('dropout', 0.2, 0.6)
    unfreeze_from = trial.suggest_categorical('unfreeze_from', ['layer3', 'layer4'])
    # build model, train 5 epochs, return val accuracy
    ...
    return val_accuracy

study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=20)
  • Agent stops here. Explain:
    • What Optuna is: Bayesian hyperparameter optimization framework
    • How suggest_float(log=True) works: searches in log space (better for LR)
    • What n_trials=20 means: 20 different hyperparameter combinations tried
    • What direction='maximize' means: we want highest val accuracy
    • Optuna vs grid search: smarter sampling (TPE algorithm), needs fewer trials
  • Wait for confirmation

STOP 11 β€” Optuna Visualization

  • optuna.visualization.plot_param_importances(study)
  • optuna.visualization.plot_optimization_history(study)
  • Print best trial params
  • Agent stops here. Explain:
    • How to read param importance: which HP matters most
    • What optimization history shows: does accuracy improve with more trials?
    • When to stop HPT: diminishing returns after ~20 trials for 4 params
  • Wait for confirmation

STOP 12 β€” Final Model with Best Params

  • Retrain with best Optuna params, full 30 epochs
  • Compare: feature extraction β†’ fine-tuning β†’ HPT fine-tuning accuracies
  • ONNX export of final model
  • Agent stops here. Explain:
    • The three-stage accuracy improvement and why each stage helps
    • Why ONNX export is important for production (as covered in Project 05)
    • Dynamic axes for variable batch size in ONNX
  • Wait for confirmation

STOP 13 β€” Confusion Matrix on 102 Classes

  • Compute test accuracy, per-class recall
  • Plot top-10 most confused class pairs
  • Agent stops here. Explain:
    • Why 102-class confusion matrix is unreadable as a full heatmap
    • How to extract most confused pairs: find off-diagonal cells with highest values
    • What visually similar flowers (e.g. roses, peonies) being confused means
    • How to improve: more data, larger model, specific augmentations
  • Wait for confirmation

dashboard_core.py

Functions:

  • load_model() β†’ model, class_names
  • predict_flower(pil_image) β†’ top-3 class predictions with confidence
  • get_training_comparison() β†’ 3 accuracy curves (feature extract, finetune, best HPT)
  • get_top_confused_pairs() β†’ list of (class_a, class_b, count)

app.py β€” Streamlit (~80 lines)

Sections:

  1. Upload flower image
  2. Show top-3 predictions with confidence bars
  3. Tab 1: Training comparison (3 curves on one chart)
  4. Tab 2: Top confused class pairs
  5. Tab 3: Optuna best params summary

Key Concepts Covered

  • ResNet-50 architecture and residual connections
  • Feature extraction vs fine-tuning
  • Layer freezing with requires_grad=False
  • Differential learning rates per layer group
  • Catastrophic forgetting prevention
  • Optuna Bayesian HPT (suggest_float log=True, n_trials)
  • 102-class confusion matrix analysis
  • Full transfer learning workflow