SmartPlate / DOC.md
Aishrica's picture
initial commit
50ba6d4
|
Raw
History Blame Contribute Delete
14.4 kB

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.


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:

[
  { "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:

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).