Eroux commited on
Commit
50506eb
·
verified ·
1 Parent(s): 5e82f0e

Yigdzin 1 weights: elie_v8_coarse_grow26_ep2 (no-leakage, benchmark held out); update card + eval numbers

Browse files
Files changed (4) hide show
  1. README.md +56 -48
  2. model.safetensors +1 -1
  3. processor_config.json +3 -3
  4. tokenizer_config.json +6 -3
README.md CHANGED
@@ -17,23 +17,27 @@ metrics:
17
 
18
  # Tibetan OCR — Yigdzin 1
19
 
20
- <!-- DRAFT model card for BDRC/tibetan-ocr, release tag v1 ("Yigdzin 1").
21
- Numbers are PRELIMINARY (v1). Confirm display name sign-off before publishing. -->
 
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 ~220k curated real + synthetic pages.
 
27
 
28
- - **Repository:** `BDRC/tibetan-ocr` · release **`v1`** (display name **Yigdzin 1**)
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, typical-page character error rate is
35
- **~1.8% (median CER 0.0179)**; corpus micro-CER is **0.0756** (greedy). It is a
36
- *specialized* OCR model, not a general chat VLM.
 
 
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 ~1.5% of pages. The surgical fix is the **DRY** ("Don't Repeat
140
- Yourself") penalty: it ties an n-gram ban on corpus CER, zeroes hard loops, and — unlike
141
- `repetition_penalty` / `no_repeat_ngram_size` — barely touches clean pages or legitimate
142
- repetitive scripture (mantras, litanies). It ships here as the self-contained
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 ~2% of pages that still loop under greedy+DRY, **re-decode at temperature and
156
- keep the cleanest sample.** The strong signal is *how often DRY fired*: the measured knee
157
- is **≥ 100 fires** — re-decode only those pages at `temperature=0.4`, `n=3` (DRY still on)
158
- and pick the sample with the lowest leftover repetition. That is ~2% of pages / ~20 s
159
- extra on the 1,070-page benchmark and clears the residual hard loops.
160
- `dry_logits_processor.py` writes per-request fire counts (pass `dry_stats_id` /
161
- `dry_stats_path` in `extra_args`, read them back with `load_dry_stats_dir`);
162
- `deploy/fast_inference/bench.py` in the training repo is the reference implementation of
163
- the full greedy → fire-count gate → temperature-retry loop.
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
- ~220k-page curated mix (`bec_mixed_elie_v6`), assembled from BDRC alignment
172
- collections + BoCorpus-rendered synthetic pages, with an easy→hard curriculum,
173
- u-med over-weighting, and repetition-aware filtering. Released component datasets:
 
174
 
175
- - Real transcriptions: [ALL-BDRC (ACIP Sungbum)](https://huggingface.co/datasets/BDRC/all-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/BDRC/stok), [TibSchol](https://huggingface.co/datasets/BDRC/tibschol) *(gated)*.
181
  - Synthetic: [Tibetan OCR synthetic v5](https://huggingface.co/datasets/BDRC/tibetan-ocr-synthetic).
182
 
183
- <!-- Fill final dataset repo links once created; see the release plan. -->
184
 
185
- ## Evaluation *(preliminary, v1)*
 
 
 
 
 
186
 
187
- Evaluated on the BDRC hand-transcribed benchmark `20260315` (1,070 pages), greedy
188
- decoding, `max_new_tokens=4096`, prompt policy `none`.
 
 
 
 
 
 
189
 
190
- | Setting | micro-CER | median CER | hard-loops |
191
- |---|---:|---:|---:|
192
- | **Yigdzin 1** (greedy) | **0.0756** | **0.0179** | **2** |
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 (~1.5% greedy). Production
206
- uses the **DRY** guard + temperature retry (see How to use), which clears them while
207
- leaving legitimate repetitive scripture (mantras) intact; keep any anti-loop mitigation
208
- this gentle.
209
- - **Line-break joins** on some dense (6-line) woodblock pecha (~1.9% of such pages).
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:c54eb065005184a30fd17c25e1393e72a457b500045fe510a79221df0af9a34d
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
- "shortest_edge": 1024,
28
- "longest_edge": 1003520
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
- "image_token": "<|IMAGE_PLACEHOLDER|>"
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
+ }