LLM 学习系列(1 / 5)

分词 → 架构 → 推理 → 训练 → 开放权重
建议按此顺序阅读:先懂文字怎么变成数字,再看模型结构,然后是它怎么生成、怎么练出来,最后是练好后如何发布。

1. 概念总览:文字怎样进入模型

LLM(Large Language Model,大语言模型)的神经网络不直接处理字符串。输入文本先由 Tokenizer 转换为整数编号,称为 Token ID;模型生成新的 ID,再由 Tokenizer 转回文字。

本系列主要讨论生成文本的 LLM。先按「使用一个已经训练好的模型」理解前 3 篇,再看第 4 篇如何训练、第 5 篇如何发布。

输入文字 Tokenizer 编码 输入 Token ID 语言模型 新生成的 Token ID Tokenizer 解码 输出文字

在文本编码层,三个核心概念的边界是:

概念定义
TokenTokenizer 切分文本后得到的离散单位
VocabularyToken 与整数 ID 之间的有限映射表
Tokenizer负责文本规范化、切分、ID 映射以及解码的完整系统

五篇共用的例子

输入 小猫跑了一天,它很,让模型接着生成 累。本篇追踪的是:这段文字如何变成 ID,生成的 ID 又如何变回文字。

为了方便手算,假设一个教学用 Tokenizer 将输入切成 小猫 · 跑 · 了 · 一天 · , · 它 · 很,对应 ID 为 [10, 11, 12, 13, 14, 15, 16];另外约定 累 = 17、。 = 18、<BOS> = 1、<EOS> = 2。

这套切分和编号是虚构的,后续各篇保持一致,不代表任何真实模型。 主线先演示纯文本续写;对话模板可能额外加入角色和边界标记。累 是选定的演示续写,并非现实中唯一合理的答案。

2. Token(词元):模型处理的文本单位

Token 是 LLM 处理文本时使用的基本离散单位。「离散」表示它来自有限的类别集合,而不是一个可以任意连续变化的数值。

Token 不一定是一个完整的词,也不一定对应一个字符。它可能是:

  • 一个完整单词,如 apple
  • 单词的一部分,如 un、believ、able
  • 一个汉字或连续的多个汉字
  • 一个字符的一部分字节,此时单个 Token 未必能独立显示成文字
  • 标点、空格或换行
  • 特殊标记,如 <BOS>、<EOS>

Note

Token 的边界由 Tokenizer 的规范化、预切分、词表和切分规则共同决定。不同 Tokenizer 对同一段文本的切分结果可能不同,因此 Token 数不是文本自身的固定属性。

Tip

「1 Token 约等于 0.75 个英文单词」只是针对特定语料和 Tokenizer 的粗略统计,不能直接套用于中文、代码或特殊符号。准确的 Token 数必须使用对应模型的 Tokenizer 计算。

2.1 Token Sequence(Token 序列)

Token 序列是多个 Token 按照它们在文本中的顺序组成的有限有序序列。

沿用开头的例子:

切分 词表映射 小猫跑了一天,它很 小猫 · 跑 · 了 · 一天 · , · 它 · 很 10 · 11 · 12 · 13 · 14 · 15 · 16

在这个例子中:

对象内容
Token 序列["小猫", "跑", "了", "一天", ",", "它", "很"]
Token ID 序列[10, 11, 12, 13, 14, 15, 16]
序列长度7,暂不计特殊 Token

Token 序列具有以下性质:

  • 有序性:交换 Token 的位置通常会改变文本含义。
  • 有限长度:输入与输出序列受模型上下文窗口和生成长度限制。
  • 可包含特殊 Token:例如 <BOS>、<EOS>、<PAD> 以及对话角色标记。
  • 依赖 Tokenizer:同一文本经过不同 Tokenizer,可能得到不同的 Token 序列及序列长度。

上下文窗口(Context Window) 是模型一次能利用的 Token 容量;在常见的 Decoder-only 文本模型中,输入和已生成输出共同占用它。可对照术语库中的 Context Window。

模型接口通常接收 Token ID 张量(Tensor,即多维数值数组)。单条序列可表示为长度为 的数组;多条一起处理时,常组成形状为 的数组。 是 Batch Size(批量大小,一起处理的序列数), 是对齐后的长度。例如,一条含 7 个 Token 的输入可以表示为形状 [1, 7] 的数组。

在自回归生成过程中,新生成的 Token ID 会不断追加到已有序列:

生成 ID 17 生成 ID 18 10 … 16小猫跑了一天,它很 10 … 16 · 17小猫跑了一天,它很累 10 … 16 · 17 · 18小猫跑了一天,它很累。

Note

工程代码经常用 tokens 同时指 Token 序列和 Token ID 序列,但两者并不相同:前者是符号序列,后者是词表中对应整数编号的序列。模型的 Embedding 层读取的是 Token ID 序列。

2.2 Special Tokens(特殊 Token)

特殊 Token 是由 Tokenizer 和模型共同约定、用于表达序列结构或控制信息的 Token。 它们存在于词表中并拥有固定的 Token ID,但通常不直接对应普通文本片段。

BOS(Beginning of Sequence,序列开始标记) 表示一个 Token 序列的起点。常见形式包括 <BOS> 和 <s>:

BOS Token 1 Token 2 Token N EOS

BOS 为模型提供明确的起始上下文,但并非所有模型都要求显式添加 BOS。

EOS(End of Sequence,序列结束标记) 表示一个 Token 序列的终点。常见形式包括 <EOS>、</s> 和 <|endoftext|>:

否 是 模型生成 Token Token ID 是 EOS? 继续生成 停止生成

在自回归训练中,模型学习在完整序列末尾预测 EOS;推理时,如果模型生成的 Token ID 等于配置的 eos_token_id,生成框架通常会停止解码。

BOS 和 EOS 的具体文本形式与 Token ID 均由模型配套的 Tokenizer 配置决定。例如,一个模型可能将 BOS 映射为 ID 1、EOS 映射为 ID 2,另一个模型则可能使用完全不同的表示。

PAD(Padding,填充标记) 常用于把一批不同长度的序列补到相同长度。框架通过掩码忽略填充位置,使它们不充当正常上下文或训练目标。

Chat Template(对话模板) 是把「用户说了什么、助手回答什么」排成模型所需输入格式的规则。例如,模板可能把用户消息包在角色标记之间,并在末尾加入助手开始作答的标记。这些格式也是模型学习协议的一部分。

例子推进 · 给序列标出边界

若教学模型要求 BOS,输入会是 [1, 10, 11, 12, 13, 14, 15, 16],长度从 7 变成 8。假设模型依次生成 [17, 18, 2],它们表示 累 · 。 · <EOS>。

。 是普通标点,通常不会自动终止生成;<EOS> 才是此处约定的结束标记。输出解码时一般隐藏它,所以读者看到的是 累。。

Warning

EOS 与 Stop Sequence 不相同。EOS 是词表中的一个特殊 Token,由模型直接预测;Stop Sequence 是推理系统在 Token 或输出文本中检测的终止模式,可以由一个或多个普通 Token 组成。

Important

Chat Template 可能自动插入 BOS、EOS、消息边界和角色标记。手动添加后再调用自动插入逻辑,可能产生重复的特殊 Token,导致输入格式偏离模型训练时使用的格式。

3. Vocabulary(词表):给 Token 编号

词表是 Token 与整数 ID 之间的有限映射表。

教学词表的一部分如下:

TokenToken ID
<BOS>1
<EOS>2
小猫10
很16
累17

ID 是地址,不是语义大小。 17 比 16 大,不表示 累 比 很 更强、更重要或更相似。下一篇的 Embedding 层会根据地址查出可计算的向量。

如果一个模型的词表大小为 100,000,表示它能够直接识别 100,000 个不同的 Token,并不表示它只能处理 100,000 个单词。词表中没有完整收录的单词,可以拆成多个已知 Token。

词表大小需要在模型参数量与序列长度之间权衡:

  • 词表较大:文本通常会被编码为更短的 Token 序列,但嵌入层和输出层的参数量更大。
  • 词表较小:嵌入层和输出层更小,但文本会被切得更碎,序列更长,训练和推理成本随之增加。
  • 语言覆盖不均衡:某些语言可能需要更多 Token 表达相同信息,导致可用上下文减少、计算成本增加。

4. Tokenizer(词元化器):编码与解码

Tokenizer 是在原始文本与 Token ID 序列之间进行转换的完整系统。

它通常提供两个方向的转换:

Encode Decode 原始文本 Token ID 序列 还原文本

4.1 Encode:从文字到 ID

Tokenizer 的编码过程通常包含以下步骤:

  1. 文本规范化:统一或保留大小写、Unicode 表示等文本形式。
  2. 预切分:按照空格、标点或语言规则对文本进行初步划分。
  3. 子词切分:把文本切成词或更小片段,例如 unbelievable 可以示意为 un · believ · able;常用 BPE 算法,见第 5 节。
  4. ID 映射:通过词表把每个 Token 映射为整数 ID。
  5. 特殊 Token 处理:按模型协议添加 <BOS>、<EOS> 等标记。

并非每个 Tokenizer 都会执行完全相同的步骤。例如,有些 Tokenizer 会执行有损的文本规范化,有些则直接以原始字节为基础编码。因此,编码与解码不一定是严格可逆的。

Unicode 为字符定义码点(可理解为字符编号),UTF-8 是把这些码点存成字节的一种编码方式,字节(Byte) 由 8 个二进制位组成。一个汉字通常占多个 UTF-8 字节,所以「按字符切」和「按字节切」不是一回事。

例子推进 · Tokenizer 到这里就完成了输入工作

对 小猫跑了一天,它很,假设不修改原文,按约定切分并映射后得到 [10, 11, 12, 13, 14, 15, 16],再按需添加 BOS。Tokenizer 负责表示转换;判断后面更可能是 累 还是 饿,是语言模型的任务。

4.2 Detokenization(反词元化)

Detokenization 是 Tokenizer 将 Token ID 序列转换为可读文本的过程,也常被称为「反分词」。

查询词表 拼接并跳过特殊标记 模型生成的 ID17 · 18 · 2 累 · 。 · EOS 累。

Detokenization 通常包含:

  1. 根据词表将 Token ID 映射回 Token。
  2. 按算法规则拼接子词、字符或字节。
  3. 恢复空格和 Unicode 字符。
  4. 按配置保留或移除 <BOS>、<EOS> 等特殊 Token。

4.2.1 为什么解码可能不可逆

如果 Tokenizer 在切分前通过规范化函数 修改了输入文本,那么编码阶段实际处理的是 ,而不是原始文本 。若其余环节可逆,且没有未知 Token 替换、特殊 Token 增删或额外文本清理,往返结果才可以写成:

不一定能保证:

原因不是 Detokenization 「解码错误」,而是规范化阶段已经丢弃了部分信息。多个不同的原始字符串可能得到相同的规范化结果,解码时无法判断输入最初是哪一种形式。

Hello 小写规范化 HELLO hello hello Encode → Token ID Decode hello

常见的不可逆情况包括:

可能导致不可逆的处理处理前表示处理后表示丢失的信息
转换为小写Hellohello原始大小写
合并连续空格hello worldhello world空格数量
删除首尾空格␠hello␠hello首尾空格
Unicode 兼容性规范化AA全角与半角形式
Unicode 组合规范化e + U+0301é原始码点序列
跳过特殊 Token<BOS>hello<EOS>hello特殊 Token

表中的 ␠ 表示一个空格。Unicode 组合规范化的例子在视觉上可能完全相同,但底层码点序列不同。因此,「恢复出相同显示文本」不等于「恢复出相同字节串」。

这里讨论的是 Decode(Encode(x)) 的输入往返。模型生成的是新的 ID 序列;把它解码成 累。,当然不要求恢复为输入的 小猫跑了一天,它很。

Important

原始字节级往返要求输入信息完整保留,并按配套规则处理特殊 Token 和文本清理。例如,编码时自动附加的 BOS/EOS,解码时可能需要移除才能还原输入;但删除原输入本身包含的标记又可能丢失信息。Byte-level Tokenizer 可以保留 UTF-8 字节,但「Byte-level」本身并不保证完整处理流程可逆。

Note

流式生成时不能假设每个 Token 都能独立解码成合法文本。一个 Unicode 字符可能跨越多个 Byte-level Token,工程实现通常需要缓存不完整的字节序列,再增量输出完整字符。

5. 切分规则怎样得到:算法与 Tokenizer 训练

Tokenizer 的「训练」通常是从语料(文本集合)中统计出词表和切分规则。它与第 4 篇通过反向传播调整神经网络权重的「模型训练」是两件事:通常先确定 Tokenizer,再用它编码语料来训练模型。

常见的 Tokenizer 算法或基础粒度方案包括:

类型核心方法典型应用
BPE从较小的基础符号集合开始,反复合并高频相邻单元LLaMA 1/2、Mistral
Byte-level BPE以 UTF-8 字节为基础单元,再执行 BPE 合并GPT-2、RoBERTa、OpenAI GPT 系列
WordPiece构建子词词表,编码时通常采用最长匹配BERT、DistilBERT
Unigram Language Model从较大的候选词表开始,根据概率模型逐步裁剪子词T5、ALBERT、XLNet
Character-level直接以字符作为基本单位CANINE 等模型
Byte-level直接以字节作为模型输入的基本单位ByT5 等模型

这些方法的构造方向不同:

BPE:反复合并 Unigram:逐步裁剪 Character-level Byte-level 较小的基础符号集合 目标子词词表 较大的候选词表 目标子词词表 原始文本 字符序列 原始文本 字节序列

Byte-level 若覆盖全部 256 种字节值,就不因新词而缺少基础表示;Character-level 能否覆盖新字符取决于字符集合,有限字符表仍可能遇到未知字符。无法表示的输入有时会被替换为 UNK(Unknown,未知标记),原始信息因此丢失。更细的基础粒度通常也意味着更长的序列。

5.1 BPE:训练时学合并,使用时按规则切分

以 BPE(Byte Pair Encoding,字节对编码) 为例:训练时,它从基础符号集合开始,每轮统计语料中的相邻单元对,合并频率最高的一对,直到词表达到目标大小或满足停止条件。

假设已学到:小 + 猫 假设已学到:一 + 天 小 · 猫 · 跑 · 了 · 一 · 天 · , · 它 · 很 小猫 · 跑 · 了 · 一 · 天 · , · 它 · 很 小猫 · 跑 · 了 · 一天 · , · 它 · 很

图中用字符作基础单元,只演示规则如何作用于贯穿例子。不能靠这一句话断言哪些相邻对在整个语料中最高频;真实规则还受预切分等约束。使用已训练好的 BPE 编码新输入时,按已有合并优先级执行,不会为每条请求重新训练词表。

经过大量合并后,常见词或词根可能成为一个 Token,罕见词和新词仍可以由多个子词组合表示:

  • 相比完整单词词表,BPE 的词表规模更可控,也能处理新词。
  • 相比单字符词表,BPE 通常可以生成更短的 Token 序列。

Note

BPE 最初是一种数据压缩算法。用于 NLP 时,初始单元可以是字符,也可以是字节;Byte-level BPE 明确以 UTF-8 字节为基础单元,因此原则上可以编码任意 Unicode 文本,通常不需要 <UNK>。

Warning

「BPE 就是 Tokenizer」并不严谨。BPE 是学习和应用子词合并规则的算法;完整的 Tokenizer 还包括文本规范化、预切分、特殊 Token 处理和 Token ID 映射。

6. 常用工程实现:算法、工具与产物

算法描述「如何切分」,工程实现负责训练或加载词表、保存规则以及执行编码和解码。

工具类型支持或用途
SentencePiece训练与运行工具支持 BPE 和 Unigram;可直接处理中文、日文等没有天然空格边界的文本
Hugging Face Tokenizers高性能实现库使用 Rust 实现,支持 BPE、Byte-level BPE、WordPiece、Unigram 等算法
tiktoken高性能实现库主要用于 OpenAI GPT 系列采用的 BPE 编码
AutoTokenizer统一加载接口根据模型配置加载匹配的 Tokenizer;本身不是分词算法或实现库

它们处于不同的概念层次:

由代码实现 训练或加载 读取模型配置 实例化 算法BPE · WordPiece · Unigram 实现库SentencePiece · Tokenizers · tiktoken 模型专用产物词表 · 切分规则 · 特殊 Token 配置 加载接口AutoTokenizer 运行时 Tokenizer

7. 选择原则:与模型配套

在使用已有模型时,不应该独立选择 Tokenizer,而应该加载模型训练时配套的 Tokenizer:

匹配的 Token ID 语义不匹配的 Token ID 配套 Tokenizer 模型 Embedding 层 其他 Tokenizer

模型的嵌入层和输出层参数与特定 Token ID 的语义一一对应。即使另一个 Tokenizer 能编码同一段文本,只要词表或 ID 映射不同,生成的 ID 对该模型就具有不同含义。

Note

「配套」不等于「独一无二」:多个模型可以共用一套 Tokenizer,也可以从同一基座继续微调。关键是模型参数已经适配这套 ID 和文本处理规则。扩展词表或迁移 Tokenizer 并非绝对不可能,但通常需要调整 Embedding、输出层并继续训练,不能当作普通配置替换。

Important

使用现成模型时,加载其配套的 Tokenizer、词表、特殊 Token 配置和文本处理规则。从头训练或专门进行 Tokenizer 迁移时,再讨论算法选型。

例子收束 · 交给下一篇的是什么

本篇得到 [10, 11, 12, 13, 14, 15, 16],按需加上 BOS。若换一套 Tokenizer,ID 17 可能代表另一段文字,模型输出与文本解释就会错位。

接下来,架构篇 解释模型如何把这些 ID 变成向量,并算出 累 的分数;模型选出 [17, 18, 2] 后,再由本篇的解码步骤还原成 累。。