天天看點

NLP《Tranformer和Self-Attention》

一:自注意力模型

上一篇文章《seq2seq》中我們學習到了attention機制,它可以看到全局的資訊,并且它也可以正确地去關注到相關的有用的資訊。

原始的encoder是以RNN為基礎的,RNN機制實際中存在長程梯度消失的問題,對于較長的句子,我們很難寄希望于将輸入的序列轉化為(編碼為)定長的向量而儲存所有的有效資訊,是以随着所需處理的句子的長度的增加,這種結構的效果會顯著下降。

從encoder到特定向量C過程中,會存在資訊丢失問題,因為那麼多豐富的語言,怎麼可能用一個特定長度的向量表示的下呢?很難吧。之前的模型很容易由于梯度消失,距離過長導緻長期依賴失效,也就是有用資訊丢失。而且注意力分散,導緻有用資訊和無用資訊無法更好區分不開。

是以,attention解決了資訊提取的問題,既關注全局資訊,也正确把握關鍵資訊。這其實也是一種方法論。我關注全部,但是每一部分我關注多少?

以上純屬回顧

但是這就完美了麼?雖然使用了Attention機制,隻解決了encoder關鍵資訊提取的問題(從全局出發,保證關鍵資訊能被正确關注到,而不是使用一個向量C來試圖包含所有資訊(理論上顯然太勉強)),但是還是基于RNN模型的啊,RNN模型隻能被遞歸運算,無法做到并行化,我們也看到了,也許注意力就是最後集中在部分,而非全局,那麼理應能夠被并行化計算,加快運算速度才對。

一個想法就是CNN,CNN可以做到并行化計算,似然能這樣,單每一層隻關注局部資訊,隻有在更高層才能關注到更廣一點的資訊,或者是全局資訊,這很明顯帶來了另外的計算量,顧此失彼。想一想人家seq2seq的attention機制,雖然是遞歸運算的,但是也就是一層就可以得到全局資訊。

有沒有兩全其美的做法呢?即可以用attention機制去獲得全局資訊,正确關注到應該被關注的部分,還可以并行化計算。這就是self-attention的工作了。

顯然不能使用RNN結構,這個結構天然就是遞歸。

是以我們一起來看看self-attention做的工作吧。

如下圖所示:

NLP《Tranformer和Self-Attention》
NLP《Tranformer和Self-Attention》
NLP《Tranformer和Self-Attention》

這一層就這麼愉快表示了。并且Wq,Wk,Wv矩陣都是學習來的,權值共享的。

但是一般呢,我們還會做出一些優化。

1:假如位置資訊,因為我們看到上述式子,輸入的詞向量之間的位置資訊丢失了。“我愛你”和“愛我你”是輸出一樣的結果,這顯然也不符合思維的,是以需要加入位置向量資訊。

NLP《Tranformer和Self-Attention》

是以Step 1需要做适量修改,增加一步位置向量相關的操作:

NLP《Tranformer和Self-Attention》

其中P={p1,p2,p3,…,pn},次元和E是一樣的,且每個元素取值是-1~1之間。

這樣一來将位置向量添加到詞嵌入中使得它們在接下來的運算中,能夠更好地表達的詞與詞之間的距離。

2:多頭self-attention(muti-head self-attention)

簡單來說呢,我們希望能從不能的角度去看待位置的注意力。

實作也簡單,就是設定多個完全獨立的Wq,Wk,Wv矩陣,多組獨立運算,分别得到自己的輸出B。假設我有H個頭。也就是有H組Wq,Wk,Wv矩陣,分别獨立地進行運算。

NLP《Tranformer和Self-Attention》

最後将這H個B對應位置輸出拼接起來,做一個線性變換即可。得,第i個位置輸出是。

NLP《Tranformer和Self-Attention》

W_O也是學習到的。

NLP《Tranformer和Self-Attention》

如上圖所示,将多個頭的值concat一起,每一行拼接後形成新的第幾個輸出,每一列是單個頭的所有N個輸出。

多頭拓展了專注于不同位置的能力。

Self-attention完全依賴注意力機制來刻畫輸入和輸出之間的全局依賴關系,而且不使用遞歸運算的RNN網絡了。這樣的好處就是:

第一:可以有效的防止RNN存在的梯度消失的問題進而導緻的有用資訊丢失問題(這也是基本的attention機制的好處),既可以考慮全局資訊,也能正确關注到應該關注的關鍵資訊。

第二:是允許所有的字全部同時訓練(RNN的訓練是疊代的,一個接一個的來,目前這個字過完,才可以進下一個字),即訓練并行,大大加快了計算效率。

切記,此結構隻用于替換RNN的一個層結構。

NLP《Tranformer和Self-Attention》

現在我們就可以試圖把所有RNN的結構夠可以替換成 self-attention結構了。

這樣一來就可以并行化計算了,可以使用GPU進行加速處理。

這個結構是Transformer結構中提出來的,将被大量使用在Transformer結構中。

二:transformer模型

下面我們來學習一下大名鼎鼎的Transformer機制。

Seq-2-Seq的主要還是encoder-decoder的結構,但是内部結構之前是RNN和CNN。效果好點的呢,就是之前學習的,增加了Attention機制的seq-2-seq了。

現在為了并行化計算,有利于GPU加速,直接使用self-attention替換掉了RNN結構。

如下圖所示:

NLP《Tranformer和Self-Attention》

整體而言,是由一個encoders部分和一個decoders部分組成的,解碼器最後有一個線性層和一個softmax層,輸出對應詞語的one-hot向量。

Encoders部分:

是由N個小編碼器堆疊而成。

每個小編碼器又是由一個多頭self-attention層,和一個小的FFNN(前饋神經網絡)組成。

Decoders部分:

是由N個小解碼器堆疊而成。

每個小解碼器又是由一個masked多頭self-attention層,一個encoder-decoder多頭 self-attention層,和一個小的FFNN(前饋神經網絡)組成。

下面我們仔細講解各個層:

0)Add && Norm Layer(相加歸一層)

這個結構在後面很多層都有用到,是以我們先講解這個層,友善定義符号和講解。

先是一個殘差計算。一點就是借鑒殘差網絡的思路,因為在應用中這個網絡很深,殘差結構的好多之前也學習過,防止網絡過深,梯度消失,導緻前面的參數無法很好更新。

NLP《Tranformer和Self-Attention》

然後還要做歸一化操作,也就是類似于batch-normorlize的操作,目的就是歸一化資料特征的分布,使其分布服從N(0~1),有利于收斂速度加快,這個在學習batch-norm的時候也學習過的,計算過程也很類似。

NLP《Tranformer和Self-Attention》

1)Muti-Head Self-Attention Layer(多頭self-attention層)

這個不用多講了,因為本文第一章節最開始就學習了這個計算過程。

NLP《Tranformer和Self-Attention》

加上相加歸一層

NLP《Tranformer和Self-Attention》

2)FFNN Layer

這是一個 Position-wise 前向神經網絡,encoder和decoder的每一層都包含一個前向神經網絡,激活函數順序是線性、RELU、線性。

NLP《Tranformer和Self-Attention》

加上相加歸一層

NLP《Tranformer和Self-Attention》

3)Masked Muti-Head Self-Attention Layer

我們給詞彙表增加如下詞彙

< BOS>:句子開始

< EOS>:句子結尾

< UNK>:未知詞彙

作為翻譯的時候,比如從“我有一隻貓”翻譯到“I have a cat”

并行計算,先從encoder一次性計算結束,等待decoer遞歸疊代運算,此時decoder有點像是RNN了。每一次輸入的序列都是把上一次輸出的序列。

比如第一次先輸入< BOS>,輸出< I> ,落下去。

比如第二次先輸入< I>,輸出< have> ,落下去。

比如第三次先輸入< I have >,輸出< a> ,落下去。

比如第四次先輸入< I have a >,輸出< cat>,落下去。

比如第五次先輸入< I have a cat >,輸出< EOS>

翻譯任務的話,遇到了EOS就終止了。

是以decoder每次輸入的句子的長度是不一緻的。怎麼辦呢?有多長取多長,這一層隻被允許處理輸出序列中更靠前的那些位置。在softmax步驟前,它會把後面的位置都是無效的,因為都沒有誕生呢,無效的都給隐去(把它們設為-inf,softmax層計算後就是權值為0,也就是不關心)。是以對于不存在的序列我們就不關心了。隻看存在的序列,如下圖所示啊,這是前倆過程。

NLP《Tranformer和Self-Attention》

其他步驟都是和正常的self-attention的一緻的,再加上加法歸一層。

4)encoder-decoder Muti-Head Self-Attention Layer

這一層的目的就是給encoder最後生成的結果C做self-attention操作,也就是對encoder的每一層的都關注多少注意力,也就是充分利用原始句子的資訊來影響自己的輸出。

Encoder最後成功的矩陣C,每一行都是輸入詞彙的計算輸出。有多少輸入詞彙,C就有多少行,這個矩陣會給每一個小decoder都傳過去,讓每一個小decoder都去對這個結果進行注意力運算。

唯一不同的是,attention過程中K和V矩陣的生成變了。

正常的self-attention的QKV矩陣都是E自己生成的,現在卻變成了,E隻産生Q矩陣,而是用C來生成K和V矩陣。

NLP《Tranformer和Self-Attention》

其他步驟都是和正常的self-attention的一緻的。再加上加法歸一層。

5)最終的Liner Layer和sofatmax Layer

這一層就是最後輸出一個詞彙的輸出層了,此層的輸入到輸出如下:

NLP《Tranformer和Self-Attention》

最後輸出是一個詞彙的one-hot向量,輸出到終結,否則落下去到下一次計算。

6)損失函數依然是交叉熵損失函數,這個不多講了,之前在學習語言模型和詞向量的時候都學習過的。下面說兩個訓練小技巧。

a)LabelSmooth,對于詞語數量巨大的話,不要将one-hot向量标記為非0即1,非1即0,而可以試圖将1改為0.95,剩下的0.05由任意五個詞彙平分,每一個是0.01,。

b)學習率變化:可以嘗試用如下的學習率變化趨勢來學習模型。簡單的說,就是先讓學習率線性增長到某個最大的值,然後再按指數的方式衰減,如下圖。

NLP《Tranformer和Self-Attention》

7)總結

核心就是transformer結構,這種結構完全依賴于注意力機制,取代了基于Encoder-Decoder的循環層,并且引入了位置嵌入,Multi-Head Attention機制。

優點就是,可解釋性強,且容易并行計算,繼承了attention機制的好處。

繼續閱讀