bert tokenizer 添加词典操作测试 add special tokens code example

Published on Aug. 22, 2023, 12:10 p.m.

Examples:


from transformers import BertTokenizer, BertModel
tokenizer = BertTokenizer.from_pretrained('uer/chinese_roberta_L-8_H-512')
model = BertModel.from_pretrained("uer/chinese_roberta_L-8_H-512")

special_tokens_dict = {'cls_token': '<CLS>'}

num_added_toks = tokenizer.add_special_tokens(special_tokens_dict)
print('We have added', num_added_toks, 'tokens')
# Notice: resize_token_embeddings expect to receive the full size of the new vocabulary, i.e., the length of the tokenizer.
# 修改对应的emb层的词典大小

model.resize_token_embeddings(len(tokenizer))

assert tokenizer.cls_token == '<CLS>'

# 修改之后记得保存词典
tokenizer.save_pretrained("chinese_roberta_L")

还有就是,有时候即便是在词典里,也会被分开,问题就出在do_basic_tokenize上。
把这个do_basic_tokenize设为False问题就解决了,前提是你需要用空格事先分割你的文字。

tokenizer = BertTokenizer.from_pretrained("uer/chinese_roberta_L-8_H-512",do_basic_tokenize=True)
text="[MASK] [unused1] 京 。"
# encoded_input = tokenizer(text, return_tensors='pt')
# encoded_input
tokenizer.tokenize(text)

[‘[MASK]’, ‘[‘, ‘u’, ‘##nus’, ‘##ed’, ‘##1’, ‘]’, ‘京’, ‘。’]

tokenizer = BertTokenizer.from_pretrained("uer/chinese_roberta_L-8_H-512",do_basic_tokenize=False)
text="[MASK] [unused1] 京 。"
# encoded_input = tokenizer(text, return_tensors='pt')
# encoded_input
tokenizer.tokenize(text)

[‘[MASK]’, ‘[unused1]’, ‘京’, ‘。’]

不事先做空格分割

tokenizer = BertTokenizer.from_pretrained("uer/chinese_roberta_L-8_H-512",do_basic_tokenize=False)
text="[MASK][unused1]这是一个测试文本 。"
# encoded_input = tokenizer(text, return_tensors='pt')
# encoded_input
tokenizer.tokenize(text)

[‘[MASK]’,
‘[unused1]’,
‘##这’,
‘##是’,
‘##一’,
‘##个’,
‘##测’,
‘##试’,
‘##文’,
‘##本’,
‘。’]

这么多的连接,估计是没法和原始的意义关联了。

加入never_split进行限制分词


tokenizer = BertTokenizer.from_pretrained("uer/chinese_roberta_L-8_H-512",do_basic_tokenize=True,never_split=["[unused1]"])
text="[MASK][unused1]这是一个测试文本 。"
# encoded_input = tokenizer(text, return_tensors='pt')
# encoded_input
tokenizer.tokenize(text)

[‘[MASK]’, ‘[unused1]’, ‘这’, ‘是’, ‘一’, ‘个’, ‘测’, ‘试’, ‘文’, ‘本’, ‘。’]

结果还是很理想的

很遗憾换成中文就不管用了

tokenizer = BertTokenizer.from_pretrained("uer/chinese_roberta_L-8_H-512",do_basic_tokenize=True,never_split=["[unused1]","文本"])
text="[MASK][unused1]这是一个测试文本 。"
# encoded_input = tokenizer(text, return_tensors='pt')
# encoded_input
tokenizer.tokenize(text)

[‘[MASK]’, ‘[unused1]’, ‘这’, ‘是’, ‘一’, ‘个’, ‘测’, ‘试’, ‘文’, ‘本’, ‘。’]

英文没用空格区分,则never_split函数有效。

既然如此,如果引入分词软件后处理是不是会更好呢?

pip install jieba

import jieba

tokenizer = BertTokenizer.from_pretrained("uer/chinese_roberta_L-8_H-512",do_basic_tokenize=False)

text="这是一个测试文本 。"
# jieba.add_word('[mask]')
jieba.load_userdict("userdict.txt")
seg_list = jieba.cut(text,  HMM=False)
newtext="  ".join(seg_list)
print("newtext",newtext)

print("text ",tokenizer.tokenize(text))
print("newtext ",tokenizer.tokenize(newtext))

newtext 这 是 一个 测试 文本 。
text [‘这’, ‘##是’, ‘##一’, ‘##个’, ‘##测’, ‘##试’, ‘##文’, ‘##本’, ‘。’]
newtext [‘这’, ‘是’, ‘一’, ‘##个’, ‘测’, ‘##试’, ‘文’, ‘##本’, ‘。’]

是不是感觉好多了,不过[mask]结巴会一直分词,加入词典依旧无效。
bowtie: 为什么所有的地方都没人说过需要这么做?感觉禁用do_basic_tokenize,并且加上分词,基本可以很完美了,还可以引入自己的词典,意义上更加明确。

修改词典

tokenizer = BertTokenizer.from_pretrained("uer/chinese_roberta_L-8_H-512",do_basic_tokenize=False)
tokenizer.vocab["模板1"]=tokenizer.vocab.pop("[unused1]")
text="[MASK][UNUSED1]京模板1。"
encoded_input = tokenizer(text, return_tensors='pt')
encoded_input

参考

https://blog.csdn.net/qq_38241346/article/details/115122655

Tags: