Skip to main content

Mon Tokenizer

PyPI Python versions Hugging Face License Ruff uv Mon language

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

MIT.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mon_tokenizer-1.0.0.tar.gz (1.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mon_tokenizer-1.0.0-py3-none-any.whl (1.1 MB view details)

Uploaded Python 3

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

Hashes for mon_tokenizer-1.0.0.tar.gz
Algorithm Hash digest
SHA256 171e46ac67b356da06e287eef54ec9bf4f5252877ccde79eef381b847c4d649c
MD5 0a8f36da38fa0315d1401cb16ad0f5b8
BLAKE2b-256 c778aa6fe53d21dbcf2a88529d84f7bfc93a6d1b3377dd4423bfcccc581a3f23

See more details on using hashes here.

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

Hashes for mon_tokenizer-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 adb4d91d4e8f2a2adb5500ec5906629434c9340320b10b4f8dcc7c7340910960
MD5 7f936fc605cea4318afa78f1faaa03b3
BLAKE2b-256 bfcc5659c05eaeae4fa48b7ab4e6da027fdf1982fd23f20fec084bb9078d9144

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 files

0.2.3

2 files

0.2.1

2 files

0.1.5

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page