一句话定义
BPE(Byte Pair Encoding,字节对编码)是一种把文本切成"子词"的分词算法:它从最小的字节出发,不断把最常一起出现的相邻符号合并成一个新符号,直到词表大小达到预设值。
它是怎么工作的
可以把它想成一个自动整理口头禅的收集器。一开始每个字节都是独立的,"l"、"o"、"w" 是三个符号。接着统计整个语料里哪些符号总挨在一起——"l" 后面跟 "o" 的次数特别多,就把它们合并成新符号 "lo";下一轮再看,"lo" 后面跟 "w" 很常见,就合并成 "low"。每一步只做一件事:合并当前最高频的一对。重复足够多轮之后,词表里就攒下了大量高频片段:英文的 "ing"、"tion"、带空格的 " the",中文的常用字和常用词,代码里的 "def "、"()"。
这样做的结果是:常见词往往是完整的一个 token,罕见词不会变成"未登录词"(OOV,out-of-vocabulary),而是被拆成几个已知片段,实在拆不动就退回到单字节。任何字符串都能被编码,这是字节级 BPE 的兜底能力。这个思路最早来自数据压缩,后来被引入到文本预处理中。
为什么"一个 token 不等于一个字"
这是最容易被误解的一点。模型拿到的不是文字,而是一串 token 编号,而 token 的边界由统计频率决定,跟"字"和"词"都不一定对齐。
- 英文里,"the" 三个字母常常是一个 token;"unbelievable" 可能被切成 "un" + "believ" + "able"。
- 中文文本先按 UTF-8 编码成字节,一个汉字占 3 个字节。如果训练语料里中文不多,一个汉字可能被拆成两三个 token;中文语料充足时,常用汉字或常见双字词会被合并成单个 token。
- 空格、换行、emoji 也各有 token 形态,"带空格的字"和"不带空格的字"在词表里是两个不同的 token。
所以同一段话,在不同模型上的 token 数可能差出不少,直接数字数是靠不住的。
和相邻概念的区别
| 粒度 | 切分单元 | 主要问题 |
|---|---|---|
| 词级分词 | 整个词 | 词表爆炸,新词和拼写变体无法处理 |
| 字符级分词 | 单个字符 | 序列太长,训练慢,语义单位太碎 |
| 子词分词(BPE) | 高频片段 | 折中:词表可控,罕见词能退化成片段 |
同属子词路线,WordPiece、Unigram 与 BPE 目标相近但做法不同:BPE 是自下而上地合并,Unigram 更像自上而下地裁剪,最终都会得到一个固定词表。
对实际工作的意义
上下文长度、接口计费和推理成本通常都按 token 计数,所以"这段提示词有多大"应该用对应模型的 tokenizer 去量。做字符级任务时——数某个字母出现几次、逐字改写、拼写校正——模型看到的是 token 而不是字符,天然容易出错,必要时把字拆开再喂给它。多语言和代码场景也要留意"token 密度"的差异:同样的信息量,不同语言消耗的 token 可能差一截。具体词表和切分规则各家模型不同,以官方文档或官方 tokenizer 为准,不要跨模型套用经验值。
