Spaces:
Runtime error
Runtime error
File size: 14,394 Bytes
50ba6d4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | # Smart Plate β Model Development Documentation
Technical documentation of the image-classification model that powers **Smart Plate**
(*Indian Food Classification and Calorie Estimation*). It covers the complete model
development workflow as implemented in
[`notebook/indian-food-image-detection-vit.ipynb`](notebook/indian-food-image-detection-vit.ipynb).
---
## Project Overview
**Objective.** Build an image-classification model that identifies an Indian dish from a
single food photograph, so that the dish can be mapped to its calorie / nutritional
profile in the Smart Plate application.
**Problem being solved.** Manually identifying a dish and looking up its nutritional value
is slow and error-prone. This project automates the first half of that task β *recognising
the dish from a photo* β across 80 popular Indian food categories. The predicted label is
later joined with a calorie database in the application layer to estimate nutrition.
The model is built by **fine-tuning a Vision Transformer (ViT)** image classifier.
---
## Dataset Information
| Property | Value |
|---|---|
| Source | Kaggle β *Indian Food Images Dataset* (`indian-food-images-dataset`) |
| Path used | `Indian Food Images/Indian Food Images/*/*.jpg` |
| Total samples | **4,000 images** |
| Classes | **80** Indian food categories |
| Samples per class | 50 (balanced) |
| Image format | RGB JPEG, variable resolution |
| Train / test split | **60% / 40%**, stratified by label, shuffled |
| Train samples | 2,400 |
| Test samples | 1,600 (20 per class) |
**Classes (80):** adhirasam, aloo_gobi, aloo_matar, aloo_methi, aloo_shimla_mirch,
aloo_tikki, anarsa, ariselu, bandar_laddu, basundi, bhatura, bhindi_masala, biryani,
boondi, butter_chicken, chak_hao_kheer, cham_cham, chana_masala, chapati, chhena_kheeri,
chicken_razala, chicken_tikka, chicken_tikka_masala, chikki, daal_baati_churma, daal_puri,
dal_makhani, dal_tadka, dharwad_pedha, doodhpak, double_ka_meetha, dum_aloo, gajar_ka_halwa,
gavvalu, ghevar, gulab_jamun, imarti, jalebi, kachori, kadai_paneer, kadhi_pakoda, kajjikaya,
kakinada_khaja, kalakand, karela_bharta, kofta, kuzhi_paniyaram, lassi, ledikeni, litti_chokha,
lyangcha, maach_jhol, makki_di_roti_sarson_da_saag, malapua, misi_roti, misti_doi, modak,
mysore_pak, naan, navrattan_korma, palak_paneer, paneer_butter_masala, phirni, pithe, poha,
poornalu, pootharekulu, qubani_ka_meetha, rabri, ras_malai, rasgulla, sandesh, shankarpali,
sheer_korma, sheera, shrikhand, sohan_halwa, sohan_papdi, sutar_feni, unni_appam.
**Preprocessing performed at load time:**
- `ImageFile.LOAD_TRUNCATED_IMAGES = True` to tolerate truncated/corrupted JPEGs.
- File paths and parent-folder names collected into a Pandas DataFrame (`image`, `label`).
- **Random oversampling** (`imblearn.RandomOverSampler`, `random_state=83`) applied for class
balancing. The dataset was already balanced (50/class), so the count remained 4,000.
- Conversion to a HuggingFace `Dataset` with the `image` column cast to `Image` and the
`label` column cast to a `ClassLabel` (string β integer id mapping).
---
## Tech Stack
**Language:** Python 3
**Core libraries & frameworks:**
- **PyTorch** + **torchvision** β deep-learning backend and image transforms
- **HuggingFace Transformers** β `ViTForImageClassification`, `ViTImageProcessor`, `Trainer`, `TrainingArguments`, `pipeline`
- **HuggingFace Datasets** β dataset construction, `ClassLabel`, stratified split, on-the-fly transforms
- **HuggingFace Evaluate** β accuracy metric
- **Accelerate** β training backend
- **scikit-learn** β accuracy, F1, confusion matrix, classification report
- **imbalanced-learn (imblearn)** β `RandomOverSampler`
- **pandas / numpy** β data handling
- **matplotlib** β confusion-matrix visualisation
- **Pillow (PIL)** / **tqdm** β image I/O and progress bars
- **huggingface_hub** β model publishing
**Development environment:** Kaggle Notebook with a single CUDA GPU (`device=0`).
---
## Methodology
The workflow, in the order performed in the notebook:
### 1. Data Loading
All `*/*.jpg` files were globbed from the dataset directory; the parent folder name of each
file was used as its class label. Paths and labels were assembled into a DataFrame
(`4000 rows Γ 2 columns`).
### 2. Data Exploration & Visualization
- Inspected the DataFrame head and the list of 80 unique labels.
- Rendered a sample image to confirm correct loading.
- Built and printed `id2label` / `label2id` mappings.
- After training, a **confusion matrix** (80Γ80) and a per-class **classification report**
were generated for analysis.
### 3. Data Cleaning & Preprocessing
- Enabled truncated-image loading.
- Oversampled to enforce class balance.
- Cast columns to `Image` and `ClassLabel`; encoded string labels to integer ids.
### 4. Data Augmentation
Augmentation was applied **on-the-fly to the training split only**, via
`dataset.set_transform`:
| Transform | Train | Validation/Test |
|---|---|---|
| `Resize((224, 224))` | β
| β
|
| `RandomRotation(90)` | β
| β |
| `RandomAdjustSharpness(2)` | β
| β |
| `RandomHorizontalFlip(0.5)` | β
| β |
| `ToTensor()` | β
| β
|
| `Normalize(mean, std)` | β
| β
|
`mean`/`std` are taken from the pretrained `ViTImageProcessor`.
### 5. Feature Engineering
Not applicable in the classical sense β the Vision Transformer learns visual feature
representations directly from pixels. "Feature engineering" here is limited to the
resize/normalise/augment pipeline above.
### 6. Model Selection
A **Vision Transformer (ViT)** was selected for image classification. The underlying base
architecture is `google/vit-base-patch16-224-in21k`. In the notebook, training starts from
the task-specific checkpoint `aishrica/indian_food_prediction`, a ViT-Base classifier
already aligned to this exact 80-class Indian-food task.
### 7. Model Architecture
`ViTForImageClassification` β a ViT-Base encoder (patch size 16, 224Γ224 input) with a
linear classification head re-initialised for `num_labels = 80`.
### 8. Training Procedure
- A custom `collate_fn` stacks `pixel_values` and `labels` into batches.
- The HuggingFace `Trainer` orchestrates training with `compute_metrics` (accuracy).
- The model was **evaluated before training** (baseline) and **after every epoch**; the best
checkpoint (by accuracy) was reloaded at the end.
- Total optimisation: **760 steps over 20 epochs**, ~31 minutes runtime on GPU.
### 9. Hyperparameter Configuration
| Hyperparameter | Value |
|---|---|
| Epochs | 20 |
| Learning rate | 1e-6 |
| Train batch size | 64 |
| Eval batch size | 32 |
| Weight decay | 0.02 |
| Warmup steps | 50 |
| Evaluation strategy | per epoch |
| Save strategy | per epoch (`save_total_limit=1`) |
| `load_best_model_at_end` | True (metric = accuracy) |
| `remove_unused_columns` | False |
### 10. Validation Strategy
A single **stratified 60/40 split** was used. The 40% split serves as the `eval_dataset`
during training (per-epoch evaluation) and as the final test set. Best-model selection is
driven by validation accuracy. *(No separate, fully held-out test set was reserved β see
Limitations.)*
### 11. Evaluation Metrics
Accuracy (HuggingFace `evaluate`) during training; **accuracy, macro-F1, confusion matrix,
and a full per-class precision/recall/F1 report** (scikit-learn) at the end.
### 12. Testing & Inference
`trainer.predict` produced final test metrics. A `transformers.pipeline`
(`image-classification`) was then used to run single-image inference, validated against the
ground-truth label.
---
## Model Details
| Attribute | Value |
|---|---|
| Base model | `google/vit-base-patch16-224-in21k` |
| Fine-tuning checkpoint | `indian_food_prediction` (published as `aishrica/indian_food_prediction`) |
| Architecture | Vision Transformer β ViT-Base, patch 16, 224Γ224 (`ViTForImageClassification`) |
| Trainable parameters | **β 85.86 M** |
| Weights file | `model.safetensors` (~343 MB) |
| Input | RGB image, resized to 224Γ224, normalised with ViT mean/std β tensor `[3, 224, 224]` |
| Output | Logits over **80 classes** β softmax probabilities; argmax = predicted dish |
---
## Results
**Baseline (before fine-tuning):**
- eval_loss: 3.1995 Β· eval_accuracy: **0.7494**
**After fine-tuning (20 epochs):**
- train_loss: 3.1225 (final)
- eval_loss: 3.1539 Β· eval_accuracy: **0.7519**
**Final test evaluation:**
| Metric | Value |
|---|---|
| Test accuracy | **0.7519** |
| Macro F1 | **0.7352** |
| Test loss | 3.1539 |
**Observations & findings:**
- The task-specific checkpoint was already fitted to this dataset, and the learning rate was very
small (1e-6); consequently fine-tuning produced only a marginal gain (**74.94% β 75.19%**).
- Performance is **highly class-dependent.** Strong classes (F1 β 0.90+) include
bhindi_masala, boondi, chak_hao_kheer, jalebi, imarti, makki_di_roti_sarson_da_saag.
Weak classes include `chhena_kheeri` (F1 = 0.00), doodhpak, karela_bharta, ledikeni β
typically dishes that are visually similar to others (e.g. curries and milk-based sweets).
- **Predicted probabilities are poorly calibrated / very flat.** In the inference example the
correct top-1 prediction carried a confidence of only ~0.04, which is consistent with the
high cross-entropy loss (~3.15) despite ~75% top-1 accuracy. Top-1 *ranking* is reliable;
the absolute confidence scores should not be read as probabilities.
---
## Inference Pipeline
**How predictions are generated.** A `transformers.pipeline('image-classification')` loads
the saved model and label mappings. An input image is resized/normalised by the ViT
processor, passed through the encoder + classification head, and softmax scores are returned
ranked by probability.
**Input format:** a single image (PIL `Image`, file path, or URL).
**Output format:** a list of `{ "label": <class>, "score": <float> }` objects sorted by
descending score. Example:
```json
[
{ "label": "butter_chicken", "score": 0.0434 },
{ "label": "chicken_tikka_masala", "score": 0.0335 },
{ "label": "chana_masala", "score": 0.0264 },
{ "label": "chicken_tikka", "score": 0.0256 },
{ "label": "paneer_butter_masala", "score": 0.0226 }
]
```
In the Smart Plate application the top label (`raw_label`) is joined with `calorie_db.json`
to return the dish category and calorie estimate.
---
## Project Structure
```
indian-food-calories/
βββ notebook/
β βββ indian-food-image-detection-vit.ipynb β model development (this document)
βββ models/
β βββ aishrica_food_predictor/ β bundled ViT weights served by the app
βββ app.py β FastAPI inference backend (/predict, /foods)
βββ calorie_db.json β calorie data for the 80 classes
βββ static/ β Smart Plate web UI (pages/css/js)
βββ requirements.txt
βββ README.md
βββ DOC.md β this file
```
> Note: the notebook trains/publishes `indian_food_prediction`; the application serves
> a bundled equivalent ViT model from `models/aishrica_food_predictor/`. Both are ViT-Base
> classifiers over the same 80 Indian-food classes.
---
## Reproducibility
**Requirements.** Python 3, a CUDA GPU (recommended), and:
```bash
pip install -U evaluate "transformers" "datasets>=2.14.5" "accelerate>=0.27" \
torch torchvision scikit-learn imbalanced-learn pandas numpy matplotlib pillow tqdm
```
**Steps to run the notebook:**
1. Download the *Indian Food Images Dataset* from Kaggle and update the dataset glob path in
the data-loading cell if you are not running on Kaggle.
2. Open `notebook/indian-food-image-detection-vit.ipynb`.
3. Run the cells in order: install β imports β data loading β preprocessing/oversampling β
split β transforms β model load β baseline eval β `trainer.train()` β evaluation/report β
`trainer.save_model()`.
4. (Optional) Run the final cells to log in to the HuggingFace Hub and push the model.
The trained model is saved to the `indian_food_prediction/` output directory and can be
loaded directly for inference.
---
## Limitations
- **Marginal fine-tuning effect.** With a near-converged task-specific checkpoint and lr = 1e-6,
training added only ~0.25% accuracy β the run is closer to verification than substantive
fine-tuning.
- **Poorly calibrated confidence.** Softmax scores are very flat (top scores β 0.04), so they
cannot be presented to users as reliable probabilities without temperature scaling.
- **No held-out test set.** The same 40% split is used for per-epoch validation and final
testing, which can optimistically bias the reported metrics.
- **Class confusion.** Visually similar dishes (curries; milk-based sweets) are frequently
confused; at least one class (`chhena_kheeri`) scores F1 = 0.
- **Small dataset.** 50 images/class limits generalisation to real-world photos with varied
lighting, plating, and backgrounds.
- **Single-dish assumption.** The model classifies one dish per image; it does not segment or
detect multiple items on a plate.
---
## Future Improvements
- **Reserve a separate test set** (train/validation/test) for unbiased evaluation.
- **Tune the learning rate / schedule** (e.g. 1e-5β5e-5 with discriminative LR) and add early
stopping for meaningful fine-tuning.
- **Calibrate outputs** (temperature scaling or label smoothing) so confidence scores are
trustworthy in the UI.
- **Expand and diversify the dataset** β more images per class and real "in-the-wild" photos;
stronger augmentation (color jitter, random erasing, mixup/cutmix).
- **Address weak classes** with targeted data collection and per-class error analysis.
- **Move toward food segmentation / multi-item detection** (e.g. instance segmentation)
to handle full plates beyond the current single-dish classification setup.
- **Add portion/volume estimation** from images to improve the downstream calorie estimate.
- **Export an optimised model** (ONNX / quantisation) to speed up and shrink the served model.
---
*Document generated from the notebookβs executed code and outputs. Metrics reflect the recorded
run (20 epochs, test accuracy 0.7519, macro-F1 0.7352).*
|