kathe-r11-restorer β Kashmiri short-vowel restoration
Restores kasra (U+0650), damma (U+064F) and fatha (U+064E) to Perso-Arabic Kashmiri text. A companion to a translation model, not a translation model.
Code and full write-up: https://github.com/AzhadArshad/kathe_2026
The shipped checkpoint is r11b_dense.pt. The other files in this repo are
earlier or differently-trained arms of the same sweep, kept for reproducibility.
Why this exists
IndicTrans2 cannot emit these three marks. Each appears in exactly one token
of its 122,672-entry target vocabulary β the bare standalone mark β while every
other Kashmiri diacritic is baked into whole-word subwords. Writing ΪΪΎΩΨ³ would
require splitting a word to insert a bare diacritic that occurs in no natural
subword context, and beam search never does. Measured across 1,730 sentences the
translation model produced exactly zero of all three, while reproducing the
subword-embedded marks at above-reference rates.
The vocabulary is frozen in the pretrained checkpoint, so no amount of fine-tuning fixes this and restoration has to be post-hoc.
It is worth a great deal. On the KATHE 2026 test set:
| System | Score |
|---|---|
| translation model alone | 10.00 |
| + diacritic lexicon | 13.52 |
| + this restorer instead | 13.99 |
| + both, as a union (shipped) | 15.05 |
That is +5.05 from restoration, against +1.17 for corpus selection and +0.83 for fine-tuning. The largest lever in the project, and it needs no GPU.
What it is
A 3.3M-parameter bidirectional transformer encoder used as a per-character
tagger: for each input character it predicts one of {none, kasra, damma, fatha}. The base-letter sequence is never an output, so restoration is
insertion-only by construction β it cannot alter, reorder or drop a
character for any label vector.
How to use it β as a union with a lexicon, not alone
The shipped configuration consults a 48k-form lexicon first and uses the
tagger only on words the lexicon has never seen (restore_merge: known). The
two fail in opposite places: the lexicon is near-unbeatable on words it has seen
and silent on the rest, while the tagger never abstains but can be talked out of
a common word by context.
git clone https://github.com/AzhadArshad/kathe_2026 && cd kathe_2026
python scripts/generate_translations.py --input input.csv --output output.csv
The lexicon ships in that repository; the weights are fetched from here automatically.
Tuning knob
restore_none_bias is a logit offset on the "no mark" class. Under
restore_merge: known it acts only on words the lexicon does not know, so
it is precisely "how freely does the tagger mark the tail":
| bias | marks /100c | score |
|---|---|---|
| β1.5 | 13.78 | 14.25 |
| 0.0 | 12.36 | 14.82 |
| +1.6836 (shipped) | 11.30 | 15.05 |
| +2.25 | 11.03 | 15.04 |
| +3.25 | 10.62 | 14.91 |
| +β (lexicon only) | 9.85 | 13.52 |
Concave with a broad flat top over [1.68, 2.25], so the shipped value is not balanced on a knife edge.
Two findings worth carrying elsewhere. First, chrF++ runs at beta=2, weighting recall four times precision β so emitting a mark the reference lacks is cheaper than omitting one it has, and tuning output density to match reference density is a handicap rather than a target. Second, that only holds where the model is confident: in the tail, extra marks are noise, which is what the table above measures.
Training data
Monolingual Kashmiri, self-supervised: strip the three marks from any sentence
and (stripped, original) is a training pair.
| source | examples |
|---|---|
nawabhussain/Kashmiri-Language-Corpus |
41,187 |
BPCC bpcc-seed-v1 |
15,467 |
BPCC daily |
3,059 |
Held-out micro-F1 60.63 (precision 73.18, recall 51.76), best at epoch 20. The parent project's development sets were excluded by exact stripped-and- normalized string.
Limitations
- Only these three marks. Others already match reference density to within 5%; "restoring" them would add noise.
- Standalone it is worse than a lexicon lookup (13.81 vs 13.52 was close, and on the internal dev set the lexicon won). Its value is on the tail β words the lexicon has never seen β which is why the shipped system is a union and why the tail is deliberately suppressed.
- Precision 73% / recall 52% on held-out text: it under-marks rather than over-marks, and the bias knob exists to trade that off.
- Trained on Perso-Arabic Kashmiri only.
Licence and attribution
Apache-2.0 β trained only on BPCC (CC-BY-4.0 / CC0) and
nawabhussain/Kashmiri-Language-Corpus (Apache-2.0), both of which permit
relicensing of derivatives with attribution. Other checkpoints from the same
sweep saw CC-BY-NC-SA text and are not published here.
Attribution remains required for the corpora above regardless of this licence;
see NOTICE in the parent repository.