# 逐块地构建标记器 [[逐块地构建标记器]]

<CourseFloatingBanner chapter={6}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/zh-CN/chapter6/section8.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/zh-CN/chapter6/section8.ipynb"},
]} />

正如我们在前几节中看到的，标记化包括几个步骤：

- 规范化（任何认为必要的文本清理，例如删除空格或重音符号、Unicode 规范化等） 
- 预标记化（将输入拆分为单词） 
- 通过模型处理输入（使用预先拆分的词来生成一系列标记） 
- 后处理（添加标记器的特殊标记，生成注意力掩码和标记类型 ID） 

提醒一下，这里再看一下整个过程

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter6/tokenization_pipeline.svg" alt="The tokenization pipeline.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter6/tokenization_pipeline-dark.svg" alt="The tokenization pipeline.">
</div>

🤗 Tokenizers 库旨在为每个步骤提供多个选项，您可以将它们混合和匹配在一起。在本节中，我们将看到如何从头开始构建标记器，而不是像我们[第二节 2](/course/chapter6/2)那样从旧的标记器训练新的标记器.然后，您将能够构建您能想到的任何类型的标记器！

<Youtube id="MR8tZm5ViWU"/>

更准确地说，该库是围绕一个中央“Tokenizer”类构建的，构建这个类的每一部分可以在子模块的列表中重新组合：

- `normalizers` 包含你可以使用的所有可能的Normalizer类型（完整列表[在这里](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)）。 
- `pre_tokenizesr` 包含您可以使用的所有可能的PreTokenizer类型（完整列表[在这里](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)）。 
- `models` 包含您可以使用的各种类型的Model，如BPE、WordPiece和Unigram（完整列表[在这里](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)）。  
- `trainers` 包含所有不同类型的 trainer，你可以使用一个语料库训练你的模型（每种模型一个；完整列表[在这里](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)）。 
- `post_processors` 包含你可以使用的各种类型的PostProcessor（完整列表[在这里](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)）。 
- `decoders` 包含各种类型的Decoder，可以用来解码标记化的输出（完整列表[在这里](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)）。 

您可以[在这里](https://huggingface.co/docs/tokenizers/python/latest/components.html)找到完整的模块列表。

## 获取语​​料库 [[获取语​​料库]]

为了训练我们的新标记器，我们将使用一个小的文本语料库（因此示例运行得很快）。获取语​​料库的步骤与我们在[在这章的开始]((/course/chapter6/2)那一小节，但这次我们将使用[WikiText-2](https://huggingface.co/datasets/wikitext)数据集：

```python
from datasets import load_dataset

dataset = load_dataset("wikitext", name="wikitext-2-raw-v1", split="train")


def get_training_corpus():
    for i in range(0, len(dataset), 1000):
        yield dataset[i : i + 1000]["text"]
```

**get_training_corpus()** 函数是一个生成器，每次调用的时候将产生 1,000 个文本，我们将用它来训练标记器。

🤗 Tokenizers 也可以直接在文本文件上进行训练。以下是我们如何生成一个文本文件，其中包含我们可以在本地使用的来自 WikiText-2 的所有文本/输入：

```python
with open("wikitext-2.txt", "w", encoding="utf-8") as f:
    for i in range(len(dataset)):
        f.write(dataset[i]["text"] + "\n")
```

接下来，我们将向您展示如何逐块构建您自己的 BERT、GPT-2 和 XLNet 标记器。这将为我们提供三个主要标记化算法的示例：WordPiece、BPE 和 Unigram。让我们从 BERT 开始吧！

## 从头开始构建 WordPiece 标记器 [[从头开始构建 WordPiece 标记器]]

要使用 🤗 Tokenizers 库构建标记器，我们首先使用**model**实例化一个 **Tokenizer** 对象与  ，然后将 **normalizer** , **pre_tokenizer** , **post_processor** ， 和 **decoder** 属性设置成我们想要的值。

对于这个例子，我们将创建一个 **Tokenizer** 使用 WordPiece 模型：

```python
from tokenizers import (
    decoders,
    models,
    normalizers,
    pre_tokenizers,
    processors,
    trainers,
    Tokenizer,
)

tokenizer = Tokenizer(models.WordPiece(unk_token="[UNK]"))
```

我们必须指定 **unk_token** 这样模型才知道当它遇到以前没有见过的字符时要返回什么。我们可以在此处设置的其他参数包括我们模型的**vocab（字典）**（我们将训练模型，所以我们不需要设置它）和 **max_input_chars_per_word** 即每个单词的最大长度（比传递的值长的单词将被拆分）

标记化的第一步是规范化，所以让我们从它开始。 由于 BERT 被广泛使用，所以有一个可以使用的 `BertNormalizer`，我们可以为 BERT 设置经典的选项：`lowercase（小写）` 和 `strip_accents（去除音调）`，不言自明； `clean_text` 删除所有控制字符并将重复的空格替换为一个； 和 `handle_chinese_chars`，在汉字周围放置空格。 要实现 `bert-base-uncased` ，我们可以这样设置这个规范器：

```python
tokenizer.normalizer = normalizers.BertNormalizer(lowercase=True)
```

然而，一般来说，在构建新的标记器时，您可以使用已经在 🤗 Tokenizers库中实现的非常方便的normalizer——所以让我们看看如何手动创建 BERT normalizer。 该库提供了一个“Lowercase（小写）”的normalizer和一个“StripAccents”的normalizer，您可以使用“序列”组合多个normalizer：

```python
tokenizer.normalizer = normalizers.Sequence(
    [normalizers.NFD(), normalizers.Lowercase(), normalizers.StripAccents()]
)
```

我们也在使用 **NFD** Unicode normalizer，否则 **StripAccents** normalizer 无法正确识别带重音的字符，因此没办法删除它们。

正如我们之前看到的，我们可以使用 **normalize** 的 **normalize_str()** 方法查看它对给定文本的影响：

```python
print(tokenizer.normalizer.normalize_str("Héllò hôw are ü?"))
```

```python out
hello how are u?
```

<Tip>

**更进一步**如果您在包含 unicode 字符的字符串上测试先前normalizers的两个版本，您肯定会注意到这两个normalizers并不完全等效。
为了不过度使用 `normalizers.Sequence` 使版本过于复杂，我们没有包含当 `clean_text` 参数设置为 `True` 时 `BertNormalizer` 需要的正则表达式替换 - 这是默认行为。 但不要担心：通过在normalizer序列中添加两个 `normalizers.Replace` 可以在不使用方便的 `BertNormalizer` 的情况下获得完全相同的规范化。

</Tip>

接下来是预标记步骤。 同样，我们可以使用一个预构建的“BertPreTokenizer”：

```python
tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
```

或者我们可以从头开始构建它：

```python
tokenizer.pre_tokenizer = pre_tokenizers.Whitespace()
```

请注意，`Whitespace` 预标记器会在空格和所有非字母、数字或下划线字符的字符上进行拆分，因此在本次的例子中上会根据空格和标点符号进行拆分：

```python
tokenizer.pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.")
```

```python out
[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)),
 ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))]
```

如果您只想在空白处进行拆分，则应使用 **WhitespaceSplit** 代替预标记器：

```python
pre_tokenizer = pre_tokenizers.WhitespaceSplit()
pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.")
```

```python out
[("Let's", (0, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre-tokenizer.', (14, 28))]
```

像normalizers一样，您可以使用 **Sequence** 组成几个预标记器：

```python
pre_tokenizer = pre_tokenizers.Sequence(
    [pre_tokenizers.WhitespaceSplit(), pre_tokenizers.Punctuation()]
)
pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.")
```

```python out
[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)),
 ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))]
```

标记化管道的下一步是输入给模型。我们已经在初始化中指定了我们的模型，但我们仍然需要训练它，这将需要一个 **WordPieceTrainer** .在 🤗 Tokenizers 中实例化训练器时要记住的主要事情是，您需要将您打算使用的所有特殊标记传递给它 - 否则它不会将它们添加到词汇表中，因为它们不在训练语料库中：

```python
special_tokens = ["[UNK]", "[PAD]", "[CLS]", "[SEP]", "[MASK]"]
trainer = trainers.WordPieceTrainer(vocab_size=25000, special_tokens=special_tokens)
```

以及指定 **vocab_size（词典大小）** 和 **special_tokens（特殊的标记）** ，我们可以设置 **min_frequency** （记号必须出现在词汇表中的次数）或更改 **continuing_subword_prefix** （如果我们想使用与 **##**指代存在与字词相同的前缀 ）。

要使用我们之前定义的迭代器训练我们的模型，我们只需要执行以下命令：

```python
tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer)
```

我们还可以使用文本文件来训练我们的标记器，它看起来像这样（我们需要先初始化一个空的 **WordPiece** ）：

```python
tokenizer.model = models.WordPiece(unk_token="[UNK]")
tokenizer.train(["wikitext-2.txt"], trainer=trainer)
```

在这两种情况下，我们都可以通过调用文本来测试标记器 **encode()** 方法：

```python
encoding = tokenizer.encode("Let's test this tokenizer.")
print(encoding.tokens)
```

```python out
['let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.']
```

这个 **encoding** 获得的是一个 **Encoding**对象 ，它的属性中包含标记器的所有必要输出： **ids** , **type_ids** , **tokens** , **offsets** , **attention_mask** , **special_tokens_mask** ， 和 **overflowing** .

标记化管道的最后一步是后处理。我们需要添加 **[CLS]** 开头的标记和 **[SEP]** 标记在末尾（或在每个句子之后，如果我们有一对句子）。我们将使用一个 **TemplateProcessor** 为此，但首先我们需要知道 **[CLS]** 和 **[SEP]** 在词汇表中的ID：

```python
cls_token_id = tokenizer.token_to_id("[CLS]")
sep_token_id = tokenizer.token_to_id("[SEP]")
print(cls_token_id, sep_token_id)
```

```python out
(2, 3)
```

为了给 **TemplateProcessor** 编写模板，我们必须指定如何处理单个句子和一对句子。对于两者，我们都编写了我们想要使用的特殊标记；第一个（或单个）句子表示为 **$A** ，而第二个句子（如果对一对进行编码）表示为 **$B** .对于这些特殊标记和句子，我们还需要使用在冒号后指定相应的标记类型 ID。

因此经典的 BERT 模板定义如下：

```python
tokenizer.post_processor = processors.TemplateProcessing(
    single=f"[CLS]:0 $A:0 [SEP]:0",
    pair=f"[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1",
    special_tokens=[("[CLS]", cls_token_id), ("[SEP]", sep_token_id)],
)
```

请注意，我们需要传递特殊标记的 ID，以便标记器可以正确地将特殊标记转换为它们的 ID。

添加后，我们之前的示例将输出出：

```python
encoding = tokenizer.encode("Let's test this tokenizer.")
print(encoding.tokens)
```

```python out
['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.', '[SEP]']
```

在一对句子中，我们得到了正确的结果：
```python
encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences.")
print(encoding.tokens)
print(encoding.type_ids)
```

```python out
['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '...', '[SEP]', 'on', 'a', 'pair', 'of', 'sentences', '.', '[SEP]']
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
```

我们几乎从头开始构建了这个标记器——但是还有最后一步是指定一个解码器：

```python
tokenizer.decoder = decoders.WordPiece(prefix="##")
```

让我们测试一下我们之前的 **encoding** ：

```python
tokenizer.decode(encoding.ids)
```

```python out
"let's test this tokenizer... on a pair of sentences."
```

很好！我们可以将标记器保存在一个 JSON 文件中，如下所示：

```python
tokenizer.save("tokenizer.json")
```

然后我们可以使用**from_file()** 方法从该文件里重新加载 **Tokenizer** 对象：

```python
new_tokenizer = Tokenizer.from_file("tokenizer.json")
```

要在 🤗 Transformers 中使用这个标记器，我们必须将它包裹在一个 **PreTrainedTokenizerFast** 类中。我们可以使用泛型类，或者，如果我们的标记器对应于现有模型，则使用该类（例如这里的 **BertTokenizerFast** ）。如果您应用本课来构建全新的标记器，则必须使用第一个选项。

要将标记器包装在 `PreTrainedTokenizerFast` 类中，我们可以将我们构建的标记器作为`tokenizer_object` 传递，或者将我们保存为`tokenizer_file` 的标记器文件传递。 要记住的关键是我们必须手动设置所有特殊标记，因为该类无法从 `tokenizer` 对象推断出哪个标记是掩码标记、`[CLS]` 标记等：

```python
from transformers import PreTrainedTokenizerFast

wrapped_tokenizer = PreTrainedTokenizerFast(
    tokenizer_object=tokenizer,
    # tokenizer_file="tokenizer.json", # You can load from the tokenizer file, alternatively
    unk_token="[UNK]",
    pad_token="[PAD]",
    cls_token="[CLS]",
    sep_token="[SEP]",
    mask_token="[MASK]",
)
```

如果您使用特定的标记器类（例如 **BertTokenizerFast** )，您只需要指定与默认标记不同的特殊标记（此处没有）：

```python
from transformers import BertTokenizerFast

wrapped_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer)
```

然后，您可以像使用任何其他 🤗 Transformers 标记器一样使用此标记器。你可以用 **save_pretrained()** 方法，或使用 **push_to_hub()** 方法。

现在我们已经了解了如何构建 WordPiece 标记器，让我们对 BPE 标记器进行同样的操作。因为您已经知道了所有步骤，所以我们会进行地更快一点，并且只突出展示两者不一样的地方。

## 从头开始构建 BPE 标记器 [[从头开始构建 BPE 标记器]]

现在让我们构建一个 GPT-2 标记器。与 BERT 标记器一样，我们首先使用 **Tokenizer** 初始化一个BPE 模型：

```python
tokenizer = Tokenizer(models.BPE())
```

和 BERT 一样，如果我们有一个词汇表，我们可以用一个词汇表来初始化这个模型（在这种情况下，我们需要传递 `vocab` 和 `merges`），但是由于我们将从头开始训练，所以我们不需要这样去做。 我们也不需要指定“unk_token”，因为 GPT-2 使用的字节级 BPE，不需要“unk_token”。

GPT-2 不使用归一化器，因此我们跳过该步骤并直接进入预标记化：

```python
tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False)
```

我们在此处添加到 `ByteLevel` 的选项是不在句子开头添加空格（默认为ture）。 我们可以看一下使用这个标记器对之前示例文本的预标记：

```python
tokenizer.pre_tokenizer.pre_tokenize_str("Let's test pre-tokenization!")
```

```python out
[('Let', (0, 3)), ("'s", (3, 5)), ('Ġtest', (5, 10)), ('Ġpre', (10, 14)), ('-', (14, 15)),
 ('tokenization', (15, 27)), ('!', (27, 28))]
```

接下来是需要训练的模型。对于 GPT-2，唯一的特殊标记是文本结束标记：

```python
trainer = trainers.BpeTrainer(vocab_size=25000, special_tokens=["<|endoftext|>"])
tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer)
```

与 `WordPieceTrainer` 以及 `vocab_size` 和 `special_tokens` 一样，我们可以指定 `min_frequency` 如果我们愿意，或者如果我们有一个词尾后缀（如 `</w>` )，我们可以使用 `end_of_word_suffix` 设置它。

这个标记器也可以在文本文件上训练：

```python
tokenizer.model = models.BPE()
tokenizer.train(["wikitext-2.txt"], trainer=trainer)
```

让我们看一下示例文本的标记化后的结果：

```python
encoding = tokenizer.encode("Let's test this tokenizer.")
print(encoding.tokens)
```

```python out
['L', 'et', "'", 's', 'Ġtest', 'Ġthis', 'Ġto', 'ken', 'izer', '.']
```

我们对 GPT-2 标记器添加字节级后处理，如下所示：

```python
tokenizer.post_processor = processors.ByteLevel(trim_offsets=False)
```

`trim_offsets = False` 选项指示我们应该保留以 'Ġ' 开头的标记的偏移量：这样偏移量的开头将指向单词之前的空格，而不是第一个单词的字符（因为空格在技术上是标记的一部分）。 让我们看看我们刚刚编码的文本的结果，其中 `'Ġtest'` 是索引第 4 处的标记：

```python
sentence = "Let's test this tokenizer."
encoding = tokenizer.encode(sentence)
start, end = encoding.offsets[4]
sentence[start:end]
```

```python out
' test'
```

最后，我们添加一个字节级解码器：

```python
tokenizer.decoder = decoders.ByteLevel()
```

我们可以仔细检查它是否正常工作：

```python
tokenizer.decode(encoding.ids)
```

```python out
"Let's test this tokenizer."
```

很好！现在我们完成了，我们可以像以前一样保存标记器，并将它包装在一个 **PreTrainedTokenizerFast** 或者 **GPT2TokenizerFast** 如果我们想在 🤗 Transformers中使用它：

```python
from transformers import PreTrainedTokenizerFast

wrapped_tokenizer = PreTrainedTokenizerFast(
    tokenizer_object=tokenizer,
    bos_token="<|endoftext|>",
    eos_token="<|endoftext|>",
)
```

或者：

```python
from transformers import GPT2TokenizerFast

wrapped_tokenizer = GPT2TokenizerFast(tokenizer_object=tokenizer)
```

作为最后一个示例，我们将向您展示如何从头开始构建 Unigram 标记器。

## 从头开始构建 Unigram 标记器 [[从头开始构建 Unigram 标记器]]

现在让我们构建一个 XLNet 标记器。与之前的标记器一样，我们首先使用 Unigram 模型初始化一个 **Tokenizer** ：

```python
tokenizer = Tokenizer(models.Unigram())
```

同样，如果我们有词汇表，我们可以用词汇表初始化这个模型。

对于标准化，XLNet 使用了一些替换的方法（来自 SentencePiece）：

```python
from tokenizers import Regex

tokenizer.normalizer = normalizers.Sequence(
    [
        normalizers.Replace("``", '"'),
        normalizers.Replace("''", '"'),
        normalizers.NFKD(),
        normalizers.StripAccents(),
        normalizers.Replace(Regex(" {2,}"), " "),
    ]
)
```

这会取代 **“** 和 **”** 和 **”** 以及任何两个或多个空格与单个空格的序列，以及删除文本中的重音以进行标记。

用于任何 SentencePiece 标记器的预标记器是 `Metaspace`：

```python
tokenizer.pre_tokenizer = pre_tokenizers.Metaspace()
```

我们可以像以前一样查看示例文本的预标记化：

```python
tokenizer.pre_tokenizer.pre_tokenize_str("Let's test the pre-tokenizer!")
```

```python out
[("▁Let's", (0, 5)), ('▁test', (5, 10)), ('▁the', (10, 14)), ('▁pre-tokenizer!', (14, 29))]
```

接下来是需要训练的模型。 XLNet 有不少特殊的标记：

```python
special_tokens = ["<cls>", "<sep>", "<unk>", "<pad>", "<mask>", "<s>", "</s>"]
trainer = trainers.UnigramTrainer(
    vocab_size=25000, special_tokens=special_tokens, unk_token="<unk>"
)
tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer)
```

不要忘记`UnigramTrainer` 的一个非常重要的参数是`unk_token`。 我们还可以传递特定于 Unigram 算法的其他参数，例如删除标记的每个步骤的“shrinking_factor（收缩因子）”（默认为 0.75）或指定给定标记的最大长度的“max_piece_length”（默认为 16） .

这个标记器也可以在文本文件上训练：

```python
tokenizer.model = models.Unigram()
tokenizer.train(["wikitext-2.txt"], trainer=trainer)
```

让我们看一下示例文本的标记化后的结果：

```python
encoding = tokenizer.encode("Let's test this tokenizer.")
print(encoding.tokens)
```

```python out
['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.']
```

A peculiarity of XLNet is that it puts the `<cls>` token at the end of the sentence, with a type ID of 2 (to distinguish it from the other tokens). It's padding on the left, as a result. We can deal with all the special tokens and token type IDs with a template, like for BERT, but first we have to get the IDs of the `<cls>` and `<sep>` tokens:
XLNet 的一个特点是它将`<cls>` 标记放在句子的末尾，类型ID 为2（以将其与其他标记区分开来）。它会将结果填充在左侧。 我们可以使用模板处理所有特殊标记和标记类型 ID，例如 BERT，但首先我们必须获取 `<cls>` 和 `<sep>` 标记的 ID：

```python
cls_token_id = tokenizer.token_to_id("<cls>")
sep_token_id = tokenizer.token_to_id("<sep>")
print(cls_token_id, sep_token_id)
```

```python out
0 1
```

模板如下所示：

```python
tokenizer.post_processor = processors.TemplateProcessing(
    single="$A:0 <sep>:0 <cls>:2",
    pair="$A:0 <sep>:0 $B:1 <sep>:1 <cls>:2",
    special_tokens=[("<sep>", sep_token_id), ("<cls>", cls_token_id)],
)
```

我们可以通过编码一对句子来测试它的工作原理：

```python
encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences!")
print(encoding.tokens)
print(encoding.type_ids)
```

```python out
['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.', '.', '.', '<sep>', '▁', 'on', '▁', 'a', '▁pair', 
  '▁of', '▁sentence', 's', '!', '<sep>', '<cls>']
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2]
```

最后，我们添加一个 **Metaspace** 解码器：

```python
tokenizer.decoder = decoders.Metaspace()
```

我们完成了这个标记器！ 我们可以像以前一样保存标记器，如果我们想在 🤗 Transformers 中使用它，可以将它包装在 `PreTrainedTokenizerFast` 或 `XLNetTokenizerFast` 中。 使用 `PreTrainedTokenizerFast` 时要注意的一件事是，我们需要告诉🤗 Transformers 库应该在左侧填充特殊标记：
```python
from transformers import PreTrainedTokenizerFast

wrapped_tokenizer = PreTrainedTokenizerFast(
    tokenizer_object=tokenizer,
    bos_token="<s>",
    eos_token="</s>",
    unk_token="<unk>",
    pad_token="<pad>",
    cls_token="<cls>",
    sep_token="<sep>",
    mask_token="<mask>",
    padding_side="left",
)
```

或者：

```python
from transformers import XLNetTokenizerFast

wrapped_tokenizer = XLNetTokenizerFast(tokenizer_object=tokenizer)
```

现在您已经了解了如何使用各种构建块来构建现有的标记器，您应该能够使用 🤗 tokenizer库编写您想要的任何标记器，并能够在 🤗 Transformers中使用它。