分词器
Tokenizer 将文本转换为张量,这些张量是模型的输入。它会进行文本的标准化和分词,应用分词算法,添加特殊标记,并将输出的 ID 解码回文本。
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
tokenizer("Sphinx of black quartz, judge my vow.", return_tensors="pt")
{
'input_ids': tensor([[ 2, 235277, 82913, 576, 2656, 30407, 235269, 11490, 970, 29871, 235265]]),
'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])
}本指南涵盖加载、编码、解码、批处理以及可用的分词器后端。
加载分词器
使用 AutoTokenizer 类或特定于模型的 tokenizer 类加载 tokenizer。
AutoTokenizer.from_pretrained() 会读取模型配置,解析出正确的 tokenizer 类,并返回其实例。你无需事先知道 tokenizer 的类名。大多数 tokenizer 都会解析为 TokenizersBackend 的子类,这是 Tokenizers 库中基于 Rust 构建的快速 tokenizer。
使用 AutoTokenizer 进行加载是推荐的方法。
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")模型特定的分词类是一个预先配置好的 TokenizersBackend,它使用了模型训练时所用的确切分词配置(归一化器、预分词器、特殊标记约定等)。
使用特定于模型的类来初始化一个用于训练的空分词器,或传递特定于模型的参数,例如 vocab 或 merges(请参阅 自定义分词器 指南以了解操作方法)。空分词器是最小化的,仅包含模型的特殊标记,例如 <pad>、<eos> 或 <bos>。
from transformers import GemmaTokenizer
tokenizer = GemmaTokenizer()
corpus = [
["Sphinx of black quartz, judge my vow."],
["Pack my box with five dozen liquor jugs."],
["How vexingly quick daft zebras jump!"],
]
new_tokenizer = tokenizer.train_new_from_iterator(corpus, vocab_size=1000)编码和解码
TokenizersBackend.call() 方法将文本或文本批次编码为 input_ids、attention_mask 以及其他模型输入。它还控制填充、截断和特殊标记的插入。
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
tokenizer("Sphinx of black quartz, judge my vow.", return_tensors="pt")
{
'input_ids': tensor([[ 2, 235277, 82913, 576, 2656, 30407, 235269, 11490, 970, 29871, 235265]]),
'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])
}TokenizersBackend.encode() 与之类似,但仅返回 input_ids。
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
input_ids = tokenizer.encode("Sphinx of black quartz, judge my vow.")
[2, 235277, 82913, 576, 2656, 30407, 235269, 11490, 970, 29871, 235265]TokenizersBackend.decode() 将单条或批量的分词 input_ids 转换回文本。
tokenizer.decode(input_ids)
'<bos>Sphinx of black quartz, judge my vow.'TokenizersBackend.decode() 会保留精确的分词空格。将 clean_up_tokenization_spaces 设为 True 可移除标点前的空格,将 skip_special_tokens 设为 True 可从输出中去除特殊标记。
tokenizer.decode(input_ids, skip_special_tokens=True)
'Sphinx of black quartz, judge my vow.'特殊标记
特殊标记用于标识序列中的结构边界,例如序列起始位置或填充位置。每个模型都定义了自己的一组特殊标记。当您调用分词器时,它会自动添加这些标记。
input_ids = tokenizer.encode("Sphinx of black quartz, judge my vow.")
[2, 235277, 82913, 576, 2656, 30407, 235269, 11490, 970, 29871, 235265]
tokenizer.decode(input_ids)
'<bos>Sphinx of black quartz, judge my vow.'使用 extra_special_tokens 参数注册额外的命名特殊标记。多模态模型将它们用作图像、视频或音频的占位符。
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(
"google/gemma-3-4b-pt",
extra_special_tokens={"image_token": "<image>"}
)批处理
批量处理会在单次调用中对多个序列进行分词。TokenizersBackend 基于 Rust 的后端能够跨线程并行处理任务,因此处理大批量数据时速度更快。
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
tokenizer(
[
"Sphinx of black quartz, judge my vow.",
"Pack my box with five dozen liquor jugs.",
"How vexingly quick daft zebras jump!"
],
return_tensors="pt"
)批处理要求所有序列具有相同的长度。填充和截断是处理不同长度序列的策略。
填充
Padding 会添加特殊标记,使较短的序列与批次中最长的序列长度一致。注意力掩码将填充位置标记为 0,以便模型忽略这些位置。设置 padding=True 可将序列填充至最长序列的长度,或传入 max_length 以填充至固定长度。
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
tokenizer(
[
"Sphinx of black quartz, judge my vow.",
"Pack my box with five dozen liquor jugs.",
"How vexingly quick daft zebras jump!"
],
return_tensors="pt",
padding=True,
)
{
'input_ids': tensor([
[ 2, 235277, 82913, 576, 2656, 30407, 235269, 11490, 970, 29871, 235265],
[ 0, 2, 6519, 970, 3741, 675, 4105, 25955, 42184, 225789, 235265],
[ 0, 2, 2299, 73378, 17844, 4320, 224463, 4949, 48977, 9902, 235341]
]),
'attention_mask': tensor([
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
])
}大型语言模型在左侧进行填充,以避免干扰生成过程,因为生成过程是从右侧预测下一个 token 的。
截断
截断(Truncation)会裁剪 token,使序列长度不超过最大长度。设置 truncation=True 并指定 max_length 即可启用该功能。
填充和截断协同工作。较短的序列会获得填充标记,而较长的序列则会丢失末尾的标记。两者共同作用,生成一个紧凑的矩形张量。
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
tokenizer(
[
"Sphinx of black quartz, judge my vow.",
"Pack my box with five dozen liquor jugs.",
"How vexingly quick daft zebras jump!"
],
return_tensors="pt",
padding=True,
truncation=True,
max_length=5
)
{
'input_ids': tensor([
[ 2, 235277, 82913, 576, 2656],
[ 2, 6519, 970, 3741, 675],
[ 2, 2299, 73378, 17844, 4320]
]),
'attention_mask': tensor([
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]
])
}后端
每个模型分词器都在单个文件中定义,并支持四种分词后端。
| backend | 实现 | 描述 |
|---|---|---|
| TokenizersBackend | 分词器 | 大多数模型的默认值 |
| SentencePieceBackend | SentencePiece | 需要 SentencePiece 的模型 |
| PythonBackend | Python | 需要专用自定义分词器的模型 |
| MistralCommonBackend | mistral-common | Mistral 和 Pixtral 模型 |
所有后端均继承自 PreTrainedTokenizerBase,并共享用于编码、解码、填充、截断、保存和加载的相同 API。区别在于底层运行的分词流水线不同。
调用 from_pretrained() 时,AutoTokenizer 会选择最佳可用的后端。
- 它会读取
tokenizer_config.json文件中的tokenizer_class字段。 - 注册表将
tokenizer_class匹配到类名。解析后的类继承自四个后端之一。例如,GemmaTokenizer 继承自 TokenizersBackend,而 SiglipTokenizer 继承自 SentencePieceBackend。 某些模型(如 GLM)直接映射到 TokenizersBackend,因为tokenizer.json文件完整描述了处理流程。GemmaTokenizer 作为子类存在,因为它在 Python 中定义了tokenizer.json未涵盖的额外模型特定设置。 当诸如 mistral-common 之类的后端未安装时,AutoTokenizer 会回退到 TokenizersBackend。
回退到 TokenizersBackend
部分模型没有专用的分词器类,且某些检查点的 tokenizer_class 与其实际的 tokenizer.json 文件不匹配。AutoTokenizer 通过通用的 TokenizersBackend 从 tokenizer.json 加载流水线,从而处理这两种情况。它优先使用序列化后的分词器,而非来自 Hub 的类名,这可以修复诸如不匹配的 tokenizer_class 导致生成错误 token id 之类的问题。
检查点会解析为通用的 TokenizersBackend,原因有三种之一。
| 原因 | 行为 | 示例 |
|---|---|---|
| 没有专用的分词器类 | 模型类型直接映射到 TokenizersBackend,因为 tokenizer.json 完整地描述了该流水线。 | GLM、Granite、OLMo 2、GPT BigCode |
| 已知错误的 Hub 分词器类 | Hub 上记录的 tokenizer_class 与该模型类型不匹配,因此 AutoTokenizer 会忽略它,转而加载 tokenizer.json。 | DeepSeek V3、LLaVA、Qwen2、ModernBERT |
| 特定检查点覆盖 | 其 Hub 配置仍需修复的检查点会通过其模型 ID 进行匹配,并强制指定到后端。 | deepseek-ai/DeepSeek-R1-Distill-*, Salesforce/blip2-*, google/umt5-small |
随着 Hub 上的配置被逐步修正,受影响的模型类型和检查点数量也在增加。当前集合请参见 tokenization_auto.py 中的 MODELS_WITH_INCORRECT_HUB_TOKENIZER_CLASS 和 MODEL_IDS_TO_TOKENIZERS_BACKEND 定义。
回退机制是自动的,不会改变你调用 from_pretrained() 的方式。生成的 tokenizer 的编码和解码行为完全遵循 tokenizer.json 中的定义。
使用 backend 属性检查分词器正在使用哪个后端。
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
tokenizer.backend
'tokenizers'检查分词器架构
使用 _tokenizer 属性检查分词器的内部组件(normalizer、pre-tokenizer、model、decoder)。
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
print(tokenizer._tokenizer.normalizer)
print(tokenizer._tokenizer.pre_tokenizer)
print(tokenizer._tokenizer.model)
print(tokenizer._tokenizer.decoder)资源
- Transformers v5 中的分词 一文介绍了新分词后端背后的设计动机。
- 请查阅迁移指南,以了解分词相关的变更。