上一章节学了 BPE 的合并过程:从 256 个字节开始,每合并一次词表增加一个 token,合并多少次就得到多大的词表。
那应该合并多少次?词表越大越好吗?
不是。词表大小是一个需要权衡的设计决策——大有大的好处,也有大的代价。
大词表的好处
词表越大,能被整体收录的词就越多。常见的词组、短语、甚至常见的句子片段都可能成为一个 token。这意味着:
同一段文本被切成更少的 token。 比如「机器学习」在小词表里可能是 3-4 个 token,在大词表里可能是 1 个 token。token 数量少意味着模型处理的步骤少,推理速度更快。
用一个具体的数字来感受:如果一段 1000 字的中文文本用 32,000 词表切出 800 个 token,换成 128,000 词表可能只需要 500 个 token。模型的计算量和 token 数量直接相关,500 步比 800 步快了将近 40%。
模型能从更完整的单位开始理解。 如果「机器学习」是一个 token,模型不需要花计算资源去理解「机」「器」「学」「习」这四个部分怎么组合——它直接拿到的就是一个完整概念的表示。
大词表的代价
嵌入层变大。 模型需要为词表中的每一个 token 存储一个向量(嵌入向量,embedding vector)。向量的维度等于模型的隐藏维度。Sophia 的隐藏维度是 1,536,所以:
词表 32,000 × 1,536 = 49,152,000 个参数(约 4,900 万)
词表 65,536 × 1,536 = 100,663,296 个参数(约 1 亿)
词表 151,936 × 1,536 = 233,373,696 个参数(约 2.3 亿)
对 Sophia 这样十亿参数的模型来说,嵌入层占 1 亿(65K 词表)和占 2.3 亿(152K 词表)的差别是巨大的。更大的嵌入层意味着更少的参数留给真正做计算的 Transformer 层。
罕见 token 训练不充分。 词表中的每一个 token 都需要在训练数据中出现足够多次,才能学到有意义的表示。如果一个 token 在 200 亿个 token 的训练数据中只出现了几十次,它的嵌入向量几乎没有被有效训练过——模型遇到这个 token 时的表现接近随机。
大词表意味着更多的罕见 token。合并到后期产生的 token 往往是很具体的组合,只在特定语境下出现。这些 token 占着词表的位置和嵌入层的参数,却几乎没有得到充分训练。
65,536:一个精心选择的数字
Sophia 使用的原始 tokenizer(来自 Qwen2.5)有 151,936 个 token。但 Sophia 的技术报告明确记载了一个决定:把词表截断到 65,536 个。
为什么是这个数字?
第一,2 的幂次。 65,536 = 2^16。计算机硬件(尤其是 GPU)在处理 2 的幂次大小的数组时效率最高。矩阵乘法、内存对齐、缓存利用率都对 2 的幂次有天然的优化。这不是决定性因素,但在其他条件相近时,2 的幂次是更干净的选择。
第二,参数预算。 65,536 × 1,536 ≈ 1 亿个参数用于嵌入层,占 Sophia 总参数量的约 10%。如果保留全部 151,936 个 token,嵌入层将占到总参数量的 23%——将近四分之一的参数花在了一张查找表上,留给 Transformer 层的太少了。
第三,覆盖率。 词表中的前 65,536 个 token 是按 BPE 合并顺序排列的——最基础的 256 个字节排在最前面,然后是最早被合并的(也就是最常见的)组合。排在 65,536 之后的 token 是合并后期才产生的罕见组合,在实际文本中出现的频率很低。砍掉它们对分词效率的影响很小——偶尔遇到这些罕见组合时,tokenizer 会自动退回到更基础的 token 来表示它们,多用一两步而已。
一个对比实验的直觉
想象两个极端:
词表 = 256(只有原始字节):每个汉字需要 3 个 token(UTF-8 编码),每个英文字母需要 1 个 token。一段 1000 字的中文文本需要约 3000 个 token。模型要用大量的层来学习字节怎么组合成字符、字符怎么组合成词。嵌入层极小(256 × 1,536 ≈ 39 万参数),几乎所有参数都留给了 Transformer 层。
词表 = 1,000,000(一百万个 token):很多常见句子片段都是单个 token,文本被极度压缩。但嵌入层有 15 亿参数——超过了 Sophia 的全部参数量。显然不可行。
最优的词表大小在这两个极端之间的某个位置。对十亿参数规模的模型来说,几万到十几万是合理的范围。Sophia 选了这个范围中的一个对 GPU 友好、参数分配合理、覆盖率足够的点:65,536。
词表确定之后
到这里,tokenizer 的三个核心问题都回答了:
- 为什么需要 tokenizer?(把文本切成模型能处理的单位)
- 怎么决定切分方式?(BPE:从字节开始,按频率合并)
- 词表多大合适?(65,536:平衡参数预算和覆盖率)
tokenizer 确定之后,文本进入模型的流程就是:
原始文本
↓ tokenizer 编码
token ID 序列(整数)
↓ 嵌入层查表
向量序列(每个 token 变成一个 1,536 维的向量)
↓ Transformer 层处理
……
嵌入层——那张 65,536 × 1,536 的大表——把每个 token ID 变成一个 1,536 维的向量。这个向量是什么?一个词怎么能变成一个「方向」?1,536 个数字各自代表什么含义?
这是下一个单元的主题:向量与矩阵。