跳到主要内容

分词与 Tokenization

问题

LLM 是如何处理文本的?BPE 算法的原理是什么?词表大小对模型有什么影响?

答案

LLM 不直接处理原始文本,而是将文本分割成 Token(最小处理单元),再映射为数字 ID。这个过程叫 Tokenization(分词)。

一、为什么需要 Tokenization

文本不能直接输入模型——需要数值化。但如何切分是关键:

方式示例:"ChatGPT is amazing"问题
按字符切C h a t G P T i s ...序列太长,失去语义
按单词切ChatGPT is amazing词表爆炸,无法处理新词
子词切分Chat GPT ▁is ▁amazing✅ 平衡词表大小和语义

子词 Tokenization(Subword Tokenization)是现代 LLM 的标准方案。

二、BPE 算法(Byte-Pair Encoding)

BPE 是最主流的子词分词算法,GPT 系列使用的基础方法。

核心思路

从单个字符开始,不断合并最频繁出现的相邻 Token 对,直到词表达到目标大小:

训练语料: "low lower lowest"

初始词表: ['l', 'o', 'w', 'e', 'r', 's', 't', ' ']

第 1 轮: 'l' + 'o' 出现最多 → 合并为 'lo'
第 2 轮: 'lo' + 'w' 出现最多 → 合并为 'low'
第 3 轮: 'e' + 'r' → 合并为 'er'
第 4 轮: 'e' + 's' → 合并为 'es'
...
最终词表: ['low', 'er', 'es', 't', ...]
直觉理解

BPE 自动学习语言的"零件"——高频词保留完整(如 the),低频词被拆成常见子词(如 un + believ + able),完全未知的词也能用字节表示。

三、主要 Tokenizer 方案

方案算法特点使用模型
GPT-2 BPEByte-level BPE从字节(256)开始合并GPT-2/3
tiktoken改进的 BPE高效 Rust 实现GPT-4、Claude
SentencePieceBPE / Unigram语言无关、支持中文LLaMA、Qwen
WordPiece类似 BPE(最大似然合并)Google 原生BERT、T5

Byte-level BPE vs 传统 BPE

  • 传统 BPE:从字符级别开始合并,遇到未知字符(如 emoji)会出 [UNK]
  • Byte-level BPE:从 256 个 字节 开始合并,任何字符都能用字节组合表示——永远不会出现 [UNK]

四、词表大小的影响

词表大小优点缺点
小(如 32K)Embedding 参数少、LM Head 小同样的文本需要更多 Token
大(如 128K+)每个 Token 承载更多信息、序列更短Embedding 矩阵大、存在稀疏 Token
模型词表大小
GPT-250,257
LLaMA 132,000
LLaMA 3128,256
GPT-4 (cl100k)100,256
Qwen 2151,643
中文 Token 效率

GPT-2 的词表以英文为主,一个中文字可能被编码为 2-3 个 Token,中文成本是英文的 2-3 倍。LLaMA 3、Qwen 等专门扩大了中文 Token 比例,大幅提升了中文效率。

五、特殊 Token

Token用途示例
<bos>序列开始Beginning of Sequence
<eos>序列结束End of Sequence
<pad>填充到相同长度Padding
<|im_start|>角色/轮次开始ChatML 格式
<|tool_call|>工具调用标记Function Calling

六、Tokenization 对 LLM 的影响

1. 数学能力

"12345" 可能被分为 "123" + "45""1" + "2345"——LLM 无法"看到"单个数字,这是算术能力弱的原因之一。

2. 代码生成

代码中的缩进、括号等被分成不同 Token,好的 Tokenizer 应该将常见代码模式(如 def return )作为完整 Token。

3. 多语言支持

词表中某语言的 Token 越多,该语言的处理效率越高、成本越低

七、实际使用

# 使用 tiktoken(GPT-4 的 tokenizer)
import tiktoken

enc = tiktoken.encoding_for_model("gpt-4")

text = "大语言模型的分词很重要"
tokens = enc.encode(text)
print(f"Token 数量: {len(tokens)}") # 约 7-8 个 Token
print(f"Token IDs: {tokens}")
print(f"解码: {[enc.decode([t]) for t in tokens]}")

# 使用 transformers(LLaMA 的 tokenizer)
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3-8B")
tokens = tokenizer.encode("Hello, world!")
print(tokenizer.convert_ids_to_tokens(tokens))

常见面试问题

Q1: BPE 和 WordPiece 的区别是什么?

答案

  • BPE:合并最高频的相邻 Token 对(按计数)
  • WordPiece:合并使语言模型似然度提升最大的 Token 对(按概率)
  • 实践中差异不大,BPE 更简单直观,是当前主流

Q2: 为什么 LLaMA 3 将词表从 32K 扩大到 128K?

答案

  1. 多语言效率:32K 词表以英文为主,中文等语言 Token 效率低。128K 词表大幅增加了多语言 Token,同样的中文需要的 Token 数减少 ~50%
  2. 更短的序列:同样内容用更少 Token 表示,等效于增加了上下文窗口
  3. 更低的推理成本:Token 越少,KV Cache 越小,推理越快
  4. 代价:Embedding 矩阵从 131M 增长到 525M 参数

Q3: Tokenization 如何影响模型性能?

答案

  • 数学:数字被不一致地切分,导致算术能力弱
  • 拼写:单词被拆成子词后,模型难以"看到"完整拼写
  • 提示注入:特殊 Token(如 <|im_start|>)如果被注入,可能绕过安全机制
  • 多语言公平性:词表偏向某些语言,导致其他语言效率低、成本高

Q4: 什么是 Token 数与 API 成本的关系?

答案: LLM API 按 Token 数量计费(如 GPT-4o:输入 2.5/Mtokens,输出2.5/M tokens,输出 10/M tokens)。因此:

  • 同样的中文文本,用 GPT-2 tokenizer 比 Qwen tokenizer 贵 2-3 倍
  • 系统提示(System Prompt)越长,每次请求的固定成本越高
  • Prompt 工程 的一个目标就是用更少 Token 达到更好效果

相关链接