一句话怎么变成数字?
本课一问:一句人类写的话,是怎么变成模型能处理的数字的?
这一课先不碰:切分规则是怎么学出来的(第 3 课)、编号之后怎么变成向量(第 5 课)。只看清一件事——从文字到一串整数,中间发生了什么。
模型的第一步收到的是什么
神经网络内部只有矩阵乘法、加法和几个非线性函数,它的输入必须是数字。下面是整条流水线的全貌,本课只点亮最左边三格:文字 → 切分 → Token ID。灰色的环节后面各章逐个讲,先看清它们在哪。
本章贯穿两个例句:对话样本里的「我喜欢机器学习」,以及后面各章都会沿用的「小明把苹果给了小王」——这一课就跟着它们从文字走到整数。
点任一已学环节,看这一步的输入 → 输出形状、参数量,以及它解决了什么问题(数字取自 Qwen/Qwen3.8-27B 真实 config)。
点开「Token ID」:这一步输出的形状是 [T],T 是切出来的块数;每个元素是一个整数,也就是词表的行号。本课要弄清的,就是这个 T 和这些整数从哪来。
最直接的办法:每个字直接用它的 Unicode 编号
先别看现成答案,自己设计一个。计算机里每个字符本来就有编号——Unicode 码点,「我」是 U+6211,也就是十进制的 25105。最省事的方案:一个字符一个 ID,ID 就用码点。下面输入任意一句话,看它变成什么。
- ① 朴素方案
- ② 它在哪失败
- ③ 改进方案
现代分词器(tokenizer)分两步:① 按一张词表把文字切成块,常用的字串整块保留;② 把每块换成它在词表里的行号。
词表的大小是人定的超参数,里面放哪些块由数据统计决定。Qwen3.8 的词表有 248,077 项(248,044 个 BPE token 加 33 个特殊 token),embedding 表按 248,320 行分配。「我喜欢」「机器学习」在它的词表里各是一项,所以这句话只需要 2 个 ID。
你也许会想:那只给语料里出现过的字编号,表不就小了?这就是「字符级词表」——第 2 课专门看它在哪失败。
真实的旅程:四步,每一步都是真数字
先看一眼全章的演进图:从最朴素的「码点当编号」出发,每一步都被上一步的某个真数字逼出来;本课站在起点,后面各课沿着它一代代往下走。
- 解决了不用训练,任何文字都能编号。卡在码点从 0 排到 1,114,111,embedding 表得开 1,114,112 行,是 Qwen3.8 实际 248,320 行的 4.5 倍;而且一个字一个 ID,序列一点不缩短。
- 解决了字符集封闭,词表小。卡在序列最长:209 字的段落按字切要做 43,681 次注意力打分,是 Qwen3.8 子词切分(106 个 token)的 3.9 倍。
- 解决了一个词一块,序列短。卡在词是开放集合:我们的语料按空白和标点切出 70,310 种块,94.8% 只出现过一次;验证集里连训练集没见过的字都有 83 种——含它们的词只能记成 UNK。
- 解决了按频次反复合并相邻对:常见的整块、罕见的拆碎,词表大小由合并次数控制。卡在初始单元是字符:要覆盖全部 Unicode,基础词表就超过 13 万(GPT-2 论文 §2.2);只收见过的字,我们的验证集照样缺 83 种字。
- 解决了初始词表就是 256 个字节,任何文字都能编码,永远不出 UNK。卡在词表没学过的语言会被切碎:同义的中文段落,GPT-2 切 461 个 token,Qwen3.8 切 106 个,差 4.3 倍;同义英文段落两者一样多。
- 解决了中文常用字串整块进词表:「我喜欢机器学习」只要 2 个 token(GPT-2 要 17 个)。各家词表:DeepSeek-V3 129,280 · Qwen3 151,936 · GLM-5.3 154,880 · Kimi K3 163,840 · Qwen3.8 248,320。卡在两头各一张 V × d 的表:2 × 248,320 × 5,120 = 2,542,796,800 个参数,占 Qwen3.8 的 9.2%;同样的词表搬到我们 d = 256 的小模型上,embedding 占 95.3%。
- 解决了ID 只是行号,取出一行 5,120 维向量;one-hot 乘矩阵与查表等价,但查表只拷现成的数。卡在表里的 1,271,398,400 个数(输入端一张表)从哪来?人填不完,也不知道每一维该是什么意思。
- 解决了用「预测下一个 token」的 loss 端到端训练,用法相近的 token 被推到相近的位置。卡在只在出现时才被推:我们的项目里一个 batch 8,192 个位置,平均只出现 1,453 个不同 token;罕见 token 学得少——MiniMax 的「嘉祺」在后训练里被推偏,输出层那一行与原来的余弦只剩 0.329。
- 解决了维度越高,每个 token 能装的信息越多。卡在参数按 d² 涨:我们的模型 d 从 128 到 256,总参数 1,066,112 → 3,688,704,val loss 4.776 → 4.641(d = 256 这一档是参照 run ref_baseline,与项目基线同配置同种子;基线记录的 4.626 与它之差是重跑波动,见 C14);没有公式能给出「最优的 d」。
下面用 Qwen3.8 的真实分词器走一遍。所有切法和编号都来自真 tokenizer 的离线计算,不是示意值;换几个例句,注意每一步的块数和编号。
两个词从这里开始要用得很精确:
- Token:词表里的一项,本质是一段固定的字节。它可以是半个汉字、一个字、几个字、一个英文词或词的一部分。
- Token ID:这一项在词表里的行号,一个整数。
分词器把一句话变成一串 Token ID,这串整数就是模型收到的全部输入。模型从来没见过「字」——它对文字的全部了解,都要从这些编号在训练数据里怎样出现、怎样搭配里学出来。
常见误解:「Token = 一个字」,或者「Token = 一个词」。 两个都不对。Qwen3.8 把「我喜欢机器学习」切成「我喜欢」「机器学习」2 块——对话样本里画的 4 块(我 / 喜欢 / 机器 / 学习)是示意;「人工智能非常强大」切成「人工智能」「非常」「强大」,一块可以比一个词还长;英文 strawberry 单独出现时切成 str / aw / berry 3 块,放在句子里前面带着空格时,「 strawberry」整个只是 1 块。切法由词表决定,词表由数据统计出来。
同一段文字换一个分词器,切法和 ID 全都不同:同一句「我喜欢机器学习」,GPT-2 的词表要用 17 个 token。为什么差这么多,第 2 课和岔路课「为什么中文更贵」会讲清楚。
编码和解码:一来一回,一个字节都不差
分词器是一对函数:encode 把文字变成 ID 序列,decode 把 ID 序列变回文字。Qwen3.8 和 GPT-2 用的都是字节级 BPE,它有一个可以证明的性质——点公式里每一项看它的意思:
这个性质保证了一件事:分词不丢信息。模型读到的编号序列和原文一一对应,它生成的编号序列也一定能还原成一段确定的文字。
试三件事: ① 在旅程动画里切到「人工智能非常强大」,对照对话样本那句「不一定切成这 3 块」——真分词器恰好就是这么切的;② 停在第 ③ 步,看词表横条上 ID 挤在哪一段——ID 的大小有没有意义,第 5 课兑现;③ 切到「今天天气真好」,记下 Qwen3.8 与 GPT-2 的块数,第 2 课会用到。
「先切分再查表」凭什么成立
- 它解决什么问题:模型只接受整数;分词器把任意文本确定地变成一个有限词表里的整数序列,词表有多少行,embedding 表就有多少行。
- 数学上为什么可能有效:字节级 BPE 的初始词表覆盖全部 256 个字节,任何文本都能编码,且 decode(encode(x)) = x 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条合并只拼接相邻字节、不删改字节;前提是输入已按 NFC 规范化 出处GPT-2 论文 §2.2 ↗ 。
- 实验上为什么最后选了它:子词切分最早在机器翻译上被证明能处理罕见词 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条Sennrich 等在 WMT 英德、英俄翻译上的实验;子词切分的来历见第 3 课 出处Sennrich 2015 · 本地 PDF ↗ ;字节级 BPE 随 GPT-2(2019)流行开来,今天的 Qwen3.8 仍用它 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条Qwen3.8 与 GPT-2 的 tokenizer.json 都是 byte-level BPE(预计算脚本读取的 tokenizer_class 与模型类型) 出处c1-tokenize.json · _meta ↗需联网 。「我喜欢机器学习」在 Qwen3.8 里是 2 个 token,是对真分词器的直接测量,换一个分词器结论就变。
一句话、下一个缺口、你的提问
一句话: 分词器先按词表把文字切成块,再把每块换成它在词表里的行号;从这一刻起,模型只看得到整数。
下一个缺口
Qwen3.8 把 7 个字切成 2 块,码点方案一字一块。那为什么不干脆按字切,或者干脆按词切?两个极端各在哪个真数字上失败——第 2 课:为什么不一字一个 Token,也不一词一个 Token?
另一个埋下的疑问:词表横条上,「我喜欢」和「机器学习」的 ID 挨得很近。ID 的大小有意义吗?这个疑问在第 5 课兑现。
你的提问
C1 的问答记录里还没有真实提问(提问请直接在对话里问,会归档到 05-问答记录/)。你可能会问:
- 「为什么 AI 数不清 strawberry 里有几个 r?」→ 岔路课:模型为什么数不清 strawberry 里的 r
- 「我能拿任意一句话试试不同的分词器吗?」→ 实验课:真 tokenizer 与我们的 tokenizer 比一比
🔍 为什么说文字进模型前就消失了
模型的第一层是 embedding 查表(第 5 课):拿 ID 去一张表里取出一行数字。这一步之后,网络里流动的只有向量,再也没有「字」这个东西。所以分词器的每个决定——词表多大、怎么切——都会跟着模型一辈子:换一个分词器,ID 全变,查表查到的就全是别的行,训练好的权重立刻作废(第 5 课回扣)。