Instructions to use sanasn/qwen2.5-1.5b-ocr-correction with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use sanasn/qwen2.5-1.5b-ocr-correction with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("unsloth/Qwen2.5-1.5B-Instruct-bnb-4bit") model = PeftModel.from_pretrained(base_model, "sanasn/qwen2.5-1.5b-ocr-correction") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- Unsloth Studio
How to use sanasn/qwen2.5-1.5b-ocr-correction with Unsloth Studio:
Install Unsloth Studio (macOS, Linux, WSL)
curl -fsSL https://unsloth.ai/install.sh | sh # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for sanasn/qwen2.5-1.5b-ocr-correction to start chatting
Install Unsloth Studio (Windows)
irm https://unsloth.ai/install.ps1 | iex # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for sanasn/qwen2.5-1.5b-ocr-correction to start chatting
Using HuggingFace Spaces for Unsloth
# No setup required # Open https://huggingface.co/spaces/unsloth/studio in your browser # Search for sanasn/qwen2.5-1.5b-ocr-correction to start chatting
Load model with FastModel
pip install unsloth from unsloth import FastModel model, tokenizer = FastModel.from_pretrained( model_name="sanasn/qwen2.5-1.5b-ocr-correction", max_seq_length=2048, )
Qwen2.5-1.5B-Instruct β Post-OCR Correction (QLoRA)
A LoRA adapter that repairs OCR-style character corruption in text. Given garbled input, it returns the corrected text and nothing else.
Headline: character error rate 0.0747 β 0.0325 (56% reduction). Word error rate 0.4231 β 0.0748 (82% reduction). The un-tuned base model degrades the input (CER 0.1889).
Results
150 held-out examples, greedy decoding, identical prompt for base and tuned.
| Split | Noisy input | Base model | Fine-tuned |
|---|---|---|---|
| Overall CER | 0.0747 | 0.1889 | 0.0325 |
| Prose CER | 0.0750 | 0.2003 | 0.0411 |
| Structured CER | 0.0740 | 0.1590 | 0.0098 |
| Overall WER | 0.4231 | 0.3345 | 0.0748 |
Why the base model makes things worse
The instruction-tuned base behaves like a copy-editor rather than a corrector. It rewrites formatting (replacing field delimiters with line breaks), "corrects" proper nouns it believes it knows better (Mangaluru β Mangalore), adds quotation marks, and restructures sentences. Fluent output, unfaithful reconstruction. Most of its CER is edits nobody asked for.
Fine-tuning teaches the constraint the prompt alone could not: change only what is broken, preserve everything else exactly.
Structured fields beat prose
Contrary to expectation, the structured split improved more. The template is fixed and the vocabulary closed, so the model learns the schema and the finite entity set and restores both reliably. Prose has open vocabulary and stays harder.
The failure that CER hides
Digits carry no linguistic context, so they cannot be recovered by inference β only guessed. Example:
NOISY Name: Diva Nadaf| DO: 2/07/1987 | ID: VA8472357 | Address: 137, Br gade Road, Mangaluru 560014
TUNED Name: Divya Nadaf | DOB: 20/07/1987 | ID: VA8472357 | Address: 137, Brigade Road, Mangaluru 560014
CLEAN Name: Divya Nadaf | DOB: 27/07/1987 | ID: VA8472357 | Address: 137, Brigade Road, Mangaluru 560014
Every field restored, schema recovered, one digit wrong. That is 2 characters out of ~90, so CER barely registers it β but on an identity document it is a total field failure. CER is the wrong metric for structured extraction; field-level exact match is the honest one, and any production system should route low-confidence numeric fields to human review rather than trusting a reconstruction.
Residual prose errors are the same class of problem. Where corruption destroys the information outright, the model produces something fluent instead of something correct:
NOISY Argos in Cyprus: tbe re wals a tempilne ,of Apollo Erithios
TUNED Argos in Cyprus: the temples of Apollo Erithios
CLEAN Argos in Cyprus: there was a temple of Apollo Erithios
Data
Synthetic. 2000 pairs, split 1700 / 150 / 150.
- 70% prose from English Wikipedia
- 30% structured records β name, date of birth, ID number, address
Corruption was not uniform random noise. Uniform noise produces non-words that are trivially fixable by nearest-dictionary-match, which inflates the result. Instead, a weighted confusion table models real OCR failure modes:
- visual confusion pairs β
rnβm,clβd,0βO,1βlβI,5βS,8βB - character dropout
- spurious word splits and merges
- punctuation substitution
Sampling: 55% confusion substitution, 20% dropout, 15% whitespace error, 10% insertion. Corruption rate was calibrated to land input CER near 0.075 β low enough that the text stays recoverable, high enough to leave headroom.
Training
| Base | unsloth/Qwen2.5-1.5B-Instruct-bnb-4bit |
| Method | QLoRA, 4-bit |
| LoRA | r=16, alpha=16, dropout=0, all attention + MLP projections |
| Epochs | 2 (~425 steps) |
| LR | 2e-4, linear, 10 warmup steps |
| Batch | 2 Γ 4 grad accum |
| Max seq | 512 |
| Optimizer | adamw_8bit, weight decay 0.01 |
| Hardware | free Colab T4, fp16 |
Loss was masked to the assistant turn only (train_on_responses_only), so no
gradient is spent learning to predict the corrupted input.
Usage
from unsloth import FastLanguageModel
model, tok = FastLanguageModel.from_pretrained(
"USERNAME/qwen2.5-1.5b-ocr-correction", max_seq_length=512, load_in_4bit=True)
FastLanguageModel.for_inference(model)
SYS = ("You correct OCR errors. Return only the corrected text, "
"with no explanation, preamble, or quotes.")
msgs = [{"role": "system", "content": SYS},
{"role": "user", "content": "the docurnent was s1gned"}]
ids = tok.apply_chat_template(msgs, return_tensors="pt",
add_generation_prompt=True).to("cuda")
print(tok.decode(model.generate(ids, max_new_tokens=256, do_sample=False)[0][ids.shape[1]:],
skip_special_tokens=True))
Limitations
- Corruption is synthetic, modeled on real OCR error modes but not sampled from a real OCR engine. Performance on genuine scanner output is unverified. The next step is rendering text to degraded images, running Tesseract, and re-evaluating against real error distributions.
- The baseline is zero-shot. A few-shot prompted baseline would be a fairer comparison and would likely land between the two numbers reported here.
- Structured results are optimistic. Names, streets, and cities come from small closed lists, so the model can memorize the entity set. Real documents have open vocabulary and would be harder.
- Single seed, single test set of 150 examples. No confidence intervals.
- English only, sequences under 512 tokens.
- Downloads last month
- 13