The model takes an after-meal photo and the served ingredients with their weights as text. It answers with the returned weight per ingredient in grams, as JSON.
Prompt, in the exact format used in training (the ingredient JSON is json.dumps(..., indent=2)):
Given this initial meal data in JSON format: ```json{ "ingredients": [ { "name": "Kartoffelpüree ", "weight": 120 }, { "name": "Grüne Bohnen ", "weight": 80 } ], "total_weight": 200}``` Please provide the amount of food returned for each ingredient in JSON format.
Answer:
Here are the ingredients with their initial weights and returned amounts: ```json{ "ingredients": [ { "name": "Kartoffelpüree ", "initial_weight": 120, "returned_weight": 0.0 }, { "name": "Grüne Bohnen ", "initial_weight": 80, "returned_weight": 26.0 } ], "total_initial_weight": 200}```
Usage
import jsonfrom PIL import Imagefrom transformers import AutoProcessor, Qwen2VLForConditionalGeneration model_id = "aihpi/food-waste-vlm"model = Qwen2VLForConditionalGeneration.from_pretrained(model_id, torch_dtype="auto", device_map="auto")# Training used at most 262144 pixels per image; match it at inference.processor = AutoProcessor.from_pretrained(model_id, max_pixels=262144) served = {"ingredients": [{"name": "Kartoffelpüree ", "weight": 120}, {"name": "Grüne Bohnen ", "weight": 80}], "total_weight": 200}prompt = ("Given this initial meal data in JSON format:\n\n```json\n" + json.dumps(served, indent=2) + "\n```\n\nPlease provide the amount of food returned for each ingredient in JSON format.") messages = [{"role": "user", "content": [{"type": "image"}, {"type": "text", "text": prompt}]}]text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)inputs = processor(text=[text], images=[Image.open("plate.jpg")], return_tensors="pt").to(model.device) output = model.generate(**inputs, max_new_tokens=512)print(processor.batch_decode(output[:, inputs.input_ids.shape[1]:], skip_special_tokens=True)[0])
Training
Trained with LLaMA-Factory (config: qwen2vl_food_waste.yaml).
Table with columns: Setting, Value| Setting | Value |
|---|
| Data | Train split: 215 images from 12 receipts (dataset revision 7f75954a), 10% held out for validation |
| Method | LoRA, rank 8, all linear layers |
| Epochs | 3 |
| Learning rate | 1e-4, cosine schedule, 10% warm-up |
| Batch size | 1 per device × 4 gradient accumulation |
| Precision | bf16 |
| Max sequence length | 2048 tokens |
| Max image size | 262144 pixels |
Evaluation
The model has not yet been evaluated on held-out data. The dataset's test split (160 images from 4 receipts) was published after this model was trained, and none of its receipts are in the train split, so it is the intended benchmark.
Limitations
- Labels are per meal, not per photo. All 12–40 photos of a receipt share the same labels, so the model learns what was returned for the meal as a whole. It cannot learn differences between photos of the same plate.
- Small training set. 12 receipts, one dish each, all from one test kitchen, with German ingredient names. Expect poor transfer to other kitchens, cuisines, plates or camera setups.
- Needs the served ingredients. The model does not identify ingredients from the photo; it expects them and their served weights in the prompt.
License
This model is licensed under Apache 2.0. It is a modified version of Qwen/Qwen2-VL-7B-Instruct, which is also licensed under Apache 2.0.
It was trained on AI-ServicesBB/food-waste-dataset by the AI Service Centre Berlin-Brandenburg, Hasso-Plattner-Institut für Digital Engineering gGmbH, licensed under CC BY 4.0.
Funding
The AI Service Centre Berlin-Brandenburg is funded by the German Federal Ministry of Research, Technology and Space under the funding code "KI-Servicezentrum Berlin-Brandenburg" 16IS22092.