分词器:LLM 背后的隐形操作者
分词器:LLM 背后的隐形操作者
在一切之前

在大模型有机会处理你的消息之前,分词器必须先把文本消化成一串(通常是)16 位整数。这份工作并不光鲜,但别搞错:这一步对你模型的上下文窗口、训练速度、提示词成本,以及你最爱的 Unicode emoji 能否幸存,都有重大影响。
这是我「101 天博客」系列的第 5 篇。如果它触发了你什么——想法、问题或批评——我的私信开放。希望它能给你一些带走就能用的东西。

分词器:LLM 背后的隐形操作者
- 模型说的是数字,不是单词。 分词器是你的文本与神经网络连续向量空间之间的翻译层。没有分词器就没有语言模型(除非你专门拿五十万个神经元去背英语词典)。
- 它决定了你的提示词「真正」的成本。 一段看起来很短的字符串可能膨胀成几十个 token(中日韩文字系统——即 CJK——最容易中招)。
- 它定义了什么是「未知」。 选错分词器可能导致你一半的提示词被替换成 [UNK] token,意义崩塌,下游各种头疼。为任务挑选正确的分词器至关重要,你要在词表大小与粒度之间取得平衡,才能把这种混乱降到最低。
从空格到子词:极速巡礼
我们按「我到底该关心什么」的务实视角,把主要流派的分词器过一遍:
词级
最元祖的分词器。按空格切分,每个词分配一个 ID。简单,但仅英语词表就会膨胀到 50 万以上,而且「dog」和「dogs」被视为不同的词条。
字符级
把词表压缩到最小,现在每个字母或符号都是一个独立 token。问题:连简单的词都变成冗长的 token 链,拖慢训练,也丢失了让大模型出彩的语义分块。
子词级
现代魔法发生的地方。把罕见词拆成碎片,常见词保持完整。自 2017 年以来基本上每个 transformer 都采用这个思路:不太大,不太小,对 GPU 内存和 token 吞吐量刚刚好。
分词算法
下面是几个主要玩家,它们如何工作,以及为什么重要:
字节对编码(BPE)——用于 GPT 家族、RoBERTa、DeBERTa
工作原理:
- 从所有唯一字符(或字节)作为基础字母表开始
- 反复合并出现频率最高的相邻符号对(字符或之前合并出的块)
- 持续到达到目标词表大小为止
为什么重要:
- 在捕获高频子词单元的同时缩减词表规模
- 对罕见词、拼写错误和多语言文本有帮助
- 在简单性和性能之间取得平衡
- 因其有效性与通用性而被广泛使用
WordPiece——用于 BERT 及相关模型
工作原理:
- 类似 BPE,但基于概率模型合并能最大化整体似然的符号对
- 常为更好的统计拟合生成出人意料的子词块
- 对词内部的 token 使用特殊前缀(如「##」)
为什么重要:
- 更灵活、更上下文敏感的切分
- 略微提升性能,对形态丰富的语言尤其如此
Unigram LM——用于 T5、mBART、XLNet
工作原理:
- 从一个庞大的候选子词池开始,每个子词分配一个概率
- 迭代剪掉可能性最低的子词
- 为每个输入找到使子词概率乘积最大化的分词方案
为什么重要:
- 基于概率与剪枝的方法给出灵活高效的词表
- 适合多样化或多语言数据
- 著名的 SentencePiece 实现即采用此法
SentencePiece——为多语言/黏着语设计
工作原理:
- 一个同时实现 BPE 和 Unigram LM 的工具包
- 直接在原始 UTF-8 字节上操作,无需基于空格的预分词
- 把输入当作原始流处理(对没有空格的语言非常友好)
为什么重要:
- 处理没有空格的语言(如日语、中文)
- 对混乱的真实世界文本足够鲁棒
- 对会搞坏其他分词器的多样 token 边界足够灵活
字节级 BPE(tiktoken)——用于 GPT-2、GPT-4o、OpenAI API
工作原理:
- 使用原始字节(0-255)作为基础字母表
- 每个字符、emoji 或符号都拆成字节;然后应用 BPE 合并
- 对语言或书写系统完全不可知
为什么重要:
- 通用:可以分词任何 Unicode 文本(emoji、所有书写系统等)
- 无需手工调规则
- 代价:对多数语言的常见词要消耗更多 token(推高 token 计数),但换来了通用覆盖与鲁棒性
词表大小:一场权衡
缩放定律极客(嘿,就是我们)都知道:随着模型规模扩大,你也需要扩大分词器的词表,这又能反过来优化模型咀嚼原始文本的效率。
拿 Llama 3 举例:它的分词器词表暴涨到 128K,相比之下 Llama 2 只有温和的 32K。为什么?词表更大,每个 token 就能表示更长或更有意义的文本块。这意味着输入序列更短(同样多的文本,模型要处理的 token 更少),可以同时加速训练和推理。你本质上是在向每一步塞进更多信息。
但没有免费午餐。更大的词表意味着你的嵌入矩阵——把 token ID 映射到向量的查找表——也随之膨胀。更多 token = 更多行 = 更多参数 = 更多 GPU 内存。对于超大模型或内存受限的部署,这可能是真正的痛点。你还会遇到收益递减:过了某个点,增加更多 token 买不到多少东西,却照样消耗硬件。
另一方面,如果词表太小,分词器就开始把词拆成大量细碎片段(「子词」)。你的模型最终要与又长又碎的序列搏斗,把算力浪费在基础重建而不是真正的语言理解上。这很低效,对形态丰富或罕见词多的语言尤其如此。
那么「刚刚好」的区间在哪?视情况而定。理想词表大小是一场平衡术:
- 算力预算: 词表更大 = 嵌入更大 = 更多 FLOPs/内存。
- 推理配置: 序列更短可能意味着推理更快,但如果你得把嵌入换出到磁盘上就另当别论。
- 覆盖语言: 多语言或领域专用分词器可能需要更大词表,以避免关键术语被打碎。
说到底,选词表大小不只是个技术微调,而是一个塑造下游一切的核心设计选择——从模型成本到多语言鲁棒性。选错了,你要么被硬件卡脖子,要么把算力浪费在不必要的长序列上。
分词器的怪癖:给自己埋雷的有趣方式
- 空格怪癖。 有些分词器会抹掉前导空格(GPT-2),另一些把空格编码成 token(Llama)。这会导致玄学 bug、生成结果不匹配,以及无数小时的「为什么我的模型会这样」。
- 特殊 token。 [CLS]、
、、<|endoftext|> 等。它们计入你的长度限制,而且一旦你忘记屏蔽,它们就会泄漏到生成结果里。 - 多语言头疼。 用以英语为中心的词表处理 CJK 或黏着语?准备好迎接三倍 token 计数和一片 [UNK] 沼泽。使用语言感知的 SentencePiece 可以免受此苦。
- 版本漂移。 只要分词器与模型词表文件失配一次——就等着收彻底的乱码输出吧。
为你的 LLM 试验场挑分词器:我的速查表
想跳过理论直接上手?速查表如下:
如果你在意的是……
训练速度与 GPU 内存:
- 选:字节级 BPE(tiktoken)
- 为什么:最少合并次数、Rust 级解码速度、OpenAI 的秘制配方。
端侧(移动设备)推理:
- 选:WordPiece
- 为什么:更小的嵌入表、更少的内存之痛、序列长度上仍有竞争力。
跨语言覆盖:
- 选:SentencePiece Unigram
- 为什么:训练一次,覆盖几十种书写系统和语言。
自己动手做研究:
- 选:Hugging Face tokenizers
- 为什么:Python 绑定、Rust 内核、内建自省能力。
结语:谦逊的分词器做的比你想的多
分词器从来不是 LLM 技术栈里最性感的部分,但影响极大。理解它们,你就掌握了真实的提示词成本、推理吞吐量,以及模型所能表达之物的形状本身。
下次你的模型吐乱码或者装不下你的提示词时,别怪 GPU 😝
给谦逊的分词器一点尊重。
与此同时,如果你想看分词器实战演示,可以查看 www.ahmadosman.com/tokenizer。
附:记住,你随时可以使用我的 DeepResearch 工作流来深入学习——无论是卡住了、需要把某件事拆解到第一性原理、想要按你的水平定制的材料、需要找出知识盲区,还是只是想探索得更深。
原文信息
作者:theahmadosman(@theahmadosman)
原文地址:
暂无评论,快来抢沙发~