跳到主要内容

文字怎么变成数 — 词元化器与嵌入的三个层级

这一章讲三件事: 模型眼里的文字长什么样;为什么两个模型面对同一段文字会「看见」完全不同的东西; 以及「嵌入」这个词在不同上下文里指的其实是三样东西。 在全书链条里,这一章是入口——第 01 章说了「文字要变成数」,这一章讲怎么变。 本章讲的那三层嵌入,是第 04、06、08 章共同的地基。

1. 先看现象:同一句话,两个模型看到的不是一个东西

这一节回答:为什么有的模型会算术、有的不会;有的能写 Python、有的一写就乱缩进。

拿同一段测试文本喂给不同模型的第一道工序,结果差得离谱。读下表之前要先有两个词。

字节就是计算机里存东西的最小计量单位:一个英文字母占一个字节,一个汉字通常占三个。 所以「一个汉字」在机器眼里从来就不是一个整体,而是三份—— 这件事是下表最后一列所有麻烦的根源。

Unicode 就是给世界上所有文字和表情符号统一编号的那套标准, 而那串编号最后就是按上面说的字节存下来的。 一个模型「认不认识中文」,说到底就是看它的词表里有没有收这些编号。

所以下表里「拆成多个字节词元」的意思是:它认不出这个整字,就退一步, 按存这个字用掉的那几个字节,一段一段地记。1

模型它看到的 600它看到的四个连续空格它看到的中文和表情
BERT(2018)600 一个整体消失了[UNK]——完全看不见
GPT-2(2019)600 一个整体三个词元拆成多个字节词元(能还原)
GPT-4(2023)600 一个整体一个词元拆成多个字节词元
StarCoder2(2024)6 0 0 三个词元一个词元拆成多个字节词元
Flan-T5(2022)12. 0 这种切法没有空白词元<unk>——完全看不见

这不是实现细节,这是能力差异。

  • BERT 看不见换行符,所以「每次对话换行的聊天记录」这类编码在换行里的信息,它天生视而不见2;
  • Flan-T5 没有空白词元,书直接说这将使模型难以处理代码3;
  • StarCoder2 把每个数字单独切开,书说这里的假设是这将带来更好的数字和数学表示4

书还给了一个特别能说明问题的例子:在 GPT-2 里,数字 870 是一个词元,但 871 是两个词元(871)。 书的评价是:你可以直观地看到这可能会如何使模型感到困惑4

记住这一句,它是这一章的中心论点:

模型的能力上限,在它开始训练之前,就已经被词元化器画掉了一部分。

2. 顶层全景:两道工序,三个层级

这张图也有意不用专业名词。 每一格的正式叫法,都留到 3.x 节第一次讲到它时再给。

「Write an email apologizing to Sarah」

│ ① 切:把这句话切成一小段一小段,每段换成一个编号

[1, 14350, 385, 4876, 27746, 5281, 304, 19235, ...]

│ ② 查:拿编号去查一张大表,每个编号查出一串数

[一串数, 一串数, 一串数, …] ← 【第一层】查表查出来的:同一段字永远查到同一串

│ ③ 把这些数送进模型完整跑一遍

[一串数, 一串数, 一串数, …] ← 【第二层】跑完之后的:同一个词在不同句子里不一样了

│ ④ 把整句的那一堆数合成一串;或者干脆用专门训过的模型直接出一串

[ 一串数 ] ← 【第三层】整句话、整篇文章,只剩一串数

图说:这三层,书里全都叫「嵌入」——同一个词,指着三样不同的东西。 分不清它们,后面所有关于「该用哪个嵌入模型」的讨论都会糊。

3. 核心原理

3.1 模型收到的是整数,不是文字

这一节回答:「模型读了我的提示词」这句话到底发生了什么。

书用一个可验证的方式把这件事拆开了:把提示词送进词元化器,打印出来的是一串整数—— 这揭示了大语言模型所响应的输入,是一系列整数;每个整数都是特定词元的唯一 ID, 这些 ID 引用词元化器内部的一个表5

把那串整数逐个解码回文字,能看见五件事6:

现象例子说明
有特殊词元(不代表任何真实文字、只起标记作用的那种)第一个是 ID 1,即 <s>表示文本开始
有的词元是完整的词Writeanemail——
有的词元只是词的一截apolog + izingtrag + ic这种「比一个完整的词还小」的切法有专门的名字,下一节整节在讲
标点自成词元.——
空格没有自己的词元——有些词元(如 izing)开头带一个特殊隐藏字符,表示它和前一个词元相连;不带这个字符的,默认前面有一个空格7

最后一行值得停一下。 空格不是被删掉了,是被编码进了「这个词元贴不贴着前一个」这个属性里。 这解释了为什么有些模型输出会莫名其妙地多一个或少一个空格。

词元化器是双向的: 它不仅把输入切成 ID,还负责把模型吐出的 ID 转回文字8。 书给的实例:模型先吐 3323(Sub),再吐 622(ject),两个拼起来才是 Subject

3.2 为什么要切成「子词」而不是整词

这一节回答:为什么不直接一个词一个编号。

书列了四种切法,并说明子词是最常用的那一种——「子词」就是「比一个完整的词还小的那一截」9:

切法好处问题
直观处理不了训练之后才出现的新词;② 词表里塞满差异很小的词元(apologyapologizeapologeticapologist 各占一格)10
子词一个 apolog 加几个后缀(-y-ize-etic-ist)就够了,而且新词可以拆成已在词表里的小片段11——
字符有原始字母兜底,新词绝不会没救建模更难:用子词的模型可以把 play 表示成一个词元,字符级模型还得额外建模「p-l-a-y 这个拼写」12
字节把词元拆成「存这个字符用掉的那几个字节」——每个字节只有 256 种可能,所以按字节切永远不会遇到「没见过的字」;多语言场景有竞争力13——

子词还有一个纯工程上的好处,书算得很清楚: 子词平均每个词元约三个字符,所以在同样 1024 的上下文长度里,子词能装下约三倍于字符级的文本12

这里有一个容易被混淆的地方,书特意澄清了: GPT-2 和 RoBERTa 的词元化器也把字节放进词表当兜底, 但这并不使它们成为无词元化的字节级词元化器,因为它们并不使用这些字节来表示所有内容,仅表示一个子集13

3.3 三个设计选择,决定了一切差异

这是这一章的骨架。 书前后说了两遍,第二遍归纳成三组设计选择14:

① 词元化方法 ── BPE(字节对编码)/ WordPiece / SentencePiece / unigram
│ 每种方法都是一套「怎么挑出一组合适词元来表示这个数据集」的算法

② 切分设定 ── 词表多大?要哪些特殊词元?大写怎么处理?


③ 数据的领域 ── 同样的方法和设定,在英文/代码/多语言上训出来的词元化器完全不同

图说:这三层是有顺序的,后一层在前一层的框架里做选择。 而第三层最容易被忽略——同样的方法、同样的设定,换个训练语料(就是拿来喂给模型读的那一大堆文字),行为就变了15

① 方法

算法(一串固定的计算步骤:喂进去什么,一步一步照做,出来什么是定死的)—— 上图第一层那四个名字,就是四套不同的步骤,谁也不比谁更「聪明」,只是切法不同。

书点名了三种,其中 BPE(字节对编码)是更流行的那一种,广泛用于 GPT 系列; WordPiece 用于 BERT16。先讲一个词:优化就是「反复调整,让某个指标变得更好」。 它们的共同目标是一样的:优化出一组高效的词元来表示这个数据集,只是实现不同16

书没有讲 BPE 具体怎么跑。 对我们够用的理解是:它们都是在给定语料上「学」出词表的,不是人写死的。 名字里的「字节对」指的就是「相邻的两小段」—— 补充(不在书里,来自通用知识):这类算法从最小的单位起步,反复把语料里最常挨在一起的相邻两段并成一段, 并够了就停,并出来的那些段就是词表。

② 切分设定

三件事17:

设定常见取值影响
词表大小(就是词表里一共存了多少个词元)30K、50K 常见,越来越多见到 100K词表越大,同一段文字切出的词元越少,但要存的那张「词元 → 一串数」的大表也越大(这张大表正是下面 3.5 节的主角)
特殊词元文本开始/结束、填充、未知、[CLS][MASK]可以按需要任意加,这是给模型加新能力的一个口子
大写处理全转小写 vs 保留书的原话:名称大写通常携带有用信息,但我们是否愿意将词表空间浪费在单词的全大写版本上?

特殊词元这一栏值得展开,因为它是「词元化器决定能力」最直接的证据:

  • Galactica(科学领域模型)加了 [START_REF] / [END_REF] 来包裹文献引用, 还加了一个 <work> 词元,让模型先把推理过程一步步写出来、再给答案—— 这套做法第 05 章整节在讲18;
  • StarCoder2(代码模型)加了 <filename><reponame><gh_stars>, 因为一个文件可能会调用另一个文件中定义的函数,模型需要能区分同仓库和不同仓库的代码19;
  • GPT-4 加了三个「填充中间」词元(<|fim_prefix|> / <|fim_middle|> / <|fim_suffix|>), 它们让模型不仅能根据前面的文本、还能考虑后面的文本来生成补全20;
  • Phi-3 / Llama 2 加了 <|user|><|assistant|><|system|>—— 聊天是一来一回的,而这一来一回叫一(就是「你问一句、它答一句」算一次); 书说这是因为聊天在 2023 年成为主要用例,词元化器通过增加表示对话轮次和发言者角色的词元来适应这一方向21

最后这一条是最重要的:「谁在说话」这件事,是被编码成词元的。 第 05 章讲提示模板时会回到这里。

③ 数据的领域

这是最容易被忽略的一层。 书的判断: 即使我们选择相同的方法和参数,词元化器的行为也会因其所训练的数据集而有所不同—— 而且这发生在我们开始模型训练之前15

代码是最好的例子:面向文本的词元化器会把缩进空格切得七零八落, 面向代码的词元化器则用不同的切法,而书的评价是—— 这些词元化选择使模型的工作更容易,从而其性能更有可能得到提升22

书还专门加了一条注解释为什么空白这么重要: 使用单个词元表示四个连续空白字符的模型更适合 Python 代码数据集; 如果表示成四个不同的词元,模型需要跟踪缩进级别,这通常会导致性能下降23

3.4 七个真实词元化器的横向对比

书这一段是全书最有实操价值的部分之一,值得压缩成一张表带走。

测试文本包含六类难点:大写、非英语、表情、代码关键字与缩进、数字、特殊词元24。结果1:

词元化器年份方法词表最值得记住的一条
BERT base (uncased)2018WordPiece30,522换行没了、全转小写、中文和表情变 [UNK]——对这些内容完全是瞎的
BERT base (cased)2018WordPiece28,996保留大写,代价是 CAPITALIZATION 被切成八个词元
GPT-22019BPE50,257换行保留了;CAPITALIZATION 四个词元;表情拆成字节但能完整还原
Flan-T52022SentencePiece32,100没有换行和空白词元 → 难处理代码;表情和中文变 <unk>
GPT-42023BPE略超 10 万四个空格一个词元(最多 83 个空格都有专属词元);elif 有自己的词元;大多数单词用更少词元
StarCoder22024BPE49,152每个数字单独一个词元;加了仓库名/文件名词元
Galactica——BPE50,000唯一把「两个制表符」也编成单个词元的;有引用词元,还有一个让它先写推理过程的词元

读这张表的正确方式:不是记住哪个更好,是记住「差异出现在哪些维度上」。 以后拿到一个陌生模型,按这六个维度过一遍,就知道它擅长什么。

GPT-4 那一行还有一条因果链值得单独指出: 书说 elif 有自己的词元、四个空格一个词元,这两点都源于该模型除了自然语言之外还专注于代码25

换句话说:从词元化器可以反推出模型的训练目标。

3.5 【第一层】词元嵌入:模型给每个词元存一个向量

它解决什么问题: 整数 ID 是任意编号,差值没有含义(第 01 章的老问题)。

它怎么做: 语言模型为其词元化器词表中的每个词元持有一个嵌入向量26。 所有这些向量合起来,就是一张数字表格:词表里有多少个词元,这张表就有多少行, 每一行排着的就是那个词元的那串数。

矩阵就是「一张数字表格」的正式叫法,横一行竖一列。上面那张表,就是一个矩阵。

而这个矩阵书叫嵌入矩阵—— 当我们下载一个预训练语言模型时,模型的一部分就是这个矩阵26

关键的一句: 这些向量在训练开始前和模型的其他权重一样被随机初始化, 是训练过程给了它们有用的值27

走查第一层:第 2 节那句话查出来的数,形状是多少。

第 2 节那句话切出来的头 8 个词元是 <s> Write an email apolog izing to Sarah, 编号依次是 1、14350、385、4876、27746、5281、304、19235。 拿这 8 个编号去嵌入矩阵里各取一行——每一行 3,072 个数 (这个长度取自第 03 章那台真实模型:它的嵌入矩阵正好是 32,064 行 × 3,072 列):

8 个编号 ──查表──▶ 8 × 3,072 的一叠数
└ 第 8 行(编号 19235,即 `Sarah`)= [ …3,072 个数… ]

图说:第一层的形状是「词元个数 × 3,072」。句子长短会改前一个数,3,072 不会变。

这一层最要紧的性质,是「查表查出来的永远一样」: 编号 14350(Write)取出的那 3,072 个数, 不管它出现在哪句话里、前后跟着什么,永远是同一串。 这既是它便宜的原因,也是下一节要治的毛病。

由此推出一条硬约束,书写得很明确:

预训练语言模型与其词元化器绑定在一起,并且未经训练就无法使用不同的词元化器28

这条约束的实际后果是:你不能给一个现成模型换词元化器。 想改切分方式,就得重训——这也是为什么第 3.3 节那三个设计选择被称为「设计时」选择。

3.6 【第二层】上下文嵌入:同一个词随句子变

它解决什么问题: 第一层的向量是查表得到的,bank 永远是同一个向量(第 01 章讲过的老毛病)。

它怎么做: 把词元序列送进语言模型跑一遍,每个位置出来一个新的向量—— 书叫上下文相关的词嵌入,它根据上下文用不同的向量来表示一个单词29

走查第二层:同样 8 个词元过完模型,形状没变,数变了。

把上一节那 8 × 3,072 送进模型完整跑一遍,出来的还是 8 × 3,072——形状一模一样。 但第 8 行(Sarah)那 3,072 个数,已经不是查表时那一串了: 它掺进了 apologizing 这两个位置的信息, 所以这一行现在代表的是「一个正在被道歉的 Sarah」。

拿另一句话作对照:Sarah drove to the bank。同样是词元 Sarah、同样是编号 19235——

两句里 Sarah 那一行的 3,072 个数
第一层(查表)完全相同
第二层(过完模型)不再相同

这就是「上下文相关」四个字的全部含义:第一层不看邻居,第二层看。

旁注:换个模型,3,072 会变成别的数。 书演示时用的是 DeBERTa v3 处理 Hello world, 输出形状是 [1, 4, 384]——中间那个 4 是词元个数 ([CLS]Helloworld[SEP] 四个),最后那个 384 是每个词元那串数的长度。 最前面那个 1 叫(就是「这一次同时送进去几句话」),一次送 5 句它就是 5; 书管这一维叫批次维度30形状里那个 384 和我们走查用的 3,072 是同一件东西,只是模型不同。

这一层的用途,书列了三类29:

  • 命名实体识别(找出文本里的人名、地名);
  • 抽取式文本摘要——书特意加了定义:通过突出显示长文本中最重要的部分来总结长文本, 而不是生成新的文本作为摘要;
  • 以及一个意外的用途:这些上下文向量还是驱动 DALL·E、Midjourney、Stable Diffusion 这类 AI 图像生成系统的基础29

最后这条书只顺带提了一句,没有交代「怎么驱动」;本组文档也不展开—— 第 07 章讲的是「能看图」那一侧,不讲「能画图」那一侧。

3.7 【第三层】文本嵌入:整段话一个向量

它解决什么问题: 很多应用要处理的是整个句子、段落甚至文档,不是单个词元31

它怎么做: 两条路32:

做法怎么弄质量
池化(就是把一堆向量合并成一个)对模型生成的所有词元嵌入取平均能用,最常见
专门训练用专门的文本嵌入模型高质量的文本嵌入模型通常专门针对文本嵌入任务进行训练

走查第三层:8 行压成 1 行。

把第二层那 8 × 3,072 逐位取平均——第一个数取 8 行第一个数的平均,第二个数取 8 行第二个数的平均, 一直到第 3,072 个——得到 1 × 3,072。整句话到这里只剩一串数了。

这句话在这一层的形状相比上一层变了什么
第一层(查表)8 × 3,072——
第二层(过完模型)8 × 3,072形状没变,但 Sarah 那一行的数变了
第三层(取平均)1 × 3,072行数从 8 压到 1,长度不变

图说:三层里只有第三层改变形状,第二层只改数值。 把这两件事混为一谈,「该用哪个嵌入模型」这类讨论就永远说不清。

书用 all-mpnet-base-v2 演示第三层,一句话被编码成 768 个数值维度的单一向量, 并提醒维度数取决于底层模型33——768 和我们走查里那个 3,072 是同一件东西,只是模型不同。

第三层是第 04 章(把文字分好类、把文字自动分堆)和第 06 章(检索—— 按意思找出最相关的那几段材料,而不是按字面找)的全部基础。

3.8 word2vec 的训练细节:第 08 章那条主线从这里起头

先讲一个词:对比学习就是「成对地喂——一对该靠近的,一对该远离的,反复调」。 书把它的完整讲解放在原书第 10 章,那一章的内容在我们这里是第 08 章,整章都在讲它。

书把 word2vec 的训练过程放在这一章,而不是放在后面讲训练的那一章。 它自己给了理由:了解 word2vec 的训练方式,将为你学习对比学习做好准备34

我们把这句话再说重一点:这一节是全书暗线的起点。

做法只有四步35:

① 拿一句话:"Thou shalt not make a machine in the likeness of a human mind"
│ 用一个滑动窗口扫过去(比如窗口 2 = 中心词左右各看两个)

② 中心词 + 每个邻居 = 一个训练样例,标签是 1(「是邻居」)


③ 问题:数据集里全是标签 1,模型只要永远输出 1 就能作弊
│ → 补上负例:随机抓两个词凑一对,标签是 0

④ 每个词一个随机初始化的向量,反复训练那个「是不是邻居」的分类器,
每次答对答错都顺手调整这两个向量

图说:注意第三步。「必须提供反例」这件事,是这条暗线全部的技术核心。

3.9 必须给它一个反面:这条暗线真正的技术核心

先给上一节第三步里那种「故意配错的一对」起个名字。

随机抓两个词凑成一对、标签打 0——这种故意配错的一对,叫负例。 它的作用不是提供更多知识,是堵死一条作弊的路: 训练数据里如果全是标签 1,模型只要永远输出 1 就百分之百正确, 它根本不用去看那两个词是什么,也就什么都学不到。

与它相对,本来就是邻居、标签是 1 的那一对,叫正例。 这两个名字从这里开始一直用到第 08 章——那一整章讲的就是「正例从哪来、负例怎么挑」。

「采样」就是「从一大堆里随机抽出几个」。 这里抽的是词:从整个词表里随手抽两个凑成一对,抽到什么算什么,不挑。

「随机抽出来凑负例」这套做法合起来,书叫负采样—— 原话是「通过从数据集中随机采样来添加负例」36

而第一步「拿中心词去配它左右的邻居」那个做法,书叫 skip-gram36。 书对它的说明只有一句:「选择相邻词的方法」。 补充(不在书里,来自通用知识):名字里的 skip 说的是邻居不必紧挨着中心词—— 窗口设成 2,左右各两个都算邻居,中间可以跳过。

关于负例,书说了一句很反直觉的话,值得原样带走:

事实证明,我们不需要在如何选择负例方面过于科学。 许多有用的模型仅仅来自于从随机生成的示例中检测正例的能力。37

书说这受一个叫噪声对比估计的思想启发37

为什么这么做有效: 因为「区分真邻居和随机词」这个任务, 逼着模型把「经常在一起出现的词」的向量拉近。意义没有被直接教,是被这个任务副产品出来的。

书对这件事的总结值得记住,它给整本书定了调:

这种让模型接收两个向量并预测它们是否具有某种关系的想法, 是机器学习中最强大的思想之一,并且一次又一次地被证明在语言模型中效果非常好。38

书随即预告:同样的思想,也是把文字和图像这两种不同形式的数据接到一起的核心所在—— 模型接收一张图和一句描述,预测这句描述是否描述了这张图38那就是第 07 章的 CLIP。

3.10 一个反直觉的用法:把歌当词元,把歌单当句子

这一节回答:嵌入这件事,和「语言」到底有没有关系。

答案是没有。书拿 word2vec 做了一个跟语言无关的东西:音乐推荐39

一个人工制作的歌单 一个句子
歌单里的一首歌 对应 句子里的一个词
经常出现在同一歌单里的两首歌 经常相邻的两个词

用完全一样的 word2vec 训练流程

得到每首歌的向量 → 找最近邻 = 推荐

图说:算法一个字没改,只是把「词」换成了「歌」。

数据是康奈尔大学 Shuo Chen 收集的、来自美国数百家电台的歌单集合39。结果40:

输入推荐出来的
Michael Jackson《Billie Jean》Prince《Kiss》、Madonna《Holiday》、以及另外三首 MJ
2Pac《California Love》Nas、Puff Daddy、The Game、Notorious B.I.G.、Snoop Dogg
Metallica《Fade To Black》Van Halen、Dio、Guns N' Roses、Judas Priest——全部是重金属和硬摇滚

这个例子的价值不在推荐系统本身,在于它证明了一件事:

「嵌入」不是语言技术,是一种通用做法—— 只要你能定义「什么算一起出现」,任何东西都能被嵌入。

书自己也这么说:嵌入被证明在许多领域都很有用,包括推荐引擎和机器人学41

4. 作者的判断与证据

说法属于哪一类说明
词元化选择影响模型在特定任务上的表现有对照证据七个词元化器的横向实测就是证据;数字、空白、大小写的差异肉眼可见1
「每个数字单独一个词元会带来更好的数学表示」书明确标为假设原文措辞是「这里的假设是」4。书没有给对照实验
「用单个词元表示四个空格的模型更适合 Python」有机制解释,无实验解释是模型不用额外跟踪缩进级别23
词元化器与模型绑定,不能换结构性事实嵌入矩阵按词表大小建,换词表等于换矩阵28
「不需要在如何选择负例方面过于科学」经验结论书归因到噪声对比估计这个思想上,没给数据37
「接收两个向量预测关系是机器学习最强大的思想之一」作者的判断这是全书最有分量的一句主张,但书没有为它举证——它的证据分散在原书第 9、10、11 章(对应我们的第 07、08 章)38

书在这一章还夹了一段自我批评,位置很不起眼但内容很重要。

它说随着模型的语言连贯性和事实生成能力越过某个阈值(就是「过了这条线情况就变了」的那条线), 一些用户开始信任模型的事实生成能力(书举例:2023 年初一些语言模型被称为「谷歌杀手」)。

不久之后,高级用户就认识到,仅靠生成模型本身并不是可靠的搜索引擎—— 这直接导致了 RAG 的兴起42

这是第 06 章的伏笔,而且它把 RAG 的动机说得比原书第 8 章的正文还清楚。

5. 边界与局限

第一,书没讲 BPE 到底怎么跑。 它列了方法名、指了 Hugging Face 的文档页, 就转去做横向对比了。想知道词表是怎么「学」出来的,这本书给不了。 书自己也把读者转走了,推荐了《Designing Large Language Model Applications》43

第二,书没有量化任何一条词元化影响。 「数字单独切会更好」「四空格一词元更适合 Python」 都只有机制解释,没有 A/B 数据。这些说法可信,但属于领域共识,不是这本书证明的。

第三,那张七个词元化器的对比表,今天要重做。 2024 年 9 月之后主流模型又换了几轮, 词表规模普遍继续变大。方法论(按六个维度测)不过时,具体结论要重测。

第四,书没有触及一个今天很关键的问题:词元化对多语言的公平性。 它注意到了 BERT 对中文吐 [UNK],但没有讨论同一句话在不同语言下词元数差异极大 这件事在成本和上下文利用率上的后果。

判断(我们的,不是书里的): 这一章真正该被记住的不是那张对比表, 而是它背后的一条排查方法:当一个模型在某类输入上莫名其妙地差, 先去看它的词元化器怎么切这类输入,再去怀疑模型本身。 数字算错、缩进乱、某种语言效果差、换行信息丢失——这四类问题的第一嫌疑人都是词元化器。 如果错,会错在: 如果问题其实出在训练数据分布(比如这类内容根本没进语料), 那换词元化器也没用。判据是:把同样内容换个写法(比如数字加空格分隔)喂进去, 效果有没有变——变了就是切分的问题,没变就是数据的问题。

6. 可带走的

  1. 模型收到的是一串整数,不是文字;那些整数是词表里的行号,本身没有含义;
  2. 空格通常没有自己的词元,它被编码进「这个词元贴不贴前一个」这个属性里;
  3. 主流切法是子词:一个词根加若干后缀,既省词表又能拆解没见过的新词;
  4. 子词平均三个字符,所以同样上下文长度能装约三倍于字符级的文本;
  5. 词元化器的三个设计选择:方法、切分设定、数据领域——第三个最容易被忽略,影响却最大;
  6. 从特殊词元可以反推模型的用途:有 <|user|> 就是聊天模型,有 <filename> 就是代码模型,有 [START_REF] 就是科学文献模型;
  7. 词元化器和模型绑死,不能换;想改切分就得重训;
  8. 「嵌入」是三个层级:词元嵌入(查表,静态)→ 上下文嵌入(过完模型,随句子变)→ 文本嵌入(整段一个向量);
  9. 文本嵌入有两种来法:对词元嵌入取平均(能用),或用专门训练的模型(更好);
  10. word2vec 的核心是「必须有负例」——只有正例的话,模型输出恒 1 就能作弊;
  11. 负例不用挑得太讲究,随机采样就能训出有用的模型(但第 08 章会告诉你难负样本——就是「像却不对」的那种反例——能更好);
  12. 嵌入不是语言技术:把歌当词元、歌单当句子,同一套算法直接变成推荐系统;
  13. 排查口诀:模型在某类输入上莫名其妙地差,先查词元化器。

7. 原文地图

主题原书章原文位置
词元不只是输出,也是输入词元与嵌入text/04-fm.txt:15(搜「词元不仅仅是模型的输出」)
模型收到的是一串整数词元与嵌入text/04-fm.txt:83(搜「一系列整数」) · text/04-fm.txt:83(搜「内部的一个表」)
切分出来的五个现象词元与嵌入text/04-fm.txt:145(搜「第一个词元是 ID 1」) · text/04-fm.txt:149(搜「例如 apolog、izing」) · text/04-fm.txt:151(搜「标点符号自成词元」) · text/04-fm.txt:153(搜「空格字符没有自己的词元」)
词元化器也管输出词元与嵌入text/04-fm.txt:195(搜「还用于处理语言模型的输出」) · text/04-fm.txt:166(搜「它们一起组成了单词 ‘Subject’」)
四种切法与取舍词元与嵌入text/04-fm.txt:201(搜「子词词元化」) · text/04-fm.txt:205(搜「apology」) · text/04-fm.txt:211(搜「字符词元」) · text/04-fm.txt:213(搜「三倍」) · text/04-fm.txt:215(搜「字节词元另一种词元化方法是将词元分解为用于表示 Unicode 字符的单个字节」)
三个决定因素(第一次说)词元与嵌入text/04-fm.txt:187(搜「三个主要因素决定了词元化器如何分解」) · text/04-fm.txt:193(搜「词元化器需要在特定数据集上进行训练」)
三组设计选择(归纳版)词元与嵌入text/04-fm.txt:508(搜「三个主要的设计选择组」) · text/04-fm.txt:518(搜「词表大小在词元化器的词表中保留多少个词元」) · text/04-fm.txt:532(搜「名称大写通常携带有用信息」)
BERT uncased 丢换行、丢大小写、丢中文表情词元与嵌入text/04-fm.txt:296(搜「换行符消失了」) · text/04-fm.txt:298(搜「所有文本都是小写」) · text/04-fm.txt:302(搜「的特殊词元 [UNK]」)
GPT-2 保留换行、字节还原表情词元与嵌入text/04-fm.txt:344(搜「换行符在词元化器中得到了保留」) · text/04-fm.txt:348(搜「🎵鸟字符现在各自被多个词元表示」)
Flan-T5 没有空白词元词元与嵌入text/04-fm.txt:375(搜「没有换行符或空白字符词元」)
GPT-4 的三条差异词元与嵌入text/04-fm.txt:402(搜「83 个空格」) · text/04-fm.txt:404(搜「elif 在 GPT-4 中有自己的词元」) · text/04-fm.txt:406(搜「更少的词元来表示大多数单词」)
GPT-4 的填充中间词元词元与嵌入text/04-fm.txt:389(搜「填充中间词元」)
StarCoder2 每个数字一个词元、仓库词元词元与嵌入text/04-fm.txt:439(搜「每个数字都被分配了自己的词元」) · text/04-fm.txt:424(搜「仓库名和文件名的特殊词元」)
Galactica 的引用与思维链词元词元与嵌入text/04-fm.txt:459(搜「引用被包裹在两个特殊词元之间」) · text/04-fm.txt:461(搜「逐步推理」)
Phi-3 / Llama 2 的聊天词元词元与嵌入text/04-fm.txt:486(搜「聊天词元」)
空白为什么重要词元与嵌入text/04-fm.txt:356(搜「空白字符有什么重要意义」)
领域影响切分词元与嵌入text/04-fm.txt:536(搜「即使我们选择相同的方法和参数」) · text/04-fm.txt:548(搜「这些词元化选择使模型的工作更容易」)
嵌入矩阵、随机初始化、与词元化器绑定词元与嵌入text/04-fm.txt:572(搜「嵌入矩阵」) · text/04-fm.txt:574(搜「随机初始化」) · text/04-fm.txt:570(搜「预训练语言模型与其词元化器绑定在一起」)
上下文嵌入及其用途词元与嵌入text/04-fm.txt:580(搜「命名实体识别或抽取式文本摘要」) · text/04-fm.txt:582(搜「上下文相关的向量还是驱动 AI 图像生成系统」) · text/04-fm.txt:612(搜「384」)
文本嵌入:平均池化 vs 专门训练词元与嵌入text/04-fm.txt:654(搜「表示比单个词元更长的文本片段」) · text/04-fm.txt:660(搜「对模型生成的所有词元嵌入的值进行平均」) · text/04-fm.txt:677(搜「这个句子现在被编码在这个具有 768 个数值维度的单一向量中」)
「谷歌杀手」与 RAG 的动机词元与嵌入text/04-fm.txt:566(搜「谷歌杀手」)
word2vec:滑动窗口、负例、作弊词元与嵌入text/04-fm.txt:727(搜「窗口大小为 2」) · text/04-fm.txt:739(搜「作弊」) · text/04-fm.txt:743(搜「噪声对比估计」)
skip-gram 与负采样这两个名字词元与嵌入text/04-fm.txt:745(搜「skip-gram」)
「最强大的思想之一」与多模态预告词元与嵌入text/04-fm.txt:761(搜「机器学习中最强大的思想之一」) · text/04-fm.txt:763(搜「桥接文本和图像」)
歌曲推荐实验词元与嵌入text/04-fm.txt:771(搜「播放列表」) · text/04-fm.txt:779(搜「Billie Jean」) · text/04-fm.txt:914(搜「Fade To Black」) · text/04-fm.txt:941(搜「Van Halen」)
嵌入超出语言的用途词元与嵌入text/04-fm.txt:681(搜「推荐引擎和机器人学」)

Footnotes

  1. 出处:「词元与嵌入」第 490 段起的并排对照表(text/04-fm.txt:490,搜「BERT base model (uncased)」)。这张表是书把七个词元化器对同一段文本的切分结果放在一起的汇总。 2 3

  2. 出处:「词元与嵌入」第 296 段(text/04-fm.txt:296,搜「换行符消失了」)。原文:这使得模型「对编码在换行符中的信息视而不见(例如,每次对话换行的聊天记录)」。

  3. 出处:「词元与嵌入」第 375 段(text/04-fm.txt:375,搜「没有换行符或空白字符词元」)。

  4. 出处:「词元与嵌入」第 439 段(text/04-fm.txt:439,搜「每个数字都被分配了自己的词元」)与同段(text/04-fm.txt:439,搜「数字 870 被表示为一个词元」)。注意原文用的是「这里的假设是」——书没有给出对照实验。 2 3

  5. 出处:「词元与嵌入」第 83 段(text/04-fm.txt:83,搜「一系列整数」)与同段(text/04-fm.txt:83,搜「内部的一个表」)。

  6. 出处:「词元与嵌入」第 145 段(text/04-fm.txt:145,搜「第一个词元是 ID 1」)、第 149 段(text/04-fm.txt:149,搜「例如 apolog、izing」)与第 151 段(text/04-fm.txt:151,搜「标点符号自成词元」)。

  7. 出处:「词元与嵌入」第 153 段(text/04-fm.txt:153,搜「空格字符没有自己的词元」)。

  8. 出处:「词元与嵌入」第 195 段(text/04-fm.txt:195,搜「还用于处理语言模型的输出」)与第 166 段(text/04-fm.txt:166,搜「它们一起组成了单词 ‘Subject’」)。

  9. 出处:「词元与嵌入」第 201 段(text/04-fm.txt:201,搜「子词词元化」)。原文:「它是最常用的词元化方案,但不是唯一的。」

  10. 出处:「词元与嵌入」第 205 段(text/04-fm.txt:205,搜「apology」)。

  11. 出处:「词元与嵌入」第 207 段(text/04-fm.txt:207,搜「分解为更小的字符」)。

  12. 出处:「词元与嵌入」第 211 段(text/04-fm.txt:211,搜「字符词元」)与第 213 段(text/04-fm.txt:213,搜「三倍」)。 2

  13. 出处:「词元与嵌入」第 215 段(text/04-fm.txt:215,搜「字节词元另一种词元化方法是将词元分解为用于表示 Unicode 字符的单个字节」)。书点名的两篇相关工作是 CANINE 和 ByT5,并称这类方法为「无词元化编码」。 2

  14. 出处:「词元与嵌入」第 508 段(text/04-fm.txt:508,搜「三个主要的设计选择组」)。书在第 187 段(text/04-fm.txt:187,搜「三个主要因素决定了词元化器如何分解」)已经说过一遍,第二次是归纳。

  15. 出处:「词元与嵌入」第 536 段(text/04-fm.txt:536,搜「即使我们选择相同的方法和参数」)。原文特意加了「甚至在我们开始模型训练之前」。 2

  16. 出处:「词元与嵌入」第 189 段(text/04-fm.txt:189,搜「字节对编码(BPE)」)与第 512 段(text/04-fm.txt:512,搜「BPE)是更流行的一种」)。 2

  17. 出处:「词元与嵌入」第 518 段(text/04-fm.txt:518,搜「词表大小在词元化器的词表中保留多少个词元」)与第 532 段(text/04-fm.txt:532,搜「名称大写通常携带有用信息」)。

  18. 出处:「词元与嵌入」第 459 段(text/04-fm.txt:459,搜「引用被包裹在两个特殊词元之间」)与第 461 段(text/04-fm.txt:461,搜「逐步推理」)。原文对 <work> 的描述:「一个有趣的词元,模型用它来进行思维链推理」。

  19. 出处:「词元与嵌入」第 424 段(text/04-fm.txt:424,搜「仓库名和文件名的特殊词元」)。

  20. 出处:「词元与嵌入」第 389 段(text/04-fm.txt:389,搜「填充中间词元」)。书说这个方法的细节超出了它的范围,只给了论文名。

  21. 出处:「词元与嵌入」第 486 段(text/04-fm.txt:486,搜「聊天词元」)。

  22. 出处:「词元与嵌入」第 548 段(text/04-fm.txt:548,搜「这些词元化选择使模型的工作更容易」)。

  23. 出处:「词元与嵌入」第 356 段(text/04-fm.txt:356,搜「空白字符有什么重要意义」)。这段在原书里是一条「注意」框。 2

  24. 出处:「词元与嵌入」第 235 段(text/04-fm.txt:235,搜「不同类型词元」)与第 229 段(text/04-fm.txt:229,搜「🎵鸟」)。测试文本本身就是精心构造的,六类难点各一。

  25. 出处:「词元与嵌入」第 404 段(text/04-fm.txt:404,搜「elif 在 GPT-4 中有自己的词元」)。

  26. 出处:「词元与嵌入」第 572 段(text/04-fm.txt:572,搜「嵌入矩阵」)。 2

  27. 出处:「词元与嵌入」第 574 段(text/04-fm.txt:574,搜「随机初始化」)。

  28. 出处:「词元与嵌入」第 570 段(text/04-fm.txt:570,搜「预训练语言模型与其词元化器绑定在一起」)。 2

  29. 出处:「词元与嵌入」第 580 段(text/04-fm.txt:580,搜「命名实体识别或抽取式文本摘要」)与第 582 段(text/04-fm.txt:582,搜「上下文相关的向量还是驱动 AI 图像生成系统」)。 2 3

  30. 出处:「词元与嵌入」第 612 段(text/04-fm.txt:612,搜「384」)与第 613 段(text/04-fm.txt:613,搜「批次维度」)。

  31. 出处:「词元与嵌入」第 654 段(text/04-fm.txt:654,搜「表示比单个词元更长的文本片段」)。

  32. 出处:「词元与嵌入」第 660 段(text/04-fm.txt:660,搜「对模型生成的所有词元嵌入的值进行平均」)。

  33. 出处:「词元与嵌入」第 677 段(text/04-fm.txt:677,搜「这个句子现在被编码在这个具有 768 个数值维度的单一向量中」)。补充(不在书里):all-mpnet-base-v2 属于 sentence-transformers,其方法论文是《Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks》(Reimers 与 Gurevych,2019-08-27),摘要里的对照数字是:在 1 万个句子里找最相似的一对,BERT 要约 5000 万次推理计算(约 65 小时),SBERT 约 5 秒。来源:https://arxiv.org/abs/1908.10084(查阅于 2026-08-25)

  34. 出处:「词元与嵌入」第 681 段(text/04-fm.txt:681,搜「为你学习第 10 章中的对比学习做好准备」)。原文里的「第 10 章」指的是原书的章号(创建文本嵌入模型),对应我们的第 08 章。

  35. 出处:「词元与嵌入」第 727 段(text/04-fm.txt:727,搜「窗口大小为 2」)、第 729 段(text/04-fm.txt:729,搜「输出 1」)与第 739 段(text/04-fm.txt:739,搜「作弊」)。例句取自 Frank Herbert 的《沙丘》。

  36. 出处:「词元与嵌入」第 745 段(text/04-fm.txt:745,搜「skip-gram」)。 2

  37. 出处:「词元与嵌入」第 743 段(text/04-fm.txt:743,搜「噪声对比估计」)。 2 3

  38. 出处:「词元与嵌入」第 761 段(text/04-fm.txt:761,搜「机器学习中最强大的思想之一」)与第 763 段(text/04-fm.txt:763,搜「桥接文本和图像」)。 2 3

  39. 出处:「词元与嵌入」第 771 段(text/04-fm.txt:771,搜「播放列表」)与第 773 段(text/04-fm.txt:773,搜「Shuo Chen」)。 2

  40. 出处:「词元与嵌入」第 779 段(text/04-fm.txt:779,搜「Billie Jean」)、第 914 段(text/04-fm.txt:914,搜「Fade To Black」)与第 941 段(text/04-fm.txt:941,搜「Van Halen」)。

  41. 出处:「词元与嵌入」第 681 段(text/04-fm.txt:681,搜「推荐引擎和机器人学」)。

  42. 出处:「词元与嵌入」第 566 段(text/04-fm.txt:566,搜「谷歌杀手」)。这段在原书里是一条以「哎呀」开头的「注意」框,位置很不起眼。

  43. 出处:「词元与嵌入」第 217 段(text/04-fm.txt:217,搜「Designing Large Language Model Applications」)与第 550 段(text/04-fm.txt:550,搜「更详细教程」)。