Downloads · 30 days
5
13% of all-time downloads
Ji-Qing/qwen2-vl-2b-cord-receipts-lora
qwen2-vl-2b-cord-receipts-lora is a image-text-to-text model from Ji-Qing. Use it for the image-text-to-text task on the model card, and read the license before you ship it in a product. It is set up for peft. The card lists the license as apache-2.0.
A LoRA adapter for Qwen/Qwen2-VL-2B-Instruct, fine-tuned to extract structured data from receipts as JSON (lineitems, subtotal, tax, total).
Downloads · 30 days
5
13% of all-time downloads
All-time downloads
38
Public
Repo size
17.5 MB
Likes
0
Public
Click a slice to open those files.
.safetensors17.5 MB · 100%
From the Hugging Face model README
A LoRA adapter for Qwen/Qwen2-VL-2B-Instruct, fine-tuned to extract structured
data from receipts as JSON (line_items, subtotal, tax, total).
Part of the Vision-Agent project — an LLM-orchestrated multi-agent receipt understanding system.
On in-domain extraction this fine-tuned 2B model matches and exceeds a frontier API (Claude Opus 4.8) zero-shot, at ~13× lower inference cost:
| Metric | Frontier zero-shot | This model (fine-tuned 2B) |
|---|---|---|
| total exact-match | 0.851 | 0.979 |
| item-price F1 | 0.825 | 0.956 |
| QA exact-match | 0.820 | 0.910 |
| cost / 1k receipts | $13.05 | $1.00 |
Note: this is an in-domain comparison (fine-tuned on CORD, tested on CORD's held-out split; the frontier model is zero-shot).
import torch
from transformers import AutoProcessor, Qwen2VLForConditionalGeneration
from peft import PeftModel
BASE = "Qwen/Qwen2-VL-2B-Instruct"
ADAPTER = "Ji-Qing/qwen2-vl-2b-cord-receipts-lora" # this repo
processor = AutoProcessor.from_pretrained(BASE)
base = Qwen2VLForConditionalGeneration.from_pretrained(BASE, torch_dtype=torch.bfloat16)
model = PeftModel.from_pretrained(base, ADAPTER).eval()
INSTRUCTION = (
"Extract the receipt as JSON with keys: line_items (a list of {name, price}), "
"subtotal, tax, total. Copy values exactly as printed. Use null if a field is "
"absent. Respond with only the JSON object."
)
messages = [{"role": "user", "content": [
{"type": "image", "image": your_pil_image},
{"type": "text", "text": INSTRUCTION},
]}]
text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = processor(text=[text], images=[your_pil_image], return_tensors="pt")
out = model.generate(**inputs, max_new_tokens=256)
print(processor.batch_decode(out[:, inputs["input_ids"].shape[1]:], skip_special_tokens=True)[0])