tokenizer comparison

Tokenizer 全面对比:BPE vs WordPiece vs Unigram vs SentencePiece

1. 为什么 Tokenizer 如此重要 Tokenizer 是大语言模型与文本世界的接口。它决定了: 模型如何"看到"文本(粒度) 词表大小与序列长度的权衡 多语言、代码、特殊字符的覆盖能力 模型的最大知识单元(token = 模型的"字母") 一个不好的 tokenizer 会导致: 序列过长 → 计算浪费 未登录词过多 → 语义丢失 跨语言不均衡 → 多语言能力差 英文 "Hello World" 的不同分词: 字符级: H e l l o W o r l d → 11 tokens 词级: Hello World → 2 tokens (但词表爆炸) BPE: Hello World → 2 tokens (高频词保留) 字节级: Hello World → 2 tokens (256基础, 递归合并) 中文 "你好世界" 的不同分词: 字符级: 你 好 世 界 → 4 tokens BPE: 你 好 世 界 → 4 tokens (中文常见) 词级: 你好世界 → 1 token (理想但不可达) 2. BPE (Byte Pair Encoding) 2.1 算法原理 BPE 最初是一种数据压缩算法,被 Sennrich 等人 (2016) 引入 NLP。核心思想:从字符级开始,迭代合并最高频的相邻 token 对。 ...

2026-06-25 · 8 min · 1626 words · 硅基 AGI 探索者
tokenizer internals

Tokenizer 原理详解:BPE/WordPiece/Unigram/SentencePiece

1. 为什么 Tokenization 至关重要 LLM 不能直接处理文本,必须将文本切分为离散的 Token 序列,再将每个 Token 映射为向量。Tokenizer 直接影响: 词汇表大小:影响 Embedding 层参数量和 Softmax 计算量 序列长度:同一段文本,不同 Tokenizer 产生的 Token 数不同,影响上下文窗口利用率 多语言公平性:中文一个字 vs 英文一个 word,Tokenizer 决定了编码效率 OOV 问题:未知 Token 的处理能力 2. BPE (Byte Pair Encoding) 2.1 算法思想 BPE 最初是数据压缩算法,被 Sennrich 等人(2016)引入 NLP。核心思路:从一个字符级词汇表开始,反复合并出现频率最高的相邻 Token 对。 2.2 训练过程 输入语料: {"low": 5, "lower": 2, "newest": 6, "widest": 3} 步骤 1: 拆分为字符序列 l o w </w> : 5 l o w e r </w> : 2 n e w e s t </w> : 6 w i d e s t </w> : 3 步骤 2: 统计相邻 Token 对频率 (l, o): 7, (o, w): 7, (e, r): 2, (n, e): 6, ... 步骤 3: 合并最高频对 (l, o) → "lo" lo w </w> : 5 lo w e r </w> : 2 n e w e s t </w> : 6 w i d e s t </w> : 3 重复直到词汇表达到目标大小 2.3 编码过程 对新文本,按训练时的合并规则顺序应用: ...

2026-06-25 · 4 min · 707 words · 硅基 AGI 探索者
tokenization guide

分词原理与工程实践:BPE/SentencePiece/WordPiece

1. 为什么需要分词 1.1 分词的核心矛盾 自然语言是连续字符序列,模型需要离散输入单元。分词面临三重矛盾: 策略 词表大小 OOV 问题 序列长度 语义完整性 字符级 ~100 无 极长 差 词级 100K+ 严重 短 好 子词级 32K-128K 少 中 较好 子词分词是最佳折中:高频词保持完整,低频词拆为有意义的子词单元。 1.2 分词影响一切 分词不仅是预处理步骤,它直接决定: 模型能力边界:词表决定模型能处理的语言和字符 推理成本:相同文本,不同 Tokenizer 产生的 token 数不同 多语言公平性:中文分词效率直接影响中文任务成本 2. BPE(Byte Pair Encoding) 2.1 算法原理 BPE 最初是数据压缩算法,被 Sennrich 等人(2016)引入 NLP。核心思想:从字符级开始,迭代合并最高频的相邻字符对。 训练算法: 1. 将所有词拆为字符序列,词尾加 </w> "low" → ['l', 'o', 'w', '</w>'] 2. 统计相邻字符对频率 3. 合并最高频字符对为新 token 4. 重复步骤 2-3 直到达到目标词表大小 2.2 代码实现 from collections import Counter, defaultdict def train_bpe(corpus, vocab_size): """BPE 训练算法""" # 初始化:每个词拆为字符 word_freqs = Counter(corpus.split()) splits = {word: list(word) + ['</w>'] for word in word_freqs} merges = [] vocab = set(char for word in word_freqs for char in list(word) + ['</w>']) while len(vocab) < vocab_size: # 统计相邻对频率 pair_freqs = defaultdict(int) for word, freq in word_freqs.items(): split = splits[word] for i in range(len(split) - 1): pair_freqs[(split[i], split[i+1])] += freq if not pair_freqs: break # 合并最高频对 best_pair = max(pair_freqs, key=pair_freqs.get) merges.append(best_pair) new_token = best_pair[0] + best_pair[1] vocab.add(new_token) # 更新所有词的分词 for word in word_freqs: split = splits[word] i = 0 while i < len(split) - 1: if (split[i], split[i+1]) == best_pair: split = split[:i] + [new_token] + split[i+2:] else: i += 1 splits[word] = split return vocab, merges def bpe_encode(text, merges): """BPE 编码""" tokens = list(text) + ['</w>'] for pair in merges: i = 0 while i < len(tokens) - 1: if (tokens[i], tokens[i+1]) == pair: tokens = tokens[:i] + [tokens[i]+tokens[i+1]] + tokens[i+2:] else: i += 1 return tokens 2.3 BPE 的特点 确定性:相同训练数据 → 相同词表 贪婪合并:高频对优先,可能不是全局最优 可逆性:token 拼接即可还原原文 增量性:可以从已有词表继续训练 3. WordPiece 3.1 与 BPE 的区别 WordPiece(Google, 2012)用于 BERT,与 BPE 类似但有关键区别: ...

2026-06-24 · 4 min · 667 words · 硅基 AGI 探索者
鲁ICP备2026018361号