trabten's picture
Update README.md
c714dae verified
|
Raw
History Blame Contribute Delete
5.57 kB
---
license: mit
language:
- bo
base_model: KoichiYasuoka/bert-base-tibetan
tags:
- token-classification
- tibetan
- word-segmentation
- bert
- onnx
library_name: onnxruntime
---
# Tibetan Word Segmentation BUDA
Fine-tuned `KoichiYasuoka/bert-base-tibetan` for syllable-level Tibetan word segmentation. Predicts **B** (begin-word) or **I** (inside-word) for each syllable. Used as the segmentation engine in [TradutorBUDA](https://tashirabten.github.io/BUDA_APPs_Port/).
**99.95% accuracy** — B F1: 99.92% | I F1: 99.97% — on 20,903 validation sequences.
## Model Files
| File | Size | Description |
|------|------|-------------|
| `model_quantized.onnx` | 104.5 MB | INT8 quantized ONNX (deployed) |
| `tokenizer.json` | 0.8 MB | HuggingFace tokenizer |
| `vocab.txt` | 0.4 MB | Vocabulary |
| `config.json` | — | Model configuration |
| `segmentation_config.json` | — | Label mappings (`B`/`I`) |
| `dictionary_words.json` | 16.6 MB | 353K Tibetan words for constraint decoding |
> The FP32 ONNX (413 MB) is not included — use the INT8 model for CPU deployment.
## Architecture
Base: `KoichiYasuoka/bert-base-tibetan` (BERT-base, 110M parameters, pre-trained on 4.63 GB Tibetan text)
Task head: token classification → 2 labels (B / I)
## Results
| Metric | Score |
|--------|-------|
| Accuracy | 99.95% |
| B precision | 99.97% |
| B recall | 99.88% |
| **B F1** | **99.92%** |
| I precision | 99.95% |
| I recall | 99.99% |
| I F1 | 99.97% |
## Dataset
- **Train:** 208,077 sequences — **Val:** 20,903 sequences
- 200K synthetic sequences generated from 353K Tibetan dictionary terms (B/I labels derived from word boundaries)
- 16K silver-standard sequences from [Botok](https://github.com/Esukhia/botok) segmentation output
- Input format: space-separated Tibetan syllables; each syllable ends with a tsheg (་)
Example:
```
Syllables: བྱང་ ཆུབ་ སེམས་ དཔའི་ སྤྱོད་ པ
Labels: B I B I B I
Words: བྱང་ཆུབ་ / སེམས་དཔའི་ / སྤྱོད་པ
```
## Training Configuration
- **Base model:** `KoichiYasuoka/bert-base-tibetan`
- **Optimizer:** AdamW (lr=3e-5, weight_decay=0.01)
- **LR schedule:** 10% linear warmup → constant
- **Epochs:** 5 (early stopping patience=3; did not trigger)
- **Batch size:** 64
- **Max sequence length:** 256 syllable-tokens
- **Mixed precision:** FP16 on NVIDIA A100 (40 GB)
- **Best checkpoint metric:** B F1
## Usage (ONNX / Java — TradutorBUDA)
The model is loaded by `TibetanSegmentationService.java` using ONNX Runtime:
```java
OrtSession session = env.createSession("models/segmentation_onnx/model_quantized.onnx", opts);
```
Inputs: `input_ids`, `attention_mask`, `token_type_ids` (shape: `[batch, 256]`)
Output: `logits` (shape: `[batch, 256, 2]`) — argmax gives B=0 / I=1 per token.
## Usage (Python)
```python
import onnxruntime as ort
from transformers import AutoTokenizer
import numpy as np
import json, re
tokenizer = AutoTokenizer.from_pretrained("trabten/tibetan_segmentation_BUDA")
session = ort.InferenceSession("model_quantized.onnx", providers=["CPUExecutionProvider"])
MAX_LENGTH = 256
ID2LABEL = {0: "B", 1: "I"}
def segment(text):
syllables = [s for s in re.split(r'(?<=་)', text.strip()) if s.strip()]
token_ids, word_ids = [], []
for i, syl in enumerate(syllables):
ids = tokenizer.encode(syl, add_special_tokens=False)
token_ids.extend(ids)
word_ids.extend([i] * len(ids))
cls, sep = tokenizer.cls_token_id, tokenizer.sep_token_id
input_ids = [cls] + token_ids[:MAX_LENGTH-2] + [sep]
word_ids = [-1] + word_ids[:MAX_LENGTH-2] + [-1]
attn_mask = [1] * len(input_ids)
tok_types = [0] * len(input_ids)
pad = MAX_LENGTH - len(input_ids)
input_ids += [tokenizer.pad_token_id] * pad
attn_mask += [0] * pad
tok_types += [0] * pad
feeds = {
"input_ids": np.array([input_ids], dtype=np.int64),
"attention_mask": np.array([attn_mask], dtype=np.int64),
"token_type_ids": np.array([tok_types], dtype=np.int64),
}
logits = session.run(None, feeds)[0][0]
preds = logits.argmax(axis=-1)
syl_labels, prev = [], None
for wid, pred in zip(word_ids, preds):
if wid == -1: continue
if wid != prev:
syl_labels.append(ID2LABEL[pred])
prev = wid
words, current = [], []
for syl, lbl in zip(syllables, syl_labels):
if lbl == "B" and current:
words.append("".join(current))
current = [syl]
else:
current.append(syl)
if current:
words.append("".join(current))
return words
print(segment("བྱང་ཆུབ་སེམས་དཔའི་སྤྱོད་པ"))
# ['བྱང་ཆུབ་', 'སེམས་དཔའི་', 'སྤྱོད་པ']
```
## Background
Tibetan has no spaces between words — segmentation is required before dictionary lookup, POS tagging, or machine translation. Traditional rule-based segmenters (e.g. Botok) rely on hand-curated lexicons and miss out-of-vocabulary terms. This model learns segmentation patterns from context, achieving near-perfect accuracy on Buddhist canonical vocabulary.
## References
- Yasuoka, K. "Universal Dependencies for Classical Tibetan." (base model)
- Esukhia. [Botok — Tibetan NLP toolkit](https://github.com/Esukhia/botok) (silver-standard data source)
- Devlin et al. "BERT: Pre-training of Deep Bidirectional Transformers." (ICLR 2019)