天天看點

NLP與深度學習(五)BERT預訓練模型

Transformer架構的出現,是NLP界的一個重要的裡程碑。它激發了很多基于此架構的模型,其中一個非常重要的模型就是BERT。

BERT的全稱是Bidirectional Encoder Representation from Transformer,如名稱所示,BERT僅使用了Transformer架構的Encoder部分。BERT自2018年由谷歌釋出後,在多種NLP任務中(例如QA、文本生成、情感分析等等)都實作了更好的結果。

BERT的效果如此優異,其中一個主要原因是:它是一個基于上下文的詞嵌入(context-based embedding)模型。我們在之前的文章中(“NLP與深度學習(一)NLP任務流程”)

提到過:

“Word2vec與GloVe都有一個特點,就是它們是上下文無關(context-free)的詞嵌入。是以它們沒有解決:一個單詞在不同上下文中代表不同的含義的問題。例如,對于單詞bank,它在不同的上下文中,有銀行、河畔這種差别非常大的含義。“

BERT的出現,解決了這個問題。下面我們便從context-based與context-free開始,逐漸介紹BERT模型。

首先我們介紹一下context-based與context-free這兩種詞嵌入(Embedding)的差別。

看看下面2條句子:

1. He got bit by Python

2. Python is my favorite programming language

作為人類,我們可以很容易分辨這2個句子中單詞Python的不同含義。在第1個句子中表示的是蟒蛇,第2個句子中表示的一種程式設計語言。而如果我們用context-free的詞嵌入(例如word2vec)來表示單詞Python,則單詞Python在上面2個句子中的表示方法都是同一個詞向量。也即是說,這樣會導緻單詞Python在2個句子中的含義是一樣的。顯然,這個在我們實際場景中是不合适的。

這便是context-free embedding的缺點:無論某個單詞的上下文語境如何,它都僅有同一種對單詞的表示方法。

另外一種更好的方式便是Context-Based Embedding,也就是BERT使用的方式。它可以基于單詞的上下文,生成不同的詞嵌入表示。例如在上面的2個句子中,它就可以根據單詞Python所處的上下文,生成對它不同的詞向量表示。

以BERT為例,再次回顧上面提到的第1個句子:He got bit by Python。

BERT會将每個單詞與句子中所有其他單詞計算相關性,據此來了解每個單詞的上下文。也就是說,為了了解單詞“Python“的上下文含義,BERT會将單詞”Python“與其句子中所有其他單詞進行關聯,了解它們之間的相關性(也就是前文介紹過的multi-head self-attention機制)。是以在第1個句子中,BERT可以通過單詞”bit“來了解單詞”Python“的含義為”蟒蛇“。如下圖所示:

NLP與深度學習(五)BERT預訓練模型

再看第2個句子“Python is my favorite programming language“。同樣,BERT會将每個單詞與句子中所有單詞進行相關性計算,并據此得到每個單詞的上下文資訊。是以對于單詞”Python“,BERT同樣會計算單詞”Python“與句子中每個單詞的相關性,并據此了解單詞“Python”的含義。例如,在這個句子中即根據單詞“programming“,BERT可以了解到單詞“Python”的含義為“程式設計語言”,如下圖所示:

NLP與深度學習(五)BERT預訓練模型

像word2voc、GloVe這種context-free的詞嵌入,總是會對單詞輸出固定的詞向量,而忽略了上下文的資訊。而BERT這種context-based的方式,可以根據不同上下文,動态生成不同詞向量的方法,更符合我們人類對語言的了解(當然,這種動态的表示也是經過了大量樣本訓練後得出)。最後,BERT在各個NLP任務中的表現,也證明了這種方式是更優秀的。

前面提到BERT基于的是Transformer模型,并且僅使用Transformer模型的Encoder部分。在Transformer模型中,Encoder的輸入是一串序列,輸出的是對序列中每個字元的表示。同樣,在BERT中,輸入的是一串序列,輸出的是也是對應序列中每個單詞的編碼。

仍以前面提到的“He got bit by Python”為例,BERT的輸入輸出如下圖所示:

NLP與深度學習(五)BERT預訓練模型

Fig. 1 Sudharsan Ravichandiran. Understanding the BERT Model[1]

其中輸入為序列“He got bit by Python”,輸出的是對每個單詞的編碼Rword。這樣在經過了BERT處理後,即得到了對每個單詞包含的上下文表示Rword。

這便是BERT的基本原理,下面我們介紹BERT的不同配置。

BERT的研究人員提出了2個标準配置的BERT模型:

l  BERT-base

l  BERT-large

BERT-base用于與其他架構進行對比,并以此衡量其他架構的性能。BERT-large則是用在了論文中對各個NLP任務的結果展示。

下面分别介紹這2個配置的BERT模型。

BERT-base包含:

12個堆疊的encoder層,上一層的Encoder的輸出是下一層Encoder的輸入

每個Encoder使用12-head attention

Encoder中的前饋網絡包含768個隐藏單元(也就是說輸出的Rword次元為768維)

使用以下符号表示這幾個概念:

Encoder堆疊的層數表示為L

Attention的頭(multi-head)數表示為A

前饋網絡的隐藏單元數表示為H

則在BERT-base模型中,L=12,A=12,H=768。模型的總參數個數為1億1千萬(100 million)。BERT-base模型如下圖所示:

NLP與深度學習(五)BERT預訓練模型

BERT-large包含:

24個堆疊的Encoder層

每個Encoder使用16-head attention

Encoder中的前饋網絡包含1024個隐藏單元(也就是說輸出的Rword次元為1024維)

也就是說,在BERT-large模型中,L=24,A=16,H=1024。模型的總參數個數為3億4千萬(340 million)。

除了上面2種标準配置外,我們也可以使用其他的配置來建構BERT模型。部分較小配置的BERT模型如:

Bert-tiny:L=2,H=128

Bert-mini:L=4,H=256

Bert-small:L=4,H=512

Bert-medium:L=8,H=512

這些小配置的BERT模型如下圖所示:

NLP與深度學習(五)BERT預訓練模型

在計算資源有限的場景下,我們可以使用更小配置的BERT模型。不過,最常用的還是BERT-base和BERT-large,它們的準确率也相對小配置BERT模型更高。

在了解了BERT的配置後,下面介紹BERT模型的訓練。

首先需要明确的一個點是:BERT是一個預訓練模型。也就是說,它是在大量資料集上進行了預訓練後,才被應用到各類NLP任務中。在對BERT模型進行預訓練時,與前面介紹過的所有模型一樣,輸入的文本需要先進行處理後,才能送入到模型中。而在将文本資料輸入到BERT前,會使用到以下3個Embedding層:

Token embedding

Segment embedding

Position embedding

下面逐個介紹這3個Embedding 層。

Token Embedding就是将一個序列做分詞,把序列轉為一串單詞以及它們對應的詞向量。舉個例子,假設有2個句子,分别為:

Beijing is a beautiful city.

I love Beijing

首先,對2個句子進行分詞得到token,結果如下所示:

Tokens = [Beijing, is, a, beautiful, city, I, love, Beijing]

(需要特别注意的是:這裡為了友善解釋,我們使用了最普遍的分詞法為例,而BERT中使用的是WordPiece分詞。這種分詞方法可以顯著減少詞庫的大小,WordPiece基于的是BPE(Byte Pair Encoding),BPE屬于subword分詞法中的一種。

有關WordPiece的介紹我們前面已在“NLP與深度學習(一)NLP任務流程”中有過介紹,在此不再贅述。)

然後,我們在最前面加上1個[CLS] 的token,例如:

Tokens = [ [CLS], Beijing, is, a, beautiful, city, I, love, Beijing]

最後,在每個句子的後面分别加上[SEP] 的token,例如:

Tokens = [ [CLS], Beijing, is, a, beautiful, city, [SEP], I, love, Beijing, [SEP]]

這2個特殊的token我們之前(見“NLP與深度學習(一)NLP任務流程” )介紹過:“ [CLS] 、[SEP] 與[PAD] 是BERT Tokenizer中的保留詞,分别代表“分類任務”、“Sequences之間的間隔”,以及序列補全(序列補全與截斷是NLP任務中常用的方法,用于将不同長度的文本統一長度)。 ”

在做完以上步驟後,在輸入到BERT中之前,還需要将每個單詞轉換為與之對應的詞向量。如:

Input:[  [CLS], Beijing, is, a, beautiful, city, [SEP], I, love, Beijing, [SEP]  ]

Embedding: [  E[CLS], EBeijing, Eis, Ea, Ebeautiful, Ecity, E[SEP], EI, Elove, EBeijing, E[SEP]  ]

這樣即完成了Token Embedding。

接下來是一層Segment Embedding,用于區分2個給定的句子。仍以上面的2個句子為例。在對這2個句子做了分詞處理後,結果為:

但是,除了[SEP] 外,我們還需要一種方式來告知模型哪個單詞屬于哪個句子。這也就是Segment Embedding做的事情。在将例子中的Tokens輸入到segment embedding後,它僅會輸出2種embedding,分别為EA或EB。也就是說,如果單詞屬于句子1,則輸出EA;如果屬于句子2,則輸出EB。如下所示:

Input:                        [  [CLS], Beijing, is, a, beautiful, city, [SEP], I, love, Beijing, [SEP]  ]

Segment Embedding:[  EA,   EA,     EA, EA, EA,      EA,  EA,  EB, EB,   EB,    EB,   ]

如果隻有1個句子,則僅輸出EA。

BERT基于的是Transformer的Encoder,而由于Transformer中Encoder本身不包含Positional Encoding,是以BERT中還需要一層Position Embedding來訓示單詞在句子中的位置。經過Position Embedding處理後,輸出如下所示:

Position Embedding: [  E0,   E1,    E2,E3,E4,     E5,  E6,  E7,E8,  E9,    E10   ]

我們在上一章(見“NLP與深度學習(四)Transformer模型”)介紹Transformer時,提到在Transformer中也有一個Positional Embedding,使用的是正弦曲線的方法:

“在原論文中,作者還提到了另一種位置編碼的方法:直接通過訓練學習得到位置編碼。并且從測試結果來看,兩者幾乎沒什麼差别。”

但是在BERT中,作者使用的是“直接通過訓練學習”得到的位置編碼,但并沒有給出具體理由。但是實驗上(從Transformer論文中的試驗來看)效果應該差不多。

在将輸入序列經過上述3層embedding處理後,将每層embedding的結果進行相加,即得到了輸入資料的最終表示,也就是BERT模型的輸入。

如下所示:

NLP與深度學習(五)BERT預訓練模型

BERT 論文[5]中的一個例子為:

NLP與深度學習(五)BERT預訓練模型

BERT模型在進行預訓練時,基于的是2種類型的任務:

Masked language modeling(帶掩碼的語言模型)

Next sentence prediction(預測下一條句子)

下面會分别介紹這2個任務。不過,在介紹Masked Language Modeling (帶掩碼的語言模型)任務前,有必要先介紹一下什麼是Language Modeling任務。

在Language Modeling任務中,我們會給模型輸入一個單詞序列(句子),并令模型預測這個序列(句子)的下一個單詞。這種Language Modeling可以劃分為2類:

Auto-regressive language modeling(自動回歸的語言模組化)

Auto-encoding language modeling(自動編碼的語言模組化)

Auto-regressive language modeling

自動回歸的語言模組化又可以分為以下2類:

前向預測(Forward prediction,從左到右)

後向預測(Backward prediction,從右到左)

以“Beijing is a beautiful city. I love Beijing”為例。我們将city單詞移除,替換為空,如下所示:

Beijing is a beautiful _. I love Beijing

接下來,我們讓模型預測空白位置的單詞:

如果使用Forward prediction,則模型從左到右讀入輸入,并做預測,例如:“Beijing is a beautiful _”。

而若是使用Backward prediction,則模型從右到左讀入輸入,并左預測,例如“_ I love Beijing”。

是以Auto-regressive models是單向的,僅從1個方向讀入句子。

Auto-encoding language modeling

與Auto-regressive models 不同的是,Auto-regressive models是雙向的。也就是說,它會從兩個方向均讀入句子,并對空白詞做預測。例如:

雙向的模型的效果會更好,因為從2個方向讀入句子會更有助于了解上下文(例如我們之前介紹過的雙向RNN)。

以上便是language modeling的介紹,下面我們繼續來讨論BERT中使用的預訓練方式——Masked Language Modeling。

BERT是一種Auto-encoding 語言模型,也就是說,它是從2個方向讀入句子并做預測。在masked language modeling 任務中(也稱為填空任務cloze task),對任何一個句子,随機遮擋(mask)其中15%的單詞,并訓練網絡預測這些單詞。在進行預測時,模型會從雙向讀入句子,并進行預測。

仍以“Beijing is a beautiful city. I love Beijing”為例。首先對句子做分詞,得到單個單詞:

然後在最前面加上[CLS],并在每個句子後加上[SEP] 的特殊标記:

下面對15%的單詞做遮擋(mask),假設遮擋的是單詞“city”,則使用特殊标記[MASK]替換單詞“city”:

Tokens = [ [CLS], Beijing, is, a, beautiful, [MASK], [SEP], I, love, Beijing, [SEP]]

這樣即可提供給BERT去做訓練了。但是,這種方法會有一個小問題:導緻pre-train與fine-tuning之間存在差異。假設我們使用了上述方式去對BERT進行訓練,而後再應用到遷移學習fine-tuning中。在預訓練的時候,語料庫裡是有[MASK] 這個标志的,但是在實際的遷移學習中,輸入的文本是不包含[MASK]标志的。是以這裡會導緻pre-train與fine-tuning在使用時有一個gap。

為了解決這個問題,研究人員制定了80%,10%,10%的規則。具體地說,在随機選擇了15%的單詞被遮擋後,對于這15%的單詞,做如下處理:

80%的機率将被遮擋的單詞替換為[MASK]。

10%的機率将被遮擋的單詞替換為1個随機單詞,例如将上例中的“city”替換為“dog”

10%的機率不做任何改變,例如上例中“city”仍然是“city”

這樣做的好處是:

解決了與fine-tuning的gap問題。80%的遮擋率既應用了[MASK],也有20%的機率不使用[MASK]

存在10%的機率不做任何改變,保留了原有語義,讓模型可以有機會了解原始資料樣貌

存在10%的機率替換随機單詞,可以使得模型不僅僅依賴于看到過的原始資料,而是還讓資料依賴于句子的上下文來預測目标詞,達到“糾錯”的目的

在對單詞序列進行了遮擋處理後,即可送入到BERT模型中進行訓練。此時,單詞序列會依次進入Token Embedding,Segment Embedding以及Position Embedding,并得到它們的最終表示。整個過程如下圖所示:

NLP與深度學習(五)BERT預訓練模型

需要注意的是,這裡僅需要将E([MASK]) 輸入到前饋網絡與softmax中即可。因為BERT基于的是multi-head self-attention,是以E([MASK]) 中已經包含了整個句子的資訊。

除了以上介紹的這種遮擋單詞的方法外,還有另一種稍微不同的方法,稱為whole word masking(WWM,全詞掩碼)。

Whole Word Masking

在介紹WWM之前,首先需要回顧的一個知識點是:BERT中使用的是WordPiece分詞法。以句子“let us start pretraining the model”為例,在對一個句子進行分詞後,生成的單詞為:

Tokens = [let, us, start, pre, ##train, ##ing, the, model]

加上 [CLS] 與 [SEP]:

Tokens = [ [CLS], let, us, start, pre, ##train, ##ing, the, model, [SEP] ]

随機遮擋15%的單詞,假設遮擋的單詞為 let 與 ##train,則:

Tokens = [ [CLS], [MASK], us, start, pre, [MASK], ##ing, the, model, [SEP] ]

但是這裡尤為需要注意的一點是:單詞 ##train 實際上僅是單詞pretraining 的一部分。在 WWM 方法中,如果遮擋的單詞為一個subword,則會遮擋這個subword對應的所有單詞,例如:

Tokens = [ [CLS], [MASK], us, start, [MASK], [MASK], [MASK], the, model, [SEP] ]

但是,WWM仍需要遵守“1個句子中僅有15%單詞被遮擋”這一規則。是以若是在遮擋 所有subword後,已經達到了這一15%的門檻值,則可以忽略其他詞(這個例子中就是單詞let)的遮擋,例如:

Tokens = [ [CLS], let, us, start, [MASK], [MASK], [MASK], the, model, [SEP] ]

在進行了WWM後,句子即可輸入到BERT中進行訓練,并讓模型預測被遮擋的單詞。

Next Sentence Prediction(NSP)是另一個訓練BERT的方法,它是一個2分類任務。在此任務中,為BERT模型輸入2個句子,需要讓模型判斷第2個句子是否是第1個句子的下一個句子。例如,準備2個句子Sentence-A和Sentence-B(2個句子合起來為1條訓練資料),若Sentence-B是Sentence-A的下一個句子,則這條訓練資料的label為isNext。反之為notNext。

在BERT訓練中,他需要完成的便是判斷Sentence-B是否為Sentence-A的下一條句子。若是,則輸出isNext,反之輸出notNext。是以這是一個二分類任務。

NSP任務的用途在于:通過NSP任務,可以讓模型了解2條句子之間的關系。很多重要的下遊任務(例如QA系統、自然語言推理等)都是基于句子之間的關系了解。而這種句子間的關系是無法通過language modeling 學習到的。

在準備訓練資料時,可以選取任何單一語言的語料庫。假設我們從語料庫擷取了大量文檔。對于isNext類别,僅需要從同一個文檔中選取2條連續的句子即可。而對于notNext類别,首先從一個文檔選取一條句子,然後從另一個随機文檔中選取一條句子即可。一個重要的注意點是:需要確定isNext與notNext的資料條目分别占50%。

在NSP任務中,輸入資料的處理方法與前面介紹的一緻,在此不再贅述。不過需要提及的一點是:NSP使用的是[CLS] 作為輸入的2個句子的代表,輸入到前饋網絡與softmax中,對結果進行預測。如下圖所示:

NLP與深度學習(五)BERT預訓練模型

BERT的預訓練語料庫使用的是Toronto BookCorpus和Wikipedia資料集。在準備訓練資料時,首先從語料庫中采樣2條句子,例如Sentence-A與Sentence-B。這裡需要注意的是:2條句子的單詞之和不能超過512個。對于采集的這些句子,50%為兩個句子是相鄰句子,另50%為兩個句子毫無關系。

假設采集了以下2條句子:

Beijing is a beautiful city

對這2條句子先做分詞:

Tokens = [ [CLS], Beijing, is, a, beautiful, city, [SEP], I, love, Beijing, [SEP] ]

然後,以15%的機率遮擋單詞,并遵循80%-10%-10%的規則。假設遮擋的單詞為city,則:

Tokens = [ [CLS], Beijing, is, a, beautiful, [MASK], [SEP], I, love, Beijing, [SEP] ]

接下來将Tokens送入到BERT中,并訓練BERT預測被遮擋的單詞,同時也要預測這2條句子是否為相鄰(句子2是句子1的下一條句子)。也就是說,BERT是同時訓練Masked Language Modeling和NSP任務。

BERT的訓練參數是:1000000個step,每個batch包含256條序列(256 * 512個單詞 = 128000單詞/batch)。使用的是Adam,learning rate為1e-4、β1 = 0.9、β2 = 0.999。L2正則權重的衰減參數為0.01。對于learning rete,前10000個steps使用了rate warmup,之後開始線性衰減learning rate(簡單地說,就是前期訓練使用一個較大的learning rate,後期開始線性減少)。對所有layer使用0.1機率的dropout。使用的激活函數為gelu,而非relu。

BERT的一個成功的關鍵在于:它提供了一個更深層的模型來學習到了一個更好的文本特征,使得它在各類NLP任務上的表現也更精準。目前BERT+遷移學習已經應用在各個實際應用中,例如情感分析、QA系統等。另一方面,研究人員基于BERT也衍生出了很多變種,例如ALBERT、RoBERTa、ELECTRA等等。後續我們會繼續介紹BERT的應用以及它的變種。

[1] https://learning.oreilly.com/library/view/getting-started-with/9781838821593/4c8629af-d59b-4df9-a830-79a83433f118.xhtml

[2] https://www.geeksforgeeks.org/explanation-of-bert-model-nlp/

[3] https://zhuanlan.zhihu.com/p/95594311

[4] https://zhuanlan.zhihu.com/p/366396747

[5] https://arxiv.org/pdf/1810.04805.pdf