基础篇

F03|文字为什么要先变成Token编号

基础篇约 2.7 千字1 组分步图解

从具体对象与小例子开始,理解计算过程与适用条件。

本章目录
动态图解 · F03

文字、字节、Token、编号是四件事

为什么不能把“一个汉字”当成“一次生成”?

Token是分词规则选出来的片段,编号是它在词表中的地址。一个Token可以跨越多个字符,也可能只覆盖字符编码的一部分。教学中把“学习”合成一个Token,只是明确的演示规则,不能当成所有模型的实际分词。

字节存储和传输文本的单位;UTF-8里的汉字通常占多个字节。
Token分词器处理的片段单位。
词表片段与编号的对照。

输入与适用条件:本图使用人为词表:PAD0、我1、爱2、学习3、你4、!5;不演示真实BPE训练。

1 / 6 · 原文字

第1步,共6步

窄屏可左右滑动图形,或点击“放大图形”。文字解释紧随图后。

文字、字节、Token、编号是四件事:原文字原文字我爱学习 / 你爱文本片段我/爱/学习;你/爱词表对应我1、爱2、学习3、你4整数序列[1,2,3] 与 [4,2]解码校验按同一规则还原片段明确边界不等于按字分词,也不是语义打分教学流程;高亮表示当前步骤,不表示真实耗时比例。

先确定待编码原文,两句之间不能直接接起来当作同一人的上下文。

本步状态由图形与说明共同给出。

默认静止。用“下一步”看完解释再继续;播放到最后一步自动停止。键盘聚焦播放器后,可用左右键逐步查看、空格播放/暂停。图中颜色辅助区分,含义同时用文字注明。

为什么需要

弄清计数单位,可避免上下文预算、输出长度和界面刷新混为一谈。

怎样实现

用目标模型配套分词器编码和解码,并分开观察字符数、字节数、Token数。

可能的代价与误解

更换分词器后沿用旧编号,会读到错误的词表项。

如何判断是否做对

对实际输入做一次往返编解码,并按所用分词器规则处理特殊Token。

字符、字节和Token先分开

你看到的“爱”是一个字符。计算机保存文字需要编码规则;例如UTF-8会把它表示为若干字节,字节是8个二进制位的存储单位。一个字符不必只占一个字节。

Token是分词器处理的片段单位。Tokenizer(分词器)是把文本按约定规则变成Token编号序列、以及把编号解回文本的工具。Token可能覆盖一个词、一部分词、标点、空格,甚至只是一个字符的部分字节,因此不等于字数。

模型内部处理数字而不是屏幕字形。分词器先回答“它是词表中的哪一项”,后面的Embedding再回答“用哪一排数表示这一项”。这两个步骤不能合成一句含糊的“转成向量”。

先分清两种“编码”:

任何整数最终都会以0、1比特的形式存进电脑,例如十进制编号2可以按8位无符号整数保存为00000010。这说的是机器如何存储整数,不是语言模型怎样表示“爱”的含义。

Token编号2表示查词表第2号项目。后面模型可以用这个编号到Embedding参数表中取出一排包含小数与负数的浮点数。它不等于把2编译成一串0和1。F05会把二进制、One-hot和Embedding三者逐一放在一起比较。

一张教学词表和两条输入

为方便手算,定义以下小词表。<PAD>表示稍后填空位的特殊项。

编号 片段
0 <PAD>
1 我
2 爱
3 学习
4 你
5 !

假设教学分词规则把“我爱学习”切成“我、爱、学习”,就得到[1,2,3];把“你爱”切成“你、爱”,得到[4,2]。编号大小没有语义大小:4不比1聪明,也不能通过4−1=3推导“你减我等于学习”。

词表有6项,用符号N=6表示。后文也会见到论文用V表示词表大小;Attention里的V又表示Value矩阵。本书在基础例子中用N,避免你把两者混淆。

BPE的“学习词表”和“编码输入”不是同一阶段

BPE是一类常见的子词构建方法。先从基础符号出发,在训练语料中反复统计相邻符号组合,选择组合并合并。例如语料中a b经常相邻,就可以增加ab这一项,再重新统计下一轮组合。这一阶段产生词表和合并规则。

使用已经准备好的分词器时,不会每收到一句话都重新统计整个世界的文本。它按固定规则把新输入拆成已有片段,并查出编号。实际实现还有预切分、特殊标记和可能的规范化步骤,不能把它理解成随意切词。

为什么代码很难按字符数估算Token?因为user_id和随机串x7b9q2的可用子词组合不同;换行、缩进和空格也可能影响切分。实际预算要使用对应模型的计数规则,教学词表只是为解释机制。

聊天角色怎样成为输入的一部分

聊天原来是带角色的消息,比如“用户问什么”“助手答什么”。聊天模板负责把这些角色与正文组织成模型训练时认识的形式。模板可能加入表示角色开始、消息结束的控制标记,这些标记也可能占Token。

普通字符串里写“system:”不自动等于真正的系统角色;模型接口如何组织消息,决定服务怎样处理它。不能把人类看见的聊天气泡逐字拼接,就声称复现了商业服务最终输入。

编码后还没发生什么

拿到[1,2,3]时,只是找到了编号;还没有得到每个位置的上下文表示,没有计算下一Token概率,也没有读任何外部文件。分词是表示转换,不是“理解已完成”。

反向解码也要注意边界:有的处理会折叠大小写或规范化文本;有的Token单独解码不是完整字符。代码任务中要区分“意思相同”和“原始字节相同”。

运行示例 · F03

把“我爱学习”编码,再原样解码

输入与条件。固定教学词表:我→1,爱→2,学习→3,你→4,PAD→0;本例明确把“学习”视为一个Token。它不代表某家模型的真实分词。

步骤与对象内部动作中间结果 / 新状态
1切片段“我爱学习”切成“我/爱/学习”四个汉字、三个Token,字符数与Token数不同。
2查编号依次查词表得到 [1,2,3],还没有查Embedding。
3编码另一句“你爱”切成“你/爱”得到 [4,2];两句话里的“爱”编号相同。
4反向查词表[1,2,3] 对应“我/爱/学习”按本例拼接规则恢复“我爱学习”。
5看字节层“我”的UTF-8字节是十六进制 E6 88 91这是字符存储,不是Token编号1,也不是Embedding的特征。

把过程连起来。先给分词规则,再给词表编号,才能知道列表究竟代表哪句话。不要从整数大小推测文字含义。

边界与反例。真实分词器还涉及空格、字节、特殊Token及规范化;本例只验证这张明确词表的编码链。

依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。

运行示例 · X11

BPE合并时,为什么不是总选左边那一对

输入与条件。输入字符序列[a,b,c]。假定已学习到两条合并规则:b+c优先级0,a+b优先级1;数字更小优先。词表里a编号1、bc编号5。

步骤与对象内部动作中间结果 / 新状态
1列候选当前相邻对为(a,b)和(b,c)分别查到优先级1和0。
2选择规则先合并优先级0的(b,c)序列变成[a,bc],不能同时再用原来的(a,b),因为b已经被合入bc。
3重新找相邻对现在只有(a,bc)假设没有该合并规则,停止。
4查最终编号a→1,bc→5输出[1,5],不是[编号ab,编号c]。

把过程连起来。BPE推理使用已经学到的规则顺序;原始相邻位置不等于合并优先级。每次合并后候选邻接关系会改变。

边界与反例。字符是教学基本单位,实际byte-level BPE可能以字节为起点,还需遵循特殊Token和预分词规则。

依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。

课后自检

自检 1

“学习”在教学词表占一个Token,现实所有模型也一样吗?

查看参考答案收起参考答案
不一样。具体切分依赖对应分词器和上下文规则,不能由这个演示推断。
自检 2

Token编号5和编号1的距离是4,能说明语义距离吗?

查看参考答案收起参考答案
不能。编号用于定位词表条目,语义表示由后续参数和计算决定。

机制依据:[BPE][UNIGRAM][CHAT]。本节数值与情景除另注外均为原创教学示例;来源不代替中文讲解。

记录保存在本机浏览器。

输入关键词即可检索。

↑ ↓ 选择 Enter 打开Esc 关闭 · 仅本地搜索

阅读设置

阅读设置仅保存在本机浏览器,不上传任何数据。