NUTRISNAP / FOOD RECOGNITION

From a meal photo
to food detection and nutrition logging.

I built NutriSnap?s ML pipeline and inference API,
from data preparation to lightweight serving.

A team project connecting a fine-tuned food detector to a nutrition-tracking application.

Role

ML & inference API

Period

Jul–Oct 2026

Scope

38-class food detection

From meal photo to nutrition record.

NutriSnap connects food detection to nutrition logging. My responsibility was the ML component: preparing the data, training the detector, examining its errors, and serving predictions to the application.

01 / INPUT

Photograph a meal

The user uploads a food photo. The current model works best with one dish at a time.

Food ? 0.94
02 / MY COMPONENT

Detect & return

The inference API returns food names, confidence scores, and bounding boxes in original-image coordinates.

03 / APPLICATION

Confirm & log

The backend looks up nutrition for the confirmed food. Portions are entered manually in the app.

My scopeEnd-to-end ML pipeline and inference service; Also contributed to Spring Boot bulletin-board CRUD in the shared application backend.

Previously integrated with the app. A refreshed walkthrough and hosted model demo are planned.

Good predictions start
with questions about the data.

AIHub JSON annotations needed conversion to normalized YOLO labels. The conversion process also exposed mismatches that could silently remove data or distort the evaluation scope.

WHAT THE DATA REVEALED
01

38 training classes.
87 validation classes.

02

One folder-name typo
hid an entire class.

03

Missing images and
invalid annotations.

WHAT I CHANGED
CLASS MAPPING

Use training classes as the source of truth.

FILE MATCHING

Align label and image folder names.

VALIDATION

Log and skip unusable entries.

TRAINING IMAGES93,573
TRAINING BOXES120,405
VALIDATION IMAGES11,679
CLASSES38

Fine-tuning a pretrained YOLOv8n

100 epochs ? 640 ? 640 input ? RTX 3050 ? approximately 22 hours. Metrics below describe the AIHub validation split, not real-world table-photo performance.

A duplicate or near-duplicate audit across splits is not documented here.

Q.01

How did the model perform on validation data?

mAP50mAP50–95

11,679 AIHub validation images.

A dedicated inference API.
A 93% smaller serving image.

The service answers a focused question: which foods are in this image, and where? Nutrition lookup, account data, and meal storage belong to the application backend.

POST /predictUpload image
Decode to RGB
→
ONNX RuntimeLetterbox → inference
Class-wise NMS → box rescaling
→
Detection JSONFood · confidence · box
Low-confidence review flag

Kept the model, removed the training stack.
A lighter service with ONNX Runtime.

Reimplemented preprocessing and postprocessing with NumPy and OpenCV, separating inference dependencies from training.

Q.02

How much smaller was the Docker image?

Q.03

What changed in the serving environment?

Image · 10.2 GB → 732 MB
↓93%
Memory · 478 → 133 MB
↓72%
Build · 486 → 43 sec
↓91%

Repository measurements; benchmark conditions and reproducible outputs will accompany the verification notes.
Labels show the measured before/after values and approximate reductions.

A smaller runtime should not mean
a different prediction.

The first preprocessing implementation used PIL resizing and produced confidence drift of up to 0.25. Matching Ultralytics with OpenCV INTER_LINEAR brought the outputs into alignment.

200validation images compared
266 / 266detected-box classes matched
0.999mean bounding-box IoU

Repository-reported comparison against Ultralytics running the same ONNX model. Confidence difference reported as 0.0. This compares serving implementations, not independent model accuracy.

Strong validation scores.
A different story on a full table.

Training photos were centered on a single plate, which could contain multiple foods. Full-table photos with several dishes were harder; testing individual dish crops produced better detections.

01 / FULL TABLE
0.01Steak confidence
02 / ISOLATED PLATE
0.80Steak confidence

Schematic illustrations of the reported crop experiment; these are not actual model-output images.

Data → behaviorDish crops worked better than the full-table image. This suggests a distribution gap; scale, background, and composition may all contribute.

A diagnostic example, not an aggregate benchmark. Current guidance: photograph one plate at a time.

Untested directionDetect plates first, crop each region, then run food detection on the crops. This is a proposed pipeline; it has not been implemented or evaluated.

Technical notes & verification

Reproduction and benchmark notes are being prepared. Nutrition and portion accuracy are outside the detector evaluation.