Pytorch tokenizer使用及补充vocab词汇表

我们现在需要对一句话做分词,然后转换成index,作为Bert的输入

tokenizer = BertTokenizer.from_pretrained(config.PRE_TRAINED_MODEL_NAME)

text = '天空下着暴雨,o2正在给c1穿雨衣,他自己却只穿着单薄的军装,完全暴露在大雨之中。角色: o2'

input_ids =tokenizer.encode(text)
output = tokenizer.decode(input_ids)

输出的output长这样,长度45:

'[CLS] 天 空 下 着 暴 雨 , o2 正 在 给 c1 穿 雨 衣 , 他 自 己 却 只 穿 着 单 薄 的 军 装 , 完 全 暴 露 在 大 雨 之 中 。 角 色 : o2 [SEP]'

但是input_ids的长度是47,??难道不是一一对应

确实不是,一一与词汇表对比,发现 'o2' 对应了两个 id,'o'对应一个, '##2'对应一个(在bert的词汇表里'##x'通常表示以'x'为后缀)

神奇的是 'c1' 词汇表中是有的

 

也就是说,为了让token和id一一对应起来,我们需要将不存在的token添加到vocab中,网上查到两种方法:

1. 利用前100里的[unused]

https://github.com/google-research/bert/issues/396

将[unused]换成自己想要添加的

具体有多少个[unused]要看自己的预训练模型,可能100个,可能1000个,但都有限

2. 利用transformers库里有个 add_tokens 方法

https://github.com/huggingface/transformers/issues/1413

https://blog.csdn.net/qq_23944915/article/details/102781463

import torch
from transformers import BertTokenizer, BertModel
import ipdb
import config   


tokenizer = BertTokenizer.from_pretrained(config.PRE_TRAINED_MODEL_NAME)
model = BertModel.from_pretrained(config.PRE_TRAINED_MODEL_NAME)

x = model.embeddings.word_embeddings.weight[-1, :]

print(len(tokenizer))  # 28996
tokenizer.add_tokens(["NEW_TOKEN"])
print(len(tokenizer))  # 28997

model.resize_token_embeddings(len(tokenizer)) 
# The new vector is added at the end of the embedding matrix

print(model.embeddings.word_embeddings.weight[-1, :])
# Randomly generated matrix

with torch.no_grad():
    model.embeddings.word_embeddings.weight[-1, :] = torch.zeros([model.config.hidden_size])

print(model.embeddings.word_embeddings.weight[-1, :])
# outputs a vector of zeros of shape [768]

y = model.embeddings.word_embeddings.weight[-2, :]

print(x == y) # 会改变原来embedding weight 吗? 不会
ipdb.set_trace()

这种方法,因为是添加token,需要修改embedding matrix

不知道它这个resize matrix会不会打扰预训练的embeddings? 经测,不会

 

感觉两种都行,待测 

也有可能都没必要,Bert可能能够学会新的组合词汇

 
posted @ 2021-11-13 00:33  Rogn  阅读(3921)  评论(0编辑  收藏  举报