首页
/ 🤗 Transformers Tokenizer 完全指南:从 PreTrainedTokenizer 到多模态特殊 Token 管理

🤗 Transformers Tokenizer 完全指南:从 PreTrainedTokenizer 到多模态特殊 Token 管理

2026-09-09 20:21:37作者:蔡怀权

本文以 docs/source/ko/main_classes/tokenizer.md 为基础撰写,并深入当前仓库源码验证实现细节。

🤗 Transformers 中的 Tokenizer(分词器) 负责将原始文本转换为模型可消费的数值输入,是任何 NLP/多模态模型推理与训练流程的第一环。本文围绕该仓库的 tokenizer 主类文档,系统讲解纯 Python 实现与基于 Rust 的 "Fast" 实现两套体系、核心基类 PreTrainedTokenizer / PreTrainedTokenizerFast、编码输出容器 BatchEncoding,以及多模态模型(如 LLaVA)特有的 extra_special_tokens 扩展机制。读完本文,你将掌握 tokenizer 的完整调用链、各类特殊 Token 的管理方法,以及如何在多模态场景下为 tokenizer 挂载自定义特殊 Token。

一、Tokenizer 在模型输入管线中的角色

一个 tokenizer 的核心职责是为模型准备输入:把字符串切分为子词(sub-word)token,再将 token 字符串映射为整数 ID,并生成 attention_mask 等模型输入。该库为几乎所有模型都内置了对应 tokenizer。

从源码结构看,tokenizer 体系呈现"基类 + 后端"的分层设计:

  • PreTrainedTokenizerBase:所有 tokenizer 后端的公共基类,定义在 tokenization_utils_base.py,负责编码方法、特殊 Token 管理、加载/保存等公共逻辑;
  • PythonBackend:慢速(slow)tokenizer 的基类,定义在 tokenization_python.py,并在同文件末尾以 PreTrainedTokenizer = PythonBackend 对外暴露;
  • TokenizersBackend:Fast tokenizer 的基类,定义在 tokenization_utils_tokenizers.py,同样以 PreTrainedTokenizerFast = TokenizersBackend 对外暴露;
  • SentencePieceBackend:SentencePiece 系 tokenizer 的专用后端,定义在 tokenization_utils_sentencepiece.py

也就是说,绝大多数模型 tokenizer 都是 PreTrainedTokenizer(Python)或 PreTrainedTokenizerFast(Fast)的子类,而这两个类共同继承 PreTrainedTokenizerBase

二、两种实现:纯 Python 与 "Fast"(Rust)

库中绝大多数 tokenizer 都提供两个版本

  1. 纯 Python 实现:完整、易读,不依赖外部编译库;
  2. "Fast" 实现:基于 Rust 库 🤗 Tokenizers 构建,带来两大核心优势:
    • 显著的加速,尤其在批量 tokenization(batch tokenization)场景下;
    • 额外的对齐方法,可在原始字符串(字符与单词)空间与 token 空间之间互相映射,例如获取"包含某个字符的 token 的索引",或"某个 token 对应的字符区间(span)"。

Fast 版本带来的对齐能力在问答、抽取式任务与可视化场景中极为实用,例如定位某段答案文本落在哪些 token 上。

两个基类 PreTrainedTokenizerPreTrainedTokenizerFast 实现了以下公共能力:

  • 加载与保存:从本地文件/目录实例化 tokenizer,或从库提供的预训练 tokenizer(经 Hub 下载)加载,也可将 tokenizer 保存到本地;
  • 编码与解码:tokenization(字符串 → 子词 token 字符串)、token 字符串 ↔ ID 互转,以及 encoding/decoding(tokenize + 转为整数,以及逆过程);
  • 词汇扩展:以与底层结构(BPE、SentencePiece、WordPiece 等)无关的方式向词汇表添加新 token;
  • 特殊 Token 管理:添加 mask、句首(BOS)等特殊 token,将其绑定到 tokenizer 属性以便随时访问,并确保这些 token 在 tokenization 过程中不会被切开(默认 split_special_tokens=False)。

判断当前 tokenizer 是否为 Fast

PythonBackend.is_fast 属性返回 False(见 tokenization_python.py),Fast 后端则返回 True。也可直接通过 tokenizer.is_fast 在运行时判断,并据此决定能否使用对齐类方法。

三、核心方法速览

依据原文档的 autodoc 列表,PreTrainedTokenizerPreTrainedTokenizerFast 暴露的核心方法完全一致:

方法 作用
__call__ 主入口方法,完成单条/批量文本的编码,返回 BatchEncoding
encode / decode 文本 → ID 列表 / ID 列表 → 文本
batch_decode 批量解码多个 ID 序列为文本
add_tokens 向词汇表添加新 token(与底层算法无关)
add_special_tokens 添加特殊 token 并自动绑定属性
apply_chat_template 将消息列表按模型对话模板渲染为输入
push_to_hub 将 tokenizer 上传共享到 Hub
all 其余全部公开方法(详见 autodoc 文档)

__call__ 的完整签名

tokenization_utils_base.pyPreTrainedTokenizerBase.__call__ 的签名为依据,常用参数包括:

  • text / text_pair:单条或批量文本,支持 strlist[str](视为已预分词时需设 is_split_into_words=True)、list[list[str]]
  • text_target / text_pair_target:序列到序列任务中的目标端文本;
  • add_special_tokens:是否自动添加特殊 token,默认 True
  • paddingbool | str | PaddingStrategy,默认 False,可传 "max_length""longest"
  • truncationbool | str | TruncationStrategy,默认 None,可传 "longest_first" / "only_first" / "only_second"
  • max_lengthstride:截断与滑窗参数;
  • pad_to_multiple_of:填充对齐到某个数的整数倍(配合 padding="max_length" 使用);
  • padding_side"right""left",覆盖 tokenizer 默认的 padding_side
  • return_tensors"pt" / "tf" / "np",返回 PyTorch / TensorFlow / NumPy 张量;
  • return_token_type_idsreturn_attention_maskreturn_overflowing_tokensreturn_special_tokens_maskreturn_offsets_mappingreturn_length:控制返回哪些字段。

调用示例:

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
batch = tokenizer(
    ["Hello world", "Second sentence"],
    padding="longest",
    truncation=True,
    max_length=128,
    return_tensors="pt",
)
# batch["input_ids"], batch["attention_mask"] 可直接送入模型

四、BatchEncoding:编码输出容器

BatchEncodingPreTrainedTokenizerBase 的编码方法(__call__encode_plusbatch_encode_plus)的输出容器,定义在 tokenization_utils_base.py继承自 Python 字典(UserDict,因此可以像普通字典一样使用。

  • 当 tokenizer 为纯 Python 实现时,BatchEncoding 行为与标准 Python 字典完全一致,持有 input_idsattention_mask 等模型输入;
  • 当 tokenizer 为 Fast 实现时,BatchEncoding 额外携带 tokenizers.Encoding 信息(构造时通过 encoding 参数传入,见 L222-L243),从而提供字符串空间与 token 空间之间的高级对齐方法,例如 token_to_charschar_to_tokenword_to_tokenssequence_ids 等。

此外,BatchEncoding 在构造时可指定 tensor_typeprepend_batch_axis,将整数列表直接转换为 PyTorch / NumPy 张量(convert_to_tensors),并可通过 n_sequences 获知每条样本由 1 条还是 2 条序列构成。

五、多模态 Tokenizer 与 extra_special_tokens

什么是多模态 Tokenizer

任何一个 tokenizer 都可以成为 "multimodal"(多模态)tokenizer:即 tokenizer 会把所有相关特殊 token 作为自身属性保存,便于随时访问。例如从 LLaVA 这类视觉-语言模型加载 tokenizer 后,可以直接通过 tokenizer.image_token_id 拿到用作占位符的特殊图像 token。

这在模型实现中确实是硬依赖:以 modeling_llava.py 为例,LLaVA 前向时会用 config.image_token_id 构造图像 token 掩码并定位 input_ids == image_token_id 的位置以插入图像特征,因此该 token 必须是 tokenizer 可访问的固定 ID。

启用额外特殊 Token

任何类型的 tokenizer 都可启用额外特殊 token:通过 extra_special_tokens 传入,然后保存 tokenizer。额外特殊 token 不必与某种模态强绑定,凡是模型需要频繁访问的 token 都可以放进来。原文档示例中,保存在 output_dir 的 tokenizer 将直接拥有三个额外特殊 token:

from transformers import AutoTokenizer

vision_tokenizer = AutoTokenizer.from_pretrained(
    "llava-hf/llava-1.5-7b-hf",
    extra_special_tokens={"image_token": "<image>", "boi_token": "<image_start>", "eoi_token": "<image_end>"}
)
print(vision_tokenizer.image_token, vision_tokenizer.image_token_id)
# ("<image>", 32000)

底层实现原理

结合 tokenization_utils_base.py 源码,extra_special_tokens 的完整处理链如下:

  1. 兼容旧参数:V5 起若检测到已废弃的 additional_special_tokens 会先转换为 extra_special_tokens(L996-L998);
  2. 字典形式 → 模型专属特殊 Token:当 extra_special_tokens 传入的是 dict 时,调用 _set_model_specific_special_tokens(L1401-L1416),将 {"image_token": "<image>"} 这样的键值对追加进 SPECIAL_TOKENS_ATTRIBUTES 并写入 _special_tokens_map,这正是示例中 tokenizer.image_token 属性得以存在的根本原因;若是 list/tuple 则存入 _extra_special_tokens(L1029-L1038);
  3. 未入词汇表则自动追加:初始化末尾(tokenization_python.py)会把不在词汇表中的特殊 token 以 special_tokens=True 方式加入,因此 <image> 会自动获得新的 token ID(示例中为 32000);
  4. 统一暴露all_special_tokens / all_special_ids(L1365-L1399)会将命名特殊 token 与额外特殊 token 合并去重后返回;
  5. 持久化:保存 tokenizer 时,tokenizer_config 会写入 extra_special_tokens 字段(L2054-L2055),保证重新加载后属性依然可用。

额外特殊 token 会被视为 added tokens,在 tokenization 时不会被切开,且在解码时若设置 skip_special_tokens=True 也会被正确跳过(L949-L952)。

注意事项

  • extra_special_tokens 支持 list[str]tupledict[str, str] 三种形式,其他类型会抛出 TypeError(L1038);
  • 字典的 key 若以 _token 结尾且不在标准 SPECIAL_TOKENS_ATTRIBUTES 中,还会触发自动探测逻辑(L1039-L1047),即某些模型子类可能自动识别 xxx_token 类参数为模型专属 token;
  • 修改特殊 token 后必须保存 tokenizer,否则重新加载时属性不会保留;
  • 命名特殊 token(bos_tokeneos_tokenpad_tokencls_tokenmask_tokenunk_tokensep_token,见 L980-L988)与额外特殊 token 在 V5 中做了清晰分离,取用时应按需区分。

六、Fast tokenizer 的导入与相关文档

PreTrainedTokenizerFast 依赖 🤗 Tokenizers(Rust 库)。从该库获得的 tokenizers.Tokenizer 对象可以非常简单地加载进 🤗 Transformers——只需将 Rust 对象或 tokenizer.json 文件路径传给 Fast tokenizer 的构造/加载方法即可;TokenizersBackend.convert_to_native_formattokenization_utils_tokenizers.py)正是负责从 tokenizer.json、sentencepiece 模型、vocab/merges 等序列化文件重建 Rust 后端的核心逻辑。

详细导入方法可参阅仓库内的《Using tokenizers from 🤗 tokenizers》页面(对应英文版为 fast_tokenizers.md)。

七、快速实践清单

from transformers import AutoTokenizer

# 1. 加载(默认优先 Fast 版本)
tok = AutoTokenizer.from_pretrained("bert-base-uncased")
print(tok.is_fast)            # 判断是否为 Fast 实现

# 2. 编码与解码
ids = tok.encode("Hello world", add_special_tokens=True)
text = tok.decode(ids, skip_special_tokens=True)

# 3. 添加词汇(与 BPE/SentencePiece 结构无关)
tok.add_tokens(["my_new_token"])
print(tok.convert_tokens_to_ids("my_new_token"))

# 4. 添加特殊 token 并绑定属性
tok.add_special_tokens({"eos_token": "<|endoftext|>"})

# 5. 批量编码为张量
enc = tok(["a b c", "d e"], padding=True, truncation=True, return_tensors="pt")

# 6. 多模态额外特殊 token(保存后重新加载仍可用)
tok.save_pretrained("./my_tokenizer")
reloaded = AutoTokenizer.from_pretrained("./my_tokenizer")

总结而言,tokenizer 层是 Transformers 输入管线的统一入口:PreTrainedTokenizerBase 定义了公共协议,PythonBackendTokenizersBackend 分别承载慢速与 Fast 实现,BatchEncoding 统一输出,而 extra_special_tokens 机制则为多模态模型(如图像 token)提供了标准化的特殊 token 挂载方式——这四条主线构成了理解本仓库全部 2000+ 模型 tokenizer 的完整框架。

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

项目优选

收起
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.89 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
602
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
396
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
526