bert中的special token到底是怎麼發揮作用的(2)之bert引入額外知識

  • 2021 年 4 月 12 日
  • AI

Modelshuggingface.co圖標

我們看官方文檔有一個非常有意思的功能,叫resize token embedding

我們來看下bert的vocab,可以save到本地之後看配置文件夾下的目錄:

//raw.githubusercontent.com/microsoft/SDNet/master/bert_vocab_files/bert-base-uncased-vocab.txtraw.githubusercontent.com

其中[unused*]這些標記是未經訓練的(隨即初始化),是 Bert 預留出來用來增量添加詞彙的標記,所以我們可以用它們來指代任何新字符。

這是一個非常有意思的功能,因為我們可以將額外的知識納入到bert的模型中訓練,而不僅僅是簡單的進行concat。

//github.com/georgian-io/Multimodal-Toolkit?ref=hackernoon.com%EF%BC%89github.com

上述的git中,作者適配了huggingface的model,封裝了文本和普通表格數據的簡易多模態bert,原理也很簡單,文本特徵進bert這個子網絡,類別和連續特徵進另一個自網絡(可以自定義設計網絡結構,根據上面的git鏈接的相關tutorial很容易上手),最後兩個子網絡的輸出concat之後共同輸出。


而bert的[unused]的這部分special token,實際上可以在更複雜的層面上引入額外的特徵,

BERT類模型的特殊符號的使用可以有哪些調整和變體?可以起到怎樣的效果?www.zhihu.com圖標

這裡的高贊提出的方法就是一個非常好的例子,這麼做和上面的例子中的多模態網絡結構不同,這裡通過將先驗知識引入unused token中,先驗知識會進入transoformer結構從而參與到後續的自注意力機制的計算中。

這是一個非常有意思的應用,這意味着,我們只要能夠將先驗知識轉化為離散的特徵,那麼我們就可以非常輕鬆地在bert fine tune的過程中引入額外的知識了。

方法1:

在詞表(vocab.txt)中添加若干個自定義的特殊 tokens,詞表大小由 N 增大到 M。
新建一個 M 維的 embedding layer。
將 BERT 原來的 N 維 embedding layer 中的 pretrained weights,按照詞表順序,複製到新的 M 維 embedding layer 中。
替換掉 BERT 原來的 N 維 embedding layer。
這裡就需要使用到bert的add special token的api以及resize token embedding的api

方法2:

將先驗知識的文本表示(bert目前主要介紹文本輸入,即token的index作為輸入)加入到原始的句子中去,然後直接修改bert的vocab,這樣bert的tokenizer分詞的時候就會把這些加入的先驗知識的文本表示獨立切分為一個token從而不會破壞先驗知識。

方法3:

對原始的文本進行tokenizer處理之後,直接在句子後面加入先驗知識,然後這個先驗知識的word index指向bert的unused的token的index即可,注意,不同的先驗知識需要指向不同的unused的token的index。

這裡建議使用方法2或者3(其實二者是一樣的處理思路沒什麼區別),因為這樣我們不會引入更多維度的embedding向量,直接服用unused的token對應的embedding即可。

為了方便理解,還是舉個例子吧。

假設我們要做文本分類的任務,判斷一句評論是不是田園女拳發的,然後我們發現,凡是來自於豆瓣或者微博的文本,田園女拳的佔比很高,而來自知乎的文本,田園女拳佔比很低,那麼這個時候我們就有了一個先驗信息,我們可以對不同文本的來源進行標註,例如來自於豆瓣的文本,我們額外標註 「豆瓣」,對於來自知乎的文本,我們額外標註「知乎」,那麼現在問題來了,我們怎麼將我們的標註納入bert中:

1、這類先驗知識通過一個子網絡進行前向傳播,並將最終的輸出和bert的輸出進行concat然後進入文本分類的任務層;

2、這類先驗知識通過方法1,或者方法2或者方法3 納入到bert finetune的過程中,因為bert的直接輸入主要還是支持文本,所以必須把先驗知識轉化為離散的文本特徵的表示,因為bert本身內置了很多unsued的token,

這部分unused的token是從未訓練過的但是他們在bert模型的token embedding中都有一個隨機初始化,從來沒訓練過的token embedding向量對應,

3、比較麻煩的問題是,bert常用的是position embedding,即絕對位置嵌入的方式,這種就比較麻煩,簡單的方法是我們對原始文本補0,padding到512位,然後512位之後加入這類文本形式的先驗知識,這樣這些先驗知識就不會用到position embedding向量了,否則模型最終會將position embedding和先驗知識對應的token embedding相加送入模型,但是這樣做沒有意義,先驗知識的embedding沒有位置的概念,第二種方式是使用相對位置編碼的方式,這樣每個位置的編碼方式是固定不可訓練的,不會對結果造成啥影響。

對於離散的先驗知識這種方法倒是可以,如果是連續的先驗知識比較麻煩,要不就裡離散化轉化為離散類型的input,要不就是使用更具有普適性的多模態bert結構:

但實際上這樣的話,沒有利用到text feature和先驗知識之間的交互信息,很尷尬。