对应:Stanford CS224N Winter 2026 Lecture 14(嘉宾讲座:Tokenization and Multilinguality)。BPE 的实现细节详见同目录 CS336 第 1 讲;本讲侧重”为什么”以及分词对多语言的影响。 配套代码:
code/lecture16/(只用 Python 标准库;02 号文件用第 8 讲的玩具影评作训练语料) 预计阅读时间:3 小时
0. 本讲导航
0.1 学完本讲,你应该能够
- 比较词、子词、字符、字节四种输入单位的优缺点:词表大小、序列长度、未登录词。
- 解释 BPE、WordPiece、Unigram LM 三种子词算法的思路和区别,以及字节级 BPE 为什么没有”未知词”。
- 说出分词带来的几种”怪现象”:开头的空格、数字的切法、“故障词元”、算术和拼写上的困难。
- 解释中文分词的难点(交集型歧义、组合型歧义、新词、标准不统一)和经典方法(最大匹配、基于词频的最优切分、序列标注),以及大模型为什么不再显式分词。
- 解释多语言模型(mBERT、XLM-R)为什么能跨语言迁移,“多语言的诅咒”是什么。
- 解释字节溢价和词元溢价,以及它们给不同语言的使用者带来的不公平;说出低资源语言面临的困难和一些应对办法。
0.2 先修知识
| 知识点 | 用在哪里 | 最低要求 |
|---|---|---|
| 第 1 讲 | 第 1 节 | 词表、one-hot、词向量 |
| 第 5 讲 | 第 4 节 | n 元语言模型、对数概率 |
| 第 9 讲 | 第 3、5 节 | 预训练;子词分词的回顾 |
| 第 13 讲 | 第 6 节 | 困惑度和分词的关系;每字节比特数 |
0.3 本讲地图
第1节 模型看到的"词"是什么?
第2节 词级和字符级各有什么问题?
第3节 子词分词:BPE、WordPiece、Unigram ← 代码 02(演示 1~3)
第4节 中文分词 ← 代码 01
第5节 多语言模型与跨语言迁移
第6节 分词带来的不公平 ← 代码 02(演示 4)
第7节 低资源语言
第8–12节 小结、与作业的关系、练习、延伸阅读、下一讲预告
关于本讲的实验数字:两个代码文件都只用标准库,运行不到一秒,编写讲义时完整运行过,讲义引用的是实际输出。01 号文件的词典和词频、02 号文件的英文语料都是为演示手写或生成的,数字说明的是机制,不是真实语料的统计。
1. 模型看到的”词”是什么?
我们一直说”语言模型预测下一个词”。但模型真正处理的是词元(token),一个词元可能是一个完整的词、一个词的一部分、一个字、甚至一个字节。把文本切成词元的过程叫分词(tokenization),它是模型和文本之间的第一道接口,也是最容易被忽视的一道。
分词的选择影响一切:
- 词表大小:决定嵌入矩阵和输出层有多大(第 7 讲: 个参数);
- 序列长度:同样的文本切成多少个词元,决定计算量(注意力是 )、上下文窗口能装多少内容、生成要多久、API 要付多少钱;
- 模型能”看到”什么:如果 “strawberry” 是一个词元,模型就看不到里面有几个字母 r;
- 公平性:同样的意思,不同语言切出的词元数可能差好几倍(第 6 节)。
2. 词级和字符级各有什么问题?
词级(每个词一个词元,第 1~8 讲的玩具数据都是这样):
- 词表巨大:英语有几十万个词形,加上人名、地名、拼写错误、新词,永远列不全;
- 未登录词(out-of-vocabulary,OOV):没见过的词只能变成
<unk>,信息全丢了; - 词形变化:play、plays、played、playing 是四个毫无关系的词元,模型要分别学它们的含义;
- 对没有空格的语言(中文、日文、泰文),“词”本身就需要先切分出来(第 4 节)。
词频服从齐夫定律:少数词非常常见,大量词非常罕见。罕见词的词向量几乎学不到东西。
字符级(每个字符一个词元):
- 词表很小(英文几十个字符),没有未登录词;
- 但序列变得很长(英文平均每个词 5~6 个字符),计算量和上下文的压力大增;
- 每个字符本身几乎没有意义,模型要用很多层去”拼出”一个词的意思。
字节级(每个 UTF-8 字节一个词元):词表只有 256 个,能表示任何语言的任何文本;但对非拉丁文字,序列更长(一个汉字 3 个字节)。
子词分词是两者之间的折中:常见的词是一个词元,罕见的词拆成几个有意义的块。 词表几万到几十万,任何词都能表示。
3. 子词分词:BPE、WordPiece、Unigram
3.1 BPE
BPE(byte pair encoding)原本是一种数据压缩算法(Gage 1994),Sennrich 等(2016)把它用到神经机器翻译上:
- 从单个字符出发(每个词前面加一个词首标记 ▁);
- 统计语料里所有相邻的两块出现的次数,把出现次数最多的一对合并成一个新块;
- 重复,直到合并了预定的次数(词表大小 ≈ 字符数 + 合并次数)。
切分新文本时,按学到的顺序依次应用这些合并规则。
代码 02 的演示 1 在 Sennrich 论文的经典例子上运行(low 5 次、lower 2 次、newest 6 次、widest 3 次):
第 1 次合并:'s' + 't' → 'st'(9 次) 第 5 次合并:'▁lo' + 'w' → '▁low'
第 2 次合并:'e' + 'st' → 'est'(9 次) 第 6 次合并:'▁' + 'n' → '▁n'
第 3 次合并:'▁' + 'l' → '▁l'(7 次) ……
很快 “est” 就成了一个块:它是一个常见的后缀。没见过的 “lowest” 被切成 “▁low” + “est”。BPE 自动发现了”词根 + 后缀”的结构,而我们从没告诉过它什么是后缀。
3.2 WordPiece
WordPiece(Schuster & Nakajima 2012,BERT 使用)也是合并算法,但选择合并哪一对的标准不同:
它会压低”两个本来就很常见的符号碰巧挨在一起”的情况,偏好”不太常见、但几乎总是一起出现”的组合。这相当于在选”合并之后语料似然增加最多”的那一对。切分时,WordPiece 用贪心的最长匹配:从左到右,每次取词表里能匹配上的最长的块(BERT 用 ”##” 标记词中间的块,如 “play ##ing”)。
3.3 Unigram LM 与 SentencePiece
Unigram 语言模型分词(Kudo 2018)的方向和前两者相反:从一个很大的候选词表出发(比如所有出现过的子串),逐步删减。
- 一种切分 的概率 ,切分时取概率最大的那种(维特比算法,和第 4 节的中文分词是同一个算法);
- 训练:用 EM 算法估计每个块的概率(E 步用前向—后向算法求每个块的期望出现次数);然后计算”删掉每个块会让语料似然下降多少”,删掉下降最少的那部分;重复直到词表缩小到目标大小。单个字符永远保留,保证任何词都能切。
Unigram 的一个独特优点是能采样:除了最优切分,还可以按概率随机地选其他切分(子词正则化,subword regularization)。训练时同一个词每次以不同的方式切分,模型就不会死记某一种切分,对拼写变化、罕见词更鲁棒。BPE 也有类似的 BPE-dropout(Provilkov 等 2020)。
SentencePiece(Kudo & Richardson 2018)是一个实现了 BPE 和 Unigram 的工具,它把空格也当作普通字符(▁),直接在原始文本上训练,不需要预先按空格切词。因此它对任何语言都一样适用,T5、LLaMA 等模型都用它。
3.4 三种算法的比较
代码 02 的演示 2 在一个由词根和词缀组合而成的小英文语料上(170 个词:play / played / player / replay、care / careful / careless……),给三种算法同样大小的词表(24 个字符 + 80 个子词),看它们怎样切分没见过的词:
| 没见过的词 | BPE | WordPiece(最长匹配) | Unigram(维特比) |
|---|---|---|---|
| replaying | ▁replay ing | ▁ r e play ing | ▁replay i n g |
| unkindly | ▁u n kind ly | ▁ unkind ly | ▁unkind ly |
| helpfulness | ▁help ful ness | ▁ h e lp ful n e s s | ▁ helpful ness |
| carelessness | ▁c a re l ess ness | ▁ ca r e l e s s n e s s | ▁care less ness |
| repainting | ▁re paint ing | ▁ r e paint ing | ▁ r e painting |
| teachable | ▁t ea ch a b l e | [UNK] | ▁teach a b l e |
- 没见过的词大多能切成有意义的块,但三种算法的切法不完全一样,也常常不是语言学上的词素边界。子词是统计出来的,不是语法规则。
- “teachable” 的 “able” 在语料里从没出现过,只能拆成单个字母;语料里没有字母 b,WordPiece 的最长匹配直接返回了 [UNK]。
- 子词采样(演示 3):“carelessness” 的最优切分是 “▁care less ness”;按 采样时,74% 的情况是这种切分,16% 是 “▁care less n e s s”,8% 是 “▁care l e s s ness”。
3.5 字节级 BPE
GPT-2(Radford 等 2019)把 BPE 用在 UTF-8 字节上:基本单位是 256 个字节,任何文本都能表示,永远没有未知词。训练前先用一个正则表达式做预切分(按空格、标点、数字分开,词前面的空格并入这个词),合并不跨越预切分的边界。GPT-2 的词表有 50,257 个词元。今天的大模型词表普遍更大:LLaMA-3 约 12.8 万,GPT-4o 约 20 万,Gemma 约 25.6 万。词表越大,常见内容的序列越短(尤其是对非英语语言),但嵌入矩阵越大,罕见词元的训练也越不充分。
3.6 分词带来的怪现象
- 空格:” hello” 和 “hello” 是不同的词元。提示末尾多一个空格,可能让模型的输出明显变差,因为训练时空格通常和下一个词粘在一起。
- 数字:不同的分词器切数字的方式不同:GPT-2 可能把 “12345” 切成 “123” + “45”,LLaMA 把每个数字单独切开,GPT-4 的分词器最多把三个数字组成一个词元。切法会影响算术能力:Singh & Strouse(2024)发现,把数字从右往左每三位一组切分(和我们写千位分隔符的方式一致),加法的准确率明显提高。
- 拼写和字符级任务:“strawberry 里有几个 r?” 曾经难倒了很多模型:模型看到的是一两个词元,而不是十个字母。
- 故障词元(glitch tokens):Rumbelow & Watkins(2023)发现 GPT-2 / GPT-3 的词表里有一些奇怪的词元(如 ” SolidGoldMagikarp”,来自一个 Reddit 用户名),它们在分词器的训练语料里很常见,在模型的训练语料里却几乎没出现过,嵌入几乎没被训练。让模型重复这些词元,它会说出莫名其妙的话。分词器和模型的训练数据不一致会带来意想不到的问题。
3.7 不要分词器行不行?
既然分词带来这么多麻烦,能不能直接在字节或字符上训练模型?ByT5(Xue 等 2022)直接在 UTF-8 字节上训练 T5,对拼写噪声更鲁棒,在一些多语言任务上更好,但序列长了好几倍,速度慢。后来的工作试图解决效率问题:MEGABYTE(Yu 等 2023)把字节分成固定大小的块,先用大模型处理块、再用小模型处理块内的字节;Byte Latent Transformer(Pagnoni 等 2024)按”下一个字节有多难预测”动态地划分块,在大规模实验中达到了和基于分词器的模型相当的效果。完全去掉分词器仍然是一个活跃的研究方向。
4. 中文分词
4.1 为什么中文需要分词
英文用空格分开单词,中文没有。词级的模型(以及很多传统的 NLP 系统:信息检索、句法分析、机器翻译)需要先把句子切成词,这就是中文分词(Chinese word segmentation)。它比看起来难得多。
4.2 难点
- 交集型歧义:相邻的两个词共用了中间的字。“研究生命起源”可以是”研究 / 生命 / 起源”,也可以被切成”研究生 / 命 / 起源”(“研究生”和”生命”共用”生”)。
- 组合型歧义:同一串字在不同语境里应该切成不同的样子。“乒乓球拍卖完了”:是”乒乓球拍 / 卖 / 完了”(球拍卖光了),还是”乒乓球 / 拍卖 / 完了”(拍卖会结束了)?两种都通顺,只能靠上下文。
- 新词(未登录词):人名、地名、机构名、网络新词,词典里永远收不全。实际中,大部分分词错误来自新词,而不是歧义。
- 标准不统一:“北京大学”是一个词还是”北京 / 大学”?不同的分词语料库(北京大学、微软亚洲研究院、宾州中文树库……)规定不同,人和人之间对”什么是一个词”的一致率也只有七八成。中文的”词”本来就没有清晰的边界。
4.3 经典方法
最大匹配:从左往右(正向)或从右往左(逆向),每次取词典里能匹配上的最长的词。代码 01 的演示 1:
| 句子 | 正向最大匹配 | 逆向最大匹配 |
|---|---|---|
| 研究生命起源 | 研究生 / 命 / 起源 ✗ | 研究 / 生命 / 起源 ✓ |
| 结婚的和尚未结婚的 | 结婚 / 的 / 和尚 / 未 / 结婚 / 的 ✗ | 结婚 / 的 / 和 / 尚未 / 结婚 / 的 ✓ |
| 他说的确实在理 | 他 / 说 / 的确 / 实在 / 理 ✗ | 他 / 说 / 的 / 确实 / 在理 ✓ |
中文里偏正结构多(修饰语在前、中心词在后),逆向最大匹配的错误率通常比正向低。双向最大匹配两边各切一次,选词数少、单字词少的那个。但贪心的”最长匹配”只看局部,不会权衡整句话的切分是否合理。
基于词频的最优切分:在所有可能的切分里,找概率最大的那个。用一元语言模型,,用动态规划(维特比算法)求解:
代码 01 的演示 2:上面几句都切对了;“他说的确实在理”里,正向切出的”的确 / 实在 / 理”有一个低频的单字”理”,整体概率比”的 / 确实 / 在理”低。一元模型偏爱切得粗(词数越少,乘的概率越少),“南京市长江大桥”切成了”南京市 / 长江大桥”(这里刚好对了)。但演示 3 的”乒乓球拍卖完了”这种组合型歧义,词频解决不了。
序列标注:把分词看成给每个字打标签:B(词首)、M(词中)、E(词尾)、S(单字词)(Xue 2003)。“研究生命起源”→ B E B E B E。这样分词就变成了第 3、4 讲那样的序列标注问题,可以用隐马尔可夫模型、条件随机场(CRF),后来用 BiLSTM-CRF、BERT。序列标注的一个大优点是能识别词典里没有的新词:模型学的是”什么样的字组合像一个词”。在 SIGHAN 分词评测上,基于字的序列标注方法很快超过了基于词典的方法。
4.4 大模型为什么不再显式分词
今天的中文大模型(以及多语言大模型)通常直接在原始文本上训练字节级的 BPE 或 SentencePiece 分词器,完全跳过”中文分词”这一步:常见的词(“我们”、“今天”)会自然地合并成一个词元,罕见的词拆成几个字,生僻字拆成字节。好处是:
- 不依赖任何分词标准,不会因为分词出错而丢失信息;
- 能处理新词、中英混排、代码;
- 和其他语言用同一套方法。
Li 等(2019)比较了基于字和基于词的深度学习模型,发现在语言建模、机器翻译、文本分类等多个中文任务上,基于字的模型并不比基于词的差,往往更好:词级模型的数据稀疏和分词错误带来的损失,超过了”词”这个单位带来的好处。
5. 多语言模型与跨语言迁移
5.1 多语言预训练
- mBERT(Devlin 等 2018):用 104 种语言的维基百科训练一个 BERT,共用一个 WordPiece 词表,没有任何平行语料(没有告诉模型哪句话是哪句话的翻译)。
- XLM(Lample & Conneau 2019):加入了”翻译语言模型”(TLM)目标:把一对平行句子拼起来做掩码语言模型,模型可以借助另一种语言的上下文来猜被遮住的词。
- XLM-R(Conneau 等 2020):用 100 种语言、2.5 TB 的网页文本训练 RoBERTa,在跨语言任务上大幅超过 mBERT。
- 今天的大语言模型虽然以英文数据为主,但几乎都是多语言的。
5.2 零样本跨语言迁移
一个惊人的发现(Pires 等 2019;Wu & Dredze 2019):用 mBERT 在英文的标注数据上微调(比如命名实体识别),直接用在德文、中文的测试集上,效果相当不错,尽管模型从没见过这些语言的标注数据。这叫零样本跨语言迁移。甚至在文字系统完全不同的语言之间(比如英文 → 印地文)也能迁移。
为什么能迁移?最初的猜测是”共享的子词”(数字、专有名词、借词在不同语言里写法相同)起到了锚点的作用。但后来的研究(K 等 2020;Conneau 等 2020)发现,即使不同语言之间没有任何共享的词元,模型仍然能学到跨语言的对齐。更重要的是语言之间结构上的相似性,以及模型的深度:为了用有限的参数同时建模很多种语言,模型倾向于学到一些跨语言共享的表示。
Wendler 等(2024)用”logit lens”(把中间层的表示直接投影到词表上)观察 LLaMA-2 处理法语→中文翻译时的中间层,发现中间层的表示更接近对应的英文词,像是模型在一个偏向英文的”概念空间”里思考。这个结论还有争议,但它说明以英文为主的训练数据深刻地影响了模型的内部表示。
5.3 多语言的诅咒
Conneau 等(2020)发现:在模型大小固定时,加入更多的语言,一开始低资源语言的表现会提升(从相似的语言迁移过来),但超过某个点之后,所有语言的表现都开始下降,因为有限的容量要分给更多的语言。这叫多语言的诅咒(curse of multilinguality)。增大模型可以缓解它。
另一个关键的设计是数据采样:如果按语料的原始比例采样,英文会占绝大多数,低资源语言几乎学不到。常用的办法是按 采样( 是第 种语言的数据量), 时会提高低资源语言的比例(XLM-R 用 )。代价是低资源语言的数据被重复很多遍,可能过拟合。
6. 分词带来的不公平
6.1 字节溢价与词元溢价
同样的意思,不同的语言要多少字节、多少词元?代码 02 的演示 4 用三个简单的句子(“今天天气很好”、“我想喝一杯咖啡”、“图书馆早上九点开门”)的八种语言版本,以及一个只在英文上训练的字节级 BPE(256 个字节 + 400 次合并):
| 语言 | 字符数 | UTF-8 字节数 | 词元数 | 字节溢价 | 词元溢价 |
|---|---|---|---|---|---|
| 英语 | 110 | 110 | 57 | 1.00 | 1.00 |
| 西班牙语 | 104 | 107 | 76 | 0.97 | 1.33 |
| 德语 | 111 | 114 | 81 | 1.04 | 1.42 |
| 俄语 | 95 | 175 | 175 | 1.59 | 3.07 |
| 中文 | 25 | 75 | 75 | 0.68 | 1.32 |
| 日语 | 40 | 120 | 120 | 1.09 | 2.11 |
| 印地语 | 82 | 218 | 218 | 1.98 | 3.82 |
| 阿拉伯语 | 80 | 145 | 145 | 1.32 | 2.54 |
- 字节溢价:UTF-8 里,拉丁字母大多 1 个字节;带重音的字母、西里尔字母、阿拉伯字母 2 个字节;汉字、日文假名、天城文 3 个字节。同样的意思,印地语要多一倍的字节。中文是个例外:每个字 3 个字节,但一个字承载的信息多,总字节数反而比英文少。
- 词元溢价:分词器只在英文上训练,英文常见的词被合并成了整块;西班牙语、德语还能共享一些拉丁字母的合并;俄语、印地语、阿拉伯语几乎只能一个字节一个字节地切(词元数 = 字节数)。同样的三句话,印地语要多将近 4 倍的词元。
这里的分词器只见过英文,是一个极端的例子。真实的多语言分词器在很多语言上训练,溢价小得多,但并没有消失:Petrov 等(2023)测量了几个常用的分词器,同样的内容在某些语言上要多十几倍的词元;Ahia 等(2023)测量了商业 API 的实际费用差异。
6.2 后果
词元溢价意味着,用溢价高的语言的人:
- 付更多的钱:API 按词元计费;
- 能用的上下文更短:同样的上下文窗口,装的内容少好几倍;
- 更慢:生成同样的内容要更多步;
- 效果可能更差:一个词被切成很多碎片,模型要用更多的层去”拼回”它的意思;每个词元在训练中见到的次数也更少。
而这些语言的使用者,往往恰好是资源更少、更难负担额外费用的群体。
6.3 缓解办法
- 在分词器的训练数据里平衡各种语言的比例;
- 使用更大的词表,给更多语言的常见词分配词元(近年的模型词表从 3 万增长到 20 万以上,部分原因就是多语言);
- 针对特定语言扩展词表,再继续预训练(中文、日文的很多开源模型这样做);
- 字节级或无分词器的模型,消除词元溢价(但字节溢价仍在)。
7. 低资源语言
世界上有七千多种语言,但 NLP 的研究和资源高度集中在少数几种上。Joshi 等(2020)把语言按资源多少分成六类:最顶层的几种语言(英语、中文、西班牙语等)有海量的数据和工具;而绝大多数语言几乎没有任何标注数据,甚至没有多少数字化的文本。
低资源语言面临的困难:
- 数据少:网上的文本少,质量往往也差(很多是机器翻译的、或者语言识别错误);
- 评估难:没有基准,模型好不好都不知道。FLORES-200(翻译)、Belebele(122 种语言变体的阅读理解,Bandarkar 等 2023)这样的多语言基准正在填补空白;
- 文化:把英文基准翻译成其他语言,题目里的文化背景却没变。Global-MMLU(Singh 等 2024)发现 MMLU 里相当一部分题目需要西方的文化知识才能回答;
- 分词与文字:前面讨论的溢价问题;一些语言有多种文字,或者没有标准的拼写。
一些努力:
- No Language Left Behind(NLLB,2022):一个支持 200 种语言的机器翻译模型,同时发布了评估集和挖掘出来的平行语料;
- 社区参与:Masakhane 等社区由非洲语言的使用者自己组织数据收集、建模和评估;
- 跨语言迁移:利用多语言预训练,从相近的高资源语言迁移;
- 合成数据:用翻译或大模型生成训练数据(要警惕质量和”翻译腔”)。
8. 本讲小结
- 分词是模型和文本之间的第一道接口,决定词表大小、序列长度、模型能”看到”什么,也影响公平性。
- 词级有未登录词和数据稀疏的问题,字符 / 字节级序列太长;子词折中:常见词一个词元,罕见词拆成块。
- 三种子词算法:BPE 合并最常见的相邻对;WordPiece 合并”似然增益”最大的相邻对、用最长匹配切分;Unigram 从大词表出发用 EM 和剪枝逐步删减,能采样多种切分。字节级 BPE 永远没有未知词。分词会带来空格、数字、拼写、故障词元等怪现象。
- 中文分词:交集型歧义、组合型歧义、新词、标准不统一;最大匹配(逆向更好)、基于词频的维特比最优切分、BMES 序列标注。大模型直接在原始文本上训练字节级分词器,跳过中文分词;基于字的模型往往不比基于词的差。
- 多语言模型:mBERT、XLM-R 能零样本跨语言迁移,共享的子词不是必需的,结构相似性和共享表示更重要;固定容量下语言越多越”诅咒”;用 采样提高低资源语言的比例。
- 不公平:字节溢价(UTF-8 编码)和词元溢价(分词器偏向训练数据里多的语言),后者在常用分词器上可达十几倍,意味着更贵、更短、更慢、可能更差。
- 低资源语言:数据、评估、文化、分词的多重困难;NLLB、社区参与、跨语言迁移等努力。
9. 与作业的关系
- CS224N 的作业里分词通常由现成的工具完成(比如 GPT-2 的分词器),但理解分词对调试很重要:模型对一个输入表现奇怪时,先看看它被切成了什么样子。
- 期末项目:多语言、低资源语言、分词对下游任务的影响,都是常见的项目方向。用不同的分词器训练同一个小模型、比较困惑度时,记得换算成每字节比特数(第 13 讲)。
- 想从零实现一个字节级 BPE 分词器(包括正则预切分和高效的合并),可以做 CS336 的作业 1。
作业的具体题目以当年官方发布的版本为准。
10. 练习
练习 1(BPE)★:语料是 “aaabdaaabac”(当作一个词,不加词首标记)。手动做 BPE:(a) 第一次合并哪一对?合并后序列是什么?(b) 再做两次合并。(c) 序列变短了多少?
参考答案
(a) 相邻对计数:aa 4 次(aaab 里两次,共两段),ab 2 次,bd 1,da 1,ba 1,ac 1。合并 “aa” → 记为 Z:序列 “ZabdZabac”。(“aaa” 里的 aa 从左往右不重叠地合并。) (b) 现在 Za 2 次、ab 2 次……按出现次数(并列时任选一种规则),比如合并 “Za” → Y:“YbdYbac”;再合并 “Yb” → X:“XdXac”。 (c) 从 11 个符号变成 5 个,词表增加了 3 个符号。这正是 BPE 作为压缩算法的原理:用更大的词表换更短的序列。
练习 2(WordPiece 的分数)★★:语料里 “e” 出现 1000 次、“s” 出现 800 次,“es” 出现 300 次;“q” 出现 20 次、“u” 出现 500 次,“qu” 出现 20 次。(a) BPE 先合并哪一对?(b) WordPiece 呢?(c) 解释 WordPiece 的选择为什么合理。
参考答案
(a) BPE 看次数:es(300)> qu(20),先合并 es。 (b) WordPiece:es 的分数 ;qu 的分数 ,先合并 qu。 (c) “q” 后面几乎总是跟着 “u”,把它们合并几乎不损失信息、让表示更紧凑;“e” 和 “s” 各自都很常见,碰巧挨在一起的次数多,不代表它们构成一个有意义的单位。
练习 3(Unigram)★★:词表和概率:▁un 0.1,▁ 0.05,u 0.02,n 0.02,help 0.1,ful 0.1,▁unhelp 0.001。(a) 列出 “▁unhelpful” 的所有切分(只用这些块),算出每种的概率。(b) 维特比会选哪一种?(c) 如果做子词采样(),选中最优切分的概率是多少?
参考答案
(a) ① ▁un + help + ful:;② ▁ + u + n + help + ful:;③ ▁unhelp + ful:。 (b) ①。 (c) 。
练习 4(中文分词)★:用正向最大匹配和逆向最大匹配切分”发展中国家用电”,词典包括:发展、发展中、中国、国家、家用、用电、中国家(假设)、电。哪个对?两种方法都错的情况,说明了什么?
参考答案
正确的切分是”发展中 / 国家 / 用电”。正向最大匹配:从”发”开始,最长匹配”发展中”(3 个字);剩下”国家用电”,最长匹配”国家”;剩下”用电”。结果”发展中 / 国家 / 用电”,正确。逆向最大匹配:从右边开始,“用电”;剩下”发展中国家”,从右往左最长匹配”中国家”(3 个字,假设在词典里);剩下”发展”。结果”发展 / 中国家 / 用电”,错误。这说明逆向最大匹配也不是总能切对,歧义的方向不同,哪种贪心策略赢就不同。两种都错时,说明需要考虑整句的概率(维特比)或者更多上下文。
练习 5(多语言采样)★★:三种语言的数据量分别是 1000 GB、10 GB、0.1 GB。(a) 按原始比例采样,各占多少?(b) 按 采样呢?(c) 如果训练总共看 1000 GB 的数据,最小的语言的数据要重复多少遍?
参考答案
(a) 约 99.0%、0.99%、0.0099%。 (b) ,,,总和约 10.44,比例约 76.1%、19.1%、4.8%。 (c) 4.8% × 1000 GB ≈ 48 GB,最小的语言只有 0.1 GB,要重复约 480 遍,很可能过拟合。这就是低资源语言的两难:采样多了会过拟合,采样少了学不到。
练习 6(词元溢价)★:一个 API 每百万词元收费 5 美元。某个文档英文版约 10 万词元;在某种语言上的词元溢价是 3。(a) 处理这份文档的另一种语言版本要多少钱?(b) 如果模型的上下文窗口是 128K 词元,两个版本各能装下吗?
参考答案
(a) 英文版 美元;另一种语言 30 万词元,1.5 美元。 (b) 英文版 10 万词元,装得下;另一种语言 30 万词元,超出上下文窗口,必须切分或检索(第 12 讲),效果可能更差。
练习 7(思考:分词与算术):为什么”把数字从右往左每三位切分”可能比”从左往右”更有利于加法?
参考答案
加法从个位开始、按位对齐。从右往左每三位切分时,不同长度的数字切出的块是按位对齐的(个、十、百位总在同一个块里),进位只在块之间按固定的方式传递;从左往右切分时,“12345” 切成 “123|45”,“1234” 切成 “123|4”,同一个块在不同数字里代表不同的位,模型很难学到统一的算法。这和我们写千位分隔符(12,345)的习惯一致。
练习 8(动手):
(a) 在代码 01 里给词典加上”发展中”、“中国家”等词,验证练习 4 的结论。
(b) 在代码 02 演示 2 里把子词数从 80 改成 30 和 150,三种算法的切分怎样变化?词表太小、太大各有什么问题?
(c) 在代码 02 演示 4 里,把训练语料换成”英文 + 等量的俄语句子”(可以自己造一些),俄语的词元溢价会降到多少?
(d) 如果你的环境能装 tiktoken,用 GPT-4(cl100k_base)和 GPT-4o(o200k_base)的分词器统计演示 4 里八种语言的词元数,词表变大之后溢价变小了吗?
11. 延伸阅读
- Sennrich et al.,Neural Machine Translation of Rare Words with Subword Units(2016):BPE。
- Schuster & Nakajima,Japanese and Korean Voice Search(2012):WordPiece;Kudo,Subword Regularization(2018);Kudo & Richardson,SentencePiece(2018);Provilkov et al.,BPE-Dropout(2020)。
- Radford et al.,Language Models are Unsupervised Multitask Learners(2019):字节级 BPE。
- Rumbelow & Watkins,SolidGoldMagikarp(2023);Singh & Strouse,Tokenization Counts: The Impact of Tokenization on Arithmetic in Frontier LLMs(2024)。
- Xue et al.,ByT5(2022);Yu et al.,MEGABYTE(2023);Pagnoni et al.,Byte Latent Transformer(2024)。
- Xue,Chinese Word Segmentation as Character Tagging(2003);Li et al.,Is Word Segmentation Necessary for Deep Learning of Chinese Representations?(2019)。
- Pires et al.,How Multilingual is Multilingual BERT?(2019);K et al.,Cross-Lingual Ability of Multilingual BERT(2020);Conneau et al.,Unsupervised Cross-lingual Representation Learning at Scale(2020,XLM-R)。
- Wendler et al.,Do Llamas Work in English? On the Latent Language of Multilingual Transformers(2024)。
- Petrov et al.,Language Model Tokenizers Introduce Unfairness Between Languages(2023);Ahia et al.,Do All Languages Cost the Same?(2023)。
- Joshi et al.,The State and Fate of Linguistic Diversity and Inclusion in the NLP World(2020);NLLB Team,No Language Left Behind(2022)。
- CS336 第 1 讲(同目录):BPE 分词器的完整实现。
12. 下一讲预告
到这里,我们已经知道怎么训练、使用、评估一个语言模型。但模型内部到底发生了什么?第 9 讲用探针看过词向量里有没有情感信息,第 11 讲证明过注意力”能够”实现梯度下降,第 14 讲讨论过思维链是不是模型”真正的想法”。
下一讲(可解释性)系统地讨论怎样”打开黑箱”:
- 探针能说明什么、不能说明什么;
- 注意力可视化和归因方法(梯度 × 输入、积分梯度);
- 机制可解释性:电路、归纳头,以及”叠加”现象:模型怎样用很少的神经元表示很多特征;
- 稀疏自编码器:把叠加在一起的特征重新拆开;
- 模型编辑与引导。