2024年,一个奇怪的现象在社交媒体上引发热议:当用户问ChatGPT"strawberry这个词里有几个r"时,模型自信地回答"两个"。这个错误如此基础,以至于有人质疑:连小学生都能数对的事,为什么拥有数千亿参数的大模型做不到?

答案指向了大语言模型最底层、也最常被忽视的组件——Tokenizer(分词器)。这个将文本切分成模型可处理单元的组件,决定了模型能够"看到"什么,也决定了它永远"看不到"什么。

从字符到子词:一场压缩的革命

Tokenizer的本质是一个翻译器。它将人类可读的文本转换为模型可处理的数字序列。但如何切分文本,却是一个充满权衡的工程问题。

词级分词(Word-level Tokenization) 是最直观的方案:按空格和标点切分,每个词对应一个token。问题显而易见:英语有数十万词汇,中文更是有数万常用汉字,组合后的词更是天文数字。一个覆盖所有可能词汇的词表将无比庞大,而且永远无法处理新词——训练数据中没见过的词将全部变成[UNK](未知符号)。

字符级分词(Character-level Tokenization) 走向另一个极端:将每个字符视为一个token。词表大小可控(英语26个字母加标点,中文数千汉字),且永不出现未知词。但代价是序列长度爆炸——“artificial intelligence"这个词级只需2个token,字符级需要23个。更长的序列意味着更多的计算开销和更难学习长程依赖。

子词分词(Subword Tokenization) 在两个极端之间找到了平衡点。它允许常用词保持完整,同时将罕见词拆解为有意义的片段。例如,“unhappiness"可以拆分为[“un”, “happiness”]或[“un”, “happy”, “ness”],模型即使从未见过"unhappiness”,也能从子词推断其含义。

BPE Tokenization Example

图片来源: sidsite.com

上图展示了GPT-3的BPE tokenizer如何将文本转换为token,每个颜色块代表一个token。

BPE:一个压缩算法的语言学旅程

Byte Pair Encoding(BPE)的故事始于1994年。程序员Philip Gage在《C Users Journal》上发表了一篇论文,提出了一种数据压缩算法。核心思想简单而优雅:找到文本中最频繁出现的相邻字符对,用一个新的符号替代它,重复这个过程直到无法继续压缩。

21年后,爱丁堡大学的Rico Sennrich等人将这个算法引入自然语言处理领域。他们的洞见是:BPE的压缩过程天然适合构建子词词表

BPE训练过程

假设我们有一个小型语料库:

"hug" (10次), "pug" (5次), "pun" (12次), "bun" (4次), "hugs" (5次)

第一步:初始化词表

基础词表包含所有出现的字符:["b", "g", "h", "n", "p", "s", "u"]

第二步:统计相邻字符对频率

  • ("u", "g") 出现在"hug”(10)、“pug”(5)、“hugs”(5)中,共20次
  • ("u", "n") 出现在"pun"(12)、“bun”(4)中,共16次
  • ("h", "u") 出现在"hug"(10)、“hugs”(5)中,共15次

第三步:合并最高频字符对

("u", "g")合并为"ug",加入词表

词表更新为:["b", "g", "h", "n", "p", "s", "u", "ug"]

第四步:重复

继续统计、合并,直到词表达到目标大小(GPT-2为50,257,GPT-4约100,000,GPT-4o约200,000)。

这个过程的结果是:高频词(如"the"、“is”)成为独立的token,罕见词被拆解为有意义的子词片段。词表大小和压缩效率之间存在一个精妙的平衡——更大的词表可以更高效地编码文本,但也意味着更大的embedding矩阵和更多的参数。

Byte-level BPE:解决未知的艺术

GPT-2引入了一个关键改进:byte-level BPE。传统BPE以字符为基础词表,遇到训练数据中未出现的字符(如特殊符号、生僻汉字)就会产生[UNK]。Byte-level BPE将基础词表设为256个可能的字节值,这意味着任何文本都可以被编码,永远不会出现未知字符

这个改进看似微小,却深刻影响了模型的多语言能力。它使得英文预训练模型能够处理中文、阿拉伯文、表情符号——尽管效率可能不高。

“Strawberry"问题:模型"看"不到字母

现在回到开头的谜题。为什么大模型数不对"strawberry"里的"r”?

关键在于:模型从未"看到"字母,它只看到token

使用GPT系列tokenizer,“strawberry"被编码为两个token:["straw", "berry"]。模型知道"straw"是一个token,“berry"是另一个token,但它并不知道这两个token内部包含哪些字母。这就像你看到一个汉字却不知道它有几笔画——你知道这个字的含义和用法,但笔画信息在编码过程中丢失了。

更准确地说,token内部的字符信息并非完全丢失,而是以embedding的形式隐式存储。模型需要"学会"从token的embedding中提取字母信息,这是一个额外的学习任务,而非内置能力。

2024年,这个问题成为检验大模型细粒度文本处理能力的经典案例。讽刺的是,当用户将问题改为"请逐字母拼写strawberry并数出r的数量"时,模型通常能够正确回答——因为它被迫将token"解压缩"为字母序列。

数学困境:当数字被切碎

Tokenizer对模型数学能力的影响更为深远。2024年的一项研究详细分析了数字tokenization的问题。

问题在于:数字的tokenization方式与数值语义无关

考虑以下例子:

"123" → ["123"]          # 一个token
"1234" → ["123", "4"]    # 两个token
"12345" → ["123", "45"]  # 两个token
"123456" → ["123", "456"] # 两个token

这种切分方式取决于token在训练语料中出现的频率,而非数值的位值结构。模型看到的是token ID序列,而非数字的十进制表示。要做加法,模型需要学会一种完全不同于人类"按位相加"的算法——它需要在embedding空间中找到某种数值表示。

研究表明,使用逐数字tokenization(每个数字一个token)可以将算术任务的表现提升高达70倍。这解释了为什么某些专门针对数学优化的模型选择重新设计tokenizer。

多语言税:非英语用户的隐形代价

Tokenizer的设计选择对不同语言的使用者有着直接的经济影响。由于大多数主流模型以英语为中心训练,其tokenizer对非拉丁语系语言的效率显著更低。

中文案例:同一个句子,中文通常比英文需要更多token。

语言 句子 Token数量(GPT-4)
英文 “Artificial Intelligence Technology Development” ~6 tokens
中文 “人工智能技术发展” ~14-16 tokens

这意味着中文用户为同样的信息量支付约2-3倍的费用。更糟糕的是,更长的token序列消耗更多的上下文窗口,限制了模型能处理的内容长度。

GPT-4o的o200k_base tokenizer在一定程度上缓解了这个问题。通过将词表从约100,000扩大到约200,000,并优化了多语言token的分配,中文token效率提升了约40-50%。但根本性的不平等依然存在。

词表大小的权衡

词表大小是一个关键的超参数,涉及多方面的权衡。

更大的词表意味着

  • 更短的token序列(更高效的文本编码)
  • 更大的embedding矩阵(更多参数)
  • 更高的内存占用
  • 更大的输出层softmax计算开销

以7B参数模型为例:

词表大小 Embedding参数量 占总参数比例
32K 32,768 × 4096 × 2 = 268M ~3.8%
50K 50,000 × 4096 × 2 = 410M ~5.9%
100K 100,000 × 4096 × 2 = 820M ~11.7%
200K 200,000 × 4096 × 2 = 1.64B ~23.4%

Embedding矩阵包括输入embedding和输出投影层(通常共享权重)。对于200K词表,仅embedding就占用了近四分之一的参数。这就是为什么许多开源模型(如LLaMA系列)选择约32K-128K的中等词表——在效率和性能间取得平衡。

有趣的是,更大的词表并不总是更好。研究发现,当词表过大时,训练数据可能不足以让每个token都获得充分学习,反而可能导致某些低频token的表示质量下降。词表大小的最优选择与训练数据规模、模型大小、目标语言分布都密切相关。

GPT-4 vs GPT-4o:Tokenizer的演进

OpenAI在GPT-4o中引入了o200k_base tokenizer,这是对cl100k_base(用于GPT-4)的重大升级。

关键变化

特性 cl100k_base (GPT-4) o200k_base (GPT-4o)
词表大小 ~100,000 ~200,000
多语言优化 一般 显著提升
发布时间 2023年3月 2024年5月

实测数据显示,o200k_base在多语言场景的效率提升明显:

  • 中文:token数量减少约35-45%
  • 阿拉伯文:token数量减少约40-50%
  • 俄文:token数量减少约30-40%
  • 英文:token数量减少约5-10%

这种提升对大规模应用有直接的经济意义。如果一个API每天处理100万个中文token请求,从GPT-4迁移到GPT-4o可以节省约40%的token消耗——在千万级的调用规模下,这意味着可观的成本节省。

Tokenizer对推理成本的影响

Token效率直接关系到两个核心成本维度:

API计费成本:主流LLM服务按token计费。更高效的tokenization意味着同样的信息用更少的token表达,从而降低API调用成本。

计算成本:Transformer的自注意力机制复杂度为$O(n^2)$,其中$n$是token序列长度。更长的序列意味着更多的计算量和内存占用。KV Cache的大小也与序列长度成正比。

一个具体的例子:对于8K上下文的请求,如果tokenizer效率提升50%,意味着模型实际上只需要处理4K有效上下文的计算量。这对于高吞吐量的生产系统影响巨大。

不同算法的竞争:BPE、WordPiece、Unigram

虽然BPE是最广泛使用的算法,但它并非唯一选择。

WordPiece(用于BERT):与BPE类似,但合并决策基于似然提升而非频率。理论上能更好地处理词边界,但在大规模实践中差异不大。

Unigram Language Model(用于T5、ALBERT):采用概率框架,从一个大词表开始,逐步剪枝低概率token。相比BPE,它提供了多种tokenization路径的概率分布,可能更适合处理歧义。

研究表明,在相同词表大小下,Unigram在语言模型困惑度上略优于BPE,但差距通常在2-5%以内。在实践中,算法选择的差异往往被训练数据规模和模型架构的影响所掩盖。

Tokenizer-Free:未来的可能性?

既然tokenizer带来这么多问题,为什么不直接去除它?

2023年,Lili Yu等人提出了MEGABYTE架构,尝试在Transformer中直接处理原始字节序列。通过层次化设计——高级模型预测低级模型的边界,低级模型填充具体内容——理论上可以处理百万级别的字节序列。

这个方向面临几个挑战:

  1. 计算开销:即使采用层次化设计,处理原始字节序列的计算量仍然远大于处理token序列
  2. 预训练数据效率:子词tokenization本质上是一种归纳偏置,帮助模型更快学习语言规律
  3. 生态兼容性:现有模型生态都基于token,迁移成本巨大

更实际的中间路线是改进tokenization质量:优化词表分配、针对特定语言或领域训练专用tokenizer、在推理时进行动态tokenization优化。

设计选择的影响:一个系统视角

从系统设计的角度看,tokenizer的选择影响整个LLM应用的性能和成本:

决策点 影响维度
词表大小 模型参数量、内存占用、训练效率
训练语料 语言覆盖、领域适应性、token效率
算法选择 tokenization一致性、歧义处理、多语言能力
特殊token设计 任务格式、微调兼容性、推理控制

对于需要处理特定领域文本的应用(如医疗、法律、编程),使用领域定制tokenizer可以显著提升效率。一个包含常见医学缩写的tokenizer可以将"myocardial infarction"编码为单个token,而非十几个token。

回到问题的本质

“为什么模型数不对strawberry里的r"这个问题,揭示了语言模型的一个根本特性:模型不是在处理人类意义上的"文本”,而是在处理一个抽象的token序列。这个序列与人类理解的文本之间存在着不可忽视的鸿沟。

Tokenizer就是这个转换过程的关键接口。它的每一个设计选择——算法、词表大小、训练语料——都深刻影响着模型的"世界观”。一个以英语为中心的tokenizer,注定了模型对英语以外语言的"偏见”;一个以词频驱动的合并策略,决定了模型对数字和罕见词的处理方式。

理解tokenizer,就是理解语言模型的边界。当我们谈论"AI理解语言"时,首先要意识到:在"理解"之前,先有一个"看见"的问题。而tokenizer,正是决定模型"看见"什么的那个隐形守门人。


参考文献

  1. Sennrich, R., Haddow, B., & Birch, A. (2015). Neural Machine Translation of Rare Words with Subword Units. arXiv:1508.07909.
  2. Gage, P. (1994). A New Algorithm for Data Compression. C Users Journal, 12(2), 23-38.
  3. Radford, A., et al. (2019). Language Models are Unsupervised Multitask Learners. OpenAI.
  4. Kudo, T. (2018). Subword Regularization: Improving Neural Network Translation Models with Multiple Subword Candidates. ACL 2018.
  5. Wu, S., et al. (2024). The Impact of Tokenization on Arithmetic in Frontier LLMs. arXiv:2402.14903.
  6. Mielke, S. J., et al. (2021). Between Words and Characters: A Brief History of Open-Vocabulary Modeling and Tokenization in NLP. arXiv:2112.10508.
  7. Yu, L., et al. (2023). MEGABYTE: Predicting Million-byte Sequences with Multiscale Transformers. arXiv:2305.07185.
  8. Hugging Face. (2024). Byte-Pair Encoding Tokenization. Hugging Face LLM Course.
  9. OpenAI. (2024). tiktoken: A fast BPE tokenizer for use with OpenAI’s models. GitHub Repository.
  10. Bojanowski, P., et al. (2017). Enriching Word Vectors with Subword Information. TACL.