bert [unused*] 特殊符号

https://mp.weixin.qq.com/s?__biz=MzA4Mjk1NzE2Mw==&mid=2247483865&idx=1&sn=6b4622c3b7c5b320144a404510f5c098&chksm=9ffc87dda88b0ecb8ad862c946293c9c013027220c9c06eede1771c24ff62e7b522b2a763b35&mpshare=1&scene=23&srcid=&sharer_sharetime=1591577748362&sharer_shareid=86eafe92d08280857c35673c6c6bc533#rd

原文在这里

bert [unused*] 特殊符号

来自 | 知乎

地址 | https://www.zhihu.com/question/387534279/answer/1269076355

作者 | Luke

编辑 | AI充电站公众号


本文仅作学术分享,转载请公众号后台留言

前言
了解 BERT 的人相信对 "[CLS]" 和 "[SEP]" 这两个特殊 tokens 不陌生,前者常被用于分类模型,后者是 BERT 在预训练阶段做 NSP 任务时句对之间的分隔符。
那是不是 BERT 就只有这两种特殊 tokens 了呢?


1为什么 BERT 类模型词表要保留特殊 tokens ?


如果我们去翻看 BERT 的词表(vocab.txt),相信很多人都会注意到开头若干个“[unused*]”的的特殊tokens,比如说,bert-uncased-base 模型就有994个此类 tokens([unused0]to[unused993])[1]。那么,为什么 BERT 要保留这么多看起来没什么用的特殊 tokens 呢?
类比 "[CLS]" 和 "[SEP]",我们不难推测,这些“[unused*]”保留字符存在的意义是为了,当下游finetune任务需要引入先验知识时,预先提供占位符。

2案例分析


需要引入先验知识的下游finetune任务并不少见。先看个例子,笔者曾经参加过Kaggle TensorFlow 2.0 Question Answering 竞赛,通过EDA[2],我们发现段落、表格、列表等语义块在文档中的位置信息对模型确定答案所在区域有很强的指示意义。据观察,答案位于文档开头的几个段落或表格的可能性远远大于文档的剩余部分[3]。既然如此,如何将这种强先验知识喂给模型呢?
一个优雅的做法是,利用前文提到的 "[unused*]" token。具体而言,可以将词表(vocab.txt)中的 "[unused*]" tokens 替换我们自定义的 tokens,如 "[Paragraph=N]"、"[Table=N]"、"[List=N]" 等,如下图:
bert [unused*] 特殊符号
这么做的好处是,我们自定义的 tokens 加入词表(vocab.txt)后,诸如 "[Paragraph=N]" 的tokens 会和 "[CLS]" 和 "[SEP]" 一样作为 meta-tokens 不会被 WordPiece tokenizer 分开。理论上,模型也将因此更好地注意到文档的特定部分。

3如果没有特殊字符,BERT 模型如何引入先验知识?


不妨再反推一下,如果没有 "[unused*]" tokens 作为占位符,为 BERT 模型引入先验知识需要怎么做?
Vanilla BERT 的输入只能是文本序列,这就意味着,先验知识只能以某种字符串的形式输入。*形式的文本在大规模语料下训练必然会引入噪声,显然没有固定形式的文本,也就是 "[unused*]" tokens 来得高效。但现在的假设是,词表中已经不再存在 "[unused*]" 保留 tokens,于是一个可能的操作就变成了:
  1. 在词表(vocab.txt)中添加若干个自定义的特殊 tokens,词表大小由 N 增大到 M。

  2. 新建一个 M 维的 embedding layer。

  3. 将 BERT 原来的 N 维 embedding layer 中的 pretrained weights,按照词表顺序,复制到新的 M 维 embedding layer 中。

  4. 替换掉 BERT 原来的 N 维 embedding layer。


看起来有点麻烦对吧?是不是还不如干脆一开始就保留若干个 "[unused*]" tokens :)