Can Small Local Models Do Receipt OCR?

Why we ran this test
We were evaluating whether open-source OCR models could power a low-cost document extraction product without cloud API dependencies. The economics are compelling on paper — cloud OCR services charge $1–$2 per 1,000 pages, while self-hosted models on commodity hardware approach zero marginal cost. But economics only matter if the accuracy is production-grade. This report documents what we found.

The Question

We needed to evaluate the feasibility of deploying a lightweight, open-source OCR pipeline that can extract structured data from receipt images — vendor, date, totals, tax, line items. The million-dollar question was simple: can a small open-source model running on consumer hardware meet production-quality thresholds?

We tested three pipeline architectures across 200 receipt images from the SROIE dataset (ICDAR 2019), all running on an RTX 3080 10GB under WSL2 via Ollama. We also evaluated two additional candidates that didn't make it to the benchmark. The short answer: not yet.

What We Tested

We evaluated three distinct pipeline architectures, each representing a different approach to the problem:

1. GLM-OCR native — two-pass VLM

A 0.9B vision-language model purpose-built for OCR tasks. In two-pass mode, it first reads the receipt image to extract raw text, then a second pass structures that text into JSON. This was our best-performing prompt strategy out of three variants tested on a 50-image sample (strict_schema, two_pass, table_first).

2. Granite3.2-vision — single-pass VLM

IBM's 2B document-focused vision model. Sends the receipt image directly with an extraction prompt and gets structured JSON back in one shot. We also tested a two-pass variant (read image, then extract from text), but single-pass outperformed it on every metric while running 2.3x faster — so single-pass is the configuration reported here.

3. PaddleOCR + GLM-OCR — OCR + LLM pipeline

A traditional two-stage approach: PaddleX PP-OCRv5 extracts raw text from the image, then GLM-OCR (the same 0.9B model, but text-only) parses that text into structured JSON. This tests whether a dedicated OCR engine feeding a language model can outperform end-to-end vision models.

Two additional models were considered but didn't reach the benchmark:

  • Tesseract + GLM-OCR — Early baseline, scored worse than GLM-OCR native across the board. Results archived.
  • dots.ocr (1.7B) — RedNote's SOTA model on OmniDocBench. Rejected due to tooling immaturity: no GGUF/Ollama support, missing HuggingFace processor files, flash_attn build failures on WSL2, and garbage output from community quantizations. The only viable path was vLLM Docker, which was too heavyweight for a validation comparison. Worth revisiting if a GGUF appears on Ollama.

How We Measured

Four metrics, each with a kill threshold — fail any one and the pipeline gets a NO-GO verdict:

MetricWhat It MeasuresThreshold
Numeric AccuracyDoes the extracted total match ground truth exactly?≥ 90%
Date AccuracyDoes the extracted date match after normalization?≥ 85%
Hallucination RateDid the model invent values not present on the receipt?≤ 5%
Structural IntegrityIs the output valid JSON with all required keys?≥ 95%

These thresholds are deliberately strict. Receipt OCR is a financial data problem — an 81% accuracy rate means roughly 1 in 5 receipts has a wrong total. That's not viable for any real application.

Results

All three pipelines received a NO-GO verdict.

Overall Verdict — All 3 Pipelines NO-GO — No pipeline meets kill thresholds
Pipeline Comparison — 200 images each, all NO-GO
PipelineNumericDateHalluc.Struct.ErrorsAvg TimeVerdict
GLM-OCR native two-pass VLM81.5%90.0%38.0%94.5%43.1sNO-GO
Granite3.2-vision single-pass VLM51.5%86.0%64.5%100%03.8sNO-GO
PaddleOCR + GLM-OCR OCR + LLM64.5%79.5%46.0%89.0%1916.7sNO-GO
GLM-OCR native is the best performer but still fails 3 of 4 kill thresholds. Granite3.2-vision (2B) achieves perfect structural output but hallucinates on 64.5% of images. PaddleOCR + GLM-OCR is worst across the board with 19 Ollama HTTP 500 errors and the highest per-image latency.
Visual Comparison
Numeric
 
81.5
51.5
64.5
thr: 90%
Date
 
90.0
86.0
79.5
thr: 85%
Halluc.
 
38.0
64.5
46.0
thr: ≤5%
Struct.
 
94.5
100
89.0
thr: 95%
GLM-OCR Granite3.2-vision PaddleOCR + GLM-OCR

Best Pipeline Detail — GLM-OCR native

Numeric Accuracy KILL
81.5%
 
 
163 / 200 totals matched exactly — threshold: ≥ 90%
Date Accuracy PASS
90.0%
 
 
180 / 200 dates normalized correctly — threshold: ≥ 85%
Hallucination Rate KILL
38.0%
 
 
76 / 200 images had ≥1 hallucinated field — threshold: ≤ 5%
Structural Integrity KILL
94.5%
 
 
189 / 200 produced valid JSON with required keys — threshold: ≥ 95%

Performance

GLM-OCR native
Images200
Errors4
Avg / image3.1s
Total time10.3 min
Model0.9B q8_0
Granite3.2-vision
Images200
Errors0
Avg / image3.8s
Total time12.6 min
Model2B fp16
PaddleOCR + GLM-OCR
Images200
Errors19
Avg / image16.7s
Total time55.8 min
OCR + ModelPPOCRv5 + 0.9B

GLM-OCR and Granite are both fast enough for interactive use (~3–4s per receipt). PaddleOCR's 16.7s average is dominated by the OCR preprocessing step, and its 19 errors (9.5% failure rate) make it the least reliable pipeline by a wide margin.

All evaluations ran on a single RTX 3080 10GB. GPU contention between Ollama models is a real constraint — concurrent model loading caused severe stalls, so all pipelines were run sequentially.

GLM-OCR Prompt Strategy

Before the full 200-image evaluation, we tested three prompt strategies for GLM-OCR on a 50-image sample:

Prompt Variant Comparison — 50 image sample
VariantNumericDateHalluc.Struct.CompositeSpeed
strict_schema 1-pass86.0%86.0%36.0%100%0.8441.4s
two_pass 2-pass88.0%90.0%34.0%92.0%0.8482.8s
table_first 2-pass70.0%30.0%20.0%4.0%0.5082.9s
The table_first variant's 4% structural integrity indicates near-total output format failure — the model returned raw tabular text instead of the requested JSON schema, producing parseable output on only 2 of 50 images.

All Models Evaluated

Model / PipelineTypeSizeStatusResult
GLM-OCR nativeVLM (OCR-specific)0.9B q8_0TestedNO-GO (best)
Granite3.2-visionVLM (document-focused)2B fp16TestedNO-GO
PaddleOCR + GLM-OCROCR + LLMPPOCRv5 + 0.9BTestedNO-GO
Tesseract + GLM-OCROCR + LLMTess 5 + 0.9BArchivedNO-GO
dots.ocrVLM1.7BRejectedTooling immaturity

What We Learned

End-to-end VLMs beat OCR+LLM pipelines

This was the biggest takeaway. We expected PaddleOCR (a modern, well-regarded OCR engine) feeding GLM-OCR to outperform GLM-OCR looking at the image directly. The opposite happened — on every single metric.

The intuition is that raw OCR text is lossy. It strips layout, spatial relationships, and visual context that vision models can use. A receipt's total is usually the largest number at the bottom — that's a visual signal. When you flatten the receipt into a text stream, that signal disappears and the model has to guess which number is the total based on surrounding keywords alone. PaddleOCR's 19 HTTP 500 errors (likely from oversized text payloads overflowing GLM-OCR's context window) didn't help either.

OCR-specific training matters more than model size

Granite3.2-vision is over twice the size of GLM-OCR (2B vs 0.9B) and is specifically marketed for document understanding. Yet GLM-OCR's OCR-focused training data gave it a 30-point lead on numeric accuracy (81.5% vs 51.5%) and far lower hallucination rates (38% vs 64.5%).

Granite does excel at one thing: structural output. It produced valid JSON with all required keys on 100% of images — perfect structural integrity. It understands what to output, it just gets the values wrong. This is an interesting signal: a model that reliably produces the right schema but fills it with hallucinated values might be fixable with better prompting or fine-tuning, whereas a model that produces broken output is harder to recover from.

Hallucination is the universal blocker

Every pipeline hallucinates at rates 7–13x above the 5% threshold. This isn't surprising for sub-2B models — they simply don't have enough capacity to reliably distinguish "I see this on the receipt" from "this seems like a reasonable value." The hallucination metric flags any image where at least one extracted field contains a value not present in the source, and at these model sizes, creative gap-filling is the norm rather than the exception.

Two-pass hurts Granite, helps GLM-OCR

An interesting divergence. For GLM-OCR, two-pass mode (read the image, then extract from text) was the best prompt strategy — it slightly outperformed single-pass structured extraction on a 50-image sample. For Granite3.2-vision, two-pass was strictly worse: -9% numeric, -5.5% date, +11% hallucination, and 2.3x slower. The likely explanation is that GLM-OCR's first pass produces high-fidelity OCR text (it's trained for exactly this), while Granite's first pass produces a rougher transcription that loses more information than it preserves.

Phase 1 Verdict: NO-GO

No locally-hosted small model pipeline meets our production thresholds on the SROIE benchmark. The best performer (GLM-OCR native at 0.9B) gets closest, but an 81.5% numeric accuracy and 38% hallucination rate are not production-viable for financial data extraction.

What's Next

Phase 1 establishes a clear baseline and eliminates the hypothesis that sub-2B local models can do receipt OCR at production quality today. The path forward likely involves one or more of:

  • Larger local models (7B+ class) that may have enough capacity to reduce hallucination rates, at the cost of higher memory requirements and slower inference
  • Cloud API comparison to establish an upper bound on what's achievable and quantify the accuracy gap between local and hosted models
  • Hybrid architectures that use a small local model for initial extraction with a cloud model for verification/correction of low-confidence results
  • Fine-tuning GLM-OCR or a similar model on receipt-specific data, since its OCR-focused pretraining already gives it a meaningful edge

The open-source OCR landscape is evolving rapidly — GLM-OCR and dots.ocr are very recent additions to the OCR ecosystem. We plan to revisit this evaluation when the next generation of models ships, particularly if dots.ocr releases Ollama-compatible weights. The scoring pipeline, evaluation harness, and dashboard are all reusable for Phase 2 testing.