三:Tokenizer¶
来源:http://mp.weixin.qq.com/s?__biz=MzYyNTk3Njg1NA==&mid=2247483754&idx=1&sn=a7af13deb4c6fec2ad995778d5837ca1&chksm=f01eb213c7693b05d476cf6053c2d97f891d1196caf775e99a7936495af54ffb51012e3754ed#rd
1. 学习定位¶
Tokenizer 是大语言模型从文本世界进入数字世界的入口。模型不能直接处理字符串,必须先把文本切成 token,再把 token 映射成 token id,随后通过 embedding table 变成连续向量。 第三天重点是 subword-based tokenizer,也就是介于字符级和词级之间的子词分词。现代 LLM 大多使用某种子词 tokenizer,例如 BPE、byte-level BPE、WordPiece、Unigram/SentencePiece 或它们的变体。 本日需要建立的知识闭环是:
raw text
-> normalization
-> pre-tokenization
-> subword segmentation
-> token ids
-> special tokens / chat template
-> embeddings
-
BPE、WordPiece、Unigram 的核心思想和区别。
-
子词 tokenizer 如何缓解 OOV 问题。
-
中文、多语言、代码、emoji 为什么会影响 token 数。
-
tokenization 如何影响上下文长度、训练成本、推理成本和模型效果。
-
special tokens、BOS/EOS/PAD/UNK、chat template 的作用。
-
tokenizer 变更为什么会影响模型 embedding 和兼容性。
2. Tokenizer 在 LLM 流程中的位置¶
LLM 的文本处理流程通常是:
用户文本
-> tokenizer.encode()
-> input_ids: [B, T]
-> embedding table lookup
-> hidden states: [B, T, d_model]
-> Transformer
-> logits: [B, T, V]
-> decoding
-> output_ids
-> tokenizer.decode()
-> 输出文本
3. Token、Vocabulary 与 Token ID¶
token 是 tokenizer 输出的基本单位,可以是字符、子词、完整单词、标点、空格模式、字节片段或特殊符号。
vocabulary 是 tokenizer 能识别的 token 集合。每个 token 对应一个整数 id。词表大小记为 V。
vocab:
"<pad>" -> 0
"<bos>" -> 1
"hello" -> 15339
" world" -> 1917
4. 字符级、词级与子词级¶
早期直觉上有三种粒度:
字符级 tokenizer: NLP -> N, L, P
词级 tokenizer: I love NLP -> I, love, NLP
子词级 tokenizer: unbelievable -> un, believe, able
5. Subword Tokenizer 的基本思想¶
Subword tokenizer 的核心思想是:
例如: 对模型来说,子词粒度可以让它共享形态信息。例如play、playing、played 之间有公共子词片段,模型可以更容易学习词形变化。
对工程来说,子词 tokenizer 可以在有限词表下覆盖开放词汇,缓解 OOV,同时保持序列长度不过分膨胀。
6. Tokenizer 训练与使用的两个阶段¶
Tokenizer 有训练阶段和使用阶段。 训练阶段根据语料构建词表和规则:
training corpus
-> normalization / pre-tokenization
-> learn vocab and merge/probability rules
-> tokenizer files
7. Normalization¶
normalization 是对原始文本做规范化处理。常见操作包括: - Unicode 规范化,例如 NFC、NFKC。
-
大小写转换,例如 lowercasing。
-
去除或规范化重音符号。
-
空白字符规范化。
-
全角/半角转换。
-
特殊符号清洗。
normalization 的目标是减少无意义变体,让相同语义的文本更可能映射到一致 token 序列。 但 normalization 也可能损失信息。例如大小写在代码、实体名、德语名词中可能有意义;全角/半角、emoji、特殊标点在某些任务中也可能承载信息。因此 tokenizer 的 normalization 策略必须与模型目标和语料匹配。
8. Pre-tokenization¶
pre-tokenization 是在正式子词切分前,先按空格、标点、数字、字母类别或语言规则做粗切分。它决定后续子词算法在哪些边界内工作。
英文常见 pre-tokenization 会利用空格和标点。中文没有天然空格分词边界,常需要不同策略。代码文本可能需要保留下划线、缩进、换行、括号等结构。
很多现代 tokenizer 会把空格作为 token 的一部分。例如 GPT 类 byte-level BPE 中,"hello" 和 " hello" 可能是不同 token。这让 tokenizer 可以保留词前空格信息。
pre-tokenization 的边界会显著影响最终 tokenization。例如是否把 New York、C++、foo_bar、2026-05-23、URL、emoji 当成连续片段,会影响 token 数和语义建模。
9. BPE 的核心思想¶
BPE 是 Byte Pair Encoding 的缩写。用于 NLP 时,它从较小的基本单位开始,不断合并语料中最频繁相邻 pair,直到达到目标词表大小或合并次数。 简化训练流程:
示例: 使用阶段不是重新统计频率,而是按训练得到的 merge rules 对新文本进行合并。 BPE 的直觉是:高频相邻片段应该成为更长 token,低频词则保留为多个较短片段。10. BPE 编码阶段¶
BPE tokenizer 训练后会得到 merge rule 的优先级列表。编码新文本时,一般流程是:
text
-> normalization
-> pre-tokenization
-> 初始拆成字符或字节单位
-> 按 merge priority 逐步合并可合并 pair
-> 得到 subword tokens
-> 查 vocab 得到 token ids
11. Byte-level BPE¶
byte-level BPE 把初始单位设为字节,而不是 Unicode 字符。这样理论上任何文本都可以编码,因为任何字符串都可以表示为 UTF-8 字节序列。
byte-level BPE 的优点:
- 覆盖能力强,几乎不需要 <unk>。
-
能处理多语言、emoji、乱码、罕见字符、代码符号。
-
对开放互联网文本更鲁棒。
缺点: - 对某些非英文文本,一个字符可能对应多个字节,token 效率可能较低。
- 人类可读的字符边界和 byte token 边界不一定一致。
GPT 系列和 OpenAI 的 tiktoken 使用的是 byte-level BPE 或相关变体。面试中需要知道:byte-level 的核心优势是开放字符覆盖,代价是某些语言下 token 数可能变多。
12. WordPiece¶
WordPiece 是 BERT 等模型常用的 subword tokenizer。它也会构建子词词表,但学习策略和 BPE 不完全相同。 BPE 通常直接合并频率最高的 pair。WordPiece 更强调选择能最大化训练语料似然或提升语言模型概率的子词。实际工程解释中,可以把 WordPiece 理解为一种基于统计评分选择子词的 greedy 子词分割方法。
WordPiece 常用 ## 标记词中续接子词:
## 表示该 token 不是一个新词的开头,而是接在前一个 token 后面。这有助于解码和保持词边界信息。
13. Unigram 与 SentencePiece¶
Unigram tokenizer 的思路和 BPE/WordPiece 不同。它不是从小单位开始逐步合并,而是先准备一个较大的候选子词词表,并为每个子词学习概率,然后逐步删除对语料似然影响较小的 token,最终得到目标词表。 - 初始构建超大候选子词库,囊括字符、长短词组
-
基于单词概率计算整体文本对数似然
-
迭代移除对整体概率贡献最小的子词
-
压缩到预设词表规模停止
-
分词时动态选概率最高的拆分方案
编码时,Unigram 可以把一个字符串切成多种可能的子词序列,并选择概率最高或代价最低的分割。
SentencePiece 是常用 tokenizer 工具,支持 Unigram 和 BPE。它的重要特点是把文本视为原始 Unicode 字符序列处理,不依赖预先按空格分词,因此对日语、中文等无空格语言更友好。
SentencePiece 常用特殊符号 ▁ 表示空格边界:
14. BPE、WordPiece、Unigram 对比¶
三者都属于 subword tokenizer,但训练思想不同:
BPE:
从小单位开始,反复合并高频相邻 pair。
直观、简单、常用于 GPT 类模型。
WordPiece:
选择能提升语料概率的子词,常用 greedy longest-match 编码。
BERT 系列常用。
Unigram:
从大候选词表开始,学习子词概率并删除低贡献 token。
SentencePiece 常用。
-
WordPiece 是 likelihood/score-based 的子词选择。
-
Unigram 是概率模型和 pruning 思路。
-
它们都在词级和字符级之间做折中。
15. Special Tokens¶
special tokens 是 tokenizer 词表中的控制符,不一定对应普通自然语言文本。常见 special tokens 包括:
<bos> / <s> 序列开始
<eos> / </s> 序列结束
<pad> padding
<unk> unknown token
<mask> mask language modeling
<sep> segment separator
<cls> classification token
<|user|> chat role token
<|assistant|> chat role token
[CLS]、[SEP]、[MASK]。decoder-only chat model 通常需要 BOS/EOS、role tokens、turn separators 等。
special token 必须和模型训练时的格式一致。错误添加或遗漏 EOS、role token、chat template,可能导致模型输出异常、角色混乱、无法停止或格式不稳定。
16. Chat Template 与 Tokenizer¶
chat model 的输入不是简单把用户问题直接 tokenize,而是先通过 chat template 转换成模型训练时见过的对话格式。 示意:
messages = [
{"role": "system", "content": "You are helpful."},
{"role": "user", "content": "Explain BPE."}
]
template ->
<|system|>
You are helpful.
<|user|>
Explain BPE.
<|assistant|>
17. OOV、UNK 与开放词汇¶
OOV 是 out-of-vocabulary,指输入中出现了词表没有的词。词级 tokenizer 容易 OOV,因为新词、拼写错误、罕见实体、网址、代码标识符几乎无限。 subword tokenizer 缓解 OOV 的方式是把未知词拆成已知子词。例如:
byte-level tokenizer 进一步把任何字符拆到字节层面,几乎可以避免<unk>。
但“可编码”不等于“模型理解得好”。罕见词如果被拆成很多碎片,模型仍可能难以准确建模,且会消耗更多上下文长度。
18. 中文与多语言 Tokenization¶
中文没有英文那样的空格词边界。中文 tokenizer 可能按字、词、子词、字节或 SentencePiece 方式切分。 例如:
不同切分会影响 token 数、语义粒度和训练效率。 多语言 tokenizer 还需要处理不同文字系统、重音符号、复合词、空格规则、emoji 和混合文本。词表容量有限时,如果英文占据太多高频 token,其他语言可能被切得更碎,导致非英文 token 效率较低。 这也是为什么同样字符数的中文、英文、代码、emoji,在不同模型上 token 数可能差异很大。19. 代码、数字、URL 与结构化文本¶
代码和结构化文本对 tokenizer 很敏感。 代码中有大量符号:
下划线、缩进、换行、括号、运算符、驼峰命名都会影响 tokenization。一个代码友好的 tokenizer 应该尽量高效表示常见代码模式,否则会导致序列变长、上下文浪费和建模困难。 数字和日期也类似: 不同 tokenizer 可能把它们切成完整数字、多个数字片段或单字符。数字切分方式会影响模型做精确复制、比较和计算的能力。 URL、路径、JSON、Markdown、LaTeX 等结构化文本也常出现大量符号和长尾片段,需要关注 token 数和边界保留。20. Tokenizer 对上下文长度和成本的影响¶
LLM 的上下文窗口通常按 token 计数,而不是按字符或词计数。 如果一个文本被切成更多 token,它会: - 占用更多上下文窗口。
-
增加 prefill 计算。
-
增加 KV cache 显存。
-
增加 API 计费成本。
-
在训练中增加序列长度和训练成本。
因此 tokenizer 的 token efficiency 很重要。对同一段中文、英文、代码,不同 tokenizer 可能产生不同 token 数。面试中可以把 tokenizer 理解为模型成本和可用上下文长度的前置决定因素之一。
21. Tokenizer 与训练数据¶
Tokenizer 通常在大规模语料上训练。语料分布会影响词表内容。 如果训练语料以英文网页为主,英文常见词和空格模式会被高效编码;如果语料包含大量代码,代码符号和常见标识符片段可能进入词表;如果语料多语言均衡,词表会给不同语言分配更多容量。 训练 tokenizer 时需要考虑: - 语料代表性。
-
语言分布。
-
领域分布,例如代码、数学、医学、法律。
-
词表大小。
-
special tokens 设计。
-
normalization 策略。
-
是否 byte-level。
Tokenizer 不是模型训练后才随便选的工具,而是预训练体系的一部分。
22. Tokenizer 与 Embedding 兼容性¶
模型的 embedding table 行号与 tokenizer token id 一一对应。
如果更换 tokenizer,即使词表大小相同,id 到 token 的映射也可能不同。原来15339 表示 "hello",新 tokenizer 中可能表示别的 token,embedding 语义会错位。
因此:
- 不能随意替换预训练模型的 tokenizer。
-
扩展词表后需要 resize embedding。
-
新增 token 的 embedding 需要初始化并训练。
-
微调和推理必须使用模型对应 tokenizer。
23. Offset Mapping 与标签对齐¶
在信息抽取、NER、QA 等任务中,常需要把 token 与原始字符位置对齐。tokenizer 通常可以返回 offset mapping:
子词切分会让一个原始词对应多个 token。做 token-level 标签时,需要决定: - 只给第一个 subword 打标签。-
所有 subword 复制同一个标签。
-
后续 subword 标记为 ignore。
如果对齐处理错误,训练标签会错位,评测指标也会失真。中文和混合文本中,这个问题尤其常见。
24. Padding、Truncation 与 Attention Mask¶
Tokenizer 通常还负责构造模型输入所需的辅助张量:
padding 把不同长度样本补齐到同一长度。truncation 把超过最大长度的样本截断。attention mask 标记哪些位置是真实 token,哪些位置是 padding。 常见问题: - 截断导致关键信息丢失。-
padding token 参与 loss。
-
attention mask 与 input_ids 长度不一致。
-
left padding/right padding 与 decoder-only 推理缓存不匹配。
训练和推理时要保证 padding/truncation 策略与模型架构和任务匹配。
25. Fast Tokenizer 与 Slow Tokenizer¶
Hugging Face 中常见 fast tokenizer 和 slow tokenizer。fast tokenizer 通常基于 Rust tokenizers 库,速度更快,并支持更完整的 offset mapping 等功能。slow tokenizer 多为 Python 实现,便于理解和调试,但速度较慢。
在大规模训练、数据预处理和在线服务中,tokenization 速度可能成为瓶颈。需要关注批量编码、缓存、并行处理和 tokenizer 线程安全。
26. 常见工程问题¶
Tokenizer 工程中常见问题包括: - 推理时 tokenizer 与模型不匹配。
-
忘记添加或错误添加 special tokens。
-
chat template 用错,导致模型角色混乱。
-
训练 label 没有 mask 掉 prompt 或 padding。
-
截断策略导致答案或关键上下文被截断。
-
中文、emoji、代码 token 数异常膨胀。
-
新增 token 后没有 resize embedding。
-
token-level 标注任务中 subword 标签对齐错误。
-
decode 时没有跳过 special tokens,输出包含控制符。
这些问题通常不会表现为语法错误,而是表现为效果差、loss 异常、输出格式错、成本升高或模型不停止。
27. 面试中的核心表达¶
Tokenizer 的面试表达可以压缩为:
Tokenizer 把原始文本映射为模型可处理的 token ids。
现代 LLM 多使用 subword tokenizer,在词级和字符级之间折中。
BPE 通过高频 pair 合并学习词表。
WordPiece 更强调基于似然或评分选择子词。
Unigram 从候选词表出发学习子词概率并裁剪。
byte-level tokenizer 能覆盖任意文本,但可能牺牲部分语言的 token 效率。
special tokens 和 chat template 是模型输入格式的一部分。
tokenizer 会影响上下文长度、成本、训练效率、OOV、标签对齐和模型兼容性。
28. 参考资料¶
-
Hugging Face Tokenizer Summary: https://huggingface.co/docs/transformers/v4.42.0/tokenizer_summary
-
Hugging Face Tokenizers Documentation: https://huggingface.co/docs/tokenizers/
-
Neural Machine Translation of Rare Words with Subword Units: https://arxiv.org/abs/1508.07909
-
SentencePiece: A simple and language independent subword tokenizer and detokenizer for Neural Text Processing: https://arxiv.org/abs/1808.06226
-
OpenAI tiktoken: https://github.com/openai/tiktoken
预览时标签不可点<div class="