transformer你不学?02|Tokenizer:从文本到 Token 的第一次转换
作 者:吴佳浩(Alben)
全栈架构师笔记
导读
大模型从不认识"字",它只认识数字。Tokenizer 是文本进入模型的第一个关卡,也是新手最容易忽略的关卡——你遇到的 90% 的"模型输出乱码"、“上下文超长”、"中文占 token 特别多"问题,根都在分词器。
本篇用真实 tokenizer 跑通"文本→Token→ID→还原"的完整闭环。
本篇你会学到什么
- 🔸 为什么需要 Tokenizer,而不是直接把字符喂给模型;
- 🔸 BPE 分词的工作直觉;
- 🔸
encode/convert_ids_to_tokens/decode三件套的真实用法与输出。
一、为什么要学这个
神经网络的输入必须是数字,但"数字怎么来"决定了三件事:
- 🔸上下文长度:同样 1000 字文章,好的分词器切 500 个 token,差的切 1500 个——直接决定模型能读多长;
- 🔸生僻词鲁棒性:按词分词(word-level)遇到没见过的词直接
<UNK>,按子词切(subword)能拼出来; - 🔸多语言公平性:早期 GPT 的 tokenizer 对中文极不友好,一句中文可能被切成 3~5 个 token,同样内容比英文贵好几倍。
上篇回顾:第 1 篇 里数据流的第一站就是 Tokenizer——文本 → Token → ID。
二、核心理论:BPE 的直觉
Byte Pair Encoding 的思路一句话说完:从字符开始,把最高频的相邻对不断合并,直到形成词表。
初始: l o w e r → 高频对 lo 合并 → low er → 最终 "lower" 是一个 token 罕见词: "transformering" → 可能切成 transform + ering 两个 token所以 token 不是"词"也不是"字",是统计意义上的高频子串。这解释了为什么常见英文单词是 1 个 token,而代码、数学符号、生僻中文会被切得很碎。
三、真实项目里怎么用
任何调用大模型 API 的场景,计费和上下文限制都是按 token 算的。写 prompt 前先本地数一遍 token,是成本控制的基本功。
四、流程图
五、真实代码
下面用本地已下载的真实 tokenizer(Qwen 系列词表)跑通完整闭环:
# Tokenizer 完整闭环:编码 → 查看Token → 还原fromtransformersimportAutoTokenizer# 使用本地完整模型自带的 tokenizer(离线可用;在线环境可换成 "Qwen/Qwen2.5-7B-Instruct")tok=AutoTokenizer.from_pretrained(r"D:\loraQwen2.5\models\Qwen2.5-7B-Instruct")text="Transformer 改变了 NLP"# 第一步:编码——文本变 ID 序列ids=tok.encode(text)print(f"IDs:{ids}")# 第二步:查看每个 ID 对应的 token 子串tokens=tok.convert_ids_to_tokens(ids)print(f"Tokens:{tokens}")# 第三步:解码——ID 序列还原文本restored=tok.decode(ids)print(f"还原:{restored}")# 往返恒等式检验:decode(encode(x)) == xprint(f"往返恒等:{restored==text}")# Tokens 数量print(f"Tokens 数量:{len(ids)}")# 词表规模print(f"词表大小:{tok.vocab_size}")输出结果怎么看(真实运行输出):
IDs: [46358, 80090, 117, 112346, 451, 12567] Tokens: ['Transformer', 'ĠæĶ', '¹', 'åıĺäºĨ', 'ĠN', 'LP'] 还原: Transformer 改变了 NLP 往返恒等: True Tokens 数量: 6 词表大小: 151643- 🔸
Transformer是 1 个 token(高频词整存),改变了被切成 3 个子串——这就是 BPE 按频率切分的直接证据; - 🔸 token 里出现的
Ġ是 BPE 的空格标记(ĠN= " N"),还原时自动变回空格; - 🔸decode(encode(x)) == x这个往返恒等式是检验 tokenizer 用法正确性的金标准。
六、拆解:三个函数各管一段
| 函数 | 输入 → 输出 | 用途 |
|---|---|---|
encode | 文本 → ID 列表 | 喂模型前 |
convert_ids_to_tokens | ID → 子串 | 调试看模型在读什么 |
decode | ID 列表 → 文本 | 模型输出后给人看 |
七、常见错误与排查
- 🔸网络报错连不上 huggingface.co:设镜像
export HF_ENDPOINT=https://hf-mirror.com,或像本例一样直接用本地缓存路径; - 🔸中文被切得稀碎:换中文友好的词表(Qwen/DeepSeek 系列对中文优化过),别用早期 GPT-2 词表处理中文;
- 🔸special token 混进正文:
encode时留意add_special_tokens参数,BERT 系会自动加[CLS]/[SEP]。
八、练习题
- 用本篇代码分别统计"你好世界"和 “hello world” 的 token 数,体会中文成本差异;
- 验证
tok.decode(tok.encode(任意句子)) == 原句是否恒成立,试一个带 emoji 的句子; - 数一数你最近一段 prompt 的 token 数,按主流 API 价格估算这条 prompt 的成本。
一句话总结:Tokenizer 用 BPE 把文本压成统计意义上的高频子串序列,encode 进模型、decode 出模型——token 数量直接决定成本与上下文长度。
下一篇:transformer你不学?03|Embedding:让文字变成向量。