/ Модель

Характеристики

Лицензия
MIT
Опубликована
10 окт 2026

calorie-lens

Классификация изображенийИзображение → label

Модель оценивает ингредиенты, их массу и пищевую ценность блюда по фотографии.

415скачиваний за 30 дней0лайковвеса обновлены12 окт 2026

Бенчмарки

Как модель справилась с задачами пользователей ailist и что о ней публикуют открытые лидерборды

Публичные оценки

Из открытых лидербордов. Сравнивайте результаты одного теста при одинаковых условиях — отсутствие оценки не значит, что модель хуже.

В подключённых источниках результатов для этой модели пока нет.

Что умеет модель

Описание составлено по карточке модели и метаданным Hugging Face

Calorie Lens — модель shalev396 для оценки состава и пищевой ценности блюда по фотографии. Она объединяет два компонента: IngredientNet на базе ConvNeXt-B с декодером ингредиентов и NutriText для оценки пищевой ценности произвольного названия продукта. Модель содержит 90,26 млн параметров, обучена с нуля и публикуется в формате safetensors; для инференса загрузка базовой модели не требуется.

По изображению модель определяет ингредиенты, оценивает их массу и рассчитывает калорийность, белки, жиры, углеводы, клетчатку, сахара, насыщенные жиры и натрий. Предназначена для анализа блюд и примерного учёта питания. На 507 тестовых сканах Nutrition5k с верхнего ракурса ошибка оценки калорий составила 18,35% в среднем; масса тарелки оценивается с ошибкой 14,3%.

Обучение проводилось на данных Nutrition5k и USDA FoodData Central. Модель рассчитана на фотографии блюд, похожие на обучающие снимки из двух кафетериев; в частности, вне фиксированной высоты камеры оценка массы может быть неточной. Скрытые масла и соусы выводятся только по внешнему виду, большие блюда свыше примерно 600 ккал модель склонна недооценивать. NutriText может ошибаться в оценках незнакомых продуктов. Лицензия кода — MIT.

Сценарии применения

  • оценка калорийности блюда по фото
  • распознавание ингредиентов на тарелке
  • оценка массы порций отдельных продуктов
  • расчёт белков, жиров и углеводов блюда
  • примерный учёт питания по фотографии

Ограничения

Обучающие снимки получены в двух кафетериях, поэтому при других ракурсах и высоте камеры оценка массы может быть неточной; скрытые масла и соусы определяются только по внешнему виду. Модель склонна недооценивать блюда свыше примерно 600 ккал, а оценки NutriText для незнакомых продуктов могут ошибаться.

Карточка модели

README от автора на Hugging Face, как он его опубликовал

Открыть на Hugging Face

Calorie Lens

A photo of a meal goes in; out come the ingredients on the plate, how many grams of each, and the nutrition of every ingredient and of the whole plate (kcal, protein, fat, carbs, fiber, sugars, saturated fat, sodium). It is two models fused into one network, trained on the Nutrition5k dishes, whose every ingredient was weighed on a scale, and on USDA FoodData Central.

Model

photo ─► backbone (ConvNeXt-B or DINOv2-B) ─► 253 ingredient queries (cross-attention)
                                              ├─ is ingredient k on the plate?   (presence)
                                              └─ how many grams, if it is?       (grams)
         backbone ─► totals head ─► plate mass
grams_k = P(k) x grams_k, rescaled to the plate mass  ──►  253 neurons  =  stage 1's output
253 neurons ─► NutritionLayer (frozen, 253 x 8 per-gram table) ─► nutrition per ingredient + totals
food name ─► NutriText (own BPE tokenizer + 4-layer transformer, from scratch) ─► nutrients / 100 g
Stage 1 (IngredientNet)backbone + a query decoder: one learned query per Nutrition5k ingredient reads the image tokens (2 cross-attention layers, no query self-attention), each query has its own presence and grams outputs. A totals head estimates the plate's mass, kcal and macros directly; the ingredient grams are rescaled to that mass (in log space, blended with their own sum; the blend weight is fitted on validation)
Stage 2a (NutritionLayer)a bias-free linear layer whose weights are per-gram nutrients and are never trained: kcal / fat / carb / protein are Nutrition5k's own values (its labels are exactly grams x this table), fiber / sugars / saturated fat / sodium come from a reviewed USDA match per ingredient. The 253 gram neurons are its input layer, so the whole thing trains end to end
Stage 2b (NutriText)open vocabulary: any food name -> nutrients per 100 g. Composition comes from a softmax x 100 g (can never exceed 100 g), sugars and saturated fat are bounded by carbs and fat, kcal stays close to the Atwater energy of the composition. Trained from scratch on ~470k USDA names
Inputany RGB photo, fitted (aspect kept) into a 378 x 504 canvas
Output{"ingredients": [{name, grams, confidence, kcal, fat_g, carb_g, protein_g, fiber_g, sugars_g, sat_fat_g, sodium_mg}], "other": {...}, "totals": {...}, "direct_estimate": {...}}; the rows add up to the totals exactly
Filesmodel.safetensors (all three stages), config.json (ingredients, per-gram table, backbone config, fitted settings), nutritext_tokenizer.json, model.py, handler.py + requirements.txt, metrics.json, assets/

config.json records pretrained: false; model.load() rebuilds every network from config.json and loads model.safetensors, so inference never downloads a base model.

Usage

Python

from huggingface_hub import snapshot_download
import sys
path = snapshot_download("shalev396/calorie-lens")
sys.path.insert(0, path)
import model
predictor = model.load(path, device="cpu")            # or "cuda"
result = predictor.predict("meal.jpg")                # a PIL image, bytes or base64 work too
result = predictor.predict("meal.jpg", total_grams=420)   # plate weighed? the scale becomes exact
result, heatmaps = predictor.analyze("meal.jpg")      # + where each ingredient's query looked
predictor.calculate([("grilled salmon", 150), ("white rice", 200)])   # stage 2b food calculator

Space API (free): the Space exposes /predict (photo + optional total grams in, [result, seconds, device] out).

Inference Endpoint: deploy this repo from its page (Deploy -> Inference Endpoints). handler.py takes an image (Content-Type: image/jpeg, or JSON {"inputs": "<base64>", "parameters": {"total_grams": 350}}) and returns the result above; {"inputs": [["oatmeal", 250], ["banana", 120]]} runs the calculator.

Training

  • Data: shalev396/calorie-lens-data, built from Nutrition5k: one overhead RGB-D scan per dish where available and 5 frames from each of the 4 side-angle videos. Label bugs were fixed (Cafe 2 totals logged as 0, x1000 scale errors, empty names, duplicate table rows) and every dish was assigned a plate group (plates were scanned once per added item), so validation never shares a plate with training. Test = the official split.
  • Recipe: see training/: AdamW with layer-wise learning-rate decay, warmup + cosine, bf16, EMA of the weights, early stopping on validation; augmentation on the GPU (any rotation for overhead scans, which keeps the camera-height scale cue).
  • Selection: both backbones are trained with the same recipe; validation picks the winner (ties go to ConvNeXt), which is retrained with an auxiliary depth head. The test split is evaluated once, at the end.

Experiments

experimentval scoretest kcal PMAE (overhead)test mass PMAEside-dish kcal PMAEbest epochparams
E1 ConvNeXt-B (deployed)17.2218.35%14.29%17.28%2490.26M
E2 DINOv2-B17.9217.53%14.09%16.82%3088.95M
E3 ConvNeXt-B + depth17.3619.02%14.27%17.10%3090.26M

Validation picked ConvNeXt-B (17.22 vs 17.92). On the test split DINOv2-B came out lower (17.53 % vs 18.35 %), but the test split makes no choices, so ConvNeXt ships. The depth head (E3) did not help: it was slightly worse on validation and on test. The whole run (NutriText + 3 experiments) took 3.1 h on a Colab GPU.

Training loss and validation score of every experiment

Test calorie error per experiment

Evaluation

Numbers: overhead test scans (the official depth_test split, labels corrected), as MAE and percent MAE (MAE / mean of the truth, the Nutrition5k convention). metrics.json also has the side-angle views, test_clean (plates never seen in training), the original labels and the 95 % CI.

metric (test)value
kcal_mae46.8789
kcal_pmae18.3503
mass_pmae14.2945
fat_pmae24.2640
carb_pmae22.3740
protein_pmae27.8922
side_dish_kcal_pmae17.2801
test_clean_kcal_pmae18.3879
presence_map0.6531
ingredient_grams_mae11.1806
nutritext_kcal_mae_per_100g31.6995

Headline: 18.35 % calorie error (46.9 kcal) on the 507 overhead test scans, 95 % CI 16.3-20.2 % (bootstrap over plate groups). The original labels give the same 18.35 % on these scans, so the number compares directly with published results. Plate mass: 14.3 %. Averaging all side-angle frames of a dish: 17.3 %.

method (official overhead test, kcal PMAE)inputerror
Nutrition5k paper (Thames et al., 2021)RGB26.1 %
Nutrition5k paperRGB + depth18.8 %
Calorie LensRGB18.35 %
best published RGB-onlyRGB14.1 %

Predicted vs true kcal on the overhead test scans

Small and medium plates are close: under 100 kcal the error is 11 kcal. Large plates are underestimated: over 600 kcal (38 dishes) the error is 167 kcal, because the model pulls toward a typical plate.

Calorie error by plate size

What each part is worth. The totals head read on its own scores 16.4 %, better than the 253 gram neurons (18.4 %): the itemised route, whose rows add up to the totals, costs about 2 points of calorie accuracy. Its estimate is returned as direct_estimate in every result. The plain sum of the soft grams, without rescaling to the plate mass, is the worst (23.6 %).

Calorie error of each way to read the model

Ingredients: presence mAP 0.65 (F1 0.73 at the display threshold 0.65); 11.2 g error per present ingredient. Each ingredient's query looks at its own part of the plate:

Where each ingredient's query looked

NutriText (stage 2b), on 633 USDA foods it never saw: kcal R² 0.89 vs 0.78 for a TF-IDF nearest-neighbour lookup, 31.7 vs 47.4 kcal per 100 g, and better on all eight nutrients. On the 253 Nutrition5k names (zero-shot): 56 vs 87 kcal per 100 g (median 18 vs 49).

NutriText vs a TF-IDF nearest-neighbour lookup

Limitations

  • Every training photo comes from two Google cafeterias: a fixed overhead camera height and 253 ingredients. On other photos the mass scale is uncertain; entering the plate's weight (total_grams) removes that error completely.
  • Hidden oil, butter, dressings and sauces can only be inferred from how the food looks.
  • Only kcal, fat, carbs and protein are Nutrition5k's own values; the other four nutrients come from a USDA food matched to each ingredient. NutriText values for names it never saw are estimates, and some are off (it gives grilled salmon 7.7 g of carbs per 100 g).
  • Plates over ~600 kcal are underestimated (see the chart above).
  • Results on corrected labels are not directly comparable with published Nutrition5k numbers; the original-label results are in metrics.json.

Code licence: MIT. Training data: Nutrition5k (CC BY 4.0, Thames et al., CVPR 2021) and USDA FoodData Central (public domain).

Как запустить

На своей GPU в ailist. Цена — по текущим предложениям провайдеров

GPU в ailist

Универсальный рантайм

Нельзя запустить

Архитектура ? неизвестна transformers в образе рантайма.

Ревизия весов
b3f585c

0 моделей