首页
/ Transformers 接入 🤗 Tokenizers 快速分词器:PreTrainedTokenizerFast 的两种加载方式与底层实现

Transformers 接入 🤗 Tokenizers 快速分词器:PreTrainedTokenizerFast 的两种加载方式与底层实现

2026-09-09 09:51:27作者:郁楠烈Hubert

本文以 docs/source/es/fast_tokenizers.md 为基础,讲解如何把用 🤗 Tokenizers 库训练出的自定义分词器接入当前 transformers 仓库,覆盖 PreTrainedTokenizerFast(即本仓库中的 TokenizersBackend 别名)的两种加载方式、保存复用流程,以及背后的源码级加载机制。读完本文,你将能够独立完成"训练自定义 BPE 分词器 → 序列化为 JSON → 在 Transformers 中加载并直接用于编码、批量处理与训练"的完整闭环。

一、背景:什么是快速分词器(Fast Tokenizer)

在 transformers 中,PreTrainedTokenizerFast 是一个基于 🤗 Tokenizers 库(Rust 核心实现)的分词器封装。与纯 Python 实现的慢速分词器不同,快速分词器的分词管线(规范化、预分词、模型、后处理)全部运行在 Rust 底层,因此在大批量文本编码时具有明显性能优势,并且天然支持 paddingtruncation 等批处理特性。

在当前仓库的源码中,这一角色由 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.TokenizerPreTrainedTokenizerFast 会直接复用其底层的 Rust 分词管线,因此不需要任何序列化往返,适合在同一个运行环境中"训练完立即使用"的场景。

实例化之后,这个 fast_tokenizer 就拥有了 Transformers 分词器的全部共享能力,包括:

  • __call__:编码文本并返回包含 input_idsattention_maskBatchEncoding 对象;
  • encode / decode:仅返回/还原 token id 序列;
  • paddingtruncationmax_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_formatsrc/transformers/tokenization_utils_tokenizers.py)会解析 tokenizer.json 并执行一系列还原工作:

  • TokenizerFast.from_file(fast_tokenizer_file) 加载 Rust 端分词器;
  • 提取并透传 post_processorpaddingtruncation 配置,保证 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_pretrainedTokenizersBackend 中得到了扩展(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

PreTrainedTokenizerFasttokenizer_object / tokenizer_file 两种加载方式并不是孤立的设计,它们在当前仓库的模型权重转换脚本中被广泛使用。例如:

这些脚本的共性模式是:读取第三方权重中的原生词表/分词配置,组装成 PreTrainedTokenizerFast 实例,再导出为标准的 tokenizer.jsontokenizer_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=Truetruncation=Truemax_length 等参数,即可得到形状一致的矩形张量。填充位置会在 attention_mask 中标记为 0,模型会忽略这些位置。

解码还原

>>> fast_tokenizer.decode(encoded["input_ids"], skip_special_tokens=True)
'Hello world'

对于自定义训练的分词器,建议在训练语料中覆盖目标领域文本,并在训练器(如 BpeTrainer)中合理设置 vocab_sizemin_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 参数,自定义分词器可以无缝融入标准的模型加载、训练与推理流程。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
900
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
927
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
603
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
397
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
525