論文鏈接: https://arxiv.org/abs/1810.04805
BERT(Bidirectional Encoder Representations from Transformers)通過預訓練來學習無標註數據中的深度雙向表示,預訓練結束後通過添加壹個額外的輸出層進行微調,最終在多個NLP任務上實現了SOTA。
預訓練語言模型在實踐中證明對提高很多自然語言處理任務有效,其中包括句子層級的任務,比如自然語言推斷(natural language inference)和復述(paraphrasing),還有token層級的任務,比如命名實體識別(named entity recognition)和問答(question answering)。
在下遊任務中應用預訓練語言模型表示的方法有兩種:feature-based的方法和fine-tuning的方法。舉例來說,ELMo這種預訓練語言模型使用feature-based的方法,通過將ELMo的預訓練的表示作為額外的特征輸入到特定於任務的模型中去;GPT使用fine-tuning的方法,通過引入少量的特定於任務的參數,在下遊任務中訓練時所有的預訓練參數。
截止BERT之前的預訓練語言模型都是單向的(unidirectional),包括GPT和ELMo,這樣的方法對句子層級的任務不是最優的,而且對於token層級的任務比如問答非常有害。BERT使用masked language model(MLM)的方法來預訓練,這種方法能夠訓練壹個雙向的(directional)語言模型。除了masked language model的預訓練的方法,BERT還使用了next sentence prediction的預訓練方法。
BERT的使用分為兩個階段:預訓練(pre-training)和微調(fine-tuning)。預訓練階段模型通過兩種不同的預訓練任務來訓練無標註數據。微調階段模型使用預訓練參數初始化,然後使用下遊任務(downstream task)的標註數據來微調參數。
BERT的壹個顯著特點是它在不同的任務上有統壹的架構,使用時只需要在BERT後面接上下遊任務的結構即可使用。
BERT的模型架構是壹個多層雙向的Transformer的encoder。我們標記模型的層數(每壹層是壹個Tranformer的block)為 ,模型的hidden size為 ,self-attention head的數量為 。兩個比較通用的BERT架構為 和 。
對比GPT,BERT使用了雙向self-attention架構,而GPT使用的是受限的self-attention, 即限制每個token只能attend到其左邊的token。
BERT的輸入表示能夠是壹個句子或者是壹個句子對,這是為了讓BERT能夠應對各種不同的下遊任務。BERT的輸入是壹個序列,該序列包含壹個句子的token或者兩個句子結合在壹起的token。
具體地,我們會將輸入的自然語言句子通過 WordPiece embeddings 來轉化為token序列。這個token序列的開頭要加上 [CLS] 這個特殊的token,最終輸出的 [CLS] 這個token的embedding可以看做句子的embedding,可以使用這個embedding來做分類任務。
由於句子對被pack到了壹起,因此我們需要在token序列中區分它們,具體需要兩種方式:
①在token序列中兩個句子的token之間添加 [SEP] 這樣壹個特殊的token;
②我們為每個token添加壹個用來學習的embedding來區分token屬於句子A還是句子B,這個embedding叫做segment embedding。
具體地,BERT的輸入由三部分相加組成:token embeddings、segment embeddings和position embeddings。如下圖所示:
BERT使用兩個無監督的任務進行預訓練,分別是Masked LM和Next Sentence Prediction(NSP)。如下圖所示,我們定義輸入的embedding為 ,BERT最終輸出的 [CLS] 的embedding為 ,最終輸出的第 個token的embedding為 。
我們有理由相信壹個深度雙向模型比left-to-right模型和left-to-right和right-to-left簡單連接的模型的效果更加強大。不幸的是,標準的條件語言模型只能夠夠left-to-right或者right-to-left地訓練,這是因為雙向條件會使每個token能夠間接地“看到自己”,並且模型能夠在多層上下文中簡單地預測目標詞。
為了能夠雙向地訓練語言模型,BERT的做法是簡單地隨機mask掉壹定比例的輸入token(這些token被替換成 [MASK] 這個特殊token),然後預測這些被遮蓋掉的token,這種方法就是Masked LM(MLM),相當於完形填空任務(cloze task)。被mask掉的詞將會被輸入到壹個softmax分類器中,分類器輸出的維度對應詞典的大小。在預訓練時通常為每個序列mask掉15%的token。與降噪自編碼器(denoising auto-encoders)相比,我們只預測被mask掉的token,並不重建整個輸入。
這種方法允許我們預訓練壹個雙向的語言模型,但是有壹個缺點就是造成了預訓練和微調之間的mismatch,這是因為 [MASK] 這個token不會在微調時出現。為了緩解這壹點,我們采取以下做法:在生成訓練數據時我們隨機選擇15%的token進行替換,被選中的token有80%的幾率被替換成 [MASK] ,10%的幾率被替換成另壹個隨機的token,10%的幾率該token不被改變。然後 將使用交叉熵損失來預測原來的token。
壹些重要的NLP任務如Question Answering (QA)或者Natural Language Inference (NLI)需要理解句子之間的關系,而這種關系通常不會被語言模型直接捕捉到。為了使得模型能夠理解句子之間的關系,我們訓練了壹個二值的Next Sentence Prediction任務,其訓練數據可以從任何單語語料庫中生成。具體的做法是:當選擇句子A和句子B作為訓練數據時,句子B有50%的幾率的確是句子A的下壹句(標簽是 IsNext ),50%的幾率是從語料庫中隨機選擇的句子(標簽是 NotNext )。 [CLS] 對應的最後壹個隱層輸出向量被用來訓練NSP任務,這個embedding就相當於sentence embedding。雖然這個預訓練任務很簡單,但是事實上在微調時其在QA和NLI任務上表現出了很好的效果。在前人的工作中,只有sentence embedding被遷移到下遊任務中,而BERT會遷移所有的參數來初始化下遊任務模型。
Transformer的self-attention機制允許BERT建模多種下遊任務。對於包含句子對的任務,通常的做法是先獨立地對句子對中的句子進行編碼,然後再應用雙向交叉註意(bidirectional cross attention)。而BERT使用self-attention機制統壹了這兩個過程,這是因為對拼接起來的句子對進行self-attention有效地包含了兩個句子之間的雙向交叉註意(bidirectional cross attention)。
對於每個任務來說,我們只需要將任務特定的輸入輸出插入到BERT中然後端到端地微調即可。舉例子來說,BERT的預訓練輸入句子A和句子B在微調時可以類比為:
①paraphrasing任務中的句子對;
②entailment任務中的hypothesis-premise對;
③question answering任務中的question-passage對;
④text classification或者sequence tagging任務中的text-?對(也就是只輸入壹個text,不必壹定需要兩個句子)。
對於BERT的輸出,對於壹些token-level的任務,BERT的token表示將被輸入到壹個輸出層,比如sequence tagging或者question answering任務;對於entailment或者sentiment analysis這樣的任務,可以將 [CLS] 對應的表示輸入到壹個輸出層。
我們使用 [CLS] 這個token的最後壹層的隱層向量 作為聚合的表示,可以認為是sentence embedding。在微調時只引入壹個新的權重 ,這裏的 代表標簽的數量,然後計算標準分類損失 。下圖展示了BERT在GLUE上的效果:
在這個數據集上,我們將question和passage拼接起來作為壹個輸入序列(中間是 [SEP] )。在微調時引入壹個start向量 和壹個end向量 ,計算 和 的點積然後通過 函數作為word 是答案的span起始位置的概率: 。答案的終止位置也做上述類似處理。從 到 的候選區間的得分記作 ,我們挑選 的最大得分區間作為預測的結果。下圖展示了BERT在SQuAD v1.1上的效果:
SQuAD v2.0有的question在提供的passage中沒有答案存在。在微調時我們設置沒有答案的問題的span的起始和結束位置都是 [CLS] 這個token,也就是start和end的可能性空間包含進了 [CLS] 的位置。在預測時,我們比較沒有答案的span得分 和最優的有答案得分 。當 時,我們預測這是壹個有答案的問題,這裏的 用來在dev set上選擇最優的 。下圖展示了BERT在SQuAD v2.0上的效果:
微調時我們為BERT構建4個輸入序列,每壹個是所給的句子(句子A)和壹個可能的延續(句子B)。然後引入壹個向量,該向量和每壹個輸入對應的 [CLS] 的embedding的點積再通過壹個 層來得到每個選擇的得分。下圖展示了BERT在SWAG上的效果: