Model Card for TwinkleTokenizer
TwinkleTokenizer 是專為中華民國台灣語境從零訓練的 byte-level BPE 詞表。不是在既有詞表上加字、也不是把別人的詞表做繁體對映,而是以 19.27 億字元的純繁中為主語料重新訓練出來的。
在自建的 tw-tokenizer-bench(24,294 筆)上,本詞表的 tokens/char 為 0.4395 ,較 Qwen3.8-27B 的 0.7120 低 38% ,而詞表規模只有它的 81% 。
⚠️ 規格重點: 本倉庫只提供 tokenizer ,不含模型權重。詞表大小 201,069(含 1,069 個特殊 token),normalizer 為 NFC (非 NFKC),純漢字 token 上限 6 字 。
Model Details
繼 Formosa-1 Series 與 T1 系列之後,Twinkle AI 一直在處理同一個結構性問題:繁體中文在主流詞表裡是二等公民 。
國際模型的中文詞表幾乎都以簡體語料訓練。以 Qwen3.8-27B 為例,它有 47,929 個多字漢字 token,其中 27,364 個是簡體專屬 ——佔其全部詞表的 11%,對繁體中文完全無用。這些名額不是「用不到」而已,是在訓練詞表時就把預算花掉了 ,繁中詞彙因此擠不進去。續訓(continued pretraining)改不了這件事:詞表在預訓練前就已固定。
唯一的解法是從零訓練。用純繁中語料訓練,那個浪費從源頭就不會產生——這就是為什麼 201K 的可用名額能勝過 Qwen 的 248K。
Twinkle ,取自 Twinkle AI;本詞表定位為 Twinkle AI 後續模型系列的共用詞表基礎。
核心特點 (Key Features)
繁中優先的詞表配置 (Traditional-First Vocabulary):
- 全部 201,069 個 token 逐一稽核:含異體字 0 個 ,含簡體專屬字僅 55 個(0.04%),逐筆判讀後真簡體約 8 個。
- 語料前處理做了 12.7 萬處異體字正規化(爲→為、裏→裡、麽→麼),並對 55 個無歧義陸用語(質量、身份、通脹、網絡…)整列丟棄 ——不改寫、不用 OpenCC 整段轉換,避免把「制作」(刑事訴訟法第 39 條)這類法定用語改壞。
切得對,不只切得少 (Segmentation Quality):
- 壓縮率高不代表切分正確。以 jieba 繁中斷詞為參考,本詞表的切點命中詞邊界 85.6% ,Qwen3.8 為 77.8%、DeepSeek-V4 為 74.9%。
- 單字 token 佔比 17.6% (Qwen 41.7%、DeepSeek 49.6%)——代表詞表真的在處理「詞」,而不是逐字拆。
多模態預留與思考通道 (Multi-modal & Thinking Ready):
- 具名特殊 token 45 個,涵蓋對話、思考(
<|think_start|>)、工具呼叫、語音(ASR/TTS/duplex)、視覺(image/video/OCR)、文件結構(page/table/cite)。 - 另保留 1,024 個 reserved token ,未來新增功能可直接改名,不必擴充 embedding 重訓。
- 具名特殊 token 45 個,涵蓋對話、思考(
實證驗證,不只報壓縮率 (Validated Three Ways):
- 近年文獻對「壓縮率 = 品質」是存疑的(Schmidt et al., EMNLP 2024;Lotz et al., 2025 量到 ρ = −0.59)。
- 因此除壓縮率外,另做了切分品質與下游從零訓練 270M 模型比 bits-per-character 兩層驗證。
Model Description
- Developed by: Liang Hsun Huang
- Model type: byte-level BPE tokenizer(
tokenizers/transformers相容) - Vocabulary size: 200,000 + 1,069 特殊 token = 201,069
- Normalizer: NFC(非 NFKC)
- Language(s) (NLP): Traditional Chinese & English
- License: apache-2.0
| 演算法 | byte-level BPE |
| 純漢字 token 上限 | 6 字 |
| 訓練語料 | 19.27 億字元 |
| 語料組成 | 繁中 60.6% / 英文 22.8% / 程式碼 10.4% / 數學 6.2% |
| 對話格式 | ChatML |
Model Sources
- Repository: twinkle-ai/TwinkleTokenizer
- Benchmark: twinkle-ai/tw-tokenizer-bench
Evaluation
tw-tokenizer-bench(主要評測)
tw-tokenizer-bench 為本團隊建置的台灣繁中詞表評測集,24,294 筆 / 1,844 萬字元 ,涵蓋 5 個正式文體領域。指標為 tokens/char,越低越好 。
| subset | 🌟TwinkleTokenizer (ours) | Pangolin | Qwen3.8-27B | DeepSeek-V4 | gemma-4-31B |
|---|---|---|---|---|---|
| law_judgment | 0.3380 | 0.7622 | 0.7570 | 0.7924 | 0.8395 |
| law_statute | 0.4355 | 0.7267 | 0.7316 | 0.7681 | 0.7767 |
| web_translated | 0.4403 | 0.6780 | 0.6496 | 0.6711 | 0.7152 |
| gov_news | 0.4967 | 0.7055 | 0.7020 | 0.7327 | 0.7771 |
| encyclopedia | 0.5557 | 0.7292 | 0.7239 | 0.7298 | 0.7835 |
| OVERALL | 0.4395 | 0.7200 | 0.7120 | 0.7402 | 0.7785 |
| vocab | 201,069 | 114,688 | 248,044 | 128,000 | 262,144 |
| 單字 token 率 | 18.0% | 46.0% | 44.4% | 52.5% | 60.6% |
關於往返正確性 :本詞表與 Qwen3.8 各有 62 筆「嚴格往返失敗」,Pangolin 與 DeepSeek 為 0。 根因是來源文本含 CJK 相容表意文字 (U+F900–FAFF,如 U+F98E「年」),而 NFC 的定義就是要把它們折疊成標準碼位 (U+5E74)。 有做 NFC 的全部「失敗」,沒做的全部「通過」——但不折疊才是缺陷,那會讓同一個字佔兩個 token。 以 NFC 為基準時,本詞表往返失敗 0 筆 。詳見 benchmark 的 dataset card。
壓縮率(held-out,訓練語料零重疊)
單位為字元/token,越高越省 (與上表的 tokens/char 互為倒數)。
| tokenizer | vocab | 中文平均 | 英文 |
|---|---|---|---|
| 🌟TwinkleTokenizer (ours) | 201,069 | 2.026 | 4.657 |
| Qwen3.8-27B | 248,044 | 1.388 | 4.674 |
| DeepSeek-V4 | 128,000 | 1.369 | 4.855 |
| OpenFormosa/PangolinTokenizer | 114,688 | 1.339 | 2.658 |
| gemma-4-31B | 262,144 | 1.282 | 4.735 |
中文提升 46% 的同時,英文效率幾乎持平 (4.657 vs Qwen 4.674,差距 0.4%)——這是刻意的取捨,繁中詞表不應該以犧牲英文為代價。
中文各領域細分:判決書 2.516 / 翻譯繁中 2.267 / 中文網頁 1.983 / 文言 1.796 / 政府文書 1.481。
PangolinBench
PangolinBench 是 OpenFormosa 為台灣語境設計的詞表評測,10 個 subset 共 30 筆樣本。指標同為 tokens/char,越低越好。
以下為本地實測(非引用官方數字)。所有詞表的往返正確率皆為 30/30。
| subset | 🌟ours | Pangolin | Qwen3.8 | gemma-4 | DeepSeek-V4 |
|---|---|---|---|---|---|
| traditional_zh_formal | 0.4902 | 0.6765 | 0.6765 | 0.7157 | 0.7353 |
| taiwan_named_entities | 0.4595 | 0.7297 | 0.7568 | 0.8919 | 0.8919 |
| taiwan_mandarin_colloquial | 0.6458 | 0.7083 | 0.7500 | 0.7500 | 0.7500 |
| bopomofo | 0.7273 | 1.0682 | 1.3864 | 0.7955 | 1.1136 |
| taigi_han_roman_mixed | 0.5495 | 0.7143 | 0.6154 | 0.5824 | 0.6374 |
| hakka_romanized | 0.4567 | 0.5591 | 0.5118 | 0.4724 | 0.5039 |
| taiwan_code_switching | 0.3696 | 0.4783 | 0.4130 | 0.3804 | 0.4022 |
| unicode_edge_cases | 0.5396 | 0.5827 | 0.5755 | 0.6187 | 0.5324 |
| rich_transcription_json | 0.4518 | 0.4003 | 0.4405 | 0.4277 | 0.3939 |
| rich_transcription_structured_text | 0.4508 | 0.1844 | 0.4631 | 0.4467 | 0.4467 |
| OVERALL | 0.4765 | 0.4852 | 0.5407 | 0.5259 | 0.5222 |
我們輸的兩格輸得有道理。 rich_transcription_structured_text 上 Pangolin 是 0.1844、本詞表 0.4508,差距來自特殊 token 命名而非壓縮能力——那個 subset 的內容就是 <|transcript_start|> 、<|speaker|> 、<|non_speech_event|> 這些標記,Pangolin 詞表內建它們(各算 1 個 token),本詞表沒有(要拆成十幾個)。PangolinBench 有一道硬性關卡要求詞表必須含這 10 個 token,本詞表是以 --no-fail-on-quality-gate 跳過該關卡才完成評測的。
樣本量很小。 10 個 subset 共 30 筆,平均一個 subset 3 筆,單筆差異就足以翻轉排名。原作者也註明這「still a synthetic test set, not enough to represent the full distribution of Taiwan text」。這張表不宜過度解讀 ——這也是我們另建 tw-tokenizer-bench 的原因。
執行正確性的佐證 :原作者報告的 Pangolin overall 為 0.485,本地實測 0.4852;其 Qwen 3.6 為 0.541,本地實測 Qwen3.8 為 0.5407——兩者皆吻合。
切分品質
以 jieba 繁中斷詞為參考,量切點是否落在詞邊界。
| tokenizer | 字/token | 切點命中詞邊界 | 單字 token 佔比 |
|---|---|---|---|
| 🌟ours | 2.169 | 85.6% | 17.6% |
| Qwen3.8-27B | 1.475 | 77.8% | 41.7% |
| PangolinTokenizer | 1.441 | 77.8% | 45.1% |
| DeepSeek-V4 | 1.391 | 74.9% | 49.6% |
專業素養、特質或經公告審查優勝
ours:['專業素養', '、', '特質', '或經', '公告', '審查', '優勝']
Qwen:['專業', '素', '養', '、', '特質', '或', ...] ← 「素養」被拆成兩字
下游驗證(bits-per-character)
用兩個詞表各從零訓練一顆 270M 模型(同架構、同資料來源),以 bits-per-character 比較——BPC 以字元數為分母,是唯一能跨詞表公平比較的指標(perplexity 不行,token 單位不同)。
| 條件 | 🌟ours | Qwen 詞表 | |
|---|---|---|---|
| 等算力 (各 200M token) | 4.434 | 4.591 | ours 低 3.4% |
| 等文字量(各 4 億字元) | 4.595 | 4.379 | Qwen 低 4.7%(但多花 43% 算力) |
等算力下本詞表勝出,且是在參數少 13% 的條件下(229M vs 259M,因 vocab 較小 → embedding 較小)。同一個 token 預算下,本詞表的模型看到 4.4 億字元,Qwen 只看到 3.08 億——多看 43% 的資料 。
等文字量下 Qwen 勝出屬預期:它用了 43% 更多的算力跑同樣內容,多花算力本來就該贏。實務上算力才是限制,所以等算力那組是主要結論。
詞表污染稽核
逐一檢查全部 201,069 個 token。
| 數量 | 佔比 | |
|---|---|---|
| 含漢字 token | 146,339 | 72.8% |
| 含異體字 | 0 | 0% |
| 含簡體專屬字 | 55 | 0.04% |
那 55 個逐一判讀後多數為誤報:叁 (大寫數字,判決書與契約的法定寫法)、恒 (人名)、咨 (咨文)、卺 (合卺)。真簡體約 8 個單字 token。
各家的多字漢字 token 中,對繁體中文可用的比例:
| tokenizer | 多字漢字 token | 繁中可用 | 簡體專屬 | 繁體專屬 |
|---|---|---|---|---|
| Qwen3.8-27B | 47,929 | 17,568(36.7%) | 27,364(57.1%) | 2,997(6.3%) |
| DeepSeek-V4 | 29,920 | 12,167(40.7%) | 16,458(55.0%) | 1,295(4.3%) |
| PangolinTokenizer | 30,164 | 11,310(37.5%) | 9,490(31.5%) | 9,364(31.0%) |
Qwen 有 27,364 個多字 token 對繁體中文完全無用——那是它 248K 詞表的 11%。它仍能拿到不錯的中文壓縮率,是靠「詞表夠大,浪費得起」。
PangolinTokenizer 的繁體專屬比例最高(31.0%),方向與本詞表一致;差別在於總量較小(114,688),且英文效率為 2.658——那是為語音模型(Barbet 1B、BlueMagpie-TTS)做的取捨,中英混雜或需保留英文能力的用途要留意。
特殊 Token
具名 45 個 + 保留 1,024 個,ChatML 風格。
| 類別 | 內容 |
|---|---|
| 核心 | <|pad|> <|bos|> <|eos|> <|unk|> |
| 對話 | <|im_start|> <|im_end|> <|system|> <|user|> <|assistant|> <|tool|> |
| 思考 | <|think_start|> <|think_end|> <|no_think|> |
| 工具 | <|tool_call_start|> <|tool_result_start|> <|tool_schema_start|> … |
| 語音 | <|audio_start|> <|task:asr|> <|task:tts|> <|duplex_user|> … |
| 視覺 | <|image_start|> <|video_start|> <|task:ocr|> … |
| 文件 | <|doc_start|> <|page_sep|> <|table_start|> <|cite_start|> … |
| 保留 | <|reserved_0000|> …<|reserved_1023|> |
保留 1,024 個是為了讓未來加新功能時能直接改名,不必擴充 embedding 重訓。
🔧 Usage
1️⃣ 基本用法
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained("twinkle-ai/TwinkleTokenizer")
tok.tokenize("中華民國憲法增修條文第十條")
# ['中華民國憲法', '增修條文', '第十條']
2️⃣ 對話模板(含思考通道)
messages = [
{"role": "user", "content": "刑法第 271 條的構成要件為何?"},
{"role": "assistant",
"reasoning": "先確認條文位置,再拆解構成要件……",
"content": "刑法第 271 條規定殺人罪,構成要件為……"},
]
tok.apply_chat_template(messages, tokenize=False, enable_thinking=True)
reasoning 欄位會被渲染進 <|think_start|> … <|think_end|> ;enable_thinking=False 則整段略去。
3️⃣ 在 benchmark 上複驗
pip install datasets transformers
python evaluate.py --tokenizer twinkle-ai/TwinkleTokenizer
evaluate.py 附在 tw-tokenizer-bench repo 內。
語料前處理
順序不可顛倒:
- 異體字正規化 (12.7 萬處)——爲→為、裏→裡、麽→麼、着→著等。不做的話同一個詞會學出兩套 merge,白白吃掉詞表名額。
- 陸用語整列丟棄 ——55 個無歧義詞(質量、身份、通脹、網絡…),命中即丟整列。不改寫、不使用 OpenCC 整段轉換 ——整段轉換會把正確的繁中一起改壞。
- NFC 正規化 ——不用 NFKC,因為 NFKC 會把全形英數轉半形、拆解「㈠」,這兩者在繁中文本裡都是有意義的。
- 近似去重 ——判決書實測近似重複率 23%。
法律語料不套第 2 步 :「制作」(刑事訴訟法第 39 條)、「公安」(同法第 10 條)是法定用語,不是陸用語。
Bias, Risks, and Limitations
- 台語與客語的支援未經充分驗證。 訓練語料中台語僅 4.7 萬字元。在以歇後語為主(漢字為主)的樣本上,台羅拼音(
á、î、iann)確實會被拆得較碎;但在 PangolinBench 的taigi_han_roman_mixed(0.5495)與hakka_romanized(0.4567)兩個 subset 上表現優於各對照組。兩者的樣本量都很小,結論尚不穩固——需要更大的台羅/客語語料才能定論。 - 下游驗證規模小。 270M 參數、200M token,遠低於實用規模。結果支持但不證明大模型上也成立。
- vocab size 未達邊際遞減點。 64K→200K 的掃描顯示增益仍在遞減但尚未轉平,更大的 vocab 可能還有空間。
- 主要 benchmark 由本團隊建置。 tw-tokenizer-bench 是我們自己做的,本詞表在全部 5 個 subset 領先。請把該表當作「作者自評」而非第三方評測。防範措施(固定字元窗格、排除訓練污染分片、指紋比對)與資料、評測腳本全部公開,歡迎複驗。
- 純漢字 token 上限 6 字是刻意的取捨。 長 token 會遮蔽詞形資訊(Haslett, Computational Linguistics 2025:GPT-4 在字元配對任務上,文本被拆成 byte 時得分 .986,作為單一 token 時掉到 .219 )。代價是壓縮率少 0.9%。
Citation
@misc{twinkleai2026tokenizer,
title = {TwinkleTokenizer: A Traditional Chinese (Taiwan) Tokenizer Trained from Scratch},
author = {Huang, Liang Hsun},
year = {2026},
howpublished = {\url{https://huggingface.co/twinkle-ai/TwinkleTokenizer}},
note = {Twinkle AI. 201,069 vocab, byte-level BPE, NFC.}
}
Acknowledge
- 感謝 APMIC 贊助 CPU 算力,本詞表的語料處理與 BPE 訓練皆在 CPU 上完成。
- 感謝 OpenFormosa 團隊公開 PangolinTokenizer 與 PangolinBench,讓繁中詞表這件事有了可對照的基準。