P110 ThaiOCR by Porsuk

P110-ThaiOCR-4B

P110-ThaiOCR-4B is a 4B vision-language model for Thai documents: printed and handwritten text, tables, forms, government PDFs and scans. It reads pages into plain text or structured output and can answer questions about a document (key information, classification, charts), without per-template rules.

BF16 weights.

  • Developed by: Porsuk Rungarunsrisuk
  • Base model: Qwen/Qwen3.5-4B (Apache-2.0), fine-tuned with LoRA and merged.
  • Languages: Thai, English.
  • Thinking: off. The model was trained and evaluated without thinking, and the included chat template turns thinking off by default.

Variants

Repo Format
PorsukR/P110-ThaiOCR-4B BF16 (transformers / vLLM)
PorsukR/P110-ThaiOCR-4B-FP8 FP8 (vLLM)
PorsukR/P110-ThaiOCR-4B-W4A16 INT4 weight-only (vLLM)
PorsukR/P110-ThaiOCR-4B-NVFP4 NVFP4 (vLLM, Blackwell)
PorsukR/P110-ThaiOCR-4B-GGUF GGUF Q8_0 / Q4_K_M (llama.cpp, Ollama)

Usage

Recommended prompt for plain transcription (Thai):

อ่านข้อความทั้งหมดในภาพนี้แบบครบถ้วนและตรงตามต้นฉบับ รวมถึงตัวเลข ตาราง หัวข้อ และเนื้อหาทุกส่วน ห้ามสรุป ห้ามข้ามส่วนใด ห้ามเพิ่มคำอธิบาย

vllm serve PorsukR/P110-ThaiOCR-4B --max-model-len 32768
from openai import OpenAI
import base64

client = OpenAI(base_url="http://localhost:8000/v1", api_key="none")
img = base64.b64encode(open("page.png", "rb").read()).decode()
resp = client.chat.completions.create(
    model="PorsukR/P110-ThaiOCR-4B",
    messages=[{"role": "user", "content": [
        {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{img}"}},
        {"type": "text", "text": "อ่านข้อความทั้งหมดในภาพนี้แบบครบถ้วนและตรงตามต้นฉบับ รวมถึงตัวเลข ตาราง หัวข้อ และเนื้อหาทุกส่วน ห้ามสรุป ห้ามข้ามส่วนใด ห้ามเพิ่มคำอธิบาย"},
    ]}],
    temperature=0,
    max_tokens=4096,  # stops a rare runaway repeat; raise it for very dense pages
    extra_body={"chat_template_kwargs": {"enable_thinking": False}},
)
print(resp.choices[0].message.content)

Tested with vLLM 0.29.0 and transformers 5.17.0.

Evaluation

All open models were run on the same hardware with the same scoring code (October 2026). Qwen3.5-4B is the base model P110 was fine-tuned from. Models with two runs are averaged. Bold marks the best score in each row.

GPT-6 Luna is a closed model, called through its API. Like every other model in these tables, it was run without thinking, with the same images, prompts and scoring code. On ThaiOCRBench, 15 of the 2,808 items were filtered by the API and returned no answer; an item with no answer scores 0.

Prompts: on ThaiOCRBench every model gets the benchmark's own prompt for each task. For CER, the text crops (ocr_th, iapp, openthaigpt) use the plain OCR prompt from the Usage section, and the PDF pages use a page-to-JSON prompt (text blocks, headings, tables) that falls back to the plain OCR prompt if the JSON is invalid. Typhoon OCR 7B is trained for its own fixed prompt, so its CER rows use its official prompt and sampling settings instead.

ThaiOCRBench (13 tasks, higher is better)

ThaiOCRBench, all 2,808 items. P110 is a general document model: it transcribes text and answers questions about documents (classification, key-information mapping, charts, infographics).

ThaiOCRBench, all 13 tasks

P110 has the highest 13-task average in this comparison: 23% above GPT-6 Luna (0.572 vs 0.465), 24% above Qwen3.5-9B (0.462) and 130% above Typhoon OCR 7B (0.249), while being much smaller than both (4B vs 9B and 7B).

Task P110-ThaiOCR-4B GPT-6 Luna (API) Qwen3.5-4B (base) Qwen3.5-9B Typhoon OCR 7B Typhoon2 Vision 7B Qwen-SEA-LION-v4-8B-VL Gemma-SEA-LION-v4-27B-VL
Chart parsing 0.757 0.774 0.109 0.758 0.001 0.245 0.744 0.775
Cognition VQA 0.686 0.400 0.472 0.566 0.486 0.521 0.502 0.410
Diagram VQA 0.476 0.417 0.456 0.538 0.358 0.277 0.403 0.280
Document classification 0.773 0.823 0.861 0.921 0.346 0.815 0.865 0.851
Document parsing 0.409 0.472 0.343 0.451 0.054 0.230 0.486 0.376
Fine-grained text recognition 0.459 0.101 0.115 0.044 0.091 0.051 0.045 0.076
Full-page OCR 0.734 0.656 0.678 0.793 0.644 0.494 0.703 0.528
Handwritten content extraction 0.395 0.134 0.131 0.135 0.205 0.146 0.134 0.180
Infographics 0.755 0.391 0.568 0.645 0.496 0.564 0.558 0.451
Key information extraction 0.217 0.425 0.212 0.314 0.000 0.039 0.369 0.417
Key information mapping 0.464 0.674 0.376 0.521 0.000 0.004 0.700 0.608
Table parsing 0.585 0.638 0.340 0.111 0.182 0.258 0.576 0.321
Text recognition 0.723 0.143 0.149 0.208 0.371 0.302 0.143 0.290
Average, all 13 tasks 0.572 0.465 0.370 0.462 0.249 0.303 0.479 0.428
Average, 5 transcription tasks 0.569 0.409 0.328 0.340 0.291 0.286 0.409 0.339

Typhoon OCR 7B with its own official prompt scores 0.476 on the 5 transcription tasks (it is not built for the other 8).

ThaiOCRBench, 5 transcription tasks vs Typhoon OCR 7B

Character error rate (CER %, lower is better)

Character error rate (CER)

Test set P110-ThaiOCR-4B GPT-6 Luna (API) Qwen3.5-4B (base) Qwen3.5-9B Typhoon OCR 7B Typhoon2 Vision 7B Qwen-SEA-LION-v4-8B-VL Gemma-SEA-LION-v4-27B-VL
Thai printed text — mekpro/ocr_th (held-out split, 400) 1.97 5.06 82.81 3.73 8.99 35.26 7.15 9.69
Thai handwriting — iapp/thai_handwriting_dataset (held-out split, 1,355) 35.70 89.78 100.00 43.41 23.50 57.38 59.95 86.05
openthaigpt/thai-ocr-evaluation (104 crops) 6.72 30.29 100.00 10.65 3.88 67.74 12.32 23.95
Thai government PDFs — set A (in-house, 20 pages) 3.49 26.58 15.59 4.78 8.41 25.68 12.95 27.18
Thai government PDFs — set B (in-house, 66 pages) 7.36 33.88 12.74 7.43 9.73 24.82 12.69 29.30
Scanned Thai government documents (in-house, 86 pages) 6.09 13.84 13.99 11.29 9.23 47.90 13.10 27.72

Typhoon OCR 7B is better on handwriting and on the openthaigpt crops. GPT-6 Luna follows the prompts but misreads much of the Thai handwriting, often replacing it with different, plausible Thai words. Qwen3.5-4B (base) often reads the text but adds explanations or summaries despite the plain-OCR prompt; those extra characters count as errors, so several of its crop scores reach the 100% cap.

How CER is measured

CER is the character edit distance (Levenshtein) between the model output and the reference text, divided by the length of the reference, averaged over items. Each item is capped at 100%, so one runaway output cannot dominate the average. Before comparing, both texts go through the same normalization for every model: Unicode NFC, a detached sara am (ํ + า) joined into ำ, curly quotes made straight, markdown table rules and |*# markup removed, dotted or underlined fill-in lines (……, ___) removed, and all whitespace removed (Thai does not separate words with spaces, and models differ in how they space and break lines).

The held-out splits of mekpro/ocr_th and iapp/thai_handwriting_dataset are 10% of each subset, chosen with a fixed seed (42) before training and never trained on. The training data was also checked for overlap with ThaiOCRBench. The three PDF sets are in-house pages of Thai government documents with verified reference text.

Quantized variants

Variant Format For CER % handwriting / printed
BF16 safetensors vLLM, transformers 35.52 / 1.98
FP8 compressed-tensors FP8 dynamic vLLM, Ada / Hopper and newer 35.58 / 2.13
W4A16 compressed-tensors INT4 (GPTQ) vLLM, Ampere and newer 36.30 / 2.38
NVFP4 compressed-tensors NVFP4 (MLP) + FP8 (attention) vLLM, Blackwell 37.80 / 2.32
Q8_0 GGUF llama.cpp, Ollama 35.69 / 2.16
Q4_K_M GGUF (Thai OCR imatrix) llama.cpp, Ollama 36.20 / 2.06

The full held-out sets from the CER table (iapp handwriting, 1,355 items; ocr_th printed text, 400 items), run on each released file, lower is better. The BF16 row is the released merged weights; the CER table above comes from the evaluation run before merging, so its numbers differ slightly. GGUF files were run in llama.cpp with --image-min-tokens 64.

Training data (summary)

Synthetic Thai documents rendered from many layouts and fonts (forms, memos, tables, receipts); realistic handwritten documents composed from real handwriting segmented into individual characters; pages from publicly available Thai documents with verified text; public Thai OCR datasets (mekpro/ocr_th, iapp/thai_handwriting_dataset, training splits only); and question–answer pairs whose answers are taken directly from the verified text. No benchmark test data was used for training.

Limitations

  • Handwriting is the weakest area (see the table above).
  • Upside-down or heavily rotated pages are not detected; rotate pages upright first.
  • Very long or dense pages can occasionally loop; set a max_tokens limit.
  • Rare stray non-Thai glyphs inside Thai words can appear.

License and attribution

Developed by Porsuk Rungarunsrisuk. Released under Apache-2.0 (see LICENSE and NOTICE). Built on Qwen3.5-4B by the Qwen team (Alibaba Cloud); this project is not affiliated with or endorsed by the Qwen team.

Citation

@misc{rungarunsrisuk2026p110thaiocr,
  title  = {P110-ThaiOCR-4B: a 4B vision-language model for Thai document OCR},
  author = {Rungarunsrisuk, Porsuk},
  year   = {2026},
  url    = {https://huggingface.co/PorsukR/P110-ThaiOCR-4B}
}
Downloads last month
59
Safetensors
Model size
5B params
Tensor type
BF16
·
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for PorsukR/P110-ThaiOCR-4B

Finetuned
Qwen/Qwen3.5-4B
Finetuned
(1110)
this model
Quantizations
5 models

Collection including PorsukR/P110-ThaiOCR-4B