Views
No views yet
formal (administrative / legal) / business (news /
encyclopaedic) / conversational (chat / forum) / literary
(classical narrative). Use the predicted register to route a text
through the right downstream checkpoint — VN diacritic /
summarization / OCR-rerank checkpoints all spread 5-10 pp accuracy
across registers, so a cheap router lifts every other tool
automatically.nom.text.word_tokenize
per the BKai gotcha (raw text drops accuracy ≥ 15 pp on PhoBERT-style
models).| Class | Precision | Recall | F1 | Support |
|---|---|---|---|---|
formal | 0.889 | 0.941 | 0.914 | 34 |
business | 0.885 | 0.928 | 0.906 | 400 |
conversational | 0.887 | 0.945 | 0.915 | 400 |
literary | 0.924 | 0.815 | 0.866 | 400 |
| macro avg | 0.896 | 0.907 | 0.900 | 1234 |
benchmarks/accuracy/register_phobert_base_baseline.json
re-runnable from a clean clone via
training/register/train.py.| Label | Source(s) | License |
|---|---|---|
formal | UDHR-vi (PD) + UDHR diacritic-eval slice (PD) | Public Domain |
business | wiki_vi (Wikipedia VN extracts) | CC-BY-SA-4.0 |
conversational | tatoeba_vi 3k + tatoeba diacritic-eval-300 | CC-BY 2.0 FR |
literary | wikisource_vi (PD) + UD-VTB train/dev/test | PD + CC-BY-SA-4.0 |
formal only has 169 unique sentences (UDHR is
naturally short), the others cap at 2 000 each. The 134 / 169 / 169 /
169 split per register survives the imbalance (model still hits 0.91
F1 on formal — class weighting wasn't needed). Future v2: add a
permissive VN legal corpus to grow formal.1from transformers import AutoTokenizer, AutoModelForSequenceClassification
2
3tok = AutoTokenizer.from_pretrained("nrl-ai/vn-register-phobert-base")
4model = AutoModelForSequenceClassification.from_pretrained("nrl-ai/vn-register-phobert-base")
5
6# IMPORTANT: PhoBERT requires word-segmented input (multi-syllable words
7# joined with underscores). Use VnCoreNLP's RDRSegmenter or nom.text:
8from nom.text import normalize, word_tokenize
9text = "Doanh thu công ty quý 2 năm 2026 tăng 18 %."
10segmented = " ".join(t.replace(" ", "_") for t in word_tokenize(normalize(text)))
11
12import torch
13ids = tok(segmented, return_tensors="pt", truncation=True, max_length=256)
14with torch.no_grad():
15 logits = model(**ids).logits
16probs = torch.softmax(logits, dim=-1).squeeze().tolist()
17labels = ["formal", "business", "conversational", "literary"]
18for label, p in sorted(zip(labels, probs), key=lambda x: -x[1]):
19 print(f" {label:<15} {p:.3f}")
20# → business 0.952
21# formal 0.029
22# conversational 0.012
23# literary 0.007nom-vn wrapper:1from nom.classify import PhoBertRegisterClassifier
2clf = PhoBertRegisterClassifier() # default model_id = this repo
3result = clf.predict("Doanh thu công ty quý 2 năm 2026 tăng 18 %.")
4print(result.label, result.score, result.distribution)literary recall 0.815 < precision 0.924. When the model says
"literary," it's usually right; when something IS literary, the
model misses ~18 % to other classes (mostly to formal because of
shared archaic vocab). Acceptable for routing — false negatives
fall back to a sensible default.word_tokenize and accuracy
drops 10-15 pp. The wrapper handles this; if you call the model
directly, you must segment.1@misc{nguyen_vn_register_phobert_base_2026,
2 author = {Nguyen, Viet-Anh and {Neural Research Lab}},
3 title = {{vn-register-phobert-base: A 4-class Vietnamese text-register
4 classifier (formal / business / conversational / literary)}},
5 year = {2026},
6 url = {https://huggingface.co/nrl-ai/vn-register-phobert-base}
7}nom-vn
project by Viet-Anh Nguyen (vietanh@nrl.ai) and Neural Research Lab.