簡介
Transformer出自于Google于2017年發(fā)表的論文《Attention is all you need》,最開始是用于機器翻譯,并且取得了非常好的效果。但是自提出以來,Transformer不僅僅在NLP領(lǐng)域大放異彩,并且在CV、RS等領(lǐng)域也取得了非常不錯的表現(xiàn)。尤其是2020年,絕對稱得上是Transformer的元年,比如在CV領(lǐng)域,基于Transformer的模型橫掃各大榜單,完爆基于CNN的模型。為什么Transformer模型表現(xiàn)如此優(yōu)異?它的原理是什么?它成功的關(guān)鍵又包含哪些?本文將簡要地回答一下這些問題。
Transformer總覽
我們知道Transformer模型最初是用于機器翻譯的,機器翻譯應(yīng)用的輸入是某種語言的一個句子,輸出是另外一種語言的句子。如下圖:



encoder的一共包含2層,分別是Self-Attention(SA)層和Feed Forward Neural Network(FFN)層,SA層的作用是在對輸出序列中的每個詞編碼的時候,讓編碼信息中包含序列中的其他單詞的信息,即保存了當(dāng)前單詞與其余單詞之間的關(guān)系。FFN層就是普通的前向網(wǎng)絡(luò),對SA層的輸出進行近一步的特征提取。
Self-Attention層
我們現(xiàn)在了解了Transformer模型的整體結(jié)構(gòu),其實并不復(fù)雜。這節(jié)主要要介紹其中的Self-Attention層,這也是困擾諸多初學(xué)者的部分。相信很多人都是第一次聽說self-attention這個詞,那么它的工作原理究竟是什么呢?接下來我們一步一步地將它分解開來。
首先我們知道encoder的輸入是序列,也就是詞向量,也叫做token。畢竟原始的句子,比如英文,是無法直接輸入到模型的,我們需要使用類似Word Embedding等方式,將單詞轉(zhuǎn)換成一個個固定長度的詞向量,比如512維。將詞向量序列直接輸入encoder,即依次經(jīng)過SA層和FNN層,如下:

Self-Attention的實現(xiàn)細節(jié)
這一節(jié)通過實際的例子來剖析SA層的實現(xiàn)細節(jié),首先是如何基于向量來計算注意力,然后我們看一下它在實際應(yīng)用中是如何基于矩陣進行加速的。整個Self-Attention過程可以分為6步,接下來我們來一探究竟。
一、 創(chuàng)建Q、K、V矩陣
首先我們需要為每個輸入向量(也就是詞向量)創(chuàng)建3個向量,分別叫做Query、Key、Value。那么如何創(chuàng)建呢?我們可以對輸入詞向量分別乘上3個矩陣來得到Q、K、V向量,這3個矩陣的參數(shù)在訓(xùn)練的過程是可以訓(xùn)練的。注意Q、K、V向量的維度是一樣的,但是它們的維度可以比輸入詞向量小一點,比如設(shè)置成64,其實這步也不是必要的,這樣設(shè)置主要是為了與后面的Mulit-head注意力機制保持一致(當(dāng)使用8頭注意力時,單頭所處理的詞向量維度為512/8=64,此時Q、K、V向量與輸入詞向量就一致了)。我們假設(shè)輸入序列為英文的"Thinking Machines",那么對應(yīng)的Q、K、V向量的計算示例圖如下:

但是究竟什么是Q、K、V向量呢?它們的具體含義是什么?如何理解記憶呢?首先Query、Key、Value這個概念出自于信息檢索系統(tǒng),我們以在Youtube上搜索視頻為例來具體說明一下它的工作流程。
當(dāng)你搜索(query)一個特定的視頻的時候,搜索引擎會將你的query映射到一組keys(比如視頻標題、描述等等)上去,然后去找與這些keys最匹配的視頻,也就是values。這就是基于特征的查詢的基本原理。整體流程如下:
二、 計算Score
得到Q、K、V矩陣之后,第一步是計算Self-Attention中的score,具體做法如下。以輸入序列的第一個單詞"Thinking"為例,我們需要計算這個單詞與輸入序列的所有單詞之間的score。當(dāng)我們在某個位置對單詞進行編碼時,這個score其實決定了將多少注意力放在輸入句子的其他部分上。
score的計算是取當(dāng)前被計算單詞的query向量,以及所有的單詞的key向量,取兩者的點積來當(dāng)做當(dāng)前單詞的score。比如我們對輸入序列的第一個單詞“Thinking”計算score,由于整個序列長度為2,那么第一個score的計算使用和
的點積,第二個score使用
和
的點積。如下圖:

三、 Softmax
接下來,我們首先將上一步得到的score除以8,為什么是8,因為在第一步中,我們定義了Q、K、V矩陣的維度為64,64開根號為8。這么做的原因是為了保證更加穩(wěn)定的梯度。然后將結(jié)果通過一個Softmax函數(shù),Softmax函數(shù)會將scores歸一化,使其全部都是整數(shù),并且累加和為1。
經(jīng)過Softmax函數(shù)后的score決定了當(dāng)前單詞對每個位置的單詞的影響程度。很顯然當(dāng)前單詞對當(dāng)前位置的影響程度一般是最大的。
四、將socre乘以values
接下來,將softmax后的scores乘以values向量,這么做的目的是為了保證我們需要關(guān)注的values向量的完整性,并且忽略掉不相關(guān)的values向量。例如對不相關(guān)的values向量乘以一個0.001,使其變得微不足道。
五、將values累加起來
這一步就很簡單,將上一步得到的各個values向量累加起來就得到當(dāng)前輸入詞向量的輸出向量了。將四五步結(jié)合起來看,其實就相當(dāng)于是一個加權(quán)求和操作,其中的權(quán)重就是第三步計算出來的scores,整個過程示意圖如下:
這就是Self-Attention層的整體計算過程。這個輸出向量就是我們需要進一步送往前饋神經(jīng)網(wǎng)絡(luò)中的。但是在實際的計算中,為了加快計算速度,我們通常會使用矩陣運算,接下來我們看下如何使用矩陣運算來簡化和加速上述的計算步驟。
Self-Attention矩陣計算
第一步是計算Query, Key,和Value向量,我們先將所有的輸入詞向量拼成一個矩陣,然后乘以已經(jīng)訓(xùn)練好的權(quán)重矩陣
。

剩下的步驟其實就是計算scores,通過softmax函數(shù),再乘以矩陣V,我們可以用一下公式來表示:注意輸入矩陣X中的每一行都代表了輸入序列中的一個詞向量。

多頭注意力機制
上面提到的Self-Attention層可以認為是單頭的,那什么叫多頭注意力機制呢?其實也非常簡單,就是對于輸入詞向量矩陣, 不再只是擁有一組權(quán)重矩陣,而是擁有多組。這樣做主要會帶來一下2個好處:
- 它擴展了模型專注于不同位置的詞向量的能力
- 它給予了attention層多種表示子空間,即擁有多組
權(quán)重矩陣,這樣可以將輸入詞向量映射到不同的特征子空間。
兩頭注意力機制
如果我們將Self-Attention的計算重復(fù)8次,每次使用不同的權(quán)重矩陣,那么我們就得到了8頭注意力機制,論文中的Transformer實現(xiàn)就是8頭的。同理,我們也會得到8個不同的輸出矩陣z但是這會引發(fā)一個問題,8個輸出矩陣無法輸入到encoder下一層的FNN層,所以我們需要設(shè)計一種方式來講這8個輸出矩陣聚合成單個矩陣。
怎么做呢?我們可以首先將這8個矩陣concat起來,然后乘以一個額外的權(quán)重矩陣,這樣就可以得到與輸入詞向量一樣大小的輸出向量,然后再傳入FNN層。
下面是多頭注意力機制的整體計算過程圖:多頭注意力機制
Positional Encoding
到目前為止,我們都還沒有考慮輸入序列的順序問題。然后對于一句話而言,詞的順序直接影響到了整句話的意思,所以順序非常重要。Transformer使用了Positional Encoding來解決這個問題,即給每個輸入詞向量都加上一個位置向量。這些位置向量可以決定每個單詞在句子中的位置,或者說可以指示句子中不同單詞之間的相對位置。

殘差連接
encoder中的SA層基本就講完了,F(xiàn)FN層其實沒有什么特別好說的,就是普通的全連接層。有一點要注意的是,為了解決深度學(xué)習(xí)中的退化問題,encoder中的SA層和FFN層都采用了殘差連接。如下圖中虛線部分

這便是encoder的整體計算流程圖了,Transformer模型中堆疊了多個這樣的encoder,無非就是輸出連接輸入罷了,常規(guī)操作。
最后再附上一個Transformer的代碼實現(xiàn),讀者有興趣可以跟著自己復(fù)現(xiàn)一下Transformer模型的代碼。



