Marble

Open benchmark

Photo to calories, measured in the open

Many apps say they can count calories from a photo. Few say how well, on what photos, or how they checked. This page sets out a fixed test that anyone can run: the same photos, the same scoring and the same rules for every reader, Marble's included.

Two tracks

Public track: run it yourself

The test dishes of Nutrition5k (Google, CC BY 4.0) that have an overhead photo: the 507 dish ids in the dataset's own depth_test_ids.txt. Each dish was weighed ingredient by ingredient, so the truth is measured, not guessed. The truth file is built from the dataset's release files by a short script, so you can rebuild it and check it byte for byte.

Because the photos and truth are public, a public-track score is only as honest as whoever ran it. We list them as reported, with who ran them.

Hidden track: we run it for you

Weighed meal photos that no reader, ours included, has been tuned on. They are the held-out half of the datasets in our study, split by participant: a leaderboard set (about 60%) for repeated checks and a vault (about 40%) read once per reader. The split is made by a fixed hash of each participant's id and frozen before either half is read. Only the vault score is quoted as a result.

The hidden track opens once our pre-registered study has finished with these photos. Until then they stay sealed, and that includes being kept from us.

Rules

  1. One read per photo. No human in the loop, no second try because an answer looked wrong. A retry after a network or server error is fine. A combined reader, such as two reads averaged, counts as one reader with its total cost and time.
  2. The photo only. No meal names, notes, weights or metadata, unless your app always asks the user for them, and if it does, say so.
  3. Every photo counts. A missing, empty or refused answer scores as 0 kcal, as it would in an app.
  4. Three numbers, always. Accuracy, cost per photo and seconds per photo. A reader that is 5 kcal better but ten times the price is a different product, and the table shows it.
  5. Declare training data. Say whether your model or prompt was trained or tuned on Nutrition5k. Tuning on it is allowed, but the score is labelled.

Scoring

One file, Python 3.8 or later, no dependencies: score.py. It takes a truth file (id,kcal[,cluster]) and your predictions (id,kcal[,cost_usd,seconds]), and prints:

python3 build_public.py path/to/nutrition5k > truth.csv
python3 score.py truth.csv your_predictions.csv

build_public.py builds the public truth file from Nutrition5k's own metadata.

How to submit

Email support@getmarble.app with:

Results

Public track, Nutrition5k overhead test dishes. Rows are never edited; a new reader is a new row.

ReaderDateDishesMAE kcalMAE % of meanBias kcalRun by
Marble production reader (Haiku 5.5), before round 2*2026-10-1350715460%+121Marble

* Read on 2026-10-13, before any tuning on this set. That harness enlarged Nutrition5k's 640×480 photos to 1,280 px, which the app doesn't do. The next row will use the app's own photo path.

Published numbers on overlapping Nutrition5k test photos exist, for example GPT-4.1 at 34.6% MAE as a share of the mean (Mu et al., 2025, 505 overhead images, which 505 not stated). Those come from a different harness, so they are context, not rows in this table.

Limits

How we use this benchmark to improve our own reader, and what it found: the research post.