參考博客
https://wmathor.com/index.php/archives/1456/
https://blog.csdn.net/sunhua93/article/details/102764783,非常詳細
預訓練模型
用巨大的數據來訓練一個泛化能力很強的模型,當我們需要在特定場景使用時,例如做文本相似度計算,那么,只需要簡單的修改一些輸出層,再用我們自己的數據進行一個增量訓練,對權重進行一個輕微的調整。
預訓練的好處在於在特定場景使用時不需要用大量的語料來進行訓練,節約時間效率高效,bert就是這樣的一個泛化能力較強的預訓練模型。
BERT
BERT 全稱為 Bidirectional Encoder Representation from Transformer,是 Google 以無監督的方式利用大量無標注文本「煉成」的語言模型,其架構為 Transformer 中的 Encoder(BERT=Encoder of Transformer)
從創新的角度來看,bert其實並沒有過多的結構方面的創新點,其和GPT一樣均是采用的transformer的結構,相對於GPT來說,其是雙向結構的,而GPT是單向的,如下圖所示:

BERT的兩個常用版本:

L是transformer的層數,H是輸出的維度,A表示multi-head attention中頭的個數。
從模型的層數來說其實已經很大了,但是由於transformer的殘差(residual)模塊,層數並不會引起梯度消失等問題,但是並不代表層數越多效果越好,有論點認為低層偏向於語法特征學習,高層偏向於語義特征學習。
BERT的預訓練過程
接下來我們看看BERT的預訓練過程,BERT的預訓練階段包括兩個任務,一個是Masked Language Model,還有一個是Next Sentence Prediction。
MLM(Masked Language Model)
MLM可以理解為完形填空,作者會隨機mask每一個句子中15%的詞,用其上下文來做預測,之后做 Loss 的時候也只計算被遮蓋部分的 Loss.其余部分不做損失,其余部分無論輸出什么東西,都無所謂。
這樣做的好處是,BERT 並不知道 [MASK] 替換的是哪一個詞,而且任何一個詞都有可能是被替換掉的,比如它看到的 apple 可能是被替換的詞。這樣強迫模型在編碼當前時刻詞的時候不能太依賴當前的詞,而要考慮它的上下文,甚至根據上下文進行 "糾錯"。
因為是mask15%的詞,其數量已經很高了,這樣就會導致某些詞在fine-tuning階段從未見過,為了解決這個問題,作者做了如下的處理:
- 有 80%的幾率是采用[mask]
- 有 10% 的幾率被替換成任意一個其它的 token
- 有 10% 的幾率原封不動
那么為啥要以一定的概率使用隨機詞呢?
這是因為transformer要保持對每個輸入token分布式的表征,否則Transformer很可能會記住這個[MASK]就是"hairy"。
至於使用隨機詞帶來的負面影響,文章中解釋說,所有其他的token(即非"hairy"的token)共享15%*10% = 1.5%的概率,其影響是可以忽略不計的。Transformer全局的可視,又增加了信息的獲取,但是不讓模型獲取全量信息。
NSP(Next Sentence Prediction)
我們首先拿到屬於上下文的一對句子,也就是兩個句子,之后我們要在這兩個句子中加一些特殊的 token:[CLS]上一句話[SEP]下一句話[SEP]。也就是在句子開頭加一個 [CLS],在兩句話之間和句末加 [SEP],具體地如下圖所示

Token Embedding 就是正常的詞向量,即 PyTorch 中的 nn.Embedding()
Segment Embedding 的作用是用 embedding 的信息讓模型分開上下句,我們給上句的 token 全 0,下句的 token 全 1,讓模型得以判斷上下句的起止位置
Position Embedding 和 Transformer 中的不一樣,不是三角函數,而是學習出來的
NSP任務:
選擇一些句子對A與B,其中50%的數據B是A的下一條句子,剩余50%的數據B是語料庫中隨機選擇的,學習其中的相關性,添加這樣的預訓練的目的是目前很多NLP的任務比如QA和NLI都需要理解兩個句子之間的關系,從而能讓預訓練的模型更好的適應這樣的任務。
BERT的優缺點
優點:
- Transformer Encoder因為有Self-attention機制,因此BERT自帶雙向功能
- 因為雙向功能以及多層Self-attention機制的影響,使得BERT必須使用Cloze版的語言模型Masked-LM來完成token級別的預訓練
- 為了獲取比詞更高級別的句子級別的語義表征,BERT加入了Next Sentence Prediction來和Masked-LM一起做聯合訓練
- 為了適配多任務下的遷移學習,BERT設計了更通用的輸入層和輸出層
- 微調成本小
缺點:
- MLM的隨機遮擋策略略顯粗獷
- [MASK]標記在實際預測中不會出現,訓練時用過多[MASK]影響模型表現,與fine-tune階段會出現gap。
- 每個batch只有15%的token被預測,所以BERT收斂得比left-to-right模型要慢(它們會預測每個token)
- BERT對硬件資源的消耗巨大(大模型需要16個tpu,歷時四天;更大的模型需要64個tpu,歷時四天。
BERT的Fine-tuning過程
BERT 的 Fine-Tuning 共分為 4 種類型,以下內容、圖片均來自台大李宏毅老師 Machine Learning 課程(以下內容 圖在上,解釋在下)
分類問題(一個句子):

如果現在的任務是 classification,首先在輸入句子的開頭加一個代表分類的符號 [CLS],然后將該位置的 output,丟給 Linear Classifier,讓其 predict 一個 class 即可。整個過程中 Linear Classifier 的參數是需要從頭開始學習的,而 BERT 中的參數微調就可以了。
關鍵問題:為什么要用CLS?
因為 BERT 內部是 Transformer,而 Transformer 內部又是 Self-Attention,所以 [CLS] 的 output 里面肯定含有整句話的完整信息。
但是 Self-Attention 向量中,自己和自己的值其實是占大頭的,現在假設使用 w1 的 output 做分類,那么這個 output 中實際上會更加看重 w1,而 w1 又是一個有實際意義的字或詞,這樣難免會影響到最終的結果。但是 [CLS] 是沒有任何實際意義的,只是一個占位符而已,所以就算 [CLS] 的 output 中自己的值占大頭也無所謂。就相當於將所有詞的 output 進行 concat,作為最終的 output。
slot filling問題(一個句子)

如果現在的任務是 Slot Filling,將句子中各個字對應位置的 output 分別送入不同的 Linear,預測出該字的標簽。
其實這本質上還是個分類問題,只不過是對每個字都要預測一個類別。
句子匹配(兩個句子,例如NLI問題)

如果現在的任務是 NLI(自然語言推理)。即給定一個前提,然后給出一個假設,模型要判斷出這個假設是 正確、錯誤還是不知道。這本質上是一個三分類的問題,和 Case 1 差不多,對 [CLS] 的 output 進行預測即可。
問答問題,閱讀理解

如果現在的任務是 QA(問答),舉例來說,如上圖,將一篇文章,和一個問題(這里的例子比較簡單,答案一定會出現在文章中)送入模型中,模型會輸出兩個數 s,e,這兩個數表示,這個問題的答案,落在文章的第 s 個詞到第 e 個詞。

還需要額外訓練兩個向量。
首先將問題和文章通過 [SEP] 分隔,送入 BERT 之后,得到上圖中黃色的輸出。
還要訓練兩個 vector,即上圖中橙色和藍色的向量。首先將橙色和所有的黃色向量進行 dot product,然后通過 softmax,看哪一個輸出的值最大,例如上圖中 d2 對應的輸出概率最大,那我們就認為 s=2。

同樣地,我們用藍色的向量和所有黃色向量進行 dot product,最終預測得 d3 的概率最大,因此 e=3。最終,答案就是 s=2,e=3。
