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 (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 for a ~0.05 percentage-point accuracy difference.
Usage
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 β 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.pydefaulted 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
/classifyAPI 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) | ~0.63 | {} | {} | {} | historical baseline only |
| EfficientNet-B0 (v1, partial unfreeze) | >0.93 | {} | {} | {} | historical baseline only |
| EfficientNetV2-S (this model) | 0.9997 | 0.9995 | 20,308,150 | 81.8 | efficient production serving |
| ViT-B/16 | 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):
@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:
@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}
}