Bert如何使用预留的[unused*]

2022-03-17  本文已影响0人  WritingHere

背景

方案1. 替换vocab.txt ★★☆☆☆

经过观察我们发现,vocab.txt的前面几行是[unusedx]。顾名思义,这种字符是没有用的,只是用来占位置的,他们在Bert Embedding层的权重是随机初始化的。那么,我们将[unused]替换为词典中没有的特殊字符,就可以让分词器识别出自定义的特殊字符了,这些特殊字符的初始权重也沿用了对应位置[unused]符号的权重,即也是随机初始化的。

根据这篇博客的内容Bert预留[unused*],直接将我们需要增加的token替换vocab.txt中原来的[unused]的对应行即可。如图所示,我们将[unused]替换为原本词典中不存在的几个表情符和特殊汉字。

vocab.txt的前几行 替换前-替换后

2. 增加special_token ★★☆☆☆

在某论坛上出现这样一个提问,Special tokens not tokenized properly #12168How to use my own additional vocabulary dictionary? #396和我们的诉求比较一致,下面给了一些讨论,大家有兴趣可以看看。总之结论跟huggingface官方论坛给出的关于add_token的方法比较类似,即用special token的方法,下面直接贴出:

# Let's see how to increase the vocabulary of Bert model and tokenizer
tokenizer = BertTokenizerFast.from_pretrained("bert-base-uncased")
model = BertModel.from_pretrained("bert-base-uncased")

num_added_toks = tokenizer.add_tokens(["new_tok1", "my_new-tok2"])
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.
model.resize_token_embeddings(len(tokenizer))

感兴趣的可以运行一下,这里直接说结论

  1. ✔这种方法可以识别出句子中的特殊token
  2. ✖这种方法会增加词表大小
  3. ✖因为改了词表大小,所以需要重置模型权重,如上面代码最后一行所示。
    由于重置模型权重不能保证原单词的权重中不变,新增单词的权重随机初始化,因此这种方法实际操作中不推荐

3. 推荐方法★★★★★

最好的方法当然是两者的结合

  1. 在vocab.txt中用新增字符替换掉对应行的[unused*]
  2. 在tokenizer中增加special token,实现方法如下图所示:
设置spedial_token

这样就可以实现如下诉求:

  1. 不改变词表大小
  2. 可以识别出特殊token
  3. 不用resize模型的预训练权重,之前的token权重可以保留,新增的token权重随机初始化。

参考资料

  1. Bert预留[unused*],链接:https://zhuanlan.zhihu.com/p/378774885
  2. huggingface的add_token函数,链接:https://huggingface.co/docs/transformers/internal/tokenization_utils#transformers.SpecialTokensMixin.add_tokens
上一篇 下一篇

猜你喜欢

热点阅读