Use
from peft import PeftModelfrom transformers import AutoModelForCausalLM, AutoTokenizer base = "Qwen/Qwen3-1.7B"tok = AutoTokenizer.from_pretrained(base)model = PeftModel.from_pretrained(AutoModelForCausalLM.from_pretrained(base, dtype="auto"), "kushagrasoni6446/qwen3-1.7b-invoice-extraction-lora")SYSTEM = open("prompts_system.txt").read() # the exact system prompt is in this repo; use it unchangedmsgs = [{"role": "system", "content": SYSTEM}, {"role": "user", "content": "Document:\n" + invoice_text}]prompt = tok.apply_chat_template(msgs, tokenize=False, add_generation_prompt=True, enable_thinking=False)out = model.generate(**tok(prompt, return_tensors="pt"), max_new_tokens=700, do_sample=False)
The adapter was trained on exactly this prompt format (the chat template, enable_thinking=False, greedy
decoding). Other prompts are untested.
Results
Test: 300 invoices, half in 2 layouts held out of training. Shift: 100 invoices in 2 other layouts, read by
Tesseract from scans and degraded scans. "Fully correct" means every header field and every line item is right.
Table with columns: Test: fully correct, Header fields, Shift: fully correct, Invented values / invoice (shift) | Test: fully correct | Header fields | Shift: fully correct | Invented values / invoice (shift) |
|---|
| this adapter (seed 9, chosen on dev) | 80.7% | 0.984 | 27% | 0.39 |
| same recipe, 3 seeds | 79.0% (77.7–80.7) | 0.978 | 28.3% (27–30) | 0.29 |
| Qwen3.6-35B-A3B, 3 examples | 76.3% | 0.988 | 51% | 0.00 |
| Qwen3-1.7B, 3 examples, no adapter | 57.7% | 0.958 | 44% | 0.07 |
| Qwen3-1.7B, zero-shot | 29.3% | 0.897 | 36% | 0.09 |
Training: rank 64, alpha 128, all linear layers, lr 2e-4 (cosine), 1 epoch, 4,000 documents, completion-only
loss. It took 54 minutes on one Kaggle T4 (fp16), with a 5.3 GB training peak and about 6 GB serving at batch 16.
Intended use and limits
- For structured extraction from invoice-like text whose layouts and noise resemble the training data. It
is also a demonstration of what a small adapter can do.
- Not for real invoices from arbitrary suppliers without your own evaluation. On the real-OCR shift set it
gets 27% fully right, and it invents values more often (0.39 per invoice) than the prompted models
(0.00–0.07). Check every amount against the document before acting on it.
- Narrow scope:
- English labels only;
- four currencies (USD, EUR, GBP, INR);
- one-page invoices of up to 5 line items.
- Forgetting: IFEval (200 prompts) moved from 21.5% to 18.0% for the rank-16 version of this recipe, a mild
and not significant drop. It was not measured for this adapter.
Data
Fully synthetic: company names and addresses from Faker, generated by code in the project. No real person,
company or document. See the data card there.
Licence
Apache-2.0, the same as the base model (Qwen/Qwen3-1.7B).