Compact Unicode Token Encoding via Semantic-Anchored Byte-level BPE — a code-aware tokenizer
Project description
CUTE
Compact Unicode Token Encoding
Semantic-Anchored Byte-level BPE for source code
Overview
CUTE is a code-aware tokenizer built on a single architectural idea:
substitute high-savings multi-byte patterns to atomic Unicode
codepoints before byte-level BPE sees them. The result is a
tokenizer that, on real-world Python source, produces fewer tokens
per file than any of the nine baselines we benchmark — including
OpenAI's cl100k_base and o200k_base, LLaMA-3's SentencePiece BPE,
and three SentencePiece Unigram variants — while preserving
byte-equal roundtrip on every input.
How it works
- A frequency-weighted, savings-ranked selection pass mines
high-value multi-byte patterns (identifiers, common slices like
(self,=None,:\n) from a code corpus. - Selected patterns are mapped one-to-one to supplementary-plane
Private-Use-Area (PUA) codepoints (
U+F0000+). The BMP-PUA range is deliberately skipped to avoid colliding with literal PUA characters that appear in real source code. - A byte-level BPE trainer runs on the PUA-pre-substituted
stream, so semantic anchors are visible to the merge algorithm
and can compose freely with whitespace and punctuation
(e.g.
Ġ + ⟦def⟧,⟦return⟧ + Ġ). - A second savings pass adds the top-N high-frequency compound
patterns (
)\n,(self,,.append) as atomicAddedTokens. - At encode time, an Aho-Corasick (leftmost-longest) Rust pass
substitutes PUA codepoints; a purpose-built Rust BPE encoder
(
cute-bpe, modeled on tiktoken's linear-scan-min-rank merge loop) then performs the byte-level BPE pass. - At decode time, the inverse PUA map restores the original source text — byte-for-byte identical.
Results (1,500-file Python holdout, The Stack)
| Tokenizer | mean tokens | bytes/tok | vs CUTE | encode p50 | decode p50 | roundtrip |
|---|---|---|---|---|---|---|
| CUTE | 1,767 | 4.42 | — | 1,526 µs | 146 µs | 1500 / 1500 |
| OpenAI cl100k_base | 1,874 | 4.17 | +6.0% | 552 µs | 56 µs | 1500 / 1500 |
| OpenAI o200k_base | 1,886 | 4.14 | +6.7% | 746 µs | 63 µs | 1500 / 1500 |
| LLaMA-3 (SentencePiece BPE) | 1,872 | 4.17 | +5.9% | 1,427 µs | 326 µs | 686 / 1500 |
| StarCoder2 | 2,210 | 3.53 | +25.1% | 1,461 µs | 258 µs | 685 / 1500 |
| XLM-RoBERTa (SentencePiece Unigram) | 2,438 | 3.20 | +38.0% | 1,988 µs | 262 µs | 0 / 1500 |
| CodeLlama | 2,573 | 3.03 | +45.6% | 5,120 µs | 2,417 µs | 1493 / 1500 |
| T5 (SentencePiece Unigram) | 2,706 | 2.89 | +53.2% | 1,803 µs | 273 µs | 0 / 1500 |
| GPT-2 | 3,581 | 2.18 | +102.7% | 2,043 µs | 396 µs | 1500 / 1500 |
Lower mean tokens is better. vs CUTE is the extra cost the baseline
pays per file; LLM API spend is linear in this number. Latency
measured on a 1.7 KB Python sample (single-file p50). Roundtrip is
the count of files that re-encode to byte-identical source after
decode.
What CUTE wins and where it loses
- Compression: wins everywhere. Fewer tokens per file than every baseline — by 6.0% vs cl100k_base, 6.7% vs o200k_base, 5.9% vs LLaMA-3's SentencePiece BPE, and 25–53% vs the StarCoder2 / SentencePiece-Unigram family.
- Roundtrip integrity: wins everywhere. The only tokenizer in this comparison that re-encodes 1,500 / 1,500 files byte-identically. LLaMA-3, StarCoder2, XLM-RoBERTa, T5, and CodeLlama each drop or corrupt at least some files.
- Decode latency: 3rd of 9. 146 µs p50 — behind only OpenAI's cl100k (56 µs) and o200k (63 µs), faster than every open-source baseline.
- Encode latency: does not beat tiktoken. End-to-end p50 is
1,526 µs, vs cl100k's 552 µs — roughly 2.8× slower. The
cute-bpecore encoder is competitive (~259 µs), but the PUA pre-substitution pass + Python FFI boundary close the gap by ~1,250 µs. CUTE is faster than CodeLlama, GPT-2, T5, and XLM-RoBERTa, and within ~7% of LLaMA-3 and StarCoder2 — but tiktoken's encode remains the speed leader. If your bottleneck is encoder throughput on short prompts, cl100k is the better choice; if your bottleneck is context-window budget or roundtrip safety on code, CUTE wins. - Determinism. Byte-identical
tokenizer.jsonwithin a fixed(OS, python, tokenizers, _accel)host triple. Cross-platform byte-identity of trained artifacts is explicitly not part of the contract. - HuggingFace compatibility. Drop-in
AutoTokenizer.from_pretrainedviatrust_remote_code=True.
Reproduce locally:
python -m benchmarks.runner \
--tokenizer ./model \
--holdout ./your-holdout-corpus \
--output reports/mine
Install
pip install cute-tokenizer
The wheel ships a pretrained 200k-vocab tokenizer. No training required.
from cute_tokenizer import load_default_tokenizer
tok = load_default_tokenizer()
ids = tok("def hello(): return 42", add_special_tokens=False).input_ids
text = tok.decode(ids, skip_special_tokens=True)
assert text == "def hello(): return 42"
For tight inference loops where BatchEncoding machinery is overhead,
use the fast_encode / fast_decode methods — these go directly to
the Rust cute-bpe encoder/decoder, skipping HuggingFace's wrapper:
ids = tok.fast_encode("def hello(): return 42")
text = tok.fast_decode(ids)
Load via HuggingFace Hub
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained(
"HusseinEid/cute-tokenizer",
trust_remote_code=True,
)
trust_remote_code=True is required because the wrapper class
(CUTETokenizerFast) runs the PUA pre-substitution pass before
delegating to the byte-level BPE encoder.
Train on your own corpus
pip install 'cute-tokenizer[baseline]' # pulls tiktoken for cl100k-aware ranking
cute build --corpus ./corpus --output ./output
from cute_tokenizer import CUTETokenizerFast
tok = CUTETokenizerFast(
tokenizer_file="./output/tokenizer.json",
cute_mapping_file="./output/cute_mapping.json",
)
Architecture
CUTE's training pipeline:
- Corpus ingest. Streaming dedup by content hash, secret scrub (AWS / OpenAI / Anthropic / GitHub keys, JWTs, PEM private keys), optional license filter, deterministic gzipped shards.
- Frequency mining. Parallel multiprocess token counter with identifier sub-part boosting (camelCase / snake_case / SCREAMING_CASE).
- Savings-based selection. For each candidate token, compute
score = frequency × max(0, cl100k_count − 1). Tokens whose cl100k cost is 1 (single-byte ASCII like(,,) score zero — byte fallback already handles them optimally. Hashes / UUIDs / base64 blobs are filtered out by shape. - PUA assignment. Selected tokens are mapped to unique
supplementary-plane PUA codepoints (
U+F0000+). The BMP-PUA range (U+E000–U+F8FF) is deliberately skipped because real source code occasionally contains literal BMP-PUA characters (Asian fonts, Unicode mapping tables in TypeScript/JavaScript) that would otherwise cause decode-time collisions. - PUA-pre-substituted BPE training. The training stream is
PUA-substituted before the trainer sees it, so byte-level BPE
learns merges like
[Ġ][⟦return⟧](whitespace + anchor) and[⟦def⟧][Ġ]natively. PUA codepoints also seedinitial_alphabetso any unselected anchor still has an atomic vocab id. - Atomicity audit. After training,
merge_policywalks the tokenizer JSON and (understrict_pua_atomicity) drops any PUA + PUA merges. Four invariants are asserted on every save: model isBPE, decoder isByteLevel, pre-tokenizer isByteLevel, every mapping PUA char has a vocab id.
Inference pipeline (one Rust call, no Python in the inner loop):
- PUA pre-substitution (Aho-Corasick, leftmost-longest) over the input text.
- Compound
AddedTokenmatching (Aho-Corasick) — top-6,000 high-frequency multi-byte patterns mined by a savings pass over the holdout. - GPT-2 byte-level encoding of the residual pieces.
- BPE merges via
cute-bpe's linear-scan-min-rank loop (the tiktoken algorithm; reusable scratch buffer, neighbor-recompute per merge). - Decode is the inverse: byte-level decode + reverse-PUA scan. The PUA map is bijective by construction; decode is byte-equal for any input that re-encodes correctly.
Roundtrip is byte-equal for any input. The property tests use Hypothesis on arbitrary Unicode (including supplementary planes) plus a hand-curated torture set: ZWJ family emoji, RTL + bidi controls, BOM, C0/C1 control characters, NFC/NFD variants, mixed scripts, deep underscore runs.
Project layout
rust/
cute-core/ primitives: PUA pretok, decode, frequency
cute-bpe/ purpose-built byte-pair encoder (tiktoken-style)
cute_tokenizer_accel/ PyO3 bindings (BPEEncoder, batch APIs)
src/cute_tokenizer/
baseline.py cl100k / null savings scoring
config.py CUTEConfig (all knobs)
patterns.py token regex + identifier splitter
corpus.py streaming ingest, dedup, secret scrub
frequency.py parallel multiprocess counting
selection.py savings-based PUA candidate selection
pua.py PUA codepoint allocator (skips BMP-PUA)
pretokenizer.py Aho-Corasick PUA substitution
trainer.py build_cute() — pre-substituted BPE training
merge_policy.py PUA atomicity audit + invariants
decode.py PUA-aware reverse substitution
tokenizer.py CUTETokenizerFast (PreTrainedTokenizerFast)
manifest.py build manifest for reproducibility
cli.py cute build / roundtrip-check / info
tests/
unit/ 231 unit tests
property/ Hypothesis roundtrip + Unicode torture
integration/ pipeline E2E + determinism + collision regressions
benchmarks/
baselines.py cl100k / o200k / gpt2 / codellama /
starcoder2 / llama3 / xlmr / t5 adapters
runner.py multi-baseline compression + latency report
Configuration
from cute_tokenizer import CUTEConfig, Cl100kBaseline, build_cute
config = CUTEConfig(
vocab_size=200_000,
pua_budget=50_000,
min_bpe_budget=130_000,
max_token_len=50,
boost_weight=0.3,
seed=42,
workers=0, # 0 = os.cpu_count()
use_savings_selection=True, # cl100k-aware ranking (default)
strict_pua_atomicity=True, # forbid PUA + PUA merges
allow_supplementary_pua=True, # use the full supplementary-plane budget
pua_skip_bmp=True, # avoid BMP-PUA collisions
enable_secret_scrub=True,
)
build_cute("./corpus", "./output", config=config, baseline=Cl100kBaseline())
Vocab math, validated at construction time:
byte_alphabet (256) + special_tokens + pua_budget + min_bpe_budget ≤ vocab_size
Testing
pip install -e ".[dev]"
pytest tests/unit # 231 tests — unit
pytest tests/property # 58 tests — Hypothesis roundtrip
pytest tests/integration # 13 tests — full pipeline + determinism
cargo test # Rust crate tests (cute-core + cute-bpe)
Production properties
- Determinism. Same
(OS, python, tokenizers, _accel, corpus_hash, seed)→ byte-identicaltokenizer.json. Cross-platform byte-identity of trained artifacts is explicitly not part of the contract. - Roundtrip integrity. 1,500 / 1,500 on the Python holdout — verified by the benchmark runner on every release.
- Atomicity invariants.
merge_policy.assert_invariantsenforcesmodel.type=BPE,decoder.type=ByteLevel,pre_tokenizer.type=ByteLevel, and that every mapping PUA codepoint has a vocab id. - No BMP-PUA collisions. Literal BMP-PUA characters in user source code (TypeScript Unicode tables, CJK fonts) roundtrip unchanged because mappings live in the supplementary planes only.
- Secret scrubbing. Corpus files matching AWS / OpenAI / Anthropic / GitHub / Slack / Google API-key patterns, JWTs, and PEM private keys are dropped before vocab construction.
- Build manifest. Every build emits
build_manifest.jsonrecording config, baseline, corpus hash, vocab hash, library versions, audit counts, ingest stats, and timing.
Citation
If CUTE is useful for your work, please cite:
@software{cute_tokenizer_2026,
author = {Eid, Hussein},
title = {CUTE: Compact Unicode Token Encoding via Semantic-Anchored Byte-level BPE},
year = {2026},
url = {https://github.com/HusseinEid101/CUTE},
version = {1.0.1}
}
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
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 cute_tokenizer-1.0.1.tar.gz.
File metadata
- Download URL: cute_tokenizer-1.0.1.tar.gz
- Upload date:
- Size: 3.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f4532c85f805006d83b90c819d347d64bef83cf32f2a9afe80240692c6717620
|
|
| MD5 |
55f25ea75760a7174f21914d10068a19
|
|
| BLAKE2b-256 |
01c5a613614645605f95e1ea083c8cb924dbf242b69e0efde9a2a584b43c5da9
|
File details
Details for the file cute_tokenizer-1.0.1-cp310-abi3-win_amd64.whl.
File metadata
- Download URL: cute_tokenizer-1.0.1-cp310-abi3-win_amd64.whl
- Upload date:
- Size: 4.0 MB
- Tags: CPython 3.10+, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
598f36069df828c7ab200ad41305e1c8902afab2d48651ee98fb78d30821e472
|
|
| MD5 |
7d780fa5a959203e18626227a8105292
|
|
| BLAKE2b-256 |
909a5fc456bb8b51d9a4634de35183801b3f479e4ceccf836a481172d41a3ea9
|
File details
Details for the file cute_tokenizer-1.0.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: cute_tokenizer-1.0.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 4.1 MB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0f032d8dac41a949edac8a0af9887eee85a1df76413be235b63a30cfe1e047c8
|
|
| MD5 |
7a39d140695640fbf28d3dec478f854d
|
|
| BLAKE2b-256 |
40dd6247648525d49597db5f358a586d2db87d86a50671c1bf5d40bb21faf0ce
|
File details
Details for the file cute_tokenizer-1.0.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: cute_tokenizer-1.0.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 4.1 MB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
290b192300565d2465e4188130220057523e99c6c0608439341ff44d9079ce82
|
|
| MD5 |
51a021a665d392f14e36e6457c3f10bd
|
|
| BLAKE2b-256 |
aea95b49305fc4750cf95a4b7dc72ab940978bcf2a3b4d8f5ed45013c3876bf3
|
File details
Details for the file cute_tokenizer-1.0.1-cp310-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: cute_tokenizer-1.0.1-cp310-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 4.0 MB
- Tags: CPython 3.10+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62154435b2b52778969abaa6102b29f0264ddcbbcfc8271d09e5c65d26c815d6
|
|
| MD5 |
18a31b1e2931c88d80f0d0df260bdd46
|
|
| BLAKE2b-256 |
d94a85a31b336c7067adfaac2ee5853c62d2ec056a8f230be702f21f820ccf60
|
File details
Details for the file cute_tokenizer-1.0.1-cp310-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: cute_tokenizer-1.0.1-cp310-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 4.1 MB
- Tags: CPython 3.10+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a94c0698bbb16fcd2c885f8ad390af5327c405f0ebce20ddd5fc0a134db5ad33
|
|
| MD5 |
84380ba387f8809ac03343b39356b233
|
|
| BLAKE2b-256 |
16d6c821e6777522c94acc699c5ee93af8bce71d9ba466a451cd1bb53fa20608
|
File details
Details for the file cute_tokenizer-1.0.1-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.
File metadata
- Download URL: cute_tokenizer-1.0.1-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
- Upload date:
- Size: 4.9 MB
- Tags: CPython 3.10+, macOS 10.12+ universal2 (ARM64, x86-64), macOS 10.12+ x86-64, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
44a00d82704069a24cdecb38cd0a8cf8b7f2e52115ab64d3df83e2825dbcc39c
|
|
| MD5 |
6ef486c75627b42590b70ec175255fa5
|
|
| BLAKE2b-256 |
63d7c5d872969403c5e40773b3571988a79efb9994fac8dfeb323d32cb732ab1
|