Tokenization

理论基础

把 tokenization 视为两步映射:

  • 编码器:把字符序列(Σ*)映射到 token 序列(Δ*)
  • 解码器:把 token 序列(Δ*)映射回字符序列(Σ*)

BPE (Byte Pair Encoding)

核心思想

从最小单元(字节/字符)出发,通过统计语料库中的高频”字节对”,迭代合并,逐步构建词汇表。

完整流程

1. 训练阶段

Pre-tokenization(预分词)

  • 用规则(正则表达式)把原始文本切成初始 segments
  • 常见规则:按空格、标点、大小写边界切分(GPT-2 用 \p{L}+|\p{N}+|'s|... 这类正则)
  • <|endoftext|> 是文档边界标记,防止跨文档合并,不是 pre-tokenization 的分界符本身

初始化词汇表

  • 把每个 segment 转成 UTF-8 字节序列(256 个基础 token = byte 0~255)
  • 用字节而非字符,好处是任意文本都能表示,无 OOV(out-of-vocabulary)问题

迭代合并

repeat N times (N = 目标词汇表大小 - 256):
    1. 统计所有相邻 token pair 的出现频率
    2. 找到频率最高的 pair (a, b)
    3. 将 (a, b) → ab 加入词汇表(merge rule)
    4. 在语料库中把所有 (a, b) 替换为 ab
  • 合并规则按顺序保存 → 这就是最终的 merge table

2. 推理(编码)阶段

输入文本
  → pre-tokenization(同训练时一样的规则切 segments)
  → 每个 segment 转 UTF-8 字节
  → 按 merge table 的顺序依次尝试合并
  → 输出 token id 序列
  • 合并顺序严格按训练时的优先级,不能 贪心地合并最长匹配

3. 解码

  • Token id → token bytes → 拼接 → UTF-8 decode → 原始文本
  • 因为以字节为基础,解码永远无损

关键细节

问题答案
为什么用 UTF-8 字节而不是 Unicode 字符?保证词汇表有限(256)且无 OOV
为什么 pre-tokenization 不能省?防止跨单词合并(如 dogdog. 共享前缀但语义不同)
merge 的结果和顺序重要吗?非常重要,推理时必须按同样顺序 apply merge rules
词汇表大小怎么定?超参数,GPT-2 用 50257,LLaMA 用 32000