A LoRA fine-tune of
SmolVLM2-500M-Video-Instruct,
merged into a standalone model. Given a photo of ingredients arranged on a surface,
it returns a JSON list of the ingredients it recognizes. Built as an end-to-end ML
portfolio project (data → fine-tune → inference endpoint → web app).
1import torch
2from transformers import AutoProcessor, AutoModelForImageTextToText
3from PIL import Image
4
5repo = "LongGrainRice/kimchi-test"
6processor = AutoProcessor.from_pretrained(repo)
7# bf16 needs an Ampere+ GPU (e.g. L4). On a T4 or older card, use torch.float16.
8model = AutoModelForImageTextToText.from_pretrained(repo, torch_dtype=torch.bfloat16).to("cuda")
9
10# Use the exact instruction the model was trained with — it keys on this wording.
11INSTRUCTION = ("You are a food recognition assistant. List every food ingredient in this image. "
12 'Respond ONLY with a JSON array of lowercase strings, e.g. ["milk", "eggs", "tomato"].')
13
14image = Image.open("slab.jpg").convert("RGB")
15messages = [{"role": "user", "content": [{"type": "image"}, {"type": "text", "text": INSTRUCTION}]}]
16prompt = processor.apply_chat_template(messages, add_generation_prompt=True, tokenize=False)
17inputs = processor(text=[prompt], images=[[image]], return_tensors="pt", padding=True).to(model.device)
18
19ids = model.generate(**inputs, max_new_tokens=128, do_sample=False)
20print(processor.batch_decode(ids[:, inputs["input_ids"].shape[1]:], skip_special_tokens=True)[0])
Synthetic composites built by unioning two single-item sources, both center-cropped with an
oval mask and pasted onto slab backgrounds with varied scale, rotation, and shadow; the label
is the set of pasted items.
The 14 ingredients shared between the two sets are normalized to a single canonical name so
they don't fragment into duplicate classes. Because the two sources differ ~60× in per-class
image count, the compositor samples classes uniformly when building scenes rather than
sampling images uniformly — otherwise the image-rich legacy classes would dominate and the new
vocabulary would rarely appear. A small set of real photos is mixed in and upweighted.
Best used on scenes composed from the known classes. A base-vs-fine-tuned comparison script is
included in the project repo for evaluating on your own slab photos.