分词器tokenizer

笔记[1](#1)[2](#2)

分词器 (tokenizer)作用

将原始文本转化为模型理解的数字序列

LLM负责"理解和生成",而tokenizer负责"把语言变成模型能理解、可复用的格式"

分词器会影响模型能力 :token划分得太"碎片化"或太"笼统",都会影响表达效率;

所以:

  • 分词算法不是唯一的:不同的分词算法(如BPE、WordPiece)会出现不同的划分结果;
  • 它是独立优化的模块 :通常先在大规模文本上训练词表(vocab),再固定下来供模型使用

训练分词器

1 准备语料

运用命名实体识别(Named Entity Recognition,NER)技术实现数据脱敏;去除私密信息;

个人信息属于噪声;干扰分词算法的统计效率

2 预分词阶段

基于空格和标点的切分、按Unicode类别划分,或直接采用字节级切分

直接对字符流做分词;会因为跨空格或者标点合并难造成难以还原、语义混乱的token

3 统计并迭代更新

字词候选统计并迭代更新

训练分词器与训练神经网络不通;往往采用贪心合并和统计频次的方式

4 最终输出产物

vocab.json: token与id

merges.txt:记录字词合并规则或者概率模型

vocab.json是最终成品清单;已知的直接匹配

merges.txt是生成成品的工艺流程;未知的按规则拆成已知的;两者配合做到零未知词(OOV)

假设词表 vocab.json 里有这些 token:

python 复制代码
"l", "o", "w", "e", "r", "er", "lo", "low", "lower", "un", "believe", "able"

现在来了一个完全没见过的词 "unlowerable"(词表里没有这个词)。

Vocab 查不到 → 这时你必须把它拆成词表里有的子词 。可问题是:该拆成什么样?

python 复制代码
可以拆成:["un", "low", "er", "able"]
也可以拆成:["un", "lo", "w", "er", "able"]
还可以拆成:["un", "l", "o", "w", "e", "r", "able"]

好几种拆法都合法 ,但效果不一样。到底用哪种?

答案就是:看 merges.txt。

阶段①:训练分词器

原始文本 → ① 预分词 → ② BPE 合并 → 得到 vocab + merges

阶段②:使用分词器(编码新文本,推理/生成时)

新文本 → ① 预分词 → ② BPE 查询 → Token IDs

↑ 这个"预分词"和"合并"在两端各出现一次!

训练阶段(离线,一次) 使用阶段(在线,每次)
输入 海量训练语料 单个用户句子
做的事 统计频次、迭代合并、构建词表 预分词 → 查表编码
有统计吗 ✅ 有(频次统计) ❌ 无
有迭代吗 ✅ 有(反复合并) ❌ 无
产出 固定 vocab.json + merges.txt token ID 序列

常用分词器

1 字节分词器

直接维护大小256的词表;与UTF-8编码一致;压缩率为1

2 字符分词器

一个字母或者汉字为一个字符

字符类型 UTF-8 字节数 Token 数 压缩比
ASCII(英文、数字) 1 字节 1 token 1
中文、日文、韩文 3 字节 1 token 3
拉丁扩展、希腊文等 2 字节 1 token 2
Emoji 🌍 4 字节 1 token 4

3 词级分词器

基于空格或者中文将文本切分为词,一个词对应一个ID

补充:正则表达式

用于描述字符串长什么样子的规则语言;正则来源于regular;表示可由一类规则描述;用于提取和判断

deepseek采用设计专门的预分词阶段;用于切块规则

4 BPE分词器

统计相邻字符对出现的频率;将频繁出现的字符对合并为Token


思考

四种分词算法对比与 LLM 为何选 BPE

机制对比

BPE WordPiece Unigram SentencePiece
合并/挑选准则 统计相邻字符对频率 语言模型概率挑最可能的合并 删词:从大到小,删掉让似然损失最小的子词 不直接是一种算法,是框架
方向 自底向上(小→大拼) 自底向上 自顶向下(大→小删) 可装 BPE / Unigram
评分依据 频次 概率/似然 似然 可配置
代表性使用 GPT、LLaMA、DeepSeek BERT T5、Gemma LLMamba、T5 等
是否依赖空格 依赖(需预分词) 依赖 不依赖 不依赖(原始字节流)

关键差异:

  • BPE :每次找"出现最频繁"的相邻对合并,纯看次数

  • WordPiece :不是看出现最多,而是看合并后整体分词似然提升最大 的对。

    python 复制代码
    选让 score = P(xy) / (P(x)·P(y)) 最大的一对合并
  • Unigram :反着来,先假设一个大词表,逐个删掉对总似然损失最小的子词,直到词表达标。

  • SentencePiece :不是独立算法,而是处理框架 。默认不依赖空格 ------把空格当作普通字符 处理,天然适配日语等无空格语言,也免去预分词步骤。

为什么现在的 LLM 普遍选 BPE

原因 说明
简单高效 只有"数频次"一个操作,训练快、实现简单、容易并行
无 OOV 子词拆到字符/字节级兜底,任何词都能编码
字节级扩展 最小单元可用 UTF-8 字节 → 能编码任何语言任何字符,绝对 OOV-free
GPU 生态成熟 GPT 全系都用它,工具链、复现资料最全
压缩好 常见词整词保留、生僻词拆零件,压缩率高,省 token

一句话:BPE 以"够用 + 简单 + 生态成熟 + 天然无 OOV"取胜。WordPiece/Unigram 概率建模更优雅,但 LLM 追求鲁棒性与性价比,实用主义压倒了理论精致


如何衡量"好的分词器":压缩效率 vs 语义一致性

维度 含义 好的表现
压缩率 平均每个 token 承载多少信息 每 token 有效信息多、token 数少
语义一致性 token 是否对应有意义的语言单元 "不开心"不要拆成"不"+"开心"割裂语义
鲁棒性 对新词、噪声、不同语言的容忍 新词能拆、不崩、产出稳定
可还原性 能否从 ID 无损还原原文 空格标点状态不丢失
效率 编码/解码速度、词表大小 词表不过大、延迟可控

核心 trade-off:压缩率 ↔ 语义一致性

压缩率和语义一致性天然冲突------很难同时要"最少的 token"和"最合理语义"。

  • 压得越狠 → 词更粗更整 → token 少,但可能把不该绑的一起绑,语义边界错乱
  • 拆得越细 → 语义更纯净 → 但 token 变多,序列变长,成本上升
python 复制代码
中文例子:
- 整词: ["不开心"]      → 3字1token,省,但"开心"难以复用到其他场景
- 子词: ["不", "开心"]  → 语义清晰,且"开心"可复用
- 单字: ["不","开","心"] → 最灵活但 token 最多

现代取平衡的做法 :高频词整词收进词表 (保语义 + 省 token),低频生僻内容拆成子词 (保证覆盖)。平衡点由词表大小训练语料分布决定。

类比:像造乐高------大积木 (整词)拼得快但形状受限;小积木(子词)灵活但拼得慢。好分词器是找到常用部分用大积木、其余用小积木的黄金配比。


分词器如何影响实际 LLM 的表现

分词器虽是"预处理",但对模型能力上限影响极大。

① 上下文窗口的"实际长度"被压缩率决定

python 复制代码
模型窗口 = 2048 token(固定)
压缩率高的分词器 → 2048 token 能塞进更多信息 → 模型"看到"更多上下文
压缩率低 → 同样文本吃满窗口 → 长文容易"截断丢失"

直接影响长文档理解、多轮对话、代码生成的好坏。

② 生成成本的直接杠杆

python 复制代码
API 按 token 收费 / 推理按 token 计算
好的分词器 token 少 → 便宜、生成快
英文 1 词≈1-2 token,中文每字≈1-2 token

直接影响经济成本和速度,是工程上最被重视的原因。

③ 学习能力与语义:token 边界 = 模型的"注意力边界"

模型基于 token 学习,token 之间是离散的,跨 token 组合主要靠注意力:

  • 语义一致的 token → 更容易学到词的用法/语法/搭配 → 生成更流畅准确
  • 语义割裂的 token → 关联被切断,模式更难学,生成质量下降
python 复制代码
好的切分:["在新","的","世界","里"]  → 模型抓住"在...里"的句式
坏的切分:["在","新","的","世","界","里"] → 每字孤立,句式规律难学

④ 特殊 token 的设计影响指令遵循

<BOS>/<EOS><PAD>、角色分隔符等设计直接影响对话模板、指令跟随能力

⑤ 数字与代码:切片方式决定推理薄弱点

python 复制代码
数字 "20242025"
拆成 ["2024","2025"] → 模型可能"看出"是相邻年份
拆成 ["20","24","20","25"] → 算术和数字关系更难学

知名现象:LLM 在大数运算、拼写、中英文混排 上出问题,根因往往是分词器把内容切碎了

★ 三个终极小结

  1. 为什么选 BPE:简单高效 + 生态成熟 + 字节级无 OOV,实用主义胜出。
  2. 好的分词器 = 在"压缩率"和"语义一致性"间找平衡,通常用"高频整词 + 低频子词"兼顾。
  3. 对 LLM 的影响:决定窗口能装多少信息、生成成本、模型能否学到语义规律,进而影响长文能力、质量、成本,甚至数字和代码推理。

参考链接


  1. 分词器 ↩︎

  2. 课程介绍与分词器 ↩︎

相关推荐
Elsa️7461 小时前
leetcode 14.最长公共前缀
算法·leetcode·职场和发展
不会代码的小猴1 小时前
6. Qt网络编程
开发语言·c++·笔记·qt·算法
Zguigo1 小时前
树的前序|中序|后序遍历【使用栈实现】
数据结构·算法
AINative软件工程2 小时前
LLM Token Budget 工程实践:给每个请求设上限,让成本和质量都在掌控中
后端·llm·ai编程
zhanghaha13142 小时前
HTML系列教程:4_什么是 HTML 元素(零基础超详细讲解)
前端·算法·html
TAN-90°-2 小时前
Deep Learning for Computer Vision——Training CNNs and CNN Architectures
人工智能·深度学习·神经网络·算法·机器学习·计算机视觉·cnn
0x3F(小茶)2 小时前
Tokenization(分词算法):一切大语言模型的地基
人工智能·算法·语言模型
Keven_112 小时前
算法札记:利用floyd判环算法优化SPFA判负环算法
算法·spfa判负环
mCell10 小时前
Lua 编程入门:从基础语法到元表
javascript·算法·lua