# 分词器

Tokenizer 将文本转换为张量，这些张量是模型的输入。它会进行文本的标准化和分词，应用分词算法，添加特殊标记，并将输出的 ID 解码回文本。

```py
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](/docs/transformers/v5.23.0/zh/model_doc/auto#transformers.AutoTokenizer) 类或特定于模型的 tokenizer 类加载 tokenizer。

[AutoTokenizer.from_pretrained()](/docs/transformers/v5.23.0/zh/model_doc/auto#transformers.AutoTokenizer.from_pretrained) 会读取模型配置，解析出正确的 tokenizer 类，并返回其实例。您无需事先了解 tokenizer 类。大多数 tokenizer 会解析为 [TokenizersBackend](/docs/transformers/v5.23.0/zh/main_classes/tokenizer#transformers.TokenizersBackend) 的子类，这是 [Tokenizers](https://huggingface.co/docs/tokenizers/index) 库中基于 Rust 的快速 tokenizer。

使用 [AutoTokenizer](/docs/transformers/v5.23.0/zh/model_doc/auto#transformers.AutoTokenizer) 进行加载是推荐的方法。

```py
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
```

模型特定的分词类是一个预先配置好的 [TokenizersBackend](/docs/transformers/v5.23.0/zh/main_classes/tokenizer#transformers.TokenizersBackend)，它使用了模型训练时所用的确切分词配置（归一化器、预分词器、特殊标记约定等）。

使用特定于模型的类来初始化一个用于训练的空分词器，或传递特定于模型的参数，例如 `vocab` 或 `merges`（请参阅 [自定义分词器](./custom_tokenizers) 指南以了解操作方法）。空分词器是最小化的，仅包含模型的特殊标记，例如 `<pad>`、`<eos>` 或 `<bos>`。

```py
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__()](/docs/transformers/v5.23.0/zh/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.__call__) 方法将文本或文本批次编码为 `input_ids`、`attention_mask` 以及其他模型输入。它还控制填充、截断和特殊标记的插入。

```py
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()](/docs/transformers/v5.23.0/zh/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.encode) 与之类似，但仅返回 `input_ids`。

```py
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()](/docs/transformers/v5.23.0/zh/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.decode) 将单条或批量的分词 `input_ids` 转换回文本。

```py
tokenizer.decode(input_ids)
'<bos>Sphinx of black quartz, judge my vow.'
```

[TokenizersBackend.decode()](/docs/transformers/v5.23.0/zh/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.decode) 会保留精确的分词空格。将 `clean_up_tokenization_spaces` 设为 True 可移除标点前的空格，将 `skip_special_tokens` 设为 True 可从输出中去除特殊标记。

```py
tokenizer.decode(input_ids, skip_special_tokens=True)
'Sphinx of black quartz, judge my vow.'
```

## 特殊标记

特殊标记用于标识序列中的结构边界，例如序列起始位置或填充位置。每个模型都定义了自己的一组特殊标记。当您调用分词器时，它会自动添加这些标记。

```py
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` 参数注册额外的命名特殊标记。多模态模型将它们用作图像、视频或音频的占位符。

```py
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained(
    "google/gemma-3-4b-pt",
    extra_special_tokens={"image_token": "<image>"}
)
```

## 批处理

批量处理会在单次调用中对多个序列进行分词。[TokenizersBackend](/docs/transformers/v5.23.0/zh/main_classes/tokenizer#transformers.TokenizersBackend) 基于 Rust 的后端能够跨线程并行处理任务，因此处理大批量数据时速度更快。

```py
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` 以填充至固定长度。

```py
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]
    ])
}
```

> [!NOTE]
> 大型语言模型在*左侧*进行填充，以避免干扰生成过程，因为生成过程是从*右侧*预测下一个 token 的。

### 截断

截断（Truncation）会裁剪 token，使序列长度不超过最大长度。设置 `truncation=True` 并指定 `max_length` 即可启用该功能。

填充和截断协同工作。较短的序列会获得填充标记，而较长的序列则会丢失末尾的标记。两者共同作用，生成一个紧凑的矩形张量。

```py
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](/docs/transformers/v5.23.0/zh/main_classes/tokenizer#transformers.TokenizersBackend)    | [分词器](https://huggingface.co/docs/tokenizers)          | 大多数模型的默认值                        |
| [SentencePieceBackend](/docs/transformers/v5.23.0/zh/main_classes/tokenizer#transformers.SentencePieceBackend) | [SentencePiece](https://github.com/google/sentencepiece)      | 需要 SentencePiece 的模型                 |
| [PythonBackend](/docs/transformers/v5.23.0/zh/main_classes/tokenizer#transformers.PythonBackend)        | Python                                                        | 需要专用自定义分词器的模型 |
| [MistralCommonBackend](/docs/transformers/v5.23.0/zh/model_doc/mistral#transformers.MistralCommonBackend) | [mistral-common](https://mistralai.github.io/mistral-common/) | Mistral 和 Pixtral 模型                     |

所有后端均继承自 [PreTrainedTokenizerBase](/docs/transformers/v5.23.0/zh/internal/tokenization_utils#transformers.PreTrainedTokenizerBase)，并共享用于编码、解码、填充、截断、保存和加载的相同 API。区别在于底层运行的分词流水线不同。

调用 [from_pretrained()](/docs/transformers/v5.23.0/zh/model_doc/auto#transformers.AutoTokenizer.from_pretrained) 时，[AutoTokenizer](/docs/transformers/v5.23.0/zh/model_doc/auto#transformers.AutoTokenizer) 会选择最佳可用的后端。

1. 它会读取 `tokenizer_config.json` 文件中的 `tokenizer_class` 字段。
2. 注册表将 `tokenizer_class` 匹配到类名。解析后的类继承自四个后端之一。例如，[GemmaTokenizer](/docs/transformers/v5.23.0/zh/model_doc/gemma#transformers.GemmaTokenizer) 继承自 [TokenizersBackend](/docs/transformers/v5.23.0/zh/main_classes/tokenizer#transformers.TokenizersBackend)，而 [SiglipTokenizer](/docs/transformers/v5.23.0/zh/model_doc/siglip#transformers.SiglipTokenizer) 继承自 [SentencePieceBackend](/docs/transformers/v5.23.0/zh/main_classes/tokenizer#transformers.SentencePieceBackend)。某些模型（如 GLM）直接映射到 [TokenizersBackend](/docs/transformers/v5.23.0/zh/main_classes/tokenizer#transformers.TokenizersBackend)，因为 `tokenizer.json` 文件完整描述了处理流程。[GemmaTokenizer](/docs/transformers/v5.23.0/zh/model_doc/gemma#transformers.GemmaTokenizer) 作为子类存在，因为它在 Python 中定义了 `tokenizer.json` 未涵盖的额外模型特定设置。当诸如 mistral-common 之类的后端未安装时，[AutoTokenizer](/docs/transformers/v5.23.0/zh/model_doc/auto#transformers.AutoTokenizer) 会回退到 [TokenizersBackend](/docs/transformers/v5.23.0/zh/main_classes/tokenizer#transformers.TokenizersBackend)。

### 回退到 TokenizersBackend

部分模型没有专用的分词器类，且某些检查点的 `tokenizer_class` 与其实际的 `tokenizer.json` 文件不匹配。[AutoTokenizer](/docs/transformers/v5.23.0/zh/model_doc/auto#transformers.AutoTokenizer) 通过通用的 [TokenizersBackend](/docs/transformers/v5.23.0/zh/main_classes/tokenizer#transformers.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](https://github.com/huggingface/transformers/blob/main/src/transformers/models/auto/tokenization_auto.py) 中的 `MODELS_WITH_INCORRECT_HUB_TOKENIZER_CLASS` 和 `MODEL_IDS_TO_TOKENIZERS_BACKEND` 定义。

回退机制是自动的，不会改变你调用 [from_pretrained()](/docs/transformers/v5.23.0/zh/model_doc/auto#transformers.AutoTokenizer.from_pretrained) 的方式。生成的 tokenizer 的编码和解码行为与 `tokenizer.json` 中的定义完全一致。

使用 `backend` 属性检查分词器正在使用哪个后端。

```py
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
tokenizer.backend
'tokenizers'
```

## 检查分词器架构

使用 `_tokenizer` 属性检查分词器的内部组件（normalizer、pre-tokenizer、model、decoder）。

```py
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 中的分词](https://huggingface.co/blog/tokenizers) 一文介绍了新分词后端背后的设计动机。
- 请查阅[迁移指南](https://github.com/huggingface/transformers/blob/main/MIGRATION_GUIDE_V5.md#tokenization)，以了解分词相关的变更。

