BPE(Byte Pair Encoding)算法的核心逻辑很简单:谁出现频率高,就把谁合并成token。但这套源自英文世界的规则,遇上中文时产生了有趣的张力。
| 维度 | 英文 | 中文 |
|---|---|---|
| 最小单位 | 字母(26个) | 汉字(数万个) |
| BPE起点 | 字符级(byte级) | 通常直接以字为起点 |
| 高频组合 | ing tion th 等后缀 | 的 了 是 等虚词,或人工智能等复合词 |
| 压缩空间 | 极大(词根+词缀模式固定) | 相对有限(字与字的组合更灵活) |
关键洞察:英文靠形态变化(morphology)压缩,中文靠语义聚合(semantic chunking)压缩,而BPE的"高频优先"策略对后者并不敏感。
高频字如的、了、是被单独保留,但次高频的组合(如的是、了的)未必能成token--因为BPE只看全局频率,不看局部搭配强度。
结果:中文prompt常出现"碎片化",
人工智能可能被切成人工+智能,也可能保留整体,取决于训练语料的领域分布。
同一个词在不同场景下的切分可能完全不同:
通用语料训练 → "深度学习" = ["深度", "学习"]
科技论文训练 → "深度学习" = ["深度学习"](整体)
👉 Prompt优化陷阱:你以为省下的token,换了个模型可能又涨回来了。
代码、论文、产品说明中常见的中英夹杂,是BPE的噩梦:
"使用PyTorch训练GPT模型"
→ ["使用", "Py", "Tor", "ch", "训练", "G", "PT", "模型"] // 糟糕
→ ["使用", "PyTorch", "训练", "GPT", "模型"] // 理想
高频子词合并对"PyTorch"这类低频外来词完全失效,因为它在整体语料中不够"高频"。
# 以OpenAI tiktoken为例
import tiktoken
enc = tiktoken.encoding_for_model("gpt-4")
text = "自然语言处理"
tokens = enc.encode(text)
print([enc.decode([t]) for t in tokens])
# 可能输出:['自然', '语言', '处理'] 或 ['自然语言', '处理']
| 策略 | 示例 | 节省token |
|---|---|---|
| 使用模型已收录的专有名词 | ChatGPT而非Chat GPT | -1 |
| 避免可切分的冗余表达 | AI而非人工智能(若上下文已明确) | -2~-3 |
| 利用数字/符号的紧凑性 | RAG而非检索增强生成 | -4~-5 |
| 警惕"伪高频"组合 | 的+确+实 ≠ 的确+实 | 可能+1 |
不是"写得更短",而是"让高频子词替你说话"。
观点A:BPE的局限
的+名词)优化不足观点B:中文的"特殊性"被夸大
我的看法:两者皆有。但作为prompt工程师,理解你的工具比抱怨工具更重要--知道tokenizer的"脾气",才能写出"对机器友好"的中文。
如果让你设计一个"中文优化版"BPE,你会修改哪个环节?
- 合并优先级(引入PMI互信息替代纯频率)?
- 初始词表(收录更多高频复合词)?
- 动态切分(根据上下文调整)?
欢迎讨论 👇
参考:OpenAI tiktoken源码、SentencePaper原始论文、Hugging Face Tokenizers文档
加入讨论
终于有人把中文tokenization的痛讲明白了!那个”PyTor”ch的切分例子看得我血压飙升😂 之前写prompt的时候发现”Transformer”有时候被切成两半,有时候又完整保留,还以为是自己眼花了,原来是训练语料搞的鬼。以后得先跑一遍encode再定稿了。
原来”深度学习”在不同语料里切法还不一样,怪不得换个模型prompt长度就变了😅 那个中英混排的切分例子太真实了,我之前写”使用HuggingFace”直接被切成”Hug”、”ging”、”Face”三块,当场愣住。
单字token泛滥这个点太真实了,我之前测过几个开源模型的tokenizer,发现”的是”这种超常见组合居然没被合并,反而一些冷门地名被整个收进去了,就很迷😂 作者说的”局部搭配强度”这个概念能不能展开讲讲?感觉是个优化方向啊
好家伙,原来我prompt里”自然语言处理”被切成三块是这个原因!之前还以为是模型傻,现在看是BPE的锅😂 话说有没有工具能一键检测哪些词组已经被合并成token了?手动试太麻烦了。
那个中英混排的”PyTor”ch真的蚌埠住了😂 我更好奇的是,如果专门用中文代码语料重新训练一遍tokenizer,能不能把PyTorch、HuggingFace这些词整个收进去?有人试过吗
突然想到,如果我在prompt里故意用「的」字把长词隔开,比如写成「人工 的 智能」,会不会反而让BPE合并出奇怪的token?🤔 有人试过这种反向操作吗
试了下文章里的代码,发现”自然语言处理”在gpt-4里真的是[‘自然’, ‘语言’, ‘处理’],但”机器学习”却是[‘机器学习’]整体,这俩词频率差这么多吗?有点反直觉😂 看来真得逐个词去测,不能想当然。
笑死,看完立刻去试了下”神经网络”,结果gpt-4切成[‘神经’, ‘网络’],但”卷积神经网络”居然整体不拆?这频率计算就很玄学… 感觉prompt优化到最后变成玄学了😂
突然好奇,如果我在prompt里用全角符号把英文词包起来,比如「使用PyTorch」,BPE会把它当成一个整体还是照样乱切?有人试过这种邪道操作吗🤔