【Transformer模型】:Attention is all your need(附attention的代碼)

tranformer已經火了好長一段時間了,一直只是只聞其名不知其意,特地看了attention is all your need。
    這篇論文摒棄了傳統encoder-decoder模型必須結合cnn或者rnn的固有模式,只用了attention模型,可謂大道至簡。現在主流的序列轉化模型都是基於端到端的encoder-decoder的RNN或者CNN網絡結構模式。現在都是在該框架中引入了attention機制來進一步提高模型的性能。而本文提出了一個新的簡單網絡,Transformer。它只使用了attention機制,完全摒棄了RNN和CNN。實驗結果表明在明顯降低訓練時間消耗的同時模型也獲得了較爲顯著的效果。

介紹

    RNN,LSTM,GRU現在已經是語言模型和語言翻譯等序列建模中最好的模型基礎了。並且已經有大量學者對循環網絡和encoder-decoder網絡結構做了改進和優化。循環網絡的計算考慮了輸入輸出序列的位置信息。在每個計算的time step中考慮序列的一個位置,將每個位置上的元素按順序輸入網絡就可以獲得當前time step下序列的隱狀態h,而該隱狀態是根據當前time step輸入的位置信息和上個time step獲得的隱狀態共同獲取得到。但是序列本身的內在序列連續性,限制了模型訓練的並行性,雖然有很多很多相關工作對其進行改進(比如多序列並行等),但是其本質問題依然存在。
Attention已經成爲序列模型的一個重要部分,它主要是爲了解決模型中序列長距離依賴的問題。但是現在主流的做法基本上還是將attention模型和循環網絡配合來使用。
本文提出了transformer模型,該模型摒棄了循環的模式,而只完全依賴attention機制來刻畫輸入輸出序列中的全局依賴信息。

背景


    現在已有一些序列處理方法ENGPU,BN,CS2S。通過使用CNN對全部輸入和輸出作爲基礎模塊來達到減少序列數據計算量,可以達到並行計算隱層表示。但是這些方法對輸入序列長度和位置關係都是呈線性和對數增長。而對距離的依賴依然是一個沒有克服的難點。在Transformer中,我們可以把這些操作都控制在常數範圍內,雖然我們用了平均attention位置方法降低了性能,但是我們利用 multi-head attention對其進行了補充。

 self-attention


    Self-Attention 是attention機制中的一種,通過關聯單個序列中的不同位置來計算序列的表示。Self-Attention已經被成功應用在不同的任務中,比如閱讀理解,摘要抽取、文本續寫。端到端記憶網絡是基於循環attention機制,而不是在循環中完成序列對齊。這種框架已經在問題回答,語言模型等中十分常見。
本文提出的Transformer模型,是第一個只依靠Self-Attention計算輸入輸出序列的轉換模型,並沒有結合RNN或者CNN。

模型結構


    常見的神經序列模型,都是基於Encoder-Decoder框架,本文的框架也不例外。Encoder階段是將符號表示的輸入序列(x1,...,xn)轉化爲連續表示的序列z=(z1,....zn).給定z,Decoder部分就可以按次輸出新的符號序列(y1,...,ym)。模型每一步都是auto-regressive,通過結合前一次生成的符號來生成下一次的輸出。
Transformer沿用了Encoder-Decoder框架,但是利用Stacked Self-Attention 和基於點的全連接層替代了CNN和RNN的編碼和解碼過程。

Transformer 沿襲了encoder-decoder的結構,並在該結構下使用的不再是cnn或者rnn,而是self-attention和基於點的全連接層。將其應用在了encoder和decoder層中。

                                                     

如上圖,就是一個單個的transfomer結構。具體的結構:

Encoder:encoder是由6層獨立的layers構成。每層由兩個子層,就是上圖左邊的兩個。第一個是一個多頭 self-attention結構。第二個是一個簡單的基於點的全連接前向網絡。並且每個子層都借鑑了殘差網絡的思想使用了一個殘差連接來連接每個子層的輸出。並且對輸出的結構層上做了LayerNorm。針對一個子層的輸出就是LayerNorm(x+Sublayer(x)),其中的Sublayer(x)就是子層結構。爲了能使用上殘差,所有的輸出維度都統一成了一樣的維度:512.

Decoder: decoder也是由6層的獨立層組成。但是和encoder由一點差異,就是decoder不同於encoder兩個子層,它用了三個子層。用於對encoder的輸出做multi-head self attention。具體結構都一樣,也是在子層上應用了殘差連接,再在子層輸出加上一個LayerNorm。但是論文在decoder中的multi-head self attention 做了一個mask修改。目的是爲了防止序列之後的位置被用於預測前面的位置信息,造成對模型的信息泄漏。

Attention

接下來解釋一下到底什麼是Attention。attention可以被描述爲將一個query,和一對key-value的鍵值對映射到輸出。什麼意思呢?可以這樣理解,現在由一個query,比如說是“蘋果好吃”,

然後key-value對分別是:

key1:蘋果好吃嗎?value1:好吃

key2:栗子好吃嗎?value2:好吃

key3:蘋果是什麼? value3:蘋果是吃的

當然一般情況下這些query,key,value都是向量,我這裏只是打個比喻。然後我們有了一個query:”蘋果好吃“,我們就可以根據這個query一一比對key,如果不管query內容,那麼query和每個key的對應關係應該都是等價的。但是很明顯,這裏的query和key1是最相似的,所以我們更關注的是key1的結果,那麼我們其實就更在意value1,所以,我們通過query對應上了value1。這個就是attention的主要結構。具體文章中介紹了兩種:

Scaled Dot-Product Attention 基於點乘的attention

                       

論文針對基於點乘的attenion做了一個優化,叫做scaled dot-product attention。

輸入是由dk維的queries和keys,dv維的values組成。然後計算按上面的解釋的思路,得去計算query“蘋果好吃”和全部keys的相似度,這裏的計算方式就是計算他們之間的點乘,然後再除以sqrt(dk),來計算query和key之間的相似度,最後用一個softmax來歸一化相似度,作爲values。然後query一般不只一個,所以把全部的query向量合併起來就是一個query矩陣,把它定義爲Q,同理,所有的keys和values就是K和V,就可以利用矩陣計算來得到結果:

Attention(Q,K,V)=softmax(QK^T/sqrt(dk))V

其實這裏就是對常見的點乘attention除以了sqrt(dk),還有一個常用的attention是Additive attention(加法attention),加法attention的話就是在queries和keys上加上了一個單層的神經網絡,其實就是一個權值,然後將經過映射的query和key加起來來比較相似度。相比的話,肯定是點乘的attention更快了,直接計算矩陣就可以了。當然如果dk的值相對比較小的話,兩個attention的效果差不多,但是如果dk比較大的話,加法attention可能還會比點乘的好點。這個可能是點乘要把所有的值乘起來相加,如果維度很大的話,值肯定小不了,那麼值一大,在softmax的導數函數中,值越大梯度越小,導致softmax難以優化。所以纔有了上面的scaled dot-product attention。

Multi-Head Attention

多頭的意思就是將單個的attention並行的做多個,不做權重共享,然後就會產生多個輸出,然後將這些結果串起來就是一個新的向量,然後再做一次映射,合併成一個值。具體的公式如下:

MultiHead(Q,K,V) = Concat(head1,head2,..,Headh)Wo 其中 headi = Attention(QWi,KWi,VWi)

Attention在模型中的應用

Transormer中的三種multi-head attention使用方式:

1.在encoder-decoder attention 層中,queries是來自之前的decoder層的輸出,keys和values是本層encoder的輸出。這使得decoder所有位置都能參與輸入序列全部位置輸入的計算。

2.encoder中的self-attention層。self-attention層中的所有keys,values,和queries都是同一個東西。

3.decoder中的self-attention層。和encoder的一樣。

基於位置的前向網絡

這個的話就是直接在self-attention之後加入一個單隱層的網絡,將子層的輸出做一個映射。

位置編碼

如果沒有位置編碼,那麼前面說了這麼多,整個模型是沒有基於位置信息的,那麼這整個模型根本沒有考慮到序列的關係,只能算是一個高階版本的類似的詞袋模型。所以如果不用cnn或者rnn就需要引入一個位置信息,這裏引入了位置編碼。論文將位置直接編碼後和輸入的embedding相加來作爲模型的輸入。而位置的編碼也不是算法學習出來的,而是直接利用數據公式計算獲得,

 

這裏的pos就是序列中元素的位置,i是用於表示該位置的dmodel維向量的第i個位置。直接將位置編碼爲正弦波,這樣就可以相對用線性的表示不同位置之間的關係。

學習了下大佬的代碼:https://kexue.fm/archives/4765

代碼可以上github看下

https://github.com/bojone/attention 

https://github.com/Shicoder/DeepLearning_Demo/tree/master/attention

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章