Bert: 雙向預訓練+微調

張雨石發表於2020-09-28

最近要開始使用Transformer去做一些事情了,特地把與此相關的知識點記錄下來,構建相關的、完整的知識結構體系。

以下是要寫的文章,文章大部分都發布在公眾號【雨石記】上,歡迎關注公眾號獲取最新文章。

背景

Bert,全稱是Bidirectional Encoder Representation from Transformers。顧名思義,主要的亮點是雙向編碼+Transformer模型。

在上一文《GPT》中,我們知道GPT是一個標準的語言模型,即用context來預測下一個詞。這樣就有兩個缺點:

  • 限制了模型結構的選擇,只有從左到右方向的模型才能夠被選擇。
  • 對句子級別的任務不是最優的。

因此,Bert這樣的雙向網路應運而生,但既然是雙向的網路,那麼就有一個問題,那就是損失函式該如何設定?GPT的損失函式非常直觀,預測下一個詞正確的概率,而Bert則是見到了所有的詞,如何構建損失函式來訓練網路呢?這就涉及到一種稱之為Masked Language Model的預訓練目標函式。另外,為了使模型更適用於句子級別的任務,Bert中還採用了一種稱之為Next Sentence Prediction的目標函式,來使得模型能更好的捕捉句子資訊。我們在下面會一一講到。

模型結構

Bert依然是依賴Transformer模型結構,我們知道GPT採用的是Transformer中的Decoder部分的模型結構,當前位置只能attend到之前的位置。而Bert中則沒有這樣的限制,因此它是用的Transformer的Encoder部分。

而Transformer是由一個一個的block組成的,其主要引數如下:

  • L: 多少個block
  • H: 隱含狀態尺寸,不同block上的隱含狀態尺寸一般相等,這個尺寸單指多頭注意力層的尺寸,有一個慣例就是在Transformer Block中全連線層的尺寸是多頭注意力層的4倍。所以指定了H相當於是把Transformer Block裡的兩層隱含狀態尺寸都指定了。
  • A: 多頭注意力的頭的個數

有了這幾個引數後,就可以定義不同配置的模型了,Bert中定義了兩個模型,
BertBase和BertLarge。其中:

  • BertBase: L=12, H=768, A=12, 引數量110M。
  • BertLarge: L=24, H=1024, A=16, 引數量340M。

輸入輸出

為了讓Bert能夠處理下游任務,Bert的輸入是兩個句子,中間用分隔符分開,在開頭加一個特殊的用於分類的字元。即Bert的輸入是: [CLS] sentence1 [SEP] sentence2

其中,兩個句子對應的詞語對應的embedding還要加上位置embedding和標明token屬於哪個句子的embedding。如下圖所示:

在這裡插入圖片描述

在[CLS]上的輸出我們認為是輸入句子的編碼。
輸入最長是512。

Masked Language Model

一般語言模型建模的方式是從左到右或者從右到左,這樣的損失函式都很直觀,即預測下一個詞的概率。

而Bert這種雙向的網路,使得下一個詞這個概念消失了,沒有了目標,如何做訓練呢?

答案就是完形填空,在輸入中,把一些詞語遮擋住,遮擋的方法就是用[Mask]這個特殊詞語代替。而在預測的時候,就預測這些被遮擋住的詞語。其中遮擋詞語佔所有詞語的15%,且是每次隨機Mask。

但這有一個問題:在預訓練中會[Mask]這個詞語,但是在下游任務中,是沒有這個詞語的,這會導致預訓練和下游任務的不匹配。

不匹配的意思我理解就是在預訓練階段任務中,模型會學到句子中有被遮擋的詞語,模型要去學習它,而在下游任務中沒有,但是模型會按照預訓練的習慣去做,會導致任務的不匹配。

解決的辦法就是不讓模型意識到有這個任務的存在,具體做法就是在所有Mask的詞語中,有80%的詞語繼續用[Mask]特殊詞語,有10%用其他詞語隨機替換,有10%的概率保持不變。這樣,模型就不知道當前句子中有沒[Mask]的詞語了。

Next Sentence Prediction

在很多下游任務中,需要判斷兩個句子之間的關係,比如QA問題,需要判斷一個句子是不是另一個句子的答案,比如NLI(Natural Language Inference)問題,直接就是兩個句子之間的三種關係判斷。

因此,為了能更好的捕捉句子之間的關係,在預訓練的時候,就做了一個句子級別的損失函式,這個損失函式的目的很簡單,就是判斷第二個句子是不是第一個句子的下一句。訓練時,會隨機選擇生成訓練語料,50%的時下一句,50%的不是。

Bert微調

有了模型,輸入輸出,目標函式,就可以訓練模型了,那麼在得到模型之後,如何去微調使之適應下游任務呢?

我們以Question-Answering問題為例來解釋,如下圖所示:

在這裡插入圖片描述

左圖是Bert的預訓練,輸入是被遮擋的句子;右圖是在Question Answer問題上微調。輸入是Question和Paragraph,想要得到的是Paragraph上的答案的位置,包括起始位置和結束位置。

所以,先預定義兩個embedding分別給起始位置和結束位置。然後,將paragraph在Bert上的每一個輸出embedding去和這兩個embedding分別做內積然後計算softmax,就得到的損失函式。有了損失函式就可以訓練了。

再比如文字分類問題,文字分類和句子之間的關係無關。因而,在微調的時候,可以把Sentence B設定為空,然後把句子輸入給bert,拿到[CLS]的輸出再加一個全連線層去做分類。

實驗結果

GLUE Task

在Glue Task上的微調的結果如下,Glue Task是一系列的任務,包括文字分類,句子關係判斷等,這些問題包括:

  • MNLI: 判斷兩個句子的關係,關係包括entailment,contradiction和neutral。
  • QQP: 判斷Quora上的兩個問題是不是同一個語義。
  • QNLI: 史丹佛QA資料集,判斷下一個句子中有沒有上個句子問題的答案。
  • SST: 文字二分類
  • CoLA: 判斷一個英文句子從語言學的角度是否是accepted
  • STS-B: 判斷兩個句子的相似程度,有1到5五個分值
  • MRPC: 兩個句子是否語義相似
  • RTE: 跟MNLI一樣,不過語料較少
  • WNLI: 跟MNLI一樣,語料較少。

在這些任務上的表現:

在這裡插入圖片描述

Bert在當時取得了最好的成績。

SQuAD Task

SQuAD就是上面微調那一節中描述的在Paragraph中找位置的問題。
在兩個版本的SquAD上取得的結果如下圖,兩個版本的區別在於SQuAD中有的樣本沒有答案。

Bert: 雙向預訓練+微調 Bert: 雙向預訓練+微調

消融實驗

把一些必備要素去掉或者換掉後的效果。可見,不管是去掉NSP,還是把Transformer替換掉,都會帶來效果的降低。

Bert: 雙向預訓練+微調

模型大小的影響

自然是大力出奇跡。

Bert: 雙向預訓練+微調

思考

勤思考, 多提問是Engineer的良好品德。

提問如下:

  • Bert中的Mask有沒有更好的策略
  • Next Sentence Prediction看起來很不直觀,有沒有更好的loss?
  • 現在的長度限制是512,因為Transformer是N^2複雜度,所以增大長度會出現效能問題,那麼問題就是,增大長度後,效果會不會有提升?如何解決效能問題。

回答後續公佈,歡迎關注公眾號【雨石記】

Bert: 雙向預訓練+微調

參考

  • [1]. Devlin, Jacob, et al. “Bert: Pre-training of deep bidirectional transformers for language understanding.” arXiv preprint arXiv:1810.04805 (2018).

相關文章