# tokenizer

tokenizer 的主要功能可以用 tokenize 和 encode 来描述。tokenize 将文本切分为 token，encode 则将（已切分或未切分的） token 按照词表转换为（或者说映射到）数值 id。tokenizer 的`tokenize` 和 `encode` 分别实现上述功能， `__call__` 方法基本上是 encode，并返回包含更多的控制信息的 `BatchEncoding` 对象。

当 `__call__` 接收一个 `List[str]` 作为参数时，它默认会把参数理解为一个文本 batch，所以如果传入的是已切分的 token 序列，就需要设置 `is_split_into_words` 参数为真。但 `encode` 方法并不需要，它默认把 `List[str]` 理解为已切分的 token 序列。

`encode` 有一个反向的方法 `decode` ，可以把已编码的 id 序列还原为文本字符串。但注意 tokenize 本身不是可逆的，tokenize 包含大小写归一化、OOV 单词处理等过程。对于 BERT tokenizer 等会做 subword 切分的 tokenizer，`decode` 可以帮助省去 subword 拼接的过程；`decode` 也会对标点进行合适的处理。

由于 token 既可以抽象地指代文本处理中的最小对象（对于 tokenizer 来说，一般就是 word 或 subword），也可以指代具体的字符串形式的（采用字符编码的） 最小对象，本文可能会在这两种意义上模糊地使用 token 这个词，但请留意这一概念上的分歧。

`BatchEncoding` 对象继承自 python dict。

tokenizer 是支持对一个 batch 的文本做 tokenize 和 encode 的。

`attention_mask` 是一个对文本做 batching 时会用到的参数。假设有若干长度不同的序列要放入同一个 batch，并且不做截断，那么只能对短的序列做 padding。但对于 BERT 这样的基于 attention 的非自回归的模型而言，输入连同 padding 会一起被 attention 机制作用，而我们不期望 padding 信息造成干扰。通过 attention mask 可以告诉模型，输入数据的哪些部分不需要参与 attention 计算（例如 padding 的部分）。直接调用 tokenizer 得到的 `BatchEncoding` 里默认包含 `attention_mask` 。它是一个和产生的 id 序列长度相同的 01 序列，1 代表对应位置的 token 将参与 attention 运算，0 代表相反。

如果希望把序列 padding 到一个统一的长度，可以考虑 `padding` 参数。它不仅支持把一个 batch 内的 sequence 补齐到 batch 内最长 sequence 的长度，也支持补齐到一个给定的任意长度。通过 `truncation` 参数则可以执行截断到给定长度。这个给定长度由参数 `max_length` 控制。

直接调用 tokenizer 返回的 id 序列默认是一个 python list。通过 `return_tensors` 参数可以要求 tokenizer 返回特定数值框架中的数值类型。`pt` 代表 PyTorch 的 `Tensor`，`tf` 代表 TensorFlow 的 `Tensor`，`np` 代表 NumPy 的 `ndarray`。

```python
# load a tokenizer
global_tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
hamlet = "To be or not to be, that is the question."

# tokenize, encode and decode
result = global_tokenizer.tokenize(hamlet)
print(result)
['to', 'be', 'or', 'not', 'to', 'be', ',', 'that', 'is', 'the', 'question', '.']
result = global_tokenizer.encode(result)
print(result)
[101, 2000, 2022, 2030, 2025, 2000, 2022, 1010, 2008, 2003, 
1996, 3160, 1012, 102]
result = global_tokenizer.decode(result)
print(repr(result))
'[CLS] to be or not to be, that is the question. [SEP]'

# subword example
hysteria = "a psychoneurosis marked by emotional excitability and disturbances " \
    "of the psychogenic, sensory, vasomotor, and visceral functions"
result = global_tokenizer.tokenize(hysteria)
print(result)
['a', 'psycho', '##ne', '##uro', '##sis', 'marked', 'by', 'emotional', 
'ex', '##cit', '##ability', 'and', 'disturbances', 'of', 'the', 'psycho', 
'##genic', ',', 'sensory', ',', 'va', '##som', '##oto', '##r', ',', 'and', 
'vis', '##cera', '##l', 'functions']

# directly encoding is supported
result = global_tokenizer.encode(hamlet)
print(result)
[101, 2000, 2022, 2030, 2025, 2000, 2022, 1010, 2008, 2003, 
1996, 3160, 1012, 102]

result = global_tokenizer(hamlet)
print(result)
{'input_ids': [101, 2000, 2022, 2030, 2025, 2000, 2022, 1010, 2008, 2003, 
1996, 3160, 1012, 102], 
'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}

# Tokenized text is not properly encoded.
# Every token is treated as an individual sentence.
result = global_tokenizer.tokenize(hamlet)
result = global_tokenizer(result)
print(result)
{'input_ids': [[101, 2000, 102], [101, 2022, 102], [101, 2030, 102], ...
result = global_tokenizer.tokenize(hamlet)
# use of is_split_into_words
result = global_tokenizer(result, is_split_into_words=True)
print(result)
{'input_ids': [101, 2000, 2022, 2030, 2025, 2000, 2022, 1010, 2008, 2003, 
1996, 3160, 1012, 102], 
'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}

# use of padding, truncation and max_length
result = global_tokenizer(hamlet,padding='max_length', max_length=20)
print(result)
{'input_ids': [101, 2000, 2022, 2030, 2025, 2000, 2022, 1010, 2008, 2003, 
1996, 3160, 1012, 102, 0, 0, 0, 0, 0, 0], 
'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0]}

result = global_tokenizer(hamlet, truncation=True, max_length=10)
print(result)
{'input_ids': [101, 2000, 2022, 2030, 2025, 2000, 2022, 1010, 2008, 102], 
'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}

# use of return_tensors
result = global_tokenizer(hamlet, return_tensors="pt")
print(result)
{'input_ids': tensor([[ 101, 2000, 2022, 2030, 2025, 2000, 2022, 1010, 
2008, 2003, 1996, 3160, 1012,  102]]), 
'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]), 
'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])}

# additional flags to control returned value
result = global_tokenizer(hamlet, 
    return_token_type_ids=False, 
    return_attention_mask=False)
print(result)
{'input_ids': [101, 2000, 2022, 2030, 2025, 2000, 2022, 1010, 2008, 2003, 
1996, 3160, 1012, 102]}
​
```

## Reference

\[1] <https://huggingface.co/transformers/main_classes/tokenizer.html>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://deemolover.gitbook.io/log-os/tools-numerical/auxiliary/transformers/tokenizer.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
