A benchmarking framework comparing 22 open-weight OCR models against 97 Australian insurance Product Disclosure Statement (PDS) PDFs (~7,500 pages). The PDFs contain native embedded text, providing free ground truth for measuring text extraction accuracy without manual annotation.
Most OCR benchmarks use academic datasets (receipts, handwriting, scene text). Real-world document processing — especially in regulated industries like insurance — involves dense multi-column layouts, nested tables, legal boilerplate, and mixed formatting. This benchmark fills that gap by evaluating models on genuine insurance documents that represent the kind of content organisations actually need to extract.
| Model | Parameters | Source | Notes |
|---|---|---|---|
| LightOn OCR 2 | 1B | LightOn | Strong benchmark leader, clean API |
| GOT-OCR2 | 0.6B | StepFun | Smallest VLM in the set |
| dots.ocr | 1.6B | NexaAI | Document-specific small model |
| DeepSeek-OCR | 2B | DeepSeek | Dedicated OCR model |
| Nanonets-OCR-s | 3B | Nanonets | Markdown output |
| OCRFlux-3B | 3B | Carkham | Qwen2.5-VL architecture |
| Florence-2 | 0.77B | Microsoft | Vision-language model with OCR tasks |
| Granite Vision 3.3 | 2B | IBM | General vision model |
| Granite-Docling-258M | 258M | IBM | Small document conversion model |
| MonkeyOCR | 1.2B | — | Specialized document OCR |
| PaddleOCR-VL-1.5 | 0.9B | PaddlePaddle | Strong layout/table parsing |
| Qwen2.5-VL-3B | 3B | Alibaba | Smaller Qwen2.5-VL variant |
| DocTR | ~25M | Mindee | Detection + recognition pipeline |
| Model | Parameters | Source | Notes |
|---|---|---|---|
| olmOCR | 7B | Allen AI | Uses custom toolkit |
| RolmOCR | 7B | Reducto | Refined olmOCR |
| Qwen2.5-VL-7B | 7B | Alibaba | General VLM, strong OCR capability |
| Chandra | 7B | — | Document-specialized VLM |
| Model | Notes |
|---|---|
| Tesseract | Classic OCR baseline |
| PaddleOCR | Baidu's detection + recognition toolkit |
| EasyOCR | 80+ language support |
| Surya | Scaffold — integration pending |
| MinerU | Scaffold — integration pending |
PDF corpus ──► Data Prep (render PNGs + extract ground truth)
│
▼
Sample Sets (stratified page manifests)
│
▼
Runner (adapters load/infer/unload sequentially)
│
▼
Evaluator (metrics + bootstrap CIs + ranking)
│
▼
Dashboard (Plotly charts + qualitative HTML viewer)
All models implement a common OCRAdapter interface with load_model() / ocr_page() / unload_model(). The runner loads one model at a time, runs inference across a sample set, saves per-page markdown outputs, then unloads before the next model. A canonical inference protocol (deterministic decoding, shared prompt) ensures fair comparison.
Ground truth is extracted from the PDFs' embedded text layer using pdfplumber and PyMuPDF with best-of selection per page:
This dual-extraction approach handles the multi-column layouts common in insurance documents, where single-extractor approaches often scramble reading order.
| Set | Pages | Documents | Purpose |
|---|---|---|---|
quick_dev | 20 | 16 | Fast adapter development and debugging |
stratified_100 | 100 | 20 | Primary benchmark set |
table_focus | 50 | 13 | Table extraction evaluation |
full_benchmark | 300 | 84 | Comprehensive comparison |
# Core (PDF processing + evaluation metrics)
pip install -e .
# Add visualisation
pip install -e ".[viz]"
# Add traditional OCR baselines (DocTR, PaddleOCR, EasyOCR, Tesseract)
pip install -e ".[traditional]"
# For Colab GPU runs
pip install -r requirements/colab_tier1.txt # T4
pip install -r requirements/colab_tier2.txt # A100
# Quick: import + instantiate all adapters
python scripts/smoke_adapters.py
# Test specific models
python scripts/smoke_adapters.py --models tesseract qwen25_vl_3b
# Deep: instantiate + load/unload (needs GPU for VLMs)
python scripts/smoke_adapters.py --load-model
pytest tests/
The benchmark is structured as a sequence of notebooks, designed to run data prep locally and GPU inference on Colab:
| # | Notebook | Environment | Purpose |
|---|---|---|---|
| 00 | data_prep | Local | Unzip PDFs, render page images, extract ground truth |
| 01 | build_sample_sets | Local | Create stratified sample set manifests |
| 02 | tier1_benchmark | Colab T4 | Run Tier 1 models (≤8 GB) |
| 03 | tier2_benchmark | Colab A100 | Run Tier 2 models (7B) |
| 04 | traditional_baselines | CPU | Run CPU/toolkit baselines |
| 05 | evaluation | Local | Compute all metrics vs ground truth |
| 06 | results_dashboard | Local | Generate comparison charts and viewer |
config/model_registry.yamlsrc/adapters/ extending OCRAdapterload_model() and ocr_page() using the base class helpers (_get_instruction(), _get_generation_kwargs(), _resolve_device(), _extract_tables())This project is open source. See LICENSE for details.
9 commits
Python
85.1%
Jupyter Notebook
14.9%
A benchmarking framework comparing 22 open-weight OCR models against 97 Australian insurance Product Disclosure Statement (PDS) PDFs (~7,500 pages). The PDFs contain native embedded text, providing free ground truth for measuring text extraction accuracy without manual annotation.
Most OCR benchmarks use academic datasets (receipts, handwriting, scene text). Real-world document processing — especially in regulated industries like insurance — involves dense multi-column layouts, nested tables, legal boilerplate, and mixed formatting. This benchmark fills that gap by evaluating models on genuine insurance documents that represent the kind of content organisations actually need to extract.
| Model | Parameters | Source | Notes |
|---|---|---|---|
| LightOn OCR 2 | 1B | LightOn | Strong benchmark leader, clean API |
| GOT-OCR2 | 0.6B | StepFun | Smallest VLM in the set |
| dots.ocr | 1.6B | NexaAI | Document-specific small model |
| DeepSeek-OCR | 2B | DeepSeek | Dedicated OCR model |
| Nanonets-OCR-s | 3B | Nanonets | Markdown output |
| OCRFlux-3B | 3B | Carkham | Qwen2.5-VL architecture |
| Florence-2 | 0.77B | Microsoft | Vision-language model with OCR tasks |
| Granite Vision 3.3 | 2B | IBM | General vision model |
| Granite-Docling-258M | 258M | IBM | Small document conversion model |
| MonkeyOCR | 1.2B | — | Specialized document OCR |
| PaddleOCR-VL-1.5 | 0.9B | PaddlePaddle | Strong layout/table parsing |
| Qwen2.5-VL-3B | 3B | Alibaba | Smaller Qwen2.5-VL variant |
| DocTR | ~25M | Mindee | Detection + recognition pipeline |
| Model | Parameters | Source | Notes |
|---|---|---|---|
| olmOCR | 7B | Allen AI | Uses custom toolkit |
| RolmOCR | 7B | Reducto | Refined olmOCR |
| Qwen2.5-VL-7B | 7B | Alibaba | General VLM, strong OCR capability |
| Chandra | 7B | — | Document-specialized VLM |
| Model | Notes |
|---|---|
| Tesseract | Classic OCR baseline |
| PaddleOCR | Baidu's detection + recognition toolkit |
| EasyOCR | 80+ language support |
| Surya | Scaffold — integration pending |
| MinerU | Scaffold — integration pending |
PDF corpus ──► Data Prep (render PNGs + extract ground truth)
│
▼
Sample Sets (stratified page manifests)
│
▼
Runner (adapters load/infer/unload sequentially)
│
▼
Evaluator (metrics + bootstrap CIs + ranking)
│
▼
Dashboard (Plotly charts + qualitative HTML viewer)
All models implement a common OCRAdapter interface with load_model() / ocr_page() / unload_model(). The runner loads one model at a time, runs inference across a sample set, saves per-page markdown outputs, then unloads before the next model. A canonical inference protocol (deterministic decoding, shared prompt) ensures fair comparison.
Ground truth is extracted from the PDFs' embedded text layer using pdfplumber and PyMuPDF with best-of selection per page:
This dual-extraction approach handles the multi-column layouts common in insurance documents, where single-extractor approaches often scramble reading order.
| Set | Pages | Documents | Purpose |
|---|---|---|---|
quick_dev | 20 | 16 | Fast adapter development and debugging |
stratified_100 | 100 | 20 | Primary benchmark set |
table_focus | 50 | 13 | Table extraction evaluation |
full_benchmark | 300 | 84 | Comprehensive comparison |
# Core (PDF processing + evaluation metrics)
pip install -e .
# Add visualisation
pip install -e ".[viz]"
# Add traditional OCR baselines (DocTR, PaddleOCR, EasyOCR, Tesseract)
pip install -e ".[traditional]"
# For Colab GPU runs
pip install -r requirements/colab_tier1.txt # T4
pip install -r requirements/colab_tier2.txt # A100
# Quick: import + instantiate all adapters
python scripts/smoke_adapters.py
# Test specific models
python scripts/smoke_adapters.py --models tesseract qwen25_vl_3b
# Deep: instantiate + load/unload (needs GPU for VLMs)
python scripts/smoke_adapters.py --load-model
pytest tests/
The benchmark is structured as a sequence of notebooks, designed to run data prep locally and GPU inference on Colab:
| # | Notebook | Environment | Purpose |
|---|---|---|---|
| 00 | data_prep | Local | Unzip PDFs, render page images, extract ground truth |
| 01 | build_sample_sets | Local | Create stratified sample set manifests |
| 02 | tier1_benchmark | Colab T4 | Run Tier 1 models (≤8 GB) |
| 03 | tier2_benchmark | Colab A100 | Run Tier 2 models (7B) |
| 04 | traditional_baselines | CPU | Run CPU/toolkit baselines |
| 05 | evaluation | Local | Compute all metrics vs ground truth |
| 06 | results_dashboard | Local | Generate comparison charts and viewer |
config/model_registry.yamlsrc/adapters/ extending OCRAdapterload_model() and ocr_page() using the base class helpers (_get_instruction(), _get_generation_kwargs(), _resolve_device(), _extract_tables())This project is open source. See LICENSE for details.
9 commits
Python
85.1%
Jupyter Notebook
14.9%