Downloads · 30 days
0
Abhi542Dev/cropguard-models
cropguard-models is a image classification model from Abhi542Dev. Use it when you need a label for an image. The card lists the license as cc-by-sa-4.0.
ResNet50 fine-tuned on PlantVillage, exported to ONNX and dynamically quantised to INT8 for CPU-only serving. Part of CropGuard, an end-to-end MLOps pipeline.
Downloads · 30 days
0
Access
Public
Updated Aug 6, 2026
Repo size
118 MB
Likes
0
Public
Click a slice to open those files.
.onnx118 MB · 100%
From the Hugging Face model README
ResNet50 fine-tuned on PlantVillage, exported to ONNX and dynamically quantised to INT8 for CPU-only serving. Part of CropGuard, an end-to-end MLOps pipeline.
| Model | Accuracy | Macro-F1 | Note |
|---|---|---|---|
| fp32 | 0.9911 | 0.9865 | reference |
| INT8 (dynamic) | not evaluated | not evaluated | not served - see below |
Macro-F1 is the metric to read here, not accuracy: the dataset is imbalanced ~36x, so accuracy is dominated by the largest classes.
cropguard.onnx (fp32) is the model that serves traffic. cropguard.static-int8.onnx is
published alongside it for comparison; the dynamic INT8 build is deliberately not
published.
Dynamic quantization was the wrong tool here. quantize_dynamic rewrites every Conv into
ConvInteger, which ONNX Runtime's CPU backend has no optimized kernel for: measured on an
Intel Alder Lake CPU it ran at 1567 ms/image against 19 ms for fp32, a 75x regression in
exchange for 4x less disk. It suits MatMul-dominated models (Transformers, RNNs), not CNNs.
Static quantization with a calibration set emits the optimized QLinearConv instead, and is
78 ms/image - 20x faster than dynamic and accuracy-neutral (0.9897 vs 0.9893 on a 3,000
image subset, 9 disagreements). It is still 3.2x slower than fp32 on the machine it was
measured on, and the reason is hardware rather than the graph: that CPU has no VNNI
instructions, without which ONNX Runtime emulates each INT8 multiply-accumulate in several
AVX2 instructions. Server CPUs usually do have VNNI, where the ranking may reverse - which is
exactly why both files are here to be benchmarked on whatever hardware you are running.
PlantVillage contains 54,305 images of only ~7,600 distinct physical leaves - roughly 7 photographs of each. A standard per-image stratified split scatters those near-duplicates across train and test, so a model can score well by memorising leaf identity rather than learning disease morphology. Measured on this dataset, a naive split leaves 74.2% of test images sharing a leaf with training.
This model was trained on a leaf-grouped split instead:
| Naive stratified | Grouped (used here) | |
|---|---|---|
| test images sharing a leaf with train | 74.2% | 0.0% |
| train / val / test | - | 38,008 / 8,172 / 8,125 |
So the accuracy above is measured on a holdout with no leaf overlap. Note that it is not much lower than typically published PlantVillage figures - the honest reading is that this dataset is genuinely easy, not that leakage was inflating everything.
Identifying disease on single leaves photographed against a plain background, matching the PlantVillage capture protocol.
Potato___healthy) has 24. A recall of 0.833 there is 4 mistakes, and
its confidence interval spans roughly +/-15 points. Do not read those per-class numbers as
precise.uncertainty is predictive entropy, not epistemic uncertainty. It cannot distinguish an
ambiguous input from one far outside the training distribution - an out-of-distribution
image can produce confidently wrong output with low entropy.ResNet50 (timm, ImageNet-pretrained), 224x224, batch 64, AdamW (lr 3e-4, weight decay 1e-4),
cosine schedule, label smoothing 0.1, medium augmentation, 12 epochs, mixed precision.
Checkpoint selected on val_f1_macro.
import numpy as np, onnxruntime as ort
from huggingface_hub import hf_hub_download
path = hf_hub_download("Abhi542Dev/cropguard-models", "cropguard.onnx")
session = ort.InferenceSession(path, providers=["CPUExecutionProvider"])
# Preprocessing must match training: resize short side to 256, centre-crop 224,
# scale to [0,1], normalise with ImageNet mean/std, NCHW.
logits = session.run(["logits"], {"input": batch})[0]
cropguard.serving.model_loader in the repo implements exactly that preprocessing.
Dataset: Mohanty, Hughes & Salathe (2016), Using deep learning for image-based plant disease detection, Frontiers in Plant Science.