一、参考资料
二、Token相关介绍
1. Token简介
在 AI 领域,Token 是指模型处理的基本数据单位。它可以是单词、字符、短语甚至图像片段、声音片段等。例如,一句话会被分割成多个 Token,每个标点符号也会被视为单独的 Token。
Token 的划分方式会影响模型对数据的理解和处理。例如,中英文的 Token 划分方式就存在差异。对于中文,由于存在多音字和词组的情况,Token 的划分需要更加细致。
2. 分词策略
常见的分词策略,有按词切分 (Word-based)、按字符切分 (Character-based)、按子词切分 (Subword)三种方法。
中文示例:今天天气很好
英文示例:Let's do tokenization!
2.1 按词切分 (Word-based)
按词切分就是基于空格的 Token 化。
bash
["今天", "天气", "很好"]
bash
tokenized_text = "let's do tokenization".split()
print(tokenized_text)
2.2 按字符切分 (Character-based)
按字符切分就是基于字的 Token 化。
bash
["今", "天", "天", "气", "候", "很", "好"]
2.3 按子词切分 (Subword)
3. 基于 BERT 的 Token 化
Bert会将不常用的词汇进行细分,比如fearless,经过分词输出 'fear','##less'。使用双#号表示连续词汇的分词。
在 BERT 的 Token 化结果中,[CLS]
和 [SEP]
是特殊的 Token,它们分别表示句子的开始和结束。
bash
["今", "天", "天", "气", "候", "[CLS]", "很", "好", "[SEP]"]
4. Hugging Face分词器
Hugging Face 提供两种分词器:
-
慢速分词器:Transformers 库自带,使用 Python 编写。
-
快速分词器:Tokenizers 库提供,使用 Rust 编写。
快速分词器只有在并行处理大量文本时才能发挥出速度优势,在处理单个句子时甚至可能慢于慢速分词器。
5. Tokenizer 工具
具体的分词效果,可以通过 OpenAI 官方的 Tokenizer 工具查看:https://platform.openai.com/tokenizer
6. Tokenizer 文件
三、示例代码
1. 加载分词器
transformers.AutoTokenizer.from_pretrained
python
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
print("词典大小:",tokenizer.vocab_size)
输出结果
bash
词典大小: 28996
2. 分词化
transformers.PreTrainedTokenizer.tokenize
python
sequence = "hello world!I am Lisa."
tokens = tokenizer.tokenize(sequence)
print("分词结果:",tokens)
输出结果
bash
分词结果: ['hello', 'world', '!', 'I', 'am', 'Lisa', '.']
3. 编码(Encode)
transformers.PreTrainedTokenizer.convert_tokens_to_ids
编码操作,实现了分词tokenize和词汇的编码convert_tokens_to_ids
。
python
token_ids = tokenizer.convert_tokens_to_ids(tokens)
print(token_ids)
# 或者
token_ids = tokenizer.encode(sequence, add_special_tokens=True)
输出结果
bash
[19082, 1362, 106, 146, 1821, 6516, 119]
4. 解码(Decode)
transformers.PreTrainedTokenizerBase.convert_tokens_to_string
transformers.PreTrainedTokenizer.convert_ids_to_tokens
解码操作,实现了词汇的解码 convert_ids_to_tokens
和转换 convert_tokens_to_string
。
python
decode_result = tokenizer.convert_tokens_to_string(tokenizer.convert_ids_to_tokens(token_ids))
print("解码结果:", decode_result)
输出结果
bash
解码结果: hello world! I am Lisa.
5. AutoTokenizer
分词器
python
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
tokenizer.save_pretrained("./models/bert-base-cased/")
调用 Tokenizer.save_pretrained()
函数会创建以下4个文件:
bash
(llama.cpp) root@notebook-1813389960667746306-scnlbe5oi5-79366:/public/home/scnlbe5oi5/Downloads# tree -L 1 ./models/bert-base-cased/
./models/bert-base-cased/
|-- special_tokens_map.json
|-- tokenizer.json
|-- tokenizer_config.json
`-- vocab.txt
special_tokens_map.json
映射文件,包含特殊字符的映射关系。
bash
{
"cls_token": "[CLS]",
"mask_token": "[MASK]",
"pad_token": "[PAD]",
"sep_token": "[SEP]",
"unk_token": "[UNK]"
}
tokenizer.json
将 vocab.txt
词表中的词按顺序生成索引表。模型根据索引表中的索引号编码生成one-hot向量,并与Bert中的 nn.embeding
训练权重矩阵相乘以获得该字符的随机词向量。
Bert与word2vec、glove等词嵌入向量获取方式不同,word2vec、glove属于静态查表法,输入一个单词就输出一个token向量,不考虑语义相似性。例如:"热狗"和"养条狗",虽然都有汉字"狗",但语义不同,Bert则需要输入完整语句后,结合上下文信息生成具有语义信息的狗字。
vocab.txt
词表示例:
对应的 tokenizer.json
索引表:
tokenizer_config.json
分词器配置文件,包含构建分词器需要的参数。
json
{
"added_tokens_decoder": {
"0": {
"content": "[PAD]",
"lstrip": false,
"normalized": false,
"rstrip": false,
"single_word": false,
"special": true
},
"100": {
"content": "[UNK]",
"lstrip": false,
"normalized": false,
"rstrip": false,
"single_word": false,
"special": true
},
"101": {
"content": "[CLS]",
"lstrip": false,
"normalized": false,
"rstrip": false,
"single_word": false,
"special": true
},
"102": {
"content": "[SEP]",
"lstrip": false,
"normalized": false,
"rstrip": false,
"single_word": false,
"special": true
},
"103": {
"content": "[MASK]",
"lstrip": false,
"normalized": false,
"rstrip": false,
"single_word": false,
"special": true
}
},
"clean_up_tokenization_spaces": true,
"cls_token": "[CLS]",
"do_lower_case": false,
"mask_token": "[MASK]",
"model_max_length": 512,
"pad_token": "[PAD]",
"sep_token": "[SEP]",
"strip_accents": null,
"tokenize_chinese_chars": true,
"tokenizer_class": "BertTokenizer",
"unk_token": "[UNK]"
}
vocab.txt
vocab.txt是词表文件,每一个 token 占一行,行号就是对应的 token ID(从 0 开始)。不同模型的词表文件会因为设置的规则不同导致内容不同,所以相同的文本序列调用不同模型的tokenizer会产生不同的整数索引。预训练模型与tokenizer必须使用相同的vocab文件和配置文件才能使输入文本序列满足模型的输入要求。
6. BertTokenizer
分词器
python
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
tokenizer.save_pretrained("./models/bert-base-cased/")