flower-classifier / efficientnetv2-s-readme.md
bengid's picture
Upload efficientnetv2-s-readme.md with huggingface_hub
d08d3b7 verified
|
Raw
History Blame Contribute Delete
8.16 kB
---
base_model: torchvision/efficientnet_v2_s (IMAGENET1K_V1)
license: apache-2.0
library_name: pytorch
pipeline_tag: image-classification
tags:
- image-classification
- flowers
- oxford-102
- torchvision
- efficientnet
- transfer-learning
metrics:
- accuracy
- f1
model-index:
- name: EfficientNetV2-S Flower Classifier
results:
- task:
type: image-classification
dataset:
name: Oxford-102 Flowers
type: oxford-102-flowers
split: validation
metrics:
- type: accuracy
value: 0.9996511340141296
- type: f1
value: 0.9994719624519348
---
# EfficientNetV2-S Flower Classifier
Fine-tuned [`torchvision.models.efficientnet_v2_s`](https://docs.pytorch.org/vision/main/models/efficientnetv2.html) (ImageNet-1K pretrained) for 102-class flower classification on the Oxford-102 Flowers dataset, with the full backbone unfrozen during fine-tuning. Achieves **0.9997 accuracy / 0.9995 F1** on the validation split.
**Recommended when** you need near-best accuracy at a fraction of the size and latency β€” the default choice for serving. At ~82MB and ~30ms mean latency it is ~4x smaller and ~3x faster than [ViT-B/16 Flower Classifier](vit-b16-readme.md) for a ~0.05 percentage-point accuracy difference.
## Usage
```python
import torch
from huggingface_hub import hf_hub_download
from torchvision import models
weights_path = hf_hub_download(repo_id="bengid/flower-classifier", filename="ft_EfficientNetV2-S.pth")
model = models.efficientnet_v2_s(weights=None)
model.classifier[1] = torch.nn.Linear(model.classifier[1].in_features, 102)
model.load_state_dict(torch.load(weights_path, map_location="cpu", weights_only=True))
model.eval()
# preprocessing: resize(256) -> center-crop(224) -> normalize with dataset mean/std
# see src/utils.py:get_transforms() in the training repo for the exact pipeline
```
## Training Data
[Oxford-102 Flowers](https://www.robots.ox.ac.uk/~vgg/data/flowers/102/) β€” 8,189 images across 102 flower species, downloaded via `torchvision.datasets.Flowers102`. Class-weighted `CrossEntropyLoss` was used to correct for the dataset's uneven per-class image counts.
## Training Procedure
Single-stage fine-tune with a **two-phase backbone unfreeze** callback (`BackboneFinetuning`): the EfficientNetV2 backbone starts frozen (only the classification head trains), then unfreezes at a fixed epoch with its own, lower learning rate and a separate parameter group β€” unlike this project's original (v1) EfficientNet-B0 model, which only ever unfroze its *last 3 backbone blocks*.
### Hyperparameters
| Parameter | Value |
|---|---|
| Optimizer | AdamW |
| LR scheduler | Cosine annealing (T_max=30, eta_min=1e-06) |
| Head LR (before unfreeze) | 1e-3 |
| Head LR (after unfreeze) | 1e-3 |
| Backbone LR (after unfreeze) | 1e-5 |
| Unfreeze epoch | 5 |
| Max epochs | 30 |
| Batch size | 32 |
| Effective batch size | 32 |
| Gradient accumulation | 1 |
| Precision | 16-mixed |
| Weight decay | 0.01 |
| Early stopping patience | 5 |
## Evaluation
| Metric | Value |
|---|---|
| **Accuracy** | **0.9997** |
| **F1** | **0.9995** |
| Parameters | 20,308,150 |
| Model size | 81.8 MB |
| Checkpoint size | 245.0 MB |
| Mean latency | 29.6 ms |
| p95 latency | 30.9 ms |
Latency measured on {} at batch size 1.
## Strengths & Weaknesses
**Strengths:**
- Within 0.05pp of ViT-B/16's accuracy and F1 while being ~4x smaller (81.8MB vs 343.5MB) and ~3x faster (29.6ms vs 86.5ms mean latency) β€” the best accuracy-per-cost tradeoff of the four models trained.
- Convolutional inductive bias generalizes well from a modest fine-tuning dataset (~8k images), needing less data than attention-based architectures to reach its ceiling.
- Small enough to fit comfortably in the Docker image and serve cheaply (this is the architecture family the v2 API's original `helpers.py` defaulted to).
**Weaknesses:**
- Marginally lower accuracy/F1 than ViT-B/16, though the gap is negligible in practice (both are within noise of a perfect validation score).
- EfficientNetV2's published training recipe (progressive resizing, adaptive regularization) is more sensitive to schedule/hyperparameter choices than a straightforward ViT fine-tune; deviating far from a tuned recipe can cost more accuracy than it would for ViT.
- Like the ViT model, still requires unfreezing the *entire* backbone to reach these numbers β€” the smaller, cheaper EfficientNet-B0 v1 model that only partially unfroze its backbone topped out well below 93% for this reason.
## Limitations
- **Closed-set, single-label**: trained on exactly 102 Oxford flower species; will confidently misclassify any other flower species, non-flower image, or multi-flower image into one of the 102 known classes β€” there is no out-of-distribution rejection.
- **Fixed input pipeline**: expects a 224Γ—224 center-cropped, normalized input (resize-then-crop). Unusual aspect ratios or off-center subjects can crop the flower out of frame.
- **No adversarial robustness or calibration guarantees** β€” confidence scores are not calibrated probabilities.
- Reported metrics are on the Oxford-102 validation split; real-world images (different lighting, backgrounds, camera quality) may perform worse.
## Intended Use
**Intended uses:**
- Flower species identification within the 102 Oxford-102 classes (gardening/botany apps, educational tools, dataset labeling).
- Default backend model for this project's v2 `/classify` API endpoint β€” chosen for its accuracy/latency/size balance.
**Out-of-scope uses:**
- General-purpose plant, object, or scene classification outside the 102 trained species.
- Medical, toxicity, or safety-related plant identification.
- Any use where a wrong classification has safety or financial consequences without human review.
## Model Comparison
This project trained four models in total, in this order:
| Model | Val Acc | Val F1 | Params | Size (MB) | Best For |
|---|---|---|---|---|---|
| [SimpleCNN (scratch)](https://huggingface.co/bengid/flower-classifier/blob/main/flower_model_weights.pth) | ~0.63 | {} | {} | {} | historical baseline only |
| [EfficientNet-B0 (v1, partial unfreeze)](https://huggingface.co/bengid/flower-classifier/blob/main/ft_EfficientNet-B0.pth) | >0.93 | {} | {} | {} | historical baseline only |
| **EfficientNetV2-S (this model)** | **0.9997** | **0.9995** | 20,308,150 | 81.8 | efficient production serving |
| [ViT-B/16](https://huggingface.co/bengid/flower-classifier/blob/main/ft_ViT-B16.pth) | 1.0 | 1.0 | 85,877,094 | 343.5 | maximum accuracy |
### Why the earlier models underperformed
- **SimpleCNN (scratch)** was trained from randomly initialized weights with no ImageNet pretraining, on a 6-block custom CNN β€” too little capacity and too little prior visual knowledge to learn 102 fine-grained flower classes from ~8k images alone.
- **EfficientNet-B0 (v1)** started from ImageNet-pretrained weights but only ever unfroze its *last 3 backbone blocks* during fine-tuning (see this project's root `README.md`, "Fine-Tuning EfficientNet-B0" section, for the original two-stage recipe) β€” the earlier backbone layers, tuned for general ImageNet features, never adapted to flower-specific low/mid-level features, capping accuracy well below the fully-unfrozen v2 models.
- Both **EfficientNetV2-S** (this model) and **ViT-B/16** unfreeze the *entire* backbone during fine-tuning, which is the main driver of the jump from ~93% to ~99.97-100% accuracy.
## License
Apache 2.0, consistent with this project's license.
## Citation
**Base model (EfficientNetV2):**
```bibtex
@inproceedings{tan2021efficientnetv2,
title={EfficientNetV2: Smaller Models and Faster Training},
author={Tan, Mingxing and Le, Quoc V},
booktitle={International Conference on Machine Learning},
year={2021}
}
```
**Training dataset:**
```bibtex
@inproceedings{nilsback2008automated,
title={Automated flower classification over a large number of classes},
author={Nilsback, Maria-Elena and Zisserman, Andrew},
booktitle={2008 Sixth Indian Conference on Computer Vision, Graphics \& Image Processing},
pages={722--729},
year={2008},
organization={IEEE}
}
```