Transformers 接入 🤗 Tokenizers 快速分词器:PreTrainedTokenizerFast 的两种加载方式与底层实现
本文以 docs/source/es/fast_tokenizers.md 为基础,讲解如何把用 🤗 Tokenizers 库训练出的自定义分词器接入当前 transformers 仓库,覆盖 PreTrainedTokenizerFast(即本仓库中的 TokenizersBackend 别名)的两种加载方式、保存复用流程,以及背后的源码级加载机制。读完本文,你将能够独立完成"训练自定义 BPE 分词器 → 序列化为 JSON → 在 Transformers 中加载并直接用于编码、批量处理与训练"的完整闭环。
一、背景:什么是快速分词器(Fast Tokenizer)
在 transformers 中,PreTrainedTokenizerFast 是一个基于 🤗 Tokenizers 库(Rust 核心实现)的分词器封装。与纯 Python 实现的慢速分词器不同,快速分词器的分词管线(规范化、预分词、模型、后处理)全部运行在 Rust 底层,因此在大批量文本编码时具有明显性能优势,并且天然支持 padding、truncation 等批处理特性。
在当前仓库的源码中,这一角色由 TokenizersBackend 类承担。位于 src/transformers/tokenization_utils_tokenizers.py 的类定义说明中写道:
"Base class for all fast tokenizers (wrapping HuggingFace tokenizers library)."
而在该文件末尾,可以看到向后兼容的别名声明:
# Backward-compatible alias: allow referring to TokenizersBackend as PreTrainedTokenizerFast
PreTrainedTokenizerFast = TokenizersBackend
也就是说,from transformers import PreTrainedTokenizerFast 实际导入的正是 TokenizersBackend,它继承自 src/transformers/tokenization_utils_base.py 中的 PreTrainedTokenizerBase,共享全部编码、解码、填充、截断、保存与加载 API。本文沿用文档中的 PreTrainedTokenizerFast 名称进行讲解。
二、第一步:用 🤗 Tokenizers 训练一个自定义分词器
在把分词器接入 Transformers 之前,先用 🤗 Tokenizers 库训练一个简单的 BPE 分词器。以下代码完整来自原文档,并补充了注释说明每一行在管线中的角色:
>>> from tokenizers import Tokenizer
>>> from tokenizers.models import BPE
>>> from tokenizers.trainers import BpeTrainer
>>> from tokenizers.pre_tokenizers import Whitespace
>>> # 1. 实例化一个空的分词器,并指定模型类型为 BPE
>>> tokenizer = Tokenizer(BPE(unk_token="[UNK]"))
>>> # 2. 创建 BPE 训练器,注册特殊 token
>>> trainer = BpeTrainer(special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"])
>>> # 3. 设置预分词器:按空白切分(例如"Hello world"会被切成两个词)
>>> tokenizer.pre_tokenizer = Whitespace()
>>> # 4. 在文本文件列表上训练(files 为存放训练语料的文件路径列表)
>>> files = [...]
>>> tokenizer.train(files, trainer)
这里有几个值得注意的细节:
BPE(unk_token="[UNK]")为 BPE 模型指定了未知 token;遇到词表中不存在的片段时会回退到[UNK]。BpeTrainer(special_tokens=[...])在训练时会把这些特殊 token 优先加入词表并保持稳定。文档示例中使用的是 BERT 风格的[CLS]/[SEP]/[PAD]/[MASK]约定;你也可以根据模型需要换成<bos>/<eos>/<pad>等风格。- 训练完成后,这个
tokenizer对象就是一个完整的、可独立工作的分词器,它可以在当前运行环境中继续使用,也可以保存为 JSON 文件供以后复用。
从源码结构看,当前仓库为 🤗 Tokenizers 的各类模型都提供了对应的训练器映射,见 src/transformers/tokenization_utils_tokenizers.py 中的 MODEL_TO_TRAINER_MAPPING:
MODEL_TO_TRAINER_MAPPING = {
"BPE": BpeTrainer,
"Unigram": UnigramTrainer,
"WordLevel": WordLevelTrainer,
"WordPiece": WordPieceTrainer,
}
这四种模型(BPE、Unigram、WordLevel、WordPiece)都能以同样的方式训练后接入 Transformers。
三、加载方式一:直接从分词器对象实例化(tokenizer_object)
训练完成后,最简单的方式是把 tokenizers.Tokenizer 对象直接交给 PreTrainedTokenizerFast。构造函数接受一个名为 tokenizer_object 的参数:
>>> from transformers import PreTrainedTokenizerFast
>>> fast_tokenizer = PreTrainedTokenizerFast(tokenizer_object=tokenizer)
这一步背后发生了什么?查看 TokenizersBackend 的类文档字符串(src/transformers/tokenization_utils_tokenizers.py),可以看到它为 __init__ 追加的说明:
tokenizer_object ([`tokenizers.Tokenizer`]):
A [`tokenizers.Tokenizer`] object from 🤗 tokenizers to instantiate from.
tokenizer_file ([`str`]):
A path to a local JSON file representing a previously serialized [`tokenizers.Tokenizer`] object from 🤗
tokenizers.
tokenizer_object 参数接受一个已实例化的 tokenizers.Tokenizer,PreTrainedTokenizerFast 会直接复用其底层的 Rust 分词管线,因此不需要任何序列化往返,适合在同一个运行环境中"训练完立即使用"的场景。
实例化之后,这个 fast_tokenizer 就拥有了 Transformers 分词器的全部共享能力,包括:
__call__:编码文本并返回包含input_ids、attention_mask的BatchEncoding对象;encode/decode:仅返回/还原 token id 序列;padding、truncation、max_length等批处理参数;save_pretrained/from_pretrained等保存加载 API。
这些方法的实现位于其基类 src/transformers/tokenization_utils_base.py 中,例如 encode(第 2241 行)、__call__(第 2418 行)与 decode(第 2853 行)都定义在 PreTrainedTokenizerBase 内。decode 支持 skip_special_tokens 参数以剔除特殊 token,并支持传入单个序列或批次序列。
四、加载方式二:保存为 JSON 后从文件加载(tokenizer_file)
如果希望把分词器保存下来供以后复用(比如持久化到磁盘、随模型一起分发),可以先把它序列化为单个 JSON 文件:
>>> tokenizer.save("tokenizer.json")
save 是 🤗 Tokenizers 库 Tokenizer 对象的方法,它会把完整的管线(模型、词表、合并规则、预分词器、后处理器等)导出为一个自包含的 tokenizer.json 文件——快速分词器只需这一个文件即可完整还原,无需额外的 vocab.json / merges.txt。
随后,把这个 JSON 文件的路径通过 tokenizer_file 参数传给 PreTrainedTokenizerFast:
>>> from transformers import PreTrainedTokenizerFast
>>> fast_tokenizer = PreTrainedTokenizerFast(tokenizer_file="tokenizer.json")
加载后,它同样拥有 Transformers 分词器的全部共享方法,可以直接用于下游任务。原文档将这两种加载方式并列介绍:tokenizer_object 适合同一运行环境内的即时使用,tokenizer_file 适合跨进程、跨机器、随仓库分发的场景。
值得一提的是,tokenizer.json 正是当前仓库定义的标准快速分词器文件名常量,见 src/transformers/tokenization_utils_tokenizers.py:
TOKENIZER_FILE = "tokenizer.json"
从 JSON 加载时的源码级处理
从文件加载并非简单反序列化。TokenizersBackend.convert_to_native_format(src/transformers/tokenization_utils_tokenizers.py)会解析 tokenizer.json 并执行一系列还原工作:
- 用
TokenizerFast.from_file(fast_tokenizer_file)加载 Rust 端分词器; - 提取并透传
post_processor、padding、truncation配置,保证 JSON 中烘焙的填充/截断设置不会丢失; - 提取 BPE 的
merges(合并规则)并规范化为二元组列表; - 针对不同模型类型还原
vocab词表(如 WordLevel 还原为token -> id字典); - 若 JSON 中含 SentencePiece 的
Precompiled规范化器,还会解码其precompiled_charsmap以便 T5 等模型使用。
因此,通过 tokenizer_file 加载得到的分词器在行为上与原始对象完全一致。
五、保存与再加载:与 AutoTokenizer 生态的衔接
在 Transformers 的标准工作流中,更常见的做法是把快速分词器与模型一起保存,并用 AutoTokenizer 统一加载:
>>> fast_tokenizer.save_pretrained("./my_tokenizer_dir/")
>>> from transformers import AutoTokenizer
>>> tokenizer = AutoTokenizer.from_pretrained("./my_tokenizer_dir/")
save_pretrained 在 TokenizersBackend 中得到了扩展(src/transformers/tokenization_utils_tokenizers.py),新增了 save_format 参数,支持:
save_format=None或"hf":默认的 HuggingFace 格式;save_format="mistral":以原生tekken.json格式保存(需要原始 tekken 词表文件可用)。
AutoTokenizer.from_pretrained 的完整解析流程定义在 src/transformers/models/auto/tokenization_auto.py:它读取 tokenizer_config.json 中的 tokenizer_class 字段,在注册表中匹配到对应类,再调用 from_pretrained 完成加载。当前仓库中,AutoTokenizer.from_pretrained 还接受一个 backend 参数(默认 "tokenizers"),可显式指定使用 🤗 Tokenizers 后端或 SentencePiece 后端:
>>> tokenizer = AutoTokenizer.from_pretrained("...", backend="tokenizers") # 默认,使用 tokenizers 库
>>> tokenizer = AutoTokenizer.from_pretrained("...", backend="sentencepiece") # 使用 SentencePiece 后端
在当前的 v5 架构中,use_fast 参数已被忽略(源码中明确注释 "V5: Always use fast tokenizers, ignore use_fast parameter"),快速分词器是默认路径。
六、仓库中的实际应用:转换脚本中的 PreTrainedTokenizerFast
PreTrainedTokenizerFast 的 tokenizer_object / tokenizer_file 两种加载方式并不是孤立的设计,它们在当前仓库的模型权重转换脚本中被广泛使用。例如:
- src/transformers/models/llama/convert_llama_weights_to_hf.py 第 462 行用
PreTrainedTokenizerFast构建转换后的分词器; - src/transformers/models/gpt_oss/convert_gpt_oss_weights_to_hf.py 第 424 行同样通过
PreTrainedTokenizerFast完成分词器迁移; - src/transformers/models/llama4/convert_llama4_weights_to_hf.py、src/transformers/models/mllama/convert_mllama_weights_to_hf.py 等脚本也有相同用法。
这些脚本的共性模式是:读取第三方权重中的原生词表/分词配置,组装成 PreTrainedTokenizerFast 实例,再导出为标准的 tokenizer.json 与 tokenizer_config.json,从而让任意模型都能通过 AutoTokenizer 无缝加载。这印证了本文介绍的加载方式正是"外部分词器 → Transformers 生态"的官方通道。
七、加载之后:能做什么
无论采用哪种方式加载,fast_tokenizer 都具备完整的 Transformers 分词器 API。以下是几个最常用的能力(详细 API 说明可继续阅读 docs/source/en/main_classes/tokenizer.md):
编码单个文本:调用分词器对象本身,返回 BatchEncoding,其中包含可直接送入模型的张量:
>>> encoded = fast_tokenizer("Hello world", return_tensors="pt")
>>> encoded["input_ids"], encoded["attention_mask"]
批量处理:传入文本列表,配合 padding=True、truncation=True、max_length 等参数,即可得到形状一致的矩形张量。填充位置会在 attention_mask 中标记为 0,模型会忽略这些位置。
解码还原:
>>> fast_tokenizer.decode(encoded["input_ids"], skip_special_tokens=True)
'Hello world'
对于自定义训练的分词器,建议在训练语料中覆盖目标领域文本,并在训练器(如 BpeTrainer)中合理设置 vocab_size 与 min_frequency,以平衡词表规模与覆盖度。
小结
本文围绕 docs/source/es/fast_tokenizers.md 展开,完整复现了"🤗 Tokenizers 训练自定义分词器 → 接入 Transformers"的两条标准路径:通过 tokenizer_object 直接传递运行时对象,或通过 tokenizer_file 从序列化后的 tokenizer.json 加载。结合 src/transformers/tokenization_utils_tokenizers.py 的源码可以看到,PreTrainedTokenizerFast 就是 TokenizersBackend 的别名,其底层由 Rust 分词管线驱动,并通过 convert_to_native_format 对 JSON 中的词表、合并规则、后处理器等配置进行完整还原;再配合 AutoTokenizer 的自动解析与 backend 参数,自定义分词器可以无缝融入标准的模型加载、训练与推理流程。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0632
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00