HuggingFace学习笔记--Tokenizer的使用
1--AutoTokenizer的使用
官方文档
AutoTokenizer() 常用于分词,其可调用现成的模型来对输入句子进行分词。
1-1--简单Demo
测试代码:
# 分词器测试Demo
from transformers import AutoTokenizer
if __name__ == "__main__":
checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" # 使用该模型
tokenlizer = AutoTokenizer.from_pretrained(checkpoint) # 加载该模型对应的分词器
raw_input = [
"I love kobe bryant.",
"Me too."
]
inputs = tokenlizer(raw_input, padding = True, return_tensors = "pt") # padding并返回pytorch版本的tensor
print("After tokenlizer: \n", inputs) # 打印分词后的结果
str1 = tokenlizer.decode(inputs['input_ids'][0]) # 将词ID恢复
print("str1: \n", str1)
print("All done!")
输出结果:
After tokenlizer:
{
'input_ids': tensor([[101, 1045, 2293, 24113, 12471, 1012, 102],
[101, 2033, 2205, 1012, 102, 0, 0]]),
'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 0, 0]])
}
str1:
[CLS] i love kobe bryant. [SEP]
分析:
上述代码将输入的句子进行分词,并将每一个词利用一个 ID 进行映射;例如上述代码中,101 对应 [CLS],1045 对应 I,2293 对应 love,24113 对应 kobe,12471 对应 bryant,1012 对应 . 符号,102 对应 [SEP];
input_ids 存储了每一个句子分词后对应的 ID,0 表示 padding 的词;由于上面测试代码设置了padding,因此会将每一个句子自动padding为最长句子的长度,padding的词用 0 来表示。
attention_mask 标记了哪些词是真正有意义的,只有为 1 的词才会参与后续的 attention 等计算。
利用 decode 可以将词 ID 重新解码为句子。
1-2--常用参数
1-2-1--padding
设置 padding 时,可以指定具体的 padding 长度;
from transformers import AutoTokenizer
if __name__ == "__main__":
checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenlizer = AutoTokenizer.from_pretrained(checkpoint)
raw_input = [
"I love kobe bryant.",
"Me too."
]
input1 = tokenlizer(raw_input, padding = "longest", return_tensors = "pt") # padding长度与输入中的最长句子相同
input2 = tokenlizer(raw_input, padding = "max_length", return_tensors = "pt") # padding到最大句子长度,默认是512
input3 = tokenlizer(raw_input, padding = "max_length", max_length = 10, return_tensors = "pt") # 指定最大长度是10
print("After tokenlizer: \n", input1['input_ids'].shape)
print("After tokenlizer: \n", input2['input_ids'].shape)
print("After tokenlizer: \n", input3['input_ids'].shape)
输出结果:
After tokenlizer:
torch.Size([2, 7])
After tokenlizer:
torch.Size([2, 512])
After tokenlizer:
torch.Size([2, 10])
1-2-2--truncation
设置 truncation 时,用于截断,可以指定截断的长度。
from transformers import AutoTokenizer
if __name__ == "__main__":
checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenlizer = AutoTokenizer.from_pretrained(checkpoint)
raw_input = [
"I love kobe bryant.",
"Me too."
]
# 长度超过5的部分会被截断
input1 = tokenlizer(raw_input, padding = "longest", truncation = True, max_length=5, return_tensors = "pt")
print("After tokenlizer: \n", input1)
str1 = tokenlizer.decode(input1['input_ids'][0]) # 将词ID恢复
print("str1: \n", str1)
输出结果:
After tokenlizer:
{
'input_ids': tensor([[ 101, 1045, 2293, 24113, 102],
[ 101, 2033, 2205, 1012, 102]]),
'attention_mask': tensor([[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]])
}
str1:
[CLS] i love kobe [SEP]
2--BertTokenizer的使用
2-1--简单Demo
① 编码两个句子:
from transformers import BertTokenizer
if __name__ == "__main__":
tokenizer = BertTokenizer.from_pretrained(pretrained_model_name_or_path = 'bert-base-chinese')
sents = ['我喜欢科比布莱恩特.', '我也是.', '我喜欢他的后仰跳投', '我喜欢他的曼巴精神']
# 编码两个句子
inputs = tokenizer.encode(
text = sents[0],
text_pair = sents[1],
truncation = True, # 截断
padding = 'max_length', # padding到最大长度
add_special_tokens = True,
max_length = 20, # 设置最大长度
return_tensors = None # None默认返回list,可取值tf,pt,np
)
print(inputs)
print(tokenizer.decode(inputs))
输出结果:
inputs:
[101, 2769, 1599, 3614, 4906, 3683, 2357, 5812, 2617, 4294, 119, 102, 2769, 738, 3221, 119, 102, 0, 0, 0]
decode:
[CLS] 我 喜 欢 科 比 布 莱 恩 特. [SEP] 我 也 是. [SEP] [PAD] [PAD] [PAD]
② 增强编码
from transformers import BertTokenizer
if __name__ == "__main__":
tokenizer = BertTokenizer.from_pretrained(pretrained_model_name_or_path = 'bert-base-chinese')
sents = ['我喜欢科比布莱恩特.', '我也是.', '我喜欢他的后仰跳投', '我喜欢他的曼巴精神']
# 增强编码两个句子
inputs = tokenizer.encode_plus(
text = sents[0],
text_pair = sents[1],
truncation = True, # 截断
padding = 'max_length', # padding到最大长度
add_special_tokens = True,
max_length = 30, # 设置最大长度
return_tensors = None, # None默认返回list,可取值tf,pt,np,
return_token_type_ids = True,
return_attention_mask = True,
return_special_tokens_mask = True,
return_length = True
)
for k, v in inputs.items():
print(k, ':', v)
print(tokenizer.decode(inputs['input_ids']))
输出结果:
input_ids : [101, 2769, 1599, 3614, 4906, 3683, 2357, 5812, 2617, 4294, 119, 102, 2769, 738, 3221, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
token_type_ids : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
special_tokens_mask : [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
attention_mask : [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
length : 30
decode:
[CLS] 我 喜 欢 科 比 布 莱 恩 特. [SEP] 我 也 是. [SEP] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD]
③ 批量编码:
from transformers import BertTokenizer
if __name__ == "__main__":
tokenizer = BertTokenizer.from_pretrained(pretrained_model_name_or_path = 'bert-base-chinese')
sents = ['我喜欢科比布莱恩特.', '我也是.', '我喜欢他的后仰跳投', '我喜欢他的曼巴精神']
# 批量编码句子
inputs = tokenizer.batch_encode_plus(
batch_text_or_text_pairs = [sents[0], sents[1]],
truncation = True, # 截断
padding = 'max_length', # padding到最大长度
add_special_tokens = True,
max_length = 20, # 设置最大长度
return_tensors = None, # None默认返回list,可取值tf,pt,np,
return_token_type_ids = True,
return_attention_mask = True,
return_special_tokens_mask = True,
return_length = True
)
for k, v in inputs.items():
print(k, ':', v)
print("decode: \n", tokenizer.decode(inputs['input_ids'][0]))
print("decode: \n", tokenizer.decode(inputs['input_ids'][1]))
输出结果:
input_ids : [[101, 2769, 1599, 3614, 4906, 3683, 2357, 5812, 2617, 4294, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0], [101, 2769, 738, 3221, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0, 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], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
special_tokens_mask : [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
length : [12, 6]
attention_mask : [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
decode:
[CLS] 我 喜 欢 科 比 布 莱 恩 特. [SEP] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD]
decode:
[CLS] 我 也 是. [SEP] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD]
④ 批量编码成对的句子:
from transformers import BertTokenizer
if __name__ == "__main__":
tokenizer = BertTokenizer.from_pretrained(pretrained_model_name_or_path = 'bert-base-chinese')
sents = ['我喜欢科比布莱恩特.', '我也是.', '我喜欢他的后仰跳投', '我喜欢他的曼巴精神']
# 批量编码成对的句子
inputs = tokenizer.batch_encode_plus(
batch_text_or_text_pairs=[(sents[0], sents[1]), (sents[2], sents[3])],
truncation = True, # 截断
padding = 'max_length', # padding到最大长度
add_special_tokens = True,
max_length = 20, # 设置最大长度
return_tensors = None, # None默认返回list,可取值tf,pt,np,
return_token_type_ids = True,
return_attention_mask = True,
return_special_tokens_mask = True,
return_length = True
)
for k, v in inputs.items():
print(k, ':', v)
print("decode: \n", tokenizer.decode(inputs['input_ids'][0]))
print("decode: \n", tokenizer.decode(inputs['input_ids'][1]))
输出结果:
input_ids : [[101, 2769, 1599, 3614, 4906, 3683, 2357, 5812, 2617, 4294, 119, 102, 2769, 738, 3221, 119, 102, 0, 0, 0], [101, 2769, 1599, 3614, 800, 4638, 1400, 814, 6663, 2832, 102, 2769, 1599, 3614, 800, 4638, 3294, 2349, 5125, 102]]
token_type_ids : [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
special_tokens_mask : [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1]]
length : [17, 20]
attention_mask : [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
decode:
[CLS] 我 喜 欢 科 比 布 莱 恩 特. [SEP] 我 也 是. [SEP] [PAD] [PAD] [PAD]
decode:
[CLS] 我 喜 欢 他 的 后 仰 跳 投 [SEP] 我 喜 欢 他 的 曼 巴 精 [SEP]
⑤ 获取字典:
from transformers import BertTokenizer
if __name__ == "__main__":
tokenizer = BertTokenizer.from_pretrained(pretrained_model_name_or_path = 'bert-base-chinese')
sents = ['我喜欢科比布莱恩特.', '我也是.', '我喜欢他的后仰跳投', '我喜欢他的曼巴精神']
# 批量编码成对的句子
inputs = tokenizer.batch_encode_plus(
batch_text_or_text_pairs=[(sents[0], sents[1]), (sents[2], sents[3])],
truncation = True, # 截断
padding = 'max_length', # padding到最大长度
add_special_tokens = True,
max_length = 20, # 设置最大长度
return_tensors = None, # None默认返回list,可取值tf,pt,np,
return_token_type_ids = True,
return_attention_mask = True,
return_special_tokens_mask = True,
return_length = True
)
# 获取字典
token_dict = tokenizer.get_vocab()
print(type(token_dict))
print(len(token_dict))
print('喜' in token_dict) # 中文是按字来编码的,因此喜在字典里
print('喜欢' in token_dict) # 同理,喜欢不在字典里
输出结果:
<class 'dict'>
21128
True
False
⑥ 添加新字典:
from transformers import BertTokenizer
if __name__ == "__main__":
tokenizer = BertTokenizer.from_pretrained(pretrained_model_name_or_path = 'bert-base-chinese')
sents = ['我喜欢科比布莱恩特.', '我也是.', '我喜欢他的后仰跳投', '我喜欢他的曼巴精神']
# 批量编码成对的句子
inputs = tokenizer.batch_encode_plus(
batch_text_or_text_pairs=[(sents[0], sents[1]), (sents[2], sents[3])],
truncation = True, # 截断
padding = 'max_length', # padding到最大长度
add_special_tokens = True,
max_length = 20, # 设置最大长度
return_tensors = None, # None默认返回list,可取值tf,pt,np,
return_token_type_ids = True,
return_attention_mask = True,
return_special_tokens_mask = True,
return_length = True
)
# 添加新词
tokenizer.add_tokens(new_tokens=['喜欢', '跳投'])
# 添加新符号
tokenizer.add_special_tokens({'eos_token': '[EOS]'})
# 获取字典
token_dict = tokenizer.get_vocab()
print('喜欢' in token_dict) # 添加新词后,喜欢在字典里
print('喜欢: ', token_dict['喜欢'])
print('跳投: ', token_dict['跳投'])
print('[EOS]: ', token_dict['[EOS]'])
# 编码新句子,测试新词的编码
test = tokenizer.encode(
text = '我喜欢科比的后仰跳投[EOS]',
text_pair = None,
truncation = True,
padding = 'max_length',
add_special_tokens = True,
max_length = 15,
return_tensors = None
)
print(test)
输出结果:
True
喜欢: 21128
跳投: 21129
[EOS]: 21130
[101, 2769, 21128, 4906, 3683, 4638, 1400, 814, 21129, 21130, 102, 0, 0, 0, 0]
# 将喜欢、跳投和[EOS]直接编码,并没有拆开按字来编码