在介紹Transformer前我們來回顧RNN的結構
#對RNN有一定了解的話,一定會知道,RNN有兩個很明顯的問題
為了緩解傳遞間的梯度和遺忘問題,設計了各式各樣的RNN cell,最著名的兩個是LSTM和GRU了
LSTM (Long Short Term Memory)
GRU (Gated Recurrent Unit)
#但是,引用網路上一個部落客的比喻,這麼做就像是在幫馬車換車輪,為什麼不直接換成汽車呢?
於是就有了我們本文要介紹的核心結構-Transformer。 Transformer 是Google Brain 2017的提出的工作,它針對RNN的弱點進行重新設計,解決了RNN效率問題和傳遞中的缺陷等,在許多問題上都超過了RNN的表現。 Transfromer的基本結構如下圖所示,它是一個N進N出的結構,也就是說每個Transformer單元相當於一層的RNN層,接收一整個句子所有詞作為輸入,然後為句子中的每個詞都做出一個輸出。但是與RNN不同的是,Transformer能夠同時處理句子中的所有詞,並且任意兩個詞之間的操作距離都是1,這麼一來就很好地解決了上面提到的RNN的效率問題和距離問題。
每個Transformer單元都有兩個最重要的子層,分別是Self-Attention層與Feed Forward層,後面會對這兩個層的詳細結構做介紹。文章使用Transformer搭建了一個類似Seq2Seq的語言翻譯模型,並為Encoder與Decoder設計了兩種不同的Transformer結構。
Decoder Transformer相對於Encoder Transformer多了一個Encoder-Decoder Attention層,用來接收來自於Encoder的輸出作為參數。最終只要按照下圖的方式堆疊,就可以完成Transformer Seq2Seq的結構搭建。
舉個範例介紹下如何使用這個Transformer Seq2Seq做翻譯
第二個解碼,將第一次的輸出Append到輸入中,輸入就變成了
了解Transformer的大致結構以及如何用它來完成翻譯任務後,接下來就看看Transformer的詳細結構:
核心元件就是上面所提到的Self-Attention和Feed Forward Networks,但還有很多其他細節,接下來我們就開始逐個結構的來解讀Transformer。
Self Attention
#Self Attention就是句子中的某個字對於本身的所有字做一次Attention。算出每個字對於這個字的權重,然後將這個字表示為所有字的加權和。每一次的Self Attention操作,就像是為每個字做了一次Convolution操作或Aggregation操作。具體操作如下:
首先,每個字都要透過三個矩陣Wq, Wk, Wv進行一次線性變化,一分為三,產生每個字自己的query, key, vector三個向量。以一個字為中心進行Self Attention時,都是用這個字的key向量與每個字的query向量做點積,再透過Softmax歸一化出權重。然後透過這些權重算出所有字的vector的加權和,作為這個字的輸出。具體過程如下圖所示
歸一化之前需要透過除以向量的維度dk來標準化,所以最終Self Attention用矩陣變換的方式可以表示為
最終每個Self Attention接受n個字向量的輸入,輸出n個Aggregated的向量。
上文提到Encoder中的Self Attention與Decoder中的有所不同,Encoder中的Q、K、V全部來自於上一層單元的輸出,而Decoder只有Q來自於上一個Decoder單元的輸出,K與V都來自於Encoder最後一層的輸出。也就是說,Decoder是要透過目前狀態與Encoder的輸出算出權重後,將Encoder的編碼加權得到下一層的狀態。
Masked Attention
#透過觀察上面的結構圖我們也可以發現Decoder與Encoder的另一個不同,就是每個Decoder單元的輸入層,要先經過一個Masked Attention層。那麼Masked的與普通版本的Attention有什麼差別呢?
Encoder因為要編碼整個句子,所以每個字都需要考慮上下文的關係。所以每個字在計算的過程中都是可以看到句子中所有的字的。但Decoder與Seq2Seq中的解碼器類似,每個字都只能看到前面字的狀態,所以是單向的Self-Attention結構。
Masked Attention的實作也非常簡單,只要在普通的Self Attention的Softmax步驟之前,與(&)上一個下三角矩陣M就好了
#Multi-Head Attention
Multi-Head Attention就是將上述的Attention做h遍,然後將h個輸出進行concat得到最終的輸出。這樣做可以很好地提高演算法的穩定性,在許多Attention相關的工作中都有相關的應用。 Transformer的實作中,為了提高Multi-Head的效率,將W擴大了h倍,然後透過view(reshape)和transpose操作將相同字的不同head的k、q、v排列在一起進行同時計算,完成計算後來再次透過reshape和transpose完成拼接,相當於對於所有的head進行了一個並行處理。
Position-wise Feed Forward Networks
#Encoder中和Decoder中經過Attention之後輸出的n個向量(這裡n是詞的個數)都分別的輸入到一個全連接層中,完成一個逐個位置的前饋網路。
Add & Norm
是一個殘差網絡,將一層的輸入與其標準化後的輸出相加即可。 Transformer中每一個Self Attention層與FFN層後面都會連一個Add & Norm層。
Positional Encoding
由於Transformer中既不存在RNN,也有別於CNN,句子裡的所有字都被同等的看待,所以字詞之間就沒有了先後關係。換句話說,很可能會帶著和詞袋模型相同的不足。為了解決這個問題,Transformer提出了Positional Encoding的方案,就是給每個輸入的詞向量疊加一個固定的向量來表示它的位置。文中所使用的Positional Encoding如下:
其中pos是指詞在句子中的位置,i是詞向量中第i位,將每個字的字向量為一行疊加,然後針對每一列都疊加上一個相位不同或波長逐漸增大的波,以此來唯一區分位置。
Transformer 工作流程
#Transformer的工作流程就是上面介紹的每個子流程的拼接
#GitHub連結:https://github .com/harvardnlp/annotated-transformer
#Post Scriptum
##雖然在Transformer文章中提出了一種自然語言翻譯的模型,很多文章都把這個模型稱為Transformer。但我們還是傾向將文章中利用Self-Attention的Encoder或Decoder的子結構稱為Transformer。文中和原始碼中還包含了許多其他的最佳化例如學習率動態變化,Residual Dropout以及Label Smoothing在這裡就不再贅述,有興趣的朋友可以閱讀相關參考文獻進行了解。
單向二階段訓練模型-OpenAI GPTGPT(Generative Pre-Training),是OpenAI在2018年提出的模型,利用Transformer模型來解決各種自然語言問題,例如分類、推理、問答、相似度等應用的模型。 GPT採用了Pre-training Fine-tuning的訓練模式,使得大量無標記的資料得以利用,大大提高了這些問題的效果。
GPT就是利用Transformer進行自然語言各種任務的嘗試之一,主要有以下三個要點
如果已經理解了Transformer的原理,那麼只需要再搞懂上面的三個內容就能夠對GPT有更深的認識。
Pre-Training 訓練方式#
很多機器學習任務都需要標籤的資料集作為輸入完成。但是我們身邊存在大量沒有標註的數據,例如文字、圖片、程式碼等等。標註這些數據需要花費大量的人力和時間,標註的速度遠不如數據產生的速度,所以帶有標籤的數據往往只佔有總數據集很小的一部分。隨著算力的不斷提高,電腦能夠處理的資料量逐漸增加。如果不能善用這些無標籤的數據就顯得很浪費。
所以半監督學習與預訓練 微調的二階段模式整變得越來越受歡迎。最常見的二階段方法就是Word2Vec,使用大量無標記的文本訓練出帶有一定語義資訊的詞向量,然後將這些詞向量作為下游機器學習任務的輸入,就能夠大大提高下游模型的泛化能力。
但是Word2Vec有一個問題,就是單字只能有一個Embedding。這樣一來,一詞多義就不能很好地進行表示。
ELMo首先想到了在預訓練階段為每個詞彙集其上下文訊息,使用的是基於bi-LSTM的語言模型給詞向量帶上上下文語義資訊:
上式分別代表了左右兩向的LSTM-RNN,他們共享輸入的詞向量X以及RNN各層權重S,也就是使用雙向RNN兩向的輸出,來同時預測下一個單字(右向的下一個,左向的上一個),具體結構如下圖所示:
但ELMo使用的是RNN來完成語言模型的預訓練,那麼如何使用Transformer來完成預訓練呢?
單向Transformer結構
#OpenAI GPT採用了單向Transformer完成了這項預訓練任務。
什麼是單向Transformer?在Transformer的文章中,提到了Encoder與Decoder所使用的Transformer Block是不同的。在Decoder Block中,使用了Masked Self-Attention,即句子中的每個詞,都只能對包括自己在內的前面所有詞進行Attention,這就是單向Transformer。 GPT使用的Transformer結構就是將Encoder中的Self-Attention替換成了Masked Self-Attention,具體結構如下圖所示:
由於採用的是單向的Transformer,只能看到上文的詞,所以語言模型為:
而訓練的過程其實非常的簡單,就是將句子n個字的字向量(第一個為
由於使用了Masked Self-Attention,所以每個位置的詞都不會「看見」後面的詞,也就是預測的時候是看不見「答案」的,保證了模型的合理性,這也是為什麼OpenAI採用了單向Transformer的原因。
Fine-Tuning與不同輸入資料結構的變化
接下來就進入模型訓練的第二步,運用少量的標籤資料對模型參數進行微調。
上一步中最後一個字的輸出我們沒有用到,在這一步驟中就要使用這一個輸出來作為下游監督學習的輸入。
為避免Fine-Tuning使得模型陷入過擬合,文中也提到了輔助訓練目標的方法,類似一個多任務模型或半監督學習。具體方法就是在使用最後一個詞的預測結果進行監督學習的同時,前面的詞繼續上一步的無監督訓練,使得最終的損失函數成為:
針對不同任務,需要修改輸入資料的格式:
GitHub連結:https://github.com/openai/finetune-transformer-lm
Post Scriptum
#OpenAI GPT在Transformer的運用和二階段訓練方式上做出了很好的探索,也取得了非常不錯的效果,為後面的BERT鋪平了道路。
雙向二階段訓練模型-BERT
BERT(Bidirectional Encoder Representation from Transformer),是Google Brain在2018年提出的基於Transformer的自然語言表示框架。是一提出就大火的明星模型。 BERT與GPT一樣,採取了Pre-training Fine-tuning的訓練方式,在分類、標註等任務下都獲得了更好的效果。
BERT與GPT非常的相似,都是基於Transformer的二階段訓練模型,都分為Pre-Training與Fine-Tuning兩個階段,都在Pre-Training階段無監督地訓練出一個可通用的Transformer模型,然後在Fine-Tuning階段對這個模型中的參數進行微調,使之能適應不同的下游任務。
雖然BERT與GPT看起來非常的相似,但是它們的訓練目標和模型結構和使用上還是有著些許的不同:
##雙向Transformer
BERT採用的是不經過Mask的Transformer,也就是與Transformer文章中的Encoder Transformer結構完全一樣:
GPT中因為要完成語言模型的訓練,也就要求Pre-Training預測下一個字的時候只能夠看見目前以及之前的詞,這也是GPT放棄原本Transformer的雙向結構轉而採用單向結構的原因。
BERT為了能夠同時得到上下文的訊息,而不是像GPT一樣完全放棄下文訊息,採用了雙向的Transformer。但這樣一來,就無法再像GPT一樣採用正常的語言模型來預訓練了,因為BERT的結構導致每個Transformer的輸出都可以看見整個句子的,無論你用這個輸出去預測什麼,都會「看見」參考答案,也就是「see itself」的問題。 ELMo中雖然採用的是雙向RNN,但兩個RNN之間是獨立的,所以可以避免see itself的問題。
Pre-Training階段
那麼BERT想用雙向的Transformer模型,就不得不放棄GPT中所採用的語言模型來作為預訓練的目標函數。取而代之的,BERT提出了一種完全不同的預訓練方法。
#在Transformer中,我們即想要知道上文的信息,又想要知道下文的信息,但同時要確保整個模型不知道要預測詞的信息,那麼就乾脆不要告訴模型這個詞的信息就可以了。也就是說,BERT在輸入的句子中,挖掉一些需要預測的詞,然後透過上下文來分析句子,最終使用其對應位置的輸出來預測被挖掉的詞。這其實就像是在做完形填空 (Cloze)。
但是,直接將大量的單字替換為
1.輸入資料中隨機選擇15%的字用於預測,這15%的字詞中,
2.80%的詞向量輸入時被替換為
3.10%的字的詞向量在輸入時被替換為其他字的字向量
4.另外10%保持不動
這樣一來就相當於告訴模型,我可能給你答案,也可能不給你答案,也可能給你錯誤的答案,有
#BERT也提出了另一個預訓練方式NSP,與MLM同時進行,組成多工預訓練。這種預先訓練的方式就是在Transformer中輸入連續的兩個句子,左邊的句子前面加上一個
為了區分兩個句子的前後關係,BERT除了加入了Positional Encoding之外,還兩外加入了一個在預訓練時需要學習的Segment Embedding來區分兩個句子。這樣一來,BERT的輸入就由詞向量、位置向量、段向量三個部分相加組成。此外,兩個句子之間使用
整體Pre-Training的示意圖如下:
##Fine-Tuning階段
BERT的Fine-Tuning階段和GPT沒有太大差別。因為採用了雙向的Transformer所以放棄了GPT在Fine-Tuning階段所使用的輔助訓練目標,也就是語言模型。另外就是將分類預測用的輸出向量從GPT的最後一個字的輸出位置改為了句子開頭
#GitHub連結:https://github.com/google-research/bert
Post Scriptum
#個人認為,BERT只是GPT模型的一種trade-off,為了在兩個階段都能夠同時獲得句子上下文的信息,使用了雙向Transformer模型。但為此卻要付出失去傳統語言模型的代價,轉而採用MLM NSP這種更複雜的方式進行預訓練。
多任務模型-MT-DNN
MT-DNN (Multi-Task Deep Neural Networks) 依然採用了BERT的二階段訓練方法以及雙向Transformer。在Pre-Training階段,MT-DNN與BERT幾乎完全一樣,但是在Fine-Tuning階段,MT-DNN採用了多任務的微調方式。同時採用Transformer輸出的上下文Embedding進行單句分類、文字對相似度、文字對分類、問答等任務的訓練。整個結構如下圖所示:
#GitHub連結:https://github.com/namisan/mt-dnn
GPT-2繼續沿用了原來在GPT種使用的單向Transformer模型,而這篇文章的目的就是盡可能利用單向Transformer的優勢,做一些BERT使用的雙向Transformer做不到的事。那就是透過上文產生下文文字。
GPT-2的想法就是完全捨棄Fine-Tuning過程,轉而使用一個容量更大、無監督訓練、更通用的語言模型來完成各種各樣的任務。我們完全不需要定義這個模型該做什麼任務,因為許多標籤所蘊含的訊息,就存在於語料當中。就像一個人如果博覽群書,自然可以根據看過的內容輕鬆的做到自動摘要、問答、續寫文章這些事。
嚴格來說GPT-2可能不算是多任務模型,但是它確實使用相同的模型、相同的參數完成了不同的任務。
通常我們針對特定任務訓練的專用模型,給定輸入,就可以回傳這個任務對應的輸出,也就是
#那麼如果我們希望設計一個通用的模型,這個模型在給定輸入的同時還需要給定任務類型,然後根據給定輸入與任務來做出相應的輸出,那麼模型就可以表示成下面這個樣子
就好像原來我需要翻譯一個句子,需要專門設計一個翻譯模型,想要問答系統需要專門設計一個問答模型。但是如果一個模型夠聰明,並且能夠根據你的上文產生下文,那我們就可以透過在輸入中加入一些標識符就可以區分各種問題。例如可以直接問他:(‘自然語言處理', 中文翻譯)來得到我們需要的結果Nature Language Processing。在我的理解中GPT-2更像是一個無所不知的問答系統,透過告知一個給定任務的標識符,就可以對多種領域的問答、多種任務做出合適的回答。 GPT-2滿足零樣本設定 (zero-shot setting), 在訓練的過程中不需要告訴他應該完成什麼樣的任務,預測是也能給出較為合理的答案。
那麼GPT-2為了做到上面這些要求,做了哪些工作呢?
拓寬並加大資料集
#首先就是要讓模型博覽群書,如果訓練樣本都不夠多,那還怎麼進行推理?前面的工作都是針對某一個特定問題的,所以資料集都比較片面。 GPT-2收集了一個規模更大、範圍更廣的資料集。同時呢,要確保這個資料集的質量,保留那些擁有高品質內容的網頁。最後組成了一個800萬個文本,40G的資料集WebText。
擴大網路容量
書多了腦袋容量也得帶一些要不然就記不住書裡的東西。為了提高網路的容量,使其擁有更強的學習潛力,GPT-2將Transformer堆疊的層數增加到48層,隱層的維度為1600,參數量達到了15億。
調整網路結構
#GPT-2將詞彙表提升到50257,最大的上下文大小(context size ) 從GPT的512提升到了1024,batchsize從512提升為1024。另外也對Transformer做出了小調整,標準化層放到沒每個sub-block之前,最後一個Self-attention後又增加了一個標準化層;改變了殘差層的初始化方法等等。
GitHub連結:https://github.com/openai/gpt-2
Post Scriptum
GPT-2其實最驚人的是其極強的生成能力,而如此強大的生成能力主要還是要歸功於其資料品質以及驚人參數量和數據規模。 GPT-2的參數量大到用於實驗的模型都還處於欠擬合狀態,如果接著訓練,效果還能再提升。
總上面這些關於Transformer工作的發展中,我也整理出了一些關於深度學習發展趨勢的個人心得:
1. 有監督模型向半監督甚至無監督方向發展
數據的規模的增長速度遠遠超過了數據的標註速度,這也導致了大量無標籤資料的產生。這些無標籤的數據並非沒有價值,相反,如果找到合適的“煉金術”,將可以從這些海量的數據中獲得意想不到的價值。如何利用上這些無標籤的資料來改善任務的表現變成了一個越來越無法輕視的問題。
2. 從少量資料複雜模型到大量資料簡單模型
#深度神經網路的擬合能力非常的強大,一個簡單的神經網路模型就足以擬合任何函數。但無奈使用越簡單的網路結構完成同一個任務,對資料量的要求也更高。資料量越是上升,資料品質越是提高,往往對模型的要求就越會降低。資料量越大,模型就越容易捕捉到符合真實世界分佈的特徵。 Word2Vec就是一個例子,它所使用的目標函數非常的簡單,但是由於使用了大量的文本,於是訓練出的詞向量中就包含了許多有趣的特性。
3. 從專用模型發展到通用模型
#GPT、BERT、MT-DNN、GPT-2都使用了經過預訓練的通用模型來繼續進行下游的機器學習任務,並不需要對模型本身再做太多的修改。如果一個模型的表達能力足夠的強,訓練時候使用的資料量足夠的大,那麼模型的通用性就會更強,就不需要針對特定的任務做太多的修改。最極端的情況就像是GPT-2這個樣子,訓練時甚至完全不需要知道後續的下游任務是什麼,就能夠訓練出一個通用的多任務模型。
4. 對資料的規模和品質要求提高
GPT、BERT、MT-DNN、GPT-2雖然先後刷榜,但是我認為成績的提升中,資料規模的提升佔有比結構調整更大的比重。隨著模型的通用化和簡化,為提升模型的性能,今後更多的注意力將會從如何設計一個複雜、專用的模型轉移到如何獲取、清洗、精化出質量更加出眾的、大量的數據上。資料的處理方式調整的作用將會大於模型結構調整的作用。
綜上所述,DL競賽遲早要成為大廠間拼資源、拼字力的較量。可能幾年內就會出現一個新的課題:綠色AI,低碳AI,永續AI等。
以上是Transformer結構及其應用詳解-GPT、BERT、MT-DNN、GPT-2的詳細內容。更多資訊請關注PHP中文網其他相關文章!