Instructions to use harsha-desaraju/telugu-ocr-model with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use harsha-desaraju/telugu-ocr-model with Transformers:
# Use a pipeline as a high-level helper # Warning: Pipeline type "image-to-text" is no longer supported in transformers v5. # You must load the model directly (see below) or downgrade to v4.x with: # 'pip install "transformers<5.0.0' from transformers import pipeline pipe = pipeline("image-to-text", model="harsha-desaraju/telugu-ocr-model", trust_remote_code=True)# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("harsha-desaraju/telugu-ocr-model", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
Telugu OCR — line recognition, trained from scratch
A Telugu text-line recogniser built end to end for Telugu: a convolutional-stem CTC image encoder joined to a Telugu grapheme language model by cross-attention. Give it an image of one line of Telugu text and it returns the text.
It makes about one fifth as many errors as the best general-purpose OCR engine available for Telugu.
Results
Scored on harsha-desaraju/telugu-line-ocr-bench — 1044 line crops whose transcriptions a human checked against the image. Every engine read the identical images and was scored against the identical references. All figures are percentages; lower is better except the last column.
| engine | CER | AER | WER | exact line |
|---|---|---|---|---|
this model (joint decode) |
1.19 | 1.98 | 9.53 | 71.7 |
this model (ctc decode) |
1.34 | 2.23 | 10.52 | 69.7 |
Tesseract 5.5 (tel, psm 13) |
6.64 | 9.99 | 31.98 | 26.7 |
| Surya 1 (0.14.x) | 9.88 | 13.54 | 36.10 | 24.1 |
PaddleOCR 3.x (te) |
9.21 | 13.84 | 42.14 | 17.2 |
AER — akshara error rate — is the number to read for Telugu. A Telugu akshara is usually three or four code points, so CER charges a missing vowel sign one edit and a garbled cluster two or three, while a reader perceives one wrong syllable either way.
By AER this model is 5.0× better than Tesseract, 6.8× better than Surya and 7.0× better than PaddleOCR. It transcribes 71.7% of lines with zero errors, against 26.7% for the strongest baseline — the difference between output you can read and output you have to correct.
Its remaining errors: 244 substitutions, 78 insertions, 205 deletions across 26,650 reference aksharas. Deletions dominate, mostly dropped spaces.
Usage
The architecture is custom, so the model ships its own code and needs
trust_remote_code=True. Nothing else to install beyond transformers, torch, pillow
and regex.
from PIL import Image
from transformers import AutoModel, AutoTokenizer
model = AutoModel.from_pretrained("harsha-desaraju/telugu-ocr-model",
trust_remote_code=True).eval()
tokenizer = AutoTokenizer.from_pretrained("harsha-desaraju/telugu-ocr-model",
trust_remote_code=True)
# one image -> str
print(model.transcribe(Image.open("line.png"), tokenizer))
# a list of images -> list[str]
print(model.transcribe([Image.open(p) for p in paths], tokenizer))
# fast mode: no beam search, ~9x quicker for ~11% more error
print(model.transcribe(images, tokenizer, decode="ctc"))
On a GPU, move the model first: model = model.to("cuda").
Input requirements
Feed it one line of text per image. Preprocessing is handled internally — grayscale,
resize to height 64 preserving aspect ratio, pad the width to a multiple of 8 — so pass a
plain PIL.Image. A line wider than 2048px once scaled to height 64 cannot be encoded and
returns "" rather than being silently truncated.
There is no page layout analysis or line detection here. Segment lines yourself first.
Decode modes
The same weights support three decoding strategies, selected per call.
| mode | how | AER | when to use |
|---|---|---|---|
ctc |
per-frame argmax off the CTC head, collapse repeats, drop blanks | 2.23 | bulk throughput — ~9× faster, only ~11% worse |
beam |
beam search over the text decoder | — | language-model reading alone |
joint |
beam n-best rescored by λ·logP_ctc + (1−λ)·logP_attn, λ=0.3 |
1.98 | best accuracy (default) |
joint is the headline number and the default. Reach for ctc when labelling millions of
crops: it costs ~11% more AER and runs about nine times faster, with no beam search at all.
Architecture
~81M parameters, float32.
line image (1×64×W, W ≤ 2048)
↓ conv stem: 6 blocks, 32→64→128→256→320→384, height→1, width÷8
↓ 10-layer pre-LN transformer encoder, d=384, 8 heads, MLP 1536
├──→ CTC head (2049 classes = 2048 aksharas + blank)
↓ enc_to_dec: linear 384 → 512
↓ 16-layer GPT decoder, d=512, SwiGLU 1368, 8 heads, ctx 256
↓ cross-attention on every second block, zero-init tanh gate
→ text
| component | tensor elements |
|---|---|
| image encoder (conv stem + transformer + CTC head) | 20,006,529 |
| text decoder (GPT + cross-attention) | 61,056,008 |
enc_to_dec bridge |
197,120 |
| total | 81,259,657 |
Counts are over the checkpoint's 388 tensors, so they include the decoder's non-trainable positional table.
Two design choices carry most of the quality:
Grapheme (akshara) tokenisation. Text is split with regex.\X into Unicode grapheme
clusters — one cluster, one token, no BPE. Vocabulary 2048. A Telugu syllable is a single
token, so the decoder predicts syllables rather than assembling them from fragments of code
points.
Two heads over one encoder. The CTC head sees the image directly and cannot hallucinate text that is not there; the attention decoder carries language knowledge and repairs what CTC garbles. Keeping both allows rescoring one against the other, which is where the best numbers come from.
Training
Three pretrained pieces, then two fine-tuning stages:
- Image encoder — trained with CTC loss on Telugu line images.
- Text decoder — a 16-layer causal grapheme language model pretrained on Telugu text.
- Stage 1 — both backbones frozen; only the new cross-attention, its norms, the gates
and the bridge are trained. The gate is zero-initialised behind a
tanh, so the image contributes nothing at initialisation and is phased in as the gate learns. - Stage 2 — everything unfrozen and trained end to end, with the encoder's CTC head kept as an auxiliary term so it cannot drift away from the features the decoder relies on.
Training data was synthetic Telugu line renders (many fonts and sizes, degraded with a scan-simulation pipeline) mixed with real line crops from Telugu Wikisource proofread page scans. Real crops were not augmented — they are already degraded.
Limitations
- Printed book text only. Trained on printed Telugu from book scans and synthetic renders. No handwriting, no signage, no scene text, no historical orthography.
- Single lines only. No layout analysis or line detection; segment before calling.
- Hard width ceiling of 2048px at height 64. Longer lines must be split.
Citation
@misc{telugu_ocr_model,
title = {Telugu OCR: a grapheme-level CTC encoder with a cross-attending Telugu language model},
author = {Desaraju, Harsha},
year = {2026},
url = {https://huggingface.co/harsha-desaraju/telugu-ocr-model}
}
- Downloads last month
- -
Datasets used to train harsha-desaraju/telugu-ocr-model
harsha-desaraju/telugu-synthetic-line-images
harsha-desaraju/telugu-wikisource-text-images
Evaluation results
- CER (%) on Telugu Wikisource line OCR benchmark (human-verified)test set self-reported1.190
- WER (%) on Telugu Wikisource line OCR benchmark (human-verified)test set self-reported9.530
- Exact-line match (%) on Telugu Wikisource line OCR benchmark (human-verified)test set self-reported71.700