Views
No views yet
1{
2 "items": [
3 {"name": "Nasi Goreng", "count": 2, "unit_price": 25000, "price": 50000}
4 ],
5 "subtotal": 50000,
6 "discount": null,
7 "service": null,
8 "tax": 5000,
9 "total": 55000
10}unsloth/Qwen3-VL-8B-Instruct-unsloth-bnb-4bit(Unsloth 預量化的 4-bit 版本,vision tower 維持 bf16)finetune_vision_layers=True、finetune_language_layers=True、finetune_attention_modules=True、finetune_mlp_modules=True| 指標 | 微調前(zero-shot) | 微調後 |
|---|---|---|
| 合法 JSON 率 | 100.0% | 100.0% |
| total exact match | 75.0% | 90.0% |
| 欄位級 micro F1 | 0.744 | 0.930 |
items.unit_price(0.32→0.91)、discount(0.27→0.86)、service(0.57→0.92)。25.000 = 兩萬五千)誤讀成小數點,輸出成 25.0;(2) 會自行「腦補」收據上沒印的 unit_price,或把品項名稱合併/截斷。微調後這兩類錯誤大幅減少。完整對照表與案例展示見 repo 內的 results/comparison.md。1import unsloth # 必須放在最前面:修正 transformers/bitsandbytes 對 Qwen3-VL vision tower 的一個載入 bug,即使下面完全不用 FastVisionModel 也需要
2from transformers import Qwen3VLForConditionalGeneration, AutoProcessor
3from peft import PeftModel
4from PIL import Image
5import torch
6
7BASE = "unsloth/Qwen3-VL-8B-Instruct-unsloth-bnb-4bit"
8model = Qwen3VLForConditionalGeneration.from_pretrained(BASE, device_map="cuda") # 不要額外傳 quantization_config,checkpoint 自帶
9model = PeftModel.from_pretrained(model, "betty0/vlm-receipt-extractor")
10processor = AutoProcessor.from_pretrained(BASE)
11
12image = Image.open("receipt.jpg").convert("RGB")
13prompt = (
14 'Extract all information from this receipt image and return it as a JSON object with exactly this structure:\n'
15 '{"items": [{"name": <string>, "count": <integer or null>, "unit_price": <number or null>, "price": <number or null>}], '
16 '"subtotal": <number or null>, "discount": <number or null>, "service": <number or null>, "tax": <number or null>, "total": <number or null>}\n'
17 'Rules: amounts must be plain numbers without currency symbols or thousands separators; use null for values not present on the receipt; '
18 'output only the JSON object with no explanation and no markdown.'
19)
20messages = [{"role": "user", "content": [{"type": "image"}, {"type": "text", "text": prompt}]}]
21text = processor.apply_chat_template(messages, add_generation_prompt=True, tokenize=False)
22inputs = processor(text=[text], images=[image], return_tensors="pt").to("cuda")
23with torch.inference_mode():
24 out = model.generate(**inputs, max_new_tokens=768, do_sample=False)
25print(processor.batch_decode(out[:, inputs["input_ids"].shape[1]:], skip_special_tokens=True)[0])gt_parse 標註本身沒有這兩欄。discount/service 在資料中出現率較低(訓練集分別 7.6%/12.2%),對應的 F1 雖有大幅提升但樣本數仍偏少,實際部署時建議針對目標場景另外驗證。r=16、lora_alpha=16、lora_dropout=0、bias=none。target_modules 是 Unsloth 產生的正規表示式,涵蓋 vision tower 與language model 兩側的 attention(q/k/v/o_proj)與 MLP(gate/up/down_proj、linear_fc1/fc2)投影層,完整內容見本 repo 的 adapter_config.json。