前途科技前途科技
  • 服务
  • 关于
  • AI
    • AI 大模型
    • 具身智能
    • 算力芯片
  • 科技
    • 智能终端
    • 软件·互联网
    • 汽车·出行
    • 科学前沿
  • 资源中心
    • 深度研究
      • AI 前沿
      • 教程
      • AI 知识库
      • 案例研究
    • 行业报告
      • 白皮书
      • 行业报告
      • 研究报告
      • 技术分享
      • 专题报告
    • 精选案例
      • 金融行业
      • 医疗行业
      • 教育行业
      • 零售行业
      • 制造行业
  • 服务
  • 关于
联系我们
教程/09.22 · 08:00/15 MIN/作者:苏晚/0 阅读

tokenizers v1 最高快 30 倍,中文却只快 6.8 倍

Hugging Face 的 tokenizers v1 候选版在 Token ID 不变的前提下,把编码提速 3 到 30 倍。但分语言数据里中文只有 6.77 倍、排倒数第二,词缓存对中文还略拖后腿。三处关键改动怎么起作用,按 Qwen2 切分规则实测中英文 pre-token 差在哪,都在这里。

9 月 21 日,Hugging Face 的 Arthur Zucker、Simon Brandeis、Luc Georges 和 Lysandre 在官方博客发了一篇《tokenizers v1: encode, decode and scaling, measured》,公布了 tokenizers 库第一个大版本的候选版(release candidate)和一整套基准数据。标题里的数字很抢眼:单线程编码比 v0.23 快 3 到 30 倍,8 线程下仍能保持 76% 的线性扩展。

但原文嵌在交互图表里的分语言数据,才是中文团队最该看的部分:14 种语言里,中文的提速只有 6.77 倍,排倒数第二;英文是 22.44 倍。v1 新加的词缓存,在中文语料上的收益是 0.98——也就是开了反而略慢。

下面先把 v1 到底改了什么讲清楚,再回答那个问题:中文为什么吃不到大头,以及你的场景能拿到多少。

分词什么时候会拖 GPU 后腿

分词长期不被当成瓶颈。相比模型本身的计算,把文本切成整数序列是很轻的活。原文的判断是,这个平衡正在变:在海量数据集上训练、同时服务大量并发请求、反复处理长输入,这些场景会把压力压到分词器上,严重时会让模型"等数据"。他们的目标写得很直白:GPU 不应该闲着等 CPU 分完词。

原文还引用了 Crusoe 和 NVIDIA 团队的一篇文章《Reducing TTFT by CPUMaxxing Tokenization》:每个 prompt 都得先分词,推理才能吐出第一个 token。在长 Agent 上下文、复用模型前缀缓存的请求里,这部分开销会直接体现在首 token 延迟(TTFT)上。换句话说,当推理侧的前缀缓存把大段计算省掉之后,剩下没法省的分词就显眼了。

v1 改了什么,没改什么

先说没改的:v1 产出的 token ID 与 v0.23 完全一致。API、词表、合并优先级(merge ranks)都保留,v0.23 能加载的分词器 v1 都能加载。库也没有为了跑分只专精 BPE,WordPiece 和 Unigram 照样支持。对使用者来说,这意味着升级不需要重新训练或重新对齐任何东西。

tokenizers 把"文本变整数"分成四个阶段:

  1. 归一化:小写化、Unicode 归一化等;
  2. 预切分(pre-tokenization):把文本切成更小的片段,叫 pre-token;
  3. 模型:把每个 pre-token 变成 token,再映射成词表里的 ID;
  4. 后处理:加上模型需要的特殊 token。

大部分优化发生在第三阶段。原文测的 10 个模型家族里有 8 个用 BPE(字节对编码):从 pre-token 的字节出发,反复把优先级最高的相邻两块合并,直到没有可合并的对。优先级在训练分词器时学出来,随分词器一起发布,所以同样的文本永远得到同样的 ID。关键的一点是:合并永远不会跨越 pre-token 的边界。后面讲中文时会用到这条。

真正起作用的几处改动

原文列了六项改动:

改动做了什么
拆分 crate原来一个 crate 拆成工作区:tk-encode 是必需的运行时,tk-serialize、tk-convert、tk-train 按需链接
零分配模型合并用的工作集放在调用方持有的 scratch buffer 里,循环不碰内存分配器
bitcannon把切分正则改写成位流上的布尔运算,用 SIMD 指令找切分点,不再走正则引擎
重写合并循环待合并的片段组成一个预分配缓冲区里的侵入式双向链表,一次合并只改两个下标,不搬数据
词缓存线程本地的备忘表,pre-token 字节 → 最终 ID,重复出现的词只合并一次
原生并行一个共享的分词器可被多线程同时调用,每个线程从自己的子池取 scratch buffer 和词缓存,不再排队抢一把锁

其中三项值得展开。

切分:用位流代替正则

BPE 模型用一个正则表达式做预切分。这个正则是模型的固定参数,随分词器发布、运行时从不改变——那就没必要每次编码都让一个通用正则引擎去解释它,完全可以针对具体模型用的那条模式,手写一个等价的切分函数。

手写之后就能用上 CPU 的 SIMD 指令(单指令多数据),一条指令处理一批字节,很适合 UTF-8 文本。bitcannon 把输入字节看成若干条并行的比特流,切分边界由整个寄存器上的布尔运算直接算出来,而不是一个字符一个字符往前扫——一次寄存器操作判定 64 个字节。同样的思路也驱动着文本处理的 Parabix 和 JSON 解析的 simdjson。

限制在于必须认得这条模式。候选版里 bitcannon 覆盖了 GPT-2、cl100k、o200k、Tekken 和 DeepSeek 这几种切分语法,原文说少数几种语法就覆盖了大多数字节级 BPE 模型;不在其中的分词器仍走正则,拿不到这部分加速。原文明确说,各模型提速差距那么大,原因就在这里。

标签:Hugging FaceRust
苏晚
苏晚Su Wan

前途科技 · 前沿主笔

关注 AI 与前沿科技的观察者,前途科技前沿内容主笔。

查看全部文章

想了解 AI 如何助力您的企业?

免费获取企业 AI 成熟度诊断报告,发现转型机会

置顶文章

tokenizers v1 最高快 30 倍,中文却只快 6.8 倍
置顶

tokenizers v1 最高快 30 倍,中文却只快 6.8 倍

亚马逊封杀 Meta Muse:问题不在 AI 购物,在浏览器跑在谁的机器上
置顶

亚马逊封杀 Meta Muse:问题不在 AI 购物,在浏览器跑在谁的机器上

前途科技前途科技
服务关于快讯技术商业报告
微信咨询二维码

咨询微信

扫码添加微信咨询

前途科技微信公众号

微信公众号

扫码关注

Copyright © 2026 AccessPath.com, 前途国际科技咨询(北京)有限公司,版权所有。|京ICP备17045010号-1|京公网安备 11010502033860号|隐私政策|服务条款

词缓存:重复的词只合并一次

真实文本里重复的词很多。既然同一个 pre-token 永远产出同样的 ID,那处理一次就可以记下来。v1 给每个线程配了一张缓存表,键是 pre-token 的字节,值是 token ID,之后再遇到就跳过合并。

原文的附带条件同样写得很清楚:缓存只在 pre-token 大量重复时有效;重复少的输入要为查表付出成本,却拿不到多少命中。记住这句话,它是理解中文数据的钥匙。

合并循环:不再每次分配内存

BPE 合并循环的旧实现,每次调用都分配新内存,每个 pre-token 都新建一个优先队列。v1 改为复用调用方持有的 scratch buffer,符号存在扁平数组里、相邻关系用数组下标串起来,合并时的更新更便宜;还把一批 pre-token 放进一次模型调用里处理。

一个小技巧:每个候选对被打包成一个 64 位整数,合并优先级放在高位。比较两个候选就是比较两个整数;"这里不能合并"用最大值表示,于是找下一个合并点不需要分支判断。

成绩单:3 到 30 倍是怎么来的

所有数字都来自 Apple M4 Max,测的是 Rust crate 的候选版。

单线程:v1 的聚合吞吐是 139.6 MB/s,v0.23 是 8.8 MB/s,约 15.9 倍。按模型拆开,最高的是 gpt2(29.83 倍),最低的是 t5-base(3.33 倍),这就是"3 到 30 倍"的两端。几个国产模型的分词器都在中上段:GLM-5.2 是 24.19 倍,DeepSeek-V4 是 14.63 倍,Qwen2 是 13.0 倍,MiniMax 是 12.42 倍。按算法看,BPE 模型聚合 18.02 倍,WordPiece(BERT)6.73 倍,Unigram(T5)3.33 倍——后两者的提速小得多,原文说那是下一步的重点。

多线程:从 1 线程到 8 线程,v1 的吞吐从 130 MB/s 涨到 833 MB/s,是线性扩展的 76%;v0.23 从 8 MB/s 涨到 44 MB/s,扩展效率 77%。两者效率差不多,但基数差了一个数量级。对比项里有个值得注意的现象:gigatoken 单线程是 137.2 MB/s,和 v1 几乎打平,但在"多线程共享一个分词器"的模式下,8 线程反而只有 101 MB/s。原文的解释是 gigatoken 更适合"每个线程一个独立实例"的用法,v1 则在原生多线程下表现最好。选型时要先想清楚你的服务是哪种并发模型。

延迟:对一篇 512 字节的英文文档单次编码,8 个模型家族的 p99 延迟中位数从 110.02 微秒降到 7.04 微秒。逐模型看,p99 快了 9 到 28 倍,DeepSeek-V4 的 p99 从 145.9 微秒降到 5.29 微秒。

解码:原文称,在测解码的 6 个模型家族上,v1 的解码吞吐是 v0.23 的 5.4 到 8.8 倍。不过解码不是 v1 的强项——聚合数据里 tokie 的解码吞吐是 444.2 MB/s,高于 v1 的 373.1 MB/s。

内存和体积:用 gpt-oss 分词器、单 worker 处理约 1 MB 英文文本,v1 加载后堆内存 16.9 MB,v0.23 是 47.8 MB。拆分 crate 之后,只含编码功能的最小构建(去符号、gzip 压缩)是 305,989 字节,拆分前是 665,263 字节。

中文为什么排倒数第二

tokenizers v1 相对 v0.23 的分语言编码提速,中文 6.77 倍,排在 14 种语言的倒数第二
按语言统计的编码提速倍数(v1 / v0.23,10 个模型家族的聚合)。图片来源:Hugging Face / tokenizers v1 基准页

分语言看,英文 22.44 倍一骑绝尘,其次是阿姆哈拉语、印地语、希伯来语等,都在 10 倍以上;中文 6.77 倍,日文 7.11 倍,泰文 6.08 倍,排在最后几位。

原文对多语言的说法只有一段:很多非拉丁文字在 UTF-8 里要占更多字节,分词实现还可能叠加额外的切分工作;性能优化通常围着英文转,v1 把非拉丁语言也列为性能目标。但各语言差异具体从哪来,原文没有拆解。

词缓存那张图给出了一条线索:

开启词缓存后的吞吐倍数,共享前缀 2.03 倍,中文 0.98 倍,英文网页 0.93 倍
开启词缓存 / 关闭词缓存的吞吐比,Apple M4 Max 实测,8 个模型家族取中位数。图片来源:Hugging Face / tokenizers v1 基准页

缓存收益最大的是"共享提示前缀"(2.03 倍,100 个真实 Agent 请求,每个 10 KiB,共享 8 KiB 前缀),其次是密集特殊 token(1.69 倍)、Agent 编程语料(1.38 倍)、源代码(1.30 倍)。中文是 0.98,比不开还略慢。

回到前面那条规则:合并不跨 pre-token 边界,缓存的单位也是 pre-token。那中文的 pre-token 长什么样?拿 Qwen2 的分词器(tokenizers 0.23.1)实际切一下就能看到。它的预切分规则会把一串连续汉字当成一个整体,于是一段中文技术新闻切出来是这样的:

['、亚马逊云科技以及由', ' CNCF', ' 支持的', ' Cure', '5', '3', ' 第三方审计', '——',
 '帮助该项目加速了开发进程', ',引入了安全审计', ',并整合了后量子密码学', '、FIPS']

而英文是这样的:

[' inputs', ' can', ' put', ' enough', ' pressure', ' on', ' the', ' tokenizer', ' that', ...]

英文一个 pre-token 基本就是一个词,中文一个 pre-token 却常常是一整个短句。短句几乎不会原样重复出现,缓存自然很难命中。

为了量化这一点,我们各取约 44 KB 的中文和英文技术文章(中文来自 InfoQ 中文、量子位和阮一峰周刊,英文来自 Hugging Face、PyTorch、Google Research 等博客),用同一个 Qwen2 预切分器切完后统计:

指标中文英文
pre-token 个数3,5508,489
平均每个 pre-token 字节数12.45.2
平均每个 pre-token 的 token 数3.021.06
按个数计,已出现过的 pre-token 占比46.8%71.2%
按字节计,已出现过的 pre-token 占比10.7%59.1%

最后一行最能说明问题。它是"缓存无限大、从头开始"时理论上能命中的字节比例:英文接近六成,中文只有一成出头。中文里重复出现的 pre-token 大多是标点、数字和夹在中间的英文词这类短片段,真正耗合并工作量的长汉字串几乎都是一次性的。

这个小实验的边界要说清楚:样本只有两份几十 KB 的语料,只看了 Qwen2 一种切分规则,不同模型的中文预切分方式并不一样。它能说明的是"缓存对中文先天难命中",但不能单独解释中文整体提速为什么最低——Hugging Face 自己的数据里,英文网页的缓存收益也只有 0.93,英文的高重复率并没有在那组测试里转化成缓存收益,而英文的整体提速仍然最高。整体差距里其他因素各占多少,原文没有给出分阶段的数据,我们也不做猜测。

想在自己的语料上看一眼,几行 Python 就够:

from tokenizers import Tokenizer

tok = Tokenizer.from_pretrained("Qwen/Qwen2-7B")
text = open("your_corpus.txt", encoding="utf-8").read()
pieces = [text[a:b] for _, (a, b) in tok.pre_tokenizer.pre_tokenize_str(text)]

seen, hit_bytes, total_bytes = set(), 0, 0
for p in pieces:
    n = len(p.encode())
    total_bytes += n
    if p in seen:
        hit_bytes += n
    seen.add(p)
print(f"pre-token {len(pieces)} 个,按字节重复占比 {hit_bytes / total_bytes:.1%}")

这个比例越高,词缓存对你越有用;如果你的中文语料也在一成左右,就别指望缓存,收益主要得靠切分和合并循环那两处改动。

测基准之前,先说清楚是哪种"热"

原文花了一整节讲测试方法,这部分比具体数字更耐用。他们给自己定的规则包括:所有引擎跑同一个计时循环,不给任何引擎开快速通道;加载词表单独计时,不算进编码;输出 ID 用 FNV-1a 哈希与基线逐一核对;只在所有引擎都跑通并验证过的格子上取中位数;每次重复都开新进程;工作线程绑定到 8 个不同的物理核,不用超线程的兄弟线程。

最值得记住的一条:反复编码同一篇文档,可能比编码一串不同的文档快得多。前者测的是"整篇文档都已在缓存里"的性能,后者测的是面对新输入、但之前见过的 pre-token 仍留在缓存里的性能。两种都常被叫做"热启动"(warm),测的却是完全不同的负载。原文的主要结果用的是不同文档组成的流,而且整个语料大到缓存装不下。他们的结论是:分词器基准必须写明用的是哪种负载,因为这个选择可能主导结果。

这对自己做选型测试的团队是个直接提醒。拿一篇长文档循环编码一万次得出的数字,放到线上面对的是千人千面的请求时,很可能对不上。

对中文团队的实际建议

先确认你在不在受益范围里。 原文所有数字都是对 Rust crate 测的。Python 绑定包的是同一份代码,但每次调用有额外开销,这些测量都没有包含。原文给出的安装方式也只有 Rust 这一条:

cargo add tokenizers --pre

训练功能默认开启,会带进一个 C++ 依赖;只需要编码的话可以关掉默认特性:

cargo add tokenizers --pre --no-default-features --features http

调用方式不变,批量编码用 encode_batch,多核扩展测的就是这个调用。更精简的 Python 绑定(减少锁和包装类型、支持 free-threaded CPython)列在 1.0.0 的待办里。所以如果你的数据管线是 Python 写的,现在能做的是评估和准备,而不是指望换个版本号就拿到 15 倍。

国产模型的分词器整体受益不小。 GLM-5.2、DeepSeek-V4、Qwen2、MiniMax 分别是 24.19、14.63、13.0、12.42 倍。注意这是 22 个语料的聚合,不是纯中文的成绩;用它们处理纯中文时的倍数,原文没有单独给出。参照中文语料在 10 个模型上聚合的 6.77 倍,别直接拿 13 倍、24 倍去估算自己的中文管线。

Agent 类负载是词缓存的主场。 共享长前缀(系统提示词、工具定义、仓库上下文)的请求,缓存收益达到 2.03 倍。如果你在做 Agent 服务、前缀又比较固定,这部分收益来自前缀本身在请求间的重复。原文给了复现这项结果的命令:

tokbench measure prefix-sharing \
  --engine pipeline \
  --engine hf-tokenizers \
  --compare-to pipeline-no-cache \
  --corpus agentic_swe

用自己的数据复测。 原文所有基准都来自开源的 tokbench 仓库,并给出了在自己硬件上重跑的命令。M4 Max 上的结果不等于你的 x86 服务器;英文语料上的结果更不等于你的中文语料。

还没做完的部分

候选版已经包含的:拆分 crate、bitcannon、词缓存、更快的查找与合并结构、可复用的模型内存、批量模型调用、更快的解码、role_to_token 支持,以及 Node.js 绑定。

1.0.0 之前还要做:训练校验也改用 tk-encode,保证训练和推理不会产出不同的分词结果;offsets 和 mask 改为按需计算,不拖累只要 token ID 的路径;重做归一化器;更简单的 Python 绑定;面向 ExecuTorch 和 llama.cpp 的纯推理 C/C++ 绑定,之后可能还有 JVM、Swift、Go。原文还说,1.0.0 之前会把更多模型家族迁到新的合并循环上。

1.0.0 之后的探索方向是 tok-devices:在 GPU 上做编码和批量解码,文本和 token ID 全程留在设备上。解码器把词表上传一次,并行算出输出位置,再在 GPU 上收集对应的字节。原文把它定位为面向大批量的可选组件,还要进一步做原型和测量。

原文还有一句姿态上的表态:重构之前,tokenizers 离它应有的性能差得很远,所以给它贡献代码可能显得不值;这次重构就是想表明,它值得贡献。他们也点名感谢了 gigatoken、tiktoken、kitoken、tokie、fastokens、wordchipper、ai-tokenizer 这些项目,说文中不少思路是别的项目先证明了值得一试。从成绩单看,v1 在单线程上和 gigatoken 基本打平、在解码上还落后 tokie——这是一个追上生态、而不是甩开生态的版本。对使用者来说,这反而是好事:token ID 不变、API 不变,升级的代价很低,等 Python 绑定跟上,大多数人不用改一行代码就能拿到这份提速。

美军险些登临中国货船:出问题的不是 AI 幻觉,是那第二次调用
置顶

美军险些登临中国货船:出问题的不是 AI 幻觉,是那第二次调用

//

24小时热榜

OpenAI呼吁建立前沿AI国际标准 应对递归自我改进风险
TOP1

OpenAI呼吁建立前沿AI国际标准 应对递归自我改进风险

长三角安全AI实验室发布星界、星驭、星鉴三大解决方案
TOP2

长三角安全AI实验室发布星界、星驭、星鉴三大解决方案

3

OceanBase登顶国际数据智能体榜单,准确率突破90%

19小时前
OceanBase登顶国际数据智能体榜单,准确率突破90%
4

API 成本吞噬利润,AI 初创公司集体转向开源权重模型

3小时前
API 成本吞噬利润,AI 初创公司集体转向开源权重模型
5

大模型接管机械臂危险测试:GPT-6 Astra执行率达97%

18小时前
大模型接管机械臂危险测试:GPT-6 Astra执行率达97%
6

清华联手无问芯穹开源具身智能基建RPent

20小时前
清华联手无问芯穹开源具身智能基建RPent
7

海力士与兆易创新:同样做存储,为何逻辑迥异?

21小时前
海力士与兆易创新:同样做存储,为何逻辑迥异?
8

苹果入局折叠屏发布iPhone Duo,反向带火三星

22小时前
苹果入局折叠屏发布iPhone Duo,反向带火三星
热门标签
大模型AgentRAG微调私有化部署Prompt EngineeringChatGPTClaudeDeepSeek智能客服知识管理内容生成代码辅助数据分析金融零售制造医疗教育AI 战略数字化转型ROI 分析OpenAIAnthropicGoogle

关注公众号

前途科技微信公众号

扫码关注,获取最新 AI 资讯

免费获取 AI 落地指南

3 步完成企业诊断,获取专属转型建议

已有 200+ 企业完成诊断