我们现在需要对一句话做分词,然后转换成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
import torch from transformers import BertTokenizer, BertModel tokenizer = BertTokenizer.from_pretrained("bert-base-cased") model = BertModel.from_pretrained("bert-base-cased") 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 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]
感觉两种都行,待测
------------恢复内容开始------------
我们现在需要对一句话做分词,然后转换成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可能能够学会新的组合词汇