BERT的理解需要分為三個部分:
- Attention
- Transformer
- BERT
所以本文從這三個步驟,BERT詳解慢慢來
Attention
(學習自:https://edu.csdn.net/course/play/27575/370647?spm=1002.2009.3001.4024)
RNN類模型的機制,決定了RNN類模型的輸出必然小於等於其輸入的參數
比如輸入4個詞,經過翻譯模型之后,最多得到4個詞
因此,為了解決這樣的問題,
衍生出了Encoder-Decoder的方法
通過encoder對輸入進行編碼,成為一個隱向量,再對隱向量進行解碼,指定想要輸出的維度
就不會受到輸入維度的限制了
很顯然,該方法的問題非常的明顯,當句子長度過長的時候
句子的信息會在編碼的過程中損失掉很多
導致在解碼中無法還原
由此,誕生了注意力機制,細化了還原語義的過程
(注意力機制學習自:
1.https://zhuanlan.zhihu.com/p/47063917,
2.https://www.cnblogs.com/Libo-Master/p/7884958.html)
Decoder驅動的Attention
還是以帶有Decoder的模型為例,
為了使得中間隱層向量的解碼帶有注意力,而不是一視同仁地統一解碼,
所以需要某種計算機制來生成一種記錄訓練過程中語義傾向的值,如圖中所示的效果:
(1) 利用RNN得到隱狀態
(2) 計算當前位置的輸入與隱狀態的關聯性(點乘,加權點乘等方法均可)
(3) 隱層加權求和
詳細帶公式總結請點擊本鏈接看原博(本博客分享物理意義抽象理解)
這樣的操作,會使得:
當前輸出位置得到比較重要的輸入位置的權重,在預測輸出時相應的會占較大的比重
就和人一樣,會集中注意力去關注想關注的東西了。
當然,單純的去理解公式,可能還是比較抽象,
結合第二篇博客
以Tom chase Jerry為例子:
假如不使用注意力機制,究竟是Jerry還是Tom該被翻譯成傑瑞,會沒有一個明顯的傾向
通過注意力機制輸出之后會得到下面類似的輸出:
每個英文單詞的概率代表了翻譯當前單詞“傑瑞”時,注意力分配模型分配給不同英文單詞的注意力大小
原博里對其中的計算有較為清楚的描述,實際就是一個累加的計算,但是卻取得了很好的效果
對於每一個單詞,在翻譯成對應的文字時,都會有一個對應的注意力進行指導,使得效果大大提升
Self Attention
既然Attention機制這么好用,那可不可以直接去掉RNN的Decoder使用Attention呢?
答案是肯定的, 本節學習自:https://zhuanlan.zhihu.com/p/48508221
Self Attention就是這么一個機制,由他繼而衍生了transformer和BERT
先上公式:
(1) 初始化QKV矩陣
開始的時候,每個單詞都會生成3個向量QKV
這三個向量都是長度為64的向量(例子與transformer的例子契合方便說明問題)
其中X是單詞的word embedding形式長度為512,可以來自於word2vec,
W_{*}是512 * 64的權重矩陣,
\((1, 512)*(512, 64) = (1, 64)\)
應用上述的公式就能初始化出QKV長度為64
(2) 計算score分數
(3) 歸一化+softmax
(4) 融合底層的特征信息
QKV均是通過原始的word embedding形式的X得到的,相當於底層的信息
通過矩陣的乘法,能夠把需要增強的注意力,進一步增大
具體方法如下公式:
(5)shortcut結構
因為計算的深度增加了,會有梯度問題出現
也就是深度學習中的退化問題
所以在Self Attention中加入了shortcut的結構進一步解決這些問題
Transformer
理解了上面說的self attention的話,transformer就比較好理解了
本節內容學習自:http://jalammar.github.io/illustrated-transformer/
整個transformer由6個encoder和6個decoder組成,圖中是以機器翻譯為任務來說明工作原理
Transformer的本質上是一個Encoder-Decoder的結構
encoder
每一個encoder的結構如下圖所示:
可以清晰的看到,encoder模塊是由self attention加上feedforward nerual network(FFNN)組成的
- Multi-head attention
self attention已經在上一節介紹過了
為了提升精度和效率,這里還使用了Multi-head attention
他是n個self attention的ensembling,模塊的結構如下圖所示:
圖中是以8個self attention為例說明的,
將8個注意力concatenate在一起組成多頭注意力機制 - FFNN
FFNN模塊由一個Relu和一個線性激活組成,公式如下:
相當於做了一個后接的映射激活
decoder
- encoder-decoder attention
用到的策略的名稱叫做encoder-decoder attention,
用原博中的兩個gif就能解釋,首先通過最末尾的一個encoder保留KV,初始化Q得到decoder的第一個輸出
圖示中的I就是decoder的第一個輸出,
接下來這個輸出當做下一個decoder的Q,然后再獲取之前的encoder的KV,繼續做self attention
如下圖所示
這樣一來就能夠通過transformer得到對應的一個不帶位置編碼的輸出
一句話總結就是:
encoder-decoder attention中,Q來自於decoder的上一個輸出,KV來自於encoder的輸出 - position embedding
通過之前的分析會發現,transformer沒有捕捉序列的能力
因為只是單純的對每個單詞計算了自身的注意力,然后求和
那么單詞之間的順序即便發生改變,對於計算也不會有影響
這肯定是不對的,比如我吃飯和飯吃我,表達的含義肯定不同
為了解決這個問題,論文中在編碼詞向量時引入了位置編碼(Position Embedding)的特征。
具體地說,位置編碼會在詞向量中加入了單詞的位置信息,這樣Transformer就能區分不同位置的單詞了。
position embedding的公式如下:
一句話總結就是:
作者在開源的源碼中有現成的工具包可以計算
最后的最后還有一個線性激活和映射到概率的softmax得到最終Transformer的結果
Transformer的一些思考
-
單詞之間的距離為1
傳統的lstm和rnn等是存在文本的長依賴問題的,且輸出小於等於輸入的個數
transformer在self attention的驅動下,注意力的計算只依賴於單詞本身,
所以將單詞之間的距離縮短為1,減少計算量的同時,帶來的是精度的飛躍 -
attention機制
文本中的注意力和圖像鄰域的注意力有異曲同工之妙
圖中所示的是attention-unet的結構,上方的是他的attention機制的說明
可以看到,大致步驟為:
- 原始feature map與同層的短接feature map融合
- relu+sigmoid得到新的feature map
- 新的feature map融合底層的短接feature map作為當前的注意力指導分割進行
而本節中的self attentin模塊兒
QKV三個向量都是從X衍生的底層語義,QK運算得到分數加上映射激活相當於提取高級語義,再與低級語義進行注意力的增強
有get到其中的相同之處嗎?
這是我對於處理圖像和文本方面的注意力機制的思考和總結
高級特征(或語義)結合底層特征(或語義)可以增加對某些特征的注意力,提升精度
也希望看到這里的大家能有共鳴
BERT
終於到本文的主角BERT,慢慢來
BERT全稱Bidirectional Encoder Representation from transformer
可以看到和transformer的淵源很深
而且從全稱上也不難看出,BERT是一種基於transformer的雙向編碼表征
可能稍微有點不准確,想表達的意思是BERT不完成特定任務,
但是作為encode的它,加以改造可以完成很多任務
語言模型
會經常聽到語言模型這個詞,BERT從某種程度上說可以算是語言模型
這里單獨拎出來解釋一下,什么是語言模型
參考憶臻大佬的好文:https://zhuanlan.zhihu.com/p/28080127
語言模型是判斷“是否為人話的概率”
當然這里只是拋磚引玉,‘人話’可以具象化為其他的任務
- 馬爾科夫假設
為了解決參數空間過大的問題。引入了馬爾科夫假設:隨意一個詞出現的概率只與它前面出現的有限的一個或者幾個詞有關。 - n-gram(圖片來自:https://zhuanlan.zhihu.com/p/52061158)
簡單說來,
語言模型就是詞與詞之間的聯系的一種表征
unigram是用當前詞自身出現的概率來表征
bigram是用當前詞和前一個詞出現的條件概率來表征
trigram是用當前詞和附近兩個詞出現的條件概率來表征
原始博客中有帶詳細樣例的解釋,由於篇幅原因,這里就不再贅述。 - 神經網絡語言模型
參考:https://zhuanlan.zhihu.com/p/52061158
從特性上可以將 n-gram 語言模型看作是基於詞與詞共現頻次的統計,
而神經網絡語言模型則是給每個詞分別賦予分布式向量表征,探索它們在高維連續空間中的依賴關系。
實驗證明,神經網絡的分布式表征以及非線性映射更加適合對自然語言進行建模
一句話總結:
語言模型==特定任務的表征
BERT結構
本部分內容學習自:https://blog.csdn.net/jiaowoshouzi/article/details/89073944?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param
elmo:將上下文當作特征,但是無監督的語料和我們真實的語料還是有區別的,不一定的符合我們特定的任務,是一種雙向的特征提取。
openai gpt就做了一個改進,也是通過transformer學習出來一個語言模型,不是固定的,通過任務 finetuning,用transfomer代替elmo的lstm。雖然可以進行fine-tuning,但是有些特殊任務與pretraining輸入有出入,單個句子與兩個句子不一致的情況,很難解決,還有就是decoder只能看到前面的信息。
bert在多方面的nlp任務變現來看效果都較好,具備較強的泛化能力,對於特定的任務只需要添加一個輸出層來進行fine-tuning即可
結構這塊兒再說說常用的預訓練模型里會提到的幾個概念:
比如:
l代表layer,代表transformer層數
h代表hidden,代表了模型輸出的維度
a代表multi-head attention的個數
其余的以此類推
BERT輸入
BERT的輸入是由三種embedding組成的,分別是:
token embedding:WordPiece tokenization subword
segment embedding:下一句是否是上一句的接續,值為0和1
position embedding:學習出來的embedding向量。這與Transformer不同
預訓練模型
BERT的預訓練階段包括兩個任務,一個是Masked Language Model,還有一個是Next Sentence Prediction。
- Masked Language Model
MLM可以理解為完形填空,作者會隨機mask每一個句子中15%的詞,用其上下文來做預測,例如:my dog is hairy → my dog is [MASK]
此處將hairy進行了mask處理,然后采用非監督學習的方法預測mask位置的詞是什么,但是該方法有一個問題,因為是mask15%的詞,其數量已經很高了,這樣就會導致某些詞在fine-tuning階段從未見過,為了解決這個問題,作者做了如下的處理:
- 80%的時間是采用[mask],my dog is hairy → my dog is [MASK]
- 10%的時間是隨機取一個詞來代替mask的詞,my dog is hairy -> my dog is apple
- 10%的時間保持不變,my dog is hairy -> my dog is hairy
那么為啥要以一定的概率使用隨機詞呢?這是因為transformer要保持對每個輸入token分布式的表征,否則Transformer很可能會記住這個[MASK]就是"hairy"。至於使用隨機詞帶來的負面影響,文章中解釋說,所有其他的token(即非"hairy"的token)共享15%*10% = 1.5%的概率,其影響是可以忽略不計的。Transformer全局的可視,又增加了信息的獲取,但是不讓模型獲取全量信息。
2. Next Sentence Prediction
選擇一些句子對A與B,其中50%的數據B是A的下一條句子,剩余50%的數據B是語料庫中隨機選擇的,學習其中的相關性,
添加這樣的預訓練的目的是目前很多NLP的任務比如QA和NLI都需要理解兩個句子之間的關系,從而能讓預訓練的模型更好的適應這樣的任務。
推薦閱讀:https://blog.csdn.net/jiaowoshouzi/article/details/89073944?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param
這里對其中的總結做一遍陳述:
- RNN類LM的視野是單側可見,從頭到當前的節點
- CBOW類的視野是窗口內可見,
- BERT則是除mask可見
其實mask的增加是增大了訓練的難度,
但是增加了NSP的訓練任務之后,兩個任務聯合,
上下句之間的聯系修正embedding引導訓練效果提升
結語
BERT的實現主要是圍繞工程化的項目來進行的
因為大部分都是針對其預訓練模型來設計封裝匹配自己的訓練任務
所以如何工程化實現封裝BERT是一件迫在眉睫的事情
也是不得不熟練掌握的事情
好在隨着時間的推移,
傾向於開箱即用的朋友們有很多福音
諸如keras_bert,bert4keras等包的出現造福了keras用戶
bert_pytorch造福了pytorch用戶
啥別說了,上手加油干,沖沖沖