← All Projects
Live Demo2024

Food vs. Not-Food Text Classifier

A DistilBERT text classifier built with a synthetic dataset from scratch, evaluated honestly, and benchmarked for batched-inference throughput.

DistilBERTHuggingFace TransformersHuggingFace DatasetsGradioPython

live demo

Food vs. Not-Food Text ClassifierOpen in HuggingFace ↗

About this project

The dataset doesn't come from an existing corpus - captions for 125 food items and 125 not-food items were synthetically generated via Mistral Chat, structured into a HuggingFace Dataset, and split 80/20 (200 train / 50 test). distilbert-base-uncased was fine-tuned via Trainer (lr=1e-4, batch size 32, 10 epochs). Validation accuracy reached 100% from epoch 1 - a result reported honestly rather than as an unqualified win, since a small, synthetically generated dataset with lexically distinct classes (food vocabulary rarely overlaps with household-object vocabulary) makes the task close to trivially separable. The more practically meaningful result is a batched-inference throughput benchmark: sequential prediction averaged 5.19ms/sample, while batched prediction held steady at roughly 0.8ms/sample from 250 up to 250,000 samples - a ~6.5x speedup that doesn't degrade at scale.

Technical details

Training used HuggingFace TrainingArguments with eval_strategy="epoch", save_strategy="epoch", and load_best_model_at_end=True, so the checkpoint retained for deployment is the best-performing one across all 10 epochs rather than simply the last. Rather than trusting the accuracy metric alone, predictions were also manually inspected by sorting by prediction probability - a habit that matters more on real-world, ambiguous data than it does here, but is demonstrated as part of the workflow regardless.

The inference benchmark tested two serving patterns using the same fine-tuned pipeline: calling the classifier once per sentence in a loop, versus passing a full batch of sentences in a single pipeline call. Sequential calls averaged 5.19ms per prediction across 1,000 samples; batched calls averaged 0.90ms at 250 samples, 0.79ms at 2,500, and 0.80ms at 25,000 and 250,000 - showing the batching speedup is stable rather than a one-off artifact of small sample size. This kind of throughput measurement is a more realistic signal for production readiness than accuracy alone, which the notebook explicitly treats as a separate concern from model correctness.

Deployment packages a standalone app.py, requirements.txt, and a Spaces-formatted README.md (with the YAML metadata block Spaces requires), uploaded programmatically via the huggingface_hub Python API rather than the web UI — the same deployment pattern used elsewhere in this portfolio for reproducible, scriptable Space publishing.