1.什么是Bert?
Bert用我自己的話就是:使用了transformer中encoder的兩階段兩任務兩版本的語言模型
沒錯,就是有好多2,每個2有什么意思呢?
先大體說一下,兩階段是指預訓練和微調階段,兩任務是指Mask Language和NSP任務,兩個版本是指Google發布的Base版本和Large版本。
Base版本:L(Layers)=12,H(Hidden)=768,A(attention head)=12,Total Parameters=110M
Large版本:L(Layers)=24,H(Hidden)=1024,A(attention head)=16,Total Parameters=340M
2.細看Bert
第一步,先來計算Bert的輸入部分參數:
通過上圖我們可以看到BERT的輸入部分由3部分組成:
Token Embedding:單詞的Embedding
Segment Embedding:句子的Embedding,BERT的訓練數據都是由兩個句子構成的,那么每個句子有個句子整體的embedding項對應給每個單詞
Position Embedding:位置Embedding,NLP中單詞順序是很重要的特征,需要在這里對位置信息進行編碼,用來表示每個單詞在輸入序列中的位置信息
仔細看上圖,input和Token Embedding中出現了##ing的符號,那么問題來了,##這個表示的是什么意思呢?
其實在Bert中,英文單詞是以Wordpiece Embeding形式進行表示,而中文則是單字切分,##表示的詞就是那些Wordpiece。可能有人又會問,Wordpiece是怎得來的呢?
首先在英文中,把每個單詞分割成單個字母,然后統計相鄰字母組合的次數,提取次數較多的部分就為一個Wordpiece,類似於我們英語語法中前綴和后綴,例如-ing在語法中表示動詞的進行時態,而在我們的詞表中則表示##ing。
使用wordpiece embeding表示有什么好處呢?
1.減少了輸入空間的表示
2.減少了oov問題
解釋完輸入問題后,我們來細看一下整個模型參數流動變化
(一)
BERT的詞表大小vocab_size=32000,那么每個詞可以表示成32000維的one-hot向量
BERT的max_length=512,也就是可以接收的最大輸入句子的長度,那么每個單詞的位置信息可以表示成512維的one-hot向量
BERT的訓練數據接收的是句子對,那么就可以用2維的one-hot向量表示兩個不同的句子
上圖是神經網絡語言模型NNLM的結構,BERT的Hidden=768,也就是上圖中的N=768,上面說的單詞,位置,和句子的one-hot向量首先均需要通過神經網絡語言模型輸入到隱藏層的映射,在這一步,就以一個單詞為例,可以發現這里的參數計算其實與輸入序列的長度是沒有關系地。
單詞one-hot向量(1,32000),需要的參數矩陣為(32000,768),
位置one-hot向量(1,512),需要的參數矩陣為(512,768),
句子one-hot向量(1,2),需要的參數矩陣為(2,768),
經過這樣的轉換就能得到Token Embedding,Segment Embedding,Position Embedding了,然后再將這3個Embedding相加就是BERT的輸入了。
因此輸入部分涉及的參數為:32000∗768+512∗768+2∗768
然后合並后的輸入Embedding便會進入Transformer的Encoder中,Encoder又分為Multi-Heads Attention和Feed Forward。
(二)
在Multi-Heads Attention輸入Embedding需要經過三個W矩陣轉換生成Q,K,V,怎么確定三個W矩陣的維度呢?
因為BERT輸入的句子最大長度為512,句子長度小於512用0補齊,大於512截斷。故輸入的序列Embedding矩陣的維度為(512,768),dmodel=768 也就是一個單詞的Embedding維度
W的維度為(dmodel,dmodel/heads)=(768,768/12)=(768,64),Base BERT是12個Heads
然后通過self-attention計算Z,這樣我們就得到了12個Z,然后將12個Z拼接成一個大的矩陣12個(512,64)拼接成(512,768)的大
接着需要對這個(512,768)的大矩陣用Wo進行線性變換,維度不變依舊是(512,768),因為參數矩陣Wo的維度也是(768,768)
那么在MultiHead Atten中參數為:3*768*64*12+768*768
(三)Add&Norm中是沒有參數的,只是添加一個殘差塊和歸一化
(四)Feed Forward
在這一步需要將輸入映射到高維空間然后再變回原本的向量維度,W1就是負責映射到高維空間,W2負責恢復成原來的維度。Feed Forward的輸入為(512,768)的矩陣,BERT的映射到高維度的變換使用的是4H,也就是4倍輸入維度,因此W1的維度就是(768,4x768),W2的維度就是(4x768,768),故Feed Forward部分參數量為:768∗4∗768+4∗768∗768
然后又進行Add&Norm,接着進入下一個Encoder,堆疊12層。
因此將這三步所有參數匯總為:
(32000+512+2)∗768+12∗(3∗768∗64∗12+768∗768+768∗4∗768∗2)=109905408=110M
3.雙向
Masked雙向語言模型向上圖展示這么做:隨機選擇語料中15%的單詞,把它摳掉,也就是用[Mask]掩碼代替原始單詞,然后要求模型去正確預測被摳掉的單詞。但是這里有個問題:訓練過程大量看到[mask]標記,這會引導模型認為輸出是針對[mask]這個標記的,但是真正后面在進行預測任務的時候是不會有這個標記的,這自然會有類似語義鴻溝的問題。為了避免這個問題,Bert改造了一下,15%的被選中要執行[mask]替換的單詞中,只有80%真正被替換成[mask]標記,10%被隨機替換成另外一個單詞,10%情況這個單詞不做改動。這就是Masked雙向語言模型的具體做法。
隨機選擇語料中的15%的單詞,意思是說從輸入的token中隨機選擇15%的token,而不是從總的BERT詞表中隨機選擇15%。然后每次對於這部分被選出來的15%的token進行預測,因為每次只能預測輸入token的15%,而且是隨機地,要想將整個句子都預測出來的話需要多迭代幾次,這也是為什么BERT預訓練需要消耗大量時間的原因。
為什么要80%,10%,10%?
BERT是一個多任務學習模型,上面MLM只是BERT預訓練中的一個任務,另一個是NSP(Next Sentence Prediction)。之前也說過BERT的訓練數據是句子對的形式。
NSP,指的是做語言模型預訓練的時候,分兩種情況選擇兩個句子,一種是選擇語料中真正順序相連的兩個句子;
另外一種是第二個句子從語料庫中拋色子,隨機選擇一個拼到第一個句子后面。
我們要求模型除了做上述的Masked語言模型任務外,附帶再做個句子關系預測,判斷第二個句子是不是真的是第一個句子的后續句子。
之所以這么做,是考慮到很多NLP任務是句子關系判斷任務,單詞預測粒度的訓練到不了句子關系這個層級,增加這個任務有助於下游句子關系判斷任務。
對NSP具體實現步驟做一個說明:
1.首先在最開始的輸入階段,我們從語料中提取出兩個句子A和B,50%的概率B是A在語料中的下一句,50%的概率B是隨機取地句子
2.將這兩個句子A和B打包成一個序列,[CLS] A [SEP] B [SEP]
3.然后就是生成句子標識,將序列中[CLS] A [SEP]的區域中每個單詞token都對應一個相同的句子Embedding EA,EA怎么算,在上面將計算參數的時候應該已經說過了,B [SEP]對應一個相同的句子Embedding EB
4.最后將[CLS]的輸出當做是包含序列A 和 序列B句子語義關系信息的輸出輸入到分類器中
這樣就完成了句子對之間關系分析的任務
那么CLS的位置是否可以隨意放置?
首先,CLS在預訓練中沒有意義,在微調中有意義,用了提取label。其次,CLS可以放在句子各個位置,因為有self-attention機制。
4.微調
關於是否微調有兩種使用方式:
(一)不微調,只利用提取出的特征:BERT 預訓練的輸出其實是輸入中每個Token經過訓練后的Embedding值,就是每個Token的詞向量,然后當我們真正在使用的時候就可以根據自己的實際業務將這些Token詞向量提取出來,接下來就像使用Word2vec的詞向量一樣進行后續任務
(二)微調:Fine-Tune的結構也應該按照BERT的預訓練結構來設計,然后就可以運用到各種NLP下游task中了
句子關系類任務:Entailment,QA,語義改寫,自然語言推理等任務都是這個模式,它的特點是給定兩個句子,模型判斷出兩個句子是否具備某種語義關系
使用BERT預訓練的模型參數處理這類問題,只需要給輸入加上一個起始[CLS]和終結符號[SEP],句子之間加個分隔符[SEP]即可。對於輸出來說,把第一個起始符號[CLS]對應的Transformer最后一層位置上面串接一個softmax分類層即可
分類任務:文本分類,情感分析等任務,特點是不管文章有多長,總體給出一個分類類別即可
對於分類問題,咱們一般都把一句話或者一篇文檔當做一個整體,那么就是輸入單句,只需要給輸入文本增加起始[CLS]和終結符號[SEP],輸出部分與句子關系類任務一樣,是要把把第一個起始符號[CLS]對應的Transformer最后一層位置上面串接一個softmax分類層即可
序列標注:這是最典型的NLP任務,比如中文分詞,詞性標注,命名實體識別,語義角色標注等都可以歸入這一類問題,它的特點是句子中每個單詞要求模型根據上下文都要給出一個分類類別。
對於序列標注問題,輸入部分和單句分類是一樣的,只需要輸出部分Transformer最后一層的每個單詞對應位置都進行softmax分類
生成式任務:比如機器翻譯,文本摘要,寫詩造句,看圖說話等都屬於這一類。它的特點是輸入文本內容后,需要自主生成另外一段文字。
關於生成式任務,原生BERT無法完成,因為BERT是一個雙向的模型,而對於像生成任務式這種,是屬於單向模型的。
5.BERT優缺點:
優點:
1.效果好,相比於GPT,GPT是單向,而BERT是雙向,相比與ELMO,ELMO采用的是LSTM,而BERT采用的是效果更好的特征提取器Transformer
2.幾乎支持所有的NLP下游任務
BERT缺點:
1.雖然說Transformer中引入了位置編碼來解決位置信息是一個還不錯的解決方案,但還是存在些許不足之處,可能需要更加強大的超越Transformer的特征提取器
2.BERT參數量巨大,計算資源消耗大
3.一些可有可無的小問題,[mask]的時候每次是隨機選取15%,比如”New York is a city”,假設我們Mask住”New”和”York”兩個詞,那么給定”is a city”的條件下”New”和”York”並不獨立,因為”New York”是一個實體,看到”New”則后面出現”York”的概率要比看到”Old”后面出現”York”概率要大得多。不過BERT預訓練數據量特別大,影響就基本上可以忽略了
4.Mask帶來的語義鴻溝問題,造成輸入與輸出分布不一致