Image-Text-to-Text
Transformers
Safetensors
Tibetan
paddleocr_vl
ocr
tibetan
vision-language
paddleocr-vl
pecha
conversational
Instructions to use BDRC/tibetan-ocr with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use BDRC/tibetan-ocr with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="BDRC/tibetan-ocr") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("BDRC/tibetan-ocr") model = AutoModelForMultimodalLM.from_pretrained("BDRC/tibetan-ocr", device_map="auto") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(processor.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use BDRC/tibetan-ocr with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "BDRC/tibetan-ocr" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "BDRC/tibetan-ocr", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/BDRC/tibetan-ocr
- SGLang
How to use BDRC/tibetan-ocr with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "BDRC/tibetan-ocr" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "BDRC/tibetan-ocr", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "BDRC/tibetan-ocr" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "BDRC/tibetan-ocr", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Docker Model Runner
How to use BDRC/tibetan-ocr with Docker Model Runner:
docker model run hf.co/BDRC/tibetan-ocr
Yigdzin 1 weights: elie_v8_coarse_grow26_ep2 (no-leakage, benchmark held out); update card + eval numbers
Browse files- README.md +56 -48
- model.safetensors +1 -1
- processor_config.json +3 -3
- tokenizer_config.json +6 -3
README.md
CHANGED
|
@@ -17,23 +17,27 @@ metrics:
|
|
| 17 |
|
| 18 |
# Tibetan OCR — Yigdzin 1
|
| 19 |
|
| 20 |
-
<!--
|
| 21 |
-
|
|
|
|
| 22 |
|
| 23 |
**A vision-first OCR model for Tibetan pecha** — modern publications, woodblock
|
| 24 |
prints, and manuscripts (uchen and u-med), including pecha layout and orthographic
|
| 25 |
shorthands. Built by the [Buddhist Digital Resource Center (BDRC)](https://bdrc.io)
|
| 26 |
-
and trained on
|
|
|
|
| 27 |
|
| 28 |
-
- **Repository:** `BDRC/tibetan-ocr`
|
| 29 |
- **Base model:** [`PaddlePaddle/PaddleOCR-VL-1.6`](https://huggingface.co/PaddlePaddle/PaddleOCR-VL-1.6) (Apache-2.0)
|
| 30 |
- **Live demo:** [ocr.bdrc.io](https://ocr.bdrc.io) · **Desktop app:** [buda-base/tibetan-ocr-app](https://github.com/buda-base/tibetan-ocr-app)
|
| 31 |
|
| 32 |
## TL;DR
|
| 33 |
|
| 34 |
-
On a 1,070-page hand-transcribed benchmark
|
| 35 |
-
|
| 36 |
-
|
|
|
|
|
|
|
| 37 |
|
| 38 |
## Model details
|
| 39 |
|
|
@@ -43,6 +47,8 @@ On a 1,070-page hand-transcribed benchmark, typical-page character error rate is
|
|
| 43 |
| Parameters | ~810M (~413M vision · ~360M 26-layer decoder · ~4M embeddings/head) |
|
| 44 |
| Vision share | ~51–59% of parameters ("big eyes, small mouth" — vision-first) |
|
| 45 |
| Tokenizer | Tibetan **unicode-stack** tokenizer, vocab **3,560** (pruned + BoCorpus-warmed) |
|
|
|
|
|
|
|
| 46 |
| Languages | Tibetan (`bo`); Tibetan script |
|
| 47 |
| License | Apache-2.0 (derivative of PaddleOCR-VL-1.6; upstream `NOTICE` retained) |
|
| 48 |
| Funder | Khyentse Foundation ("The BDRC Etext Corpus") |
|
|
@@ -136,11 +142,11 @@ export OCR_VLLM_IMAGE_TOKEN_POSITIONS=sequential # 'grid' / unset = no-op
|
|
| 136 |
Without it, structured (book/list) pages skip or merge lines and CER regresses badly.
|
| 137 |
|
| 138 |
**2. DRY anti-loop guard + temperature retry (recommended).** Greedy decoding runs
|
| 139 |
-
away into repetition on
|
| 140 |
-
Yourself") penalty: it ties an n-gram ban on corpus CER, zeroes hard
|
| 141 |
-
`repetition_penalty` / `no_repeat_ngram_size` — barely touches
|
| 142 |
-
repetitive scripture (mantras, litanies). It ships here as
|
| 143 |
-
`dry_logits_processor.py` (torch-only):
|
| 144 |
|
| 145 |
```python
|
| 146 |
from vllm import LLM, SamplingParams
|
|
@@ -152,15 +158,15 @@ params = SamplingParams(temperature=0, max_tokens=4096, extra_args={
|
|
| 152 |
})
|
| 153 |
```
|
| 154 |
|
| 155 |
-
For the
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
and pick the sample with the lowest leftover repetition.
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
|
| 165 |
Do **not** reach for aggressive `repetition_penalty` / `no_repeat_ngram_size`: they
|
| 166 |
"correct away" legitimate repeated scripture. DRY with the config above is the tested,
|
|
@@ -168,47 +174,49 @@ surgical choice.
|
|
| 168 |
|
| 169 |
## Training data
|
| 170 |
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
|
|
|
| 174 |
|
| 175 |
-
- Real transcriptions: [ALL-BDRC (ACIP Sungbum)](https://huggingface.co/datasets/BDRC/
|
| 176 |
[PalriParkhang](https://huggingface.co/datasets/BDRC/palri-parkhang),
|
| 177 |
[Berkeley](https://huggingface.co/datasets/BDRC/berkeley),
|
| 178 |
[MonlamAI-transcriptions](https://huggingface.co/datasets/BDRC/monlamai-transcriptions),
|
| 179 |
[MonlamAI-handwritten](https://huggingface.co/datasets/BDRC/monlamai-handwritten),
|
| 180 |
-
[Stok](https://huggingface.co/datasets/
|
| 181 |
- Synthetic: [Tibetan OCR synthetic v5](https://huggingface.co/datasets/BDRC/tibetan-ocr-synthetic).
|
| 182 |
|
| 183 |
-
|
| 184 |
|
| 185 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
|
| 187 |
-
|
| 188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
| PaddleOCR-VL 18-layer baseline (ep1) | 0.1198 | 0.0211 | 16 |
|
| 194 |
-
|
| 195 |
-
Production serving adds the **DRY anti-loop guard + temperature retry** described in
|
| 196 |
-
[How to use](#how-to-use); that production configuration is reported on the leaderboard
|
| 197 |
-
as **Yigdzin-v1**.
|
| 198 |
-
|
| 199 |
-
CER = Levenshtein(hyp, ref)/len(ref) after botok normalization, whitespace
|
| 200 |
-
stripping, tsheg folding, and placeholder removal. Full method + the multi-system
|
| 201 |
-
leaderboard: **[BDRC Tibetan OCR benchmark](https://huggingface.co/datasets/BDRC/tibetan-ocr-benchmark)** and the **[leaderboard](https://huggingface.co/spaces/BDRC/tibetan-ocr-leaderboard)**.
|
| 202 |
|
| 203 |
## Limitations & recommendations
|
| 204 |
|
| 205 |
-
- **Residual repetition loops** on a small fraction of pages
|
| 206 |
-
|
| 207 |
-
leaving legitimate repetitive scripture (mantras) intact;
|
| 208 |
-
this gentle.
|
| 209 |
-
- **Line-break joins** on some dense (6-line) woodblock pecha
|
| 210 |
- Struggles on illustrations, non-Tibetan text, and illegible/damaged pages.
|
| 211 |
-
- Metrics are **preliminary (v1)** and may change in later generations.
|
| 212 |
|
| 213 |
## Citation
|
| 214 |
|
|
|
|
| 17 |
|
| 18 |
# Tibetan OCR — Yigdzin 1
|
| 19 |
|
| 20 |
+
<!-- Model card for BDRC/tibetan-ocr ("Yigdzin 1").
|
| 21 |
+
Weights: checkpoint elie_v8_coarse_grow26_ep2 (bec_mixed_elie_v8 mix, evaluation
|
| 22 |
+
benchmark pages held out of training via images_exclude_from_train.csv). -->
|
| 23 |
|
| 24 |
**A vision-first OCR model for Tibetan pecha** — modern publications, woodblock
|
| 25 |
prints, and manuscripts (uchen and u-med), including pecha layout and orthographic
|
| 26 |
shorthands. Built by the [Buddhist Digital Resource Center (BDRC)](https://bdrc.io)
|
| 27 |
+
and trained on the `bec_mixed_elie_v8` mix of curated real + synthetic pages, with
|
| 28 |
+
the **evaluation-benchmark pages held out of training**.
|
| 29 |
|
| 30 |
+
- **Repository:** `BDRC/tibetan-ocr` (display name **Yigdzin 1**)
|
| 31 |
- **Base model:** [`PaddlePaddle/PaddleOCR-VL-1.6`](https://huggingface.co/PaddlePaddle/PaddleOCR-VL-1.6) (Apache-2.0)
|
| 32 |
- **Live demo:** [ocr.bdrc.io](https://ocr.bdrc.io) · **Desktop app:** [buda-base/tibetan-ocr-app](https://github.com/buda-base/tibetan-ocr-app)
|
| 33 |
|
| 34 |
## TL;DR
|
| 35 |
|
| 36 |
+
On a 1,070-page hand-transcribed benchmark (production serving: vLLM + sequential
|
| 37 |
+
regime + DRY guard + temperature-retry), **median page CER is ~1.4%** and clean-page
|
| 38 |
+
(non-catastrophic) mean CER is **~4.0%**, with **0 hard repetition loops**. The
|
| 39 |
+
benchmark pages are held out of training. It is a *specialized* OCR model, not a
|
| 40 |
+
general chat VLM.
|
| 41 |
|
| 42 |
## Model details
|
| 43 |
|
|
|
|
| 47 |
| Parameters | ~810M (~413M vision · ~360M 26-layer decoder · ~4M embeddings/head) |
|
| 48 |
| Vision share | ~51–59% of parameters ("big eyes, small mouth" — vision-first) |
|
| 49 |
| Tokenizer | Tibetan **unicode-stack** tokenizer, vocab **3,560** (pruned + BoCorpus-warmed) |
|
| 50 |
+
| Decoder growth | grow26: SOLAR-style depth-upscale 18L→26L, then annealed |
|
| 51 |
+
| Position regime | **sequential** image-token M-RoPE (1-D); `max_pixels` 1280 budget |
|
| 52 |
| Languages | Tibetan (`bo`); Tibetan script |
|
| 53 |
| License | Apache-2.0 (derivative of PaddleOCR-VL-1.6; upstream `NOTICE` retained) |
|
| 54 |
| Funder | Khyentse Foundation ("The BDRC Etext Corpus") |
|
|
|
|
| 142 |
Without it, structured (book/list) pages skip or merge lines and CER regresses badly.
|
| 143 |
|
| 144 |
**2. DRY anti-loop guard + temperature retry (recommended).** Greedy decoding runs
|
| 145 |
+
away into repetition on a small fraction of pages. The surgical fix is the **DRY**
|
| 146 |
+
("Don't Repeat Yourself") penalty: it ties an n-gram ban on corpus CER, zeroes hard
|
| 147 |
+
loops, and — unlike `repetition_penalty` / `no_repeat_ngram_size` — barely touches
|
| 148 |
+
clean pages or legitimate repetitive scripture (mantras, litanies). It ships here as
|
| 149 |
+
the self-contained `dry_logits_processor.py` (torch-only):
|
| 150 |
|
| 151 |
```python
|
| 152 |
from vllm import LLM, SamplingParams
|
|
|
|
| 158 |
})
|
| 159 |
```
|
| 160 |
|
| 161 |
+
For the pages that still loop under greedy+DRY, **re-decode at temperature and keep the
|
| 162 |
+
cleanest sample.** The strong signal is *how often DRY fired*: the measured knee is
|
| 163 |
+
**≥ 100 fires** — re-decode only those pages at `temperature=0.4`, `n=3` (DRY still on)
|
| 164 |
+
and pick the sample with the lowest leftover repetition. On this benchmark that is ~2%
|
| 165 |
+
of pages and clears the residual hard loops. `dry_logits_processor.py` writes
|
| 166 |
+
per-request fire counts (pass `dry_stats_id` / `dry_stats_path` in `extra_args`, read
|
| 167 |
+
them back with `load_dry_stats_dir`); `deploy/fast_inference/bench.py` in the training
|
| 168 |
+
repo is the reference implementation of the full greedy → fire-count gate →
|
| 169 |
+
temperature-retry loop.
|
| 170 |
|
| 171 |
Do **not** reach for aggressive `repetition_penalty` / `no_repeat_ngram_size`: they
|
| 172 |
"correct away" legitimate repeated scripture. DRY with the config above is the tested,
|
|
|
|
| 174 |
|
| 175 |
## Training data
|
| 176 |
|
| 177 |
+
Curated mix (`bec_mixed_elie_v8`), assembled from BDRC alignment collections +
|
| 178 |
+
BoCorpus-rendered synthetic pages, with an easy→hard curriculum, u-med over-weighting,
|
| 179 |
+
and repetition-aware filtering. **The evaluation-benchmark pages are held out of
|
| 180 |
+
training** (`images_exclude_from_train.csv`). Released component datasets:
|
| 181 |
|
| 182 |
+
- Real transcriptions: [ALL-BDRC (ACIP Sungbum)](https://huggingface.co/datasets/BDRC/ALL-BDRC-alignments),
|
| 183 |
[PalriParkhang](https://huggingface.co/datasets/BDRC/palri-parkhang),
|
| 184 |
[Berkeley](https://huggingface.co/datasets/BDRC/berkeley),
|
| 185 |
[MonlamAI-transcriptions](https://huggingface.co/datasets/BDRC/monlamai-transcriptions),
|
| 186 |
[MonlamAI-handwritten](https://huggingface.co/datasets/BDRC/monlamai-handwritten),
|
| 187 |
+
[Stok](https://huggingface.co/datasets/openpecha/stok), [TibSchol](https://huggingface.co/datasets/BDRC/tibschol) *(gated)*.
|
| 188 |
- Synthetic: [Tibetan OCR synthetic v5](https://huggingface.co/datasets/BDRC/tibetan-ocr-synthetic).
|
| 189 |
|
| 190 |
+
## Evaluation
|
| 191 |
|
| 192 |
+
Evaluated on the BDRC hand-transcribed benchmark `20260315` (1,070 pages) in the
|
| 193 |
+
**production configuration** (vLLM + `vllm_paddleocr_seqpos` sequential regime + DRY
|
| 194 |
+
guard `mult=0.8 base=1.75 allowed_length=12` + temperature-retry `temp=0.4 n=3` on
|
| 195 |
+
pages with ≥100 DRY fires). Metrics from the benchmark's `compute_cer.py` (botok
|
| 196 |
+
normalization, whitespace stripping, tsheg folding, placeholder removal); pages with
|
| 197 |
+
CER > 50% are counted as *catastrophic* and reported separately.
|
| 198 |
|
| 199 |
+
| Metric (1,070 pages) | **Yigdzin 1** |
|
| 200 |
+
|---|---:|
|
| 201 |
+
| Median page CER | **0.0142** |
|
| 202 |
+
| Mean page CER (all) | 0.0628 |
|
| 203 |
+
| Catastrophic (>50%) share | 3.3% (35) |
|
| 204 |
+
| Clean mean CER (non-catastrophic) | **0.0404** |
|
| 205 |
+
| Clean mean SER | **0.0764** |
|
| 206 |
+
| Hard repetition loops | **0** |
|
| 207 |
|
| 208 |
+
Full method + the multi-system leaderboard:
|
| 209 |
+
**[BDRC Tibetan OCR benchmark](https://huggingface.co/datasets/BDRC/tibetan-ocr-benchmark)**
|
| 210 |
+
and the **[leaderboard](https://huggingface.co/spaces/BDRC/tibetan-ocr-leaderboard)**.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 211 |
|
| 212 |
## Limitations & recommendations
|
| 213 |
|
| 214 |
+
- **Residual repetition loops** on a small fraction of pages. Production uses the
|
| 215 |
+
**DRY** guard + temperature retry (see How to use), which clears them (0 hard loops
|
| 216 |
+
on the benchmark) while leaving legitimate repetitive scripture (mantras) intact;
|
| 217 |
+
keep any anti-loop mitigation this gentle.
|
| 218 |
+
- **Line-break joins** on some dense (6-line) woodblock pecha.
|
| 219 |
- Struggles on illustrations, non-Tibetan text, and illegible/damaged pages.
|
|
|
|
| 220 |
|
| 221 |
## Citation
|
| 222 |
|
model.safetensors
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 1628770560
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2a698bc88308b27656c808c87c33778feb3873c54ebf4bf334f9e17185532514
|
| 3 |
size 1628770560
|
processor_config.json
CHANGED
|
@@ -24,10 +24,10 @@
|
|
| 24 |
"resample": 3,
|
| 25 |
"rescale_factor": 0.00392156862745098,
|
| 26 |
"size": {
|
| 27 |
-
"
|
| 28 |
-
"
|
| 29 |
},
|
| 30 |
"temporal_patch_size": 1
|
| 31 |
},
|
| 32 |
"processor_class": "PaddleOCRVLProcessor"
|
| 33 |
-
}
|
|
|
|
| 24 |
"resample": 3,
|
| 25 |
"rescale_factor": 0.00392156862745098,
|
| 26 |
"size": {
|
| 27 |
+
"longest_edge": 1003520,
|
| 28 |
+
"shortest_edge": 1024
|
| 29 |
},
|
| 30 |
"temporal_patch_size": 1
|
| 31 |
},
|
| 32 |
"processor_class": "PaddleOCRVLProcessor"
|
| 33 |
+
}
|
tokenizer_config.json
CHANGED
|
@@ -1040,14 +1040,17 @@
|
|
| 1040 |
"<|image_pad|>",
|
| 1041 |
"<|video_pad|>"
|
| 1042 |
],
|
|
|
|
| 1043 |
"is_local": true,
|
| 1044 |
"local_files_only": false,
|
| 1045 |
"mask_token": "<mask:1>",
|
| 1046 |
"model_max_length": 1000000000000000019884624838656,
|
|
|
|
|
|
|
|
|
|
| 1047 |
"pad_token": "<unk>",
|
| 1048 |
"processor_class": "PaddleOCRVLProcessor",
|
| 1049 |
"sep_token": "<|end_of_sentence|>",
|
| 1050 |
"tokenizer_class": "TokenizersBackend",
|
| 1051 |
-
"unk_token": "<unk>"
|
| 1052 |
-
|
| 1053 |
-
}
|
|
|
|
| 1040 |
"<|image_pad|>",
|
| 1041 |
"<|video_pad|>"
|
| 1042 |
],
|
| 1043 |
+
"image_token": "<|IMAGE_PLACEHOLDER|>",
|
| 1044 |
"is_local": true,
|
| 1045 |
"local_files_only": false,
|
| 1046 |
"mask_token": "<mask:1>",
|
| 1047 |
"model_max_length": 1000000000000000019884624838656,
|
| 1048 |
+
"model_specific_special_tokens": {
|
| 1049 |
+
"image_token": "<|IMAGE_PLACEHOLDER|>"
|
| 1050 |
+
},
|
| 1051 |
"pad_token": "<unk>",
|
| 1052 |
"processor_class": "PaddleOCRVLProcessor",
|
| 1053 |
"sep_token": "<|end_of_sentence|>",
|
| 1054 |
"tokenizer_class": "TokenizersBackend",
|
| 1055 |
+
"unk_token": "<unk>"
|
| 1056 |
+
}
|
|
|