Mon Tokenizer
Unigram tokenizer for Mon (mnw), Burmese and English, with full byte fallback
Mon mixes with Burmese constantly and English routinely, so all three are trained on and measured separately. Anything else on the page — Thai, emoji, IPA, CJK — round-trips through byte fallback rather than being lost.
pip install mon-tokenizer
from mon_tokenizer import MonTokenizer
tokenizer = MonTokenizer()
result = tokenizer.encode("ဂွံအခေါင်အရာမွဲသ္ဂောံဒုင်စသိုင်ကၠာကၠာရ။")
result["pieces"] # ['▁ဂွံ', 'အခေါင်အရာ', 'မွဲ', 'သ္ဂောံ', 'ဒုင်စသိုင်', 'ကၠာ', 'ကၠာရ။']
result["ids"] # token ids
result["text"] # the normalized string that was encoded
assert tokenizer.decode_ids(result["ids"]) == result["text"]
Also on the Hub, producing identical ids:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("janakhpon/mon_tokenizer")
Measured
Vocabulary 64,256 · trained on the train split of 893,936 lines / 85.8M characters · scored on the whole validation split.
| stratum | chars/token | syllable violations | round-trip | byte fallback |
|---|---|---|---|---|
| Mon | 4.686 | 1.07% (n=492,469) | 100% | 0.00% |
| Burmese | 4.117 | 0.93% (n=25,546) | 100% | 0.00% |
| English | 4.112 | — (n=0) | 100% | 0.02% |
| mixed script | 3.804 | 0.81% (n=28,133) | 100% | 0.19% |
100% of characters in the Mon validation split are single tokens.
Compression describes a corpus, not a tokenizer — quote it with the corpus. Violations count token boundaries inside a Myanmar syllable; the denominator is given because English legitimately has none. Round-trip compares after normalization, which is a deliberate transform.
model_card() returns these machine-readably, and a test fails if they drift
from what the artifact does.
Round-trip, and its two known limits
for text in ["🙏 emoji", "ภาษาไทย", "漢字", "Ωπ√∫", "ကျော် page 42 — “quoted” ၏"]:
r = tokenizer.encode(text)
assert tokenizer.decode_ids(r["ids"]) == r["text"]
Without byte fallback, characters outside the vocabulary aren't flagged — they're deleted, leaving fluent-looking output with content missing. That matters if you feed OCR output back into a corpus.
Two inputs are known not to round-trip. The loss happens at encode, so no
decoder can recover it:
tokenizer.encode(" abc")["ids"] == tokenizer.encode("abc")["ids"] # True
tokenizer.encode("a b")["ids"] == tokenizer.encode("a▁b")["ids"] # True
A single leading space is dropped, and a literal U+2581 is read as a space. The table above still holds: the corpus it was measured on is stripped per line and contains no U+2581, so it excludes both cases by construction rather than disproving them. Both are recorded as xfail tests.
Fixing this needs prepend_scheme="never", which changes every token id and so
requires a retrain and a new Hub artifact. Deferred on purpose, because id
stability is worth more than these two cases. Interior and trailing whitespace,
tabs, newlines, NUL and control characters all round-trip.
Normalization
Applied automatically, and stored inside the artifact so it cannot drift from
the model: invisible characters stripped, Unicode space separators folded to
U+0020, then NFC. Runs of spaces are preserved.
API
encode(text) |
{"pieces": [...], "ids": [...], "text": normalized} |
encode_ids(text) / encode_batch(texts) |
list[int] / list[list[int]] |
decode(pieces) / decode_ids(ids) |
str |
normalize(text) |
the artifact's own normalizer |
get_vocab_size() / get_vocab() |
int / dict[str, int] |
id_to_piece(id) / piece_to_id(piece) |
str / int |
unk_id bos_id eos_id pad_id |
0 1 2 3 |
model_card() |
artifact_version, corpus digest, config, measured metrics |
The artifact is cached by path, so constructing many instances is cheap.
CLI
pip install 'mon-tokenizer[cli]'
mon-tokenizer "ဂွံအခေါင်အရာမွဲ" # tokenize
mon-tokenizer -v "ဂွံအခေါင်အရာမွဲ" # per-token table
mon-tokenizer -d --ids "316,12644,294" # decode ids
Exit codes: 0 ok · 1 usage · 2 artifact failed to load · 130 interrupted.
Upgrading from 0.2.x
Every token id has changed. Rebuild any embedding matrix built against 0.2.x,
or pin mon-tokenizer<1.0 — it stays on PyPI and works.
Requirements
Python 3.11+. Two direct dependencies: tokenizers and regex. The install is
17 packages / ~30MB, because tokenizers requires huggingface-hub.
Development
uv sync --all-extras
uv run ruff format --check . && uv run ruff check . && uv run mypy && uv run pytest
Retraining, releasing and the house rules for tests: docs/how_to_contribute.md.
Design
docs/architecture.md — every decision with the measurement behind it and the condition that would reverse it: algorithm, vocabulary size, why grapheme clusters are the wrong unit for Myanmar, and what was rejected.
Links
- Hugging Face
- MonCorpusCollection — the corpus
- Awesome Mon NLP — the ecosystem
MIT.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mon_tokenizer-1.0.0.tar.gz.
File metadata
- Download URL: mon_tokenizer-1.0.0.tar.gz
- Upload date:
- Size: 1.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
171e46ac67b356da06e287eef54ec9bf4f5252877ccde79eef381b847c4d649c
|
|
| MD5 |
0a8f36da38fa0315d1401cb16ad0f5b8
|
|
| BLAKE2b-256 |
c778aa6fe53d21dbcf2a88529d84f7bfc93a6d1b3377dd4423bfcccc581a3f23
|
File details
Details for the file mon_tokenizer-1.0.0-py3-none-any.whl.
File metadata
- Download URL: mon_tokenizer-1.0.0-py3-none-any.whl
- Upload date:
- Size: 1.1 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
adb4d91d4e8f2a2adb5500ec5906629434c9340320b10b4f8dcc7c7340910960
|
|
| MD5 |
7f936fc605cea4318afa78f1faaa03b3
|
|
| BLAKE2b-256 |
bfcc5659c05eaeae4fa48b7ab4e6da027fdf1982fd23f20fec084bb9078d9144
|