今天給大家分享一篇關于深度學習模型Transformer的文章。我愿稱之為講解Transformer模型最好的文章。
文章內容主要介紹 Transformer 模型的具體實現:
Transformer整體架構
Transformer概覽
引入張量
多頭注意力機制Mutil-Head Attention
位置反饋網絡(Position-wise Feed-Forward Networks)
殘差連接和層歸一化(Add & Normalize)
位置編碼(Positional Encoding)
解碼器Decoder
掩碼Mask:Padding Mask + Sequence Mask
最后的線性層和Softmax層
嵌入層和最終的線性層
正則化操作
博客地址:https://blog.csdn.net/benzhujie1245com/article/details/117173090
英文地址:http://jalammar.github.io/illustrated-transformer/
文章有點長,建議收藏
1、Transformer模型架構
2017 年,Google 在論文 Attentions is All you need(論文地址:https://arxiv.org/abs/1706.03762) 中提出了 Transformer 模型,其使用 Self-Attention 結構取代了在 NLP 任務中常用的 RNN 網絡結構。
相比 RNN 網絡結構,其最大的優(yōu)點是可以并行計算。Transformer 的整體模型架構如圖所示:
Transformer模型架構
2、Transformer 概覽
首先,讓我們先將 Transformer 模型視為一個黑盒,如圖所示。在機器翻譯任務中,將一種語言的一個句子作為輸入,然后將其翻譯成另一種語言的一個句子作為輸出:
Transformer 模型(黑盒模式)
2.1 Encoder-Decoder
Transformer 本質上是一個 Encoder-Decoder 架構。因此中間部分的 Transformer 可以分為兩個部分:編碼組件和解碼組件
Transformer 模型(Encoder-Decoder 架構模式)
其中,編碼組件由多層編碼器(Encoder)組成(在論文中作者使用了 6 層編碼器,在實際使用過程中你可以嘗試其他層數)。解碼組件也是由相同層數的解碼器(Decoder)組成(在論文也使用了 6 層)。
編碼器/解碼器組成
每個編碼器由兩個子層組成:
Self-Attention層(自注意力層)
Position-wise Feed Forward Network(前饋網絡,縮寫為 FFN)
如下圖所示:每個編碼器的結構都是相同的,但是它們使用不同的權重參數(6個編碼器的架構相同,但是參數不同)
Encoder編碼器組成
編碼器的輸入會先流入 Self-Attention 層。它可以讓編碼器在對特定詞進行編碼時使用輸入句子中的其他詞的信息(可以理解為:當我們翻譯一個詞時,不僅只關注當前的詞,而且還會關注其他詞的信息)。
注:關注詞語的上下文環(huán)境,不僅僅是詞語本身
后面我們將會詳細介紹 Self-Attention 的內部結構。然后,Self-Attention 層的輸出會流入前饋網絡。
解碼器也有編碼器中這兩層,但是它們之間還有一個注意力層(即 Encoder-Decoder Attention),其用來幫忙解碼器關注輸入句子的相關部分(類似于 seq2seq 模型中的注意力)
編碼器:self-attention層 + 前饋網絡FFN(Position-wise Feed Forward Network)
解碼器:self-attention層 + Encoder-Decoder Attention + 前饋網絡FFN(Position-wise Feed Forward Network)
3、引入張量
現在我們已經了解了模型的主要組成部分,讓我們開始研究各種向量/張量,以及他們在這些組成部分之間是如何流動的,從而將輸入經過已訓練的模型轉換為輸出。
3.1 引入詞嵌入Embedding
和通常的 NLP 任務一樣,首先,我們使用詞嵌入算法(Embedding) 將每個詞轉換為一個詞向量。
在 Transformer 論文中,詞嵌入向量的維度是 512。
每個詞被嵌入到大小為 512 的向量中。我們將用這些簡單的框代表這些向量。
詞嵌入僅發(fā)生在最底層的編碼器中。所有編碼器都會接收到一個大小為 512 的向量列表:
底部編碼器接收的是詞嵌入向量
其他編碼器接收的是上一個編碼器的輸出。
這個列表大小是我們可以設置的超參數——基本上這個參數就是訓練數據集中最長句子的長度。
3.2 詞嵌入后編碼
對輸入序列完成嵌入操作后,每個詞都會流經編碼器的兩層。
詞嵌入與編碼
接下來,我們將換一個更短的句子作為示例,來說明在編碼器的每個子層中發(fā)生了什么。
上面我們提到,編碼器會接收一個向量作為輸入。編碼器首先將這些向量傳遞到 Self-Attention 層,然后傳遞到前饋網絡,最后將輸出傳遞到下一個編碼器。
編碼器揭秘
4、Self-Attention(自注意力)
4.1 Self-Attention概覽
首先我們通過一個例子,來對 Self-Attention 有一個直觀的認識。假如我們要翻譯下面這個句子:
The?animal?didn’t?cross?the?street?because?it?was?too?tired
這個句子中的 it 指的是什么?是指 animal 還是 street ?對人來說,這是一個簡單的問題,但是算法來說卻不那么簡單。
當模型在處理 it 時,Self-Attention 機制使其能夠將 it 和 animal 關聯(lián)起來。
當模型處理每個詞(輸入序列中的每個位置)時,Self-Attention 機制使得模型不僅能夠關注當前位置的詞,而且能夠關注句子中其他位置的詞,從而可以更好地編碼這個詞。
如果你熟悉 循環(huán)神經網絡 RNN,想想如何維護隱狀態(tài),使 RNN 將已處理的先前詞/向量的表示與當前正在處理的詞/向量進行合并。Transformer 使用 Self-Attention 機制將其他詞的理解融入到當前詞中。
圖注:當我們在編碼器 #5(堆棧中的頂部編碼器)中對單詞it進行編碼時,有一部分注意力集中在The animal上,并將它們的部分信息融入到it的編碼中。
4.2 Self-Attention機制
下面我們來看一下Self-Attention的具體機制。其基本結構如圖所示:
Scaled Dot-Product Attention(縮放點積注意力)
對于 Self Attention 來講,Q(Query),K(Key)和 V(Value) 三個矩陣均來自同一輸入,并按照以下步驟計算:
首先計算 Q 和 K 之間的點積,為了防止其結果過大,會除以;其中為 Key 向量的維度。
然后利用Softmax操作將其結果歸一化為概率分布,再乘以矩陣 V 就得到權重求和的表示。
整個計算過程可以表示為:
為了更好的理解 Self-Attention,下面我們通過具體的例子進行詳細說明。
4.3 Self-Attention詳解
下面通過一個例子,讓我們看一下如何使用向量計算 Self-Attention。計算Self-Attention的步驟如下:
第 1 步:對編碼器的每個輸入向量(在本例中,即每個詞的詞向量)創(chuàng)建三個向量:
Query 向量
Key 向量
Value 向量
它們是通過詞向量分別和3個矩陣相乘得到的,這3個矩陣通過訓練獲得。
請注意,這些向量的維數小于詞向量的維數。新向量的維數為 64,而 embedding 和編碼器輸入/輸出向量的維數為 512。
新向量不一定非要更小,這是為了使多頭注意力計算保持一致的結構性選擇。
上圖中,乘以權重矩陣得到,即與該單詞關聯(lián)的Query向量。
最終會為輸入句子中的每個詞創(chuàng)建一個 Query,一個 Key 和一個 Value 向量
什么是 Query,Key 和 Value 向量?它們是一種抽象,對于注意力的計算和思考非常有用。繼續(xù)閱讀下面的注意力計算過程,你將了解這些向量所扮演的角色。
第 2 步:計算注意力分數。
假設我們正在計算這個例子中第一個詞 Thinking 的自注意力。我們需要根據 Thinking 這個詞,對句子中的每個詞都計算一個分數。這些分數決定了我們在編碼 Thinking 這個詞時,需要對句子中其他位置的每個詞放置多少的注意力。
這些分數,是通過計算 Thinking 的 Query 向量和需要評分的詞的Key向量的點積得到的。如果我們計算句子中第一個位置詞的注意力分數,則第一個分數是和的乘=點積,第二個分數是和的點積。
第 3 步:將每個分數除以;其中為 Key 向量的維度。
目的是在反向傳播時,求梯度更加穩(wěn)定。實際上,你也可以除以其他數。
第 4 步:將這些分數進行 Softmax 操作。Softmax 將分數進行歸一化處理,使得它們都為正數并且和為1。
Softmax操作
這些 Softmax 分數決定了在編碼當前位置的詞時,對所有位置的詞分別有多少的注意力。很明顯,當前位置的詞匯有最高的分數,但有時注意一下與當前位置的詞相關的詞是很有用的。
第 5 步:將每個 Softmax 分數分別與每個 Value 向量相乘。
這種做法背后的直覺理解是:對于分數高的位置,相乘后的值就越大,我們把更多的注意力放在它們身上;對于分數低的位置,相乘后的值就越小,這些位置的詞可能是相關性不大,我們就可以忽略這些位置的詞。
越大越重視
第 6 步:將加權 Value 向量(即上一步求得的向量)求和。這樣就得到了自注意力層在這個位置的輸出。
self-attention完整過程
這樣就完成了自注意力的計算。生成的向量會輸入到前饋網絡中。但是在實際實現中,此計算是以矩陣形式進行,以便實現更快的處理速度。下面我們來看看如何使用矩陣計算。
4.4 使用矩陣計算 Self-Attention
第一步:計算Query、Key和Value矩陣。
首先將所有詞向量放到一個矩陣X中,然后分別和3個我們訓練過的權重矩陣()相乘,即得到矩陣。
計算QKV矩陣
矩陣 X 中的每一行,表示輸入句子中的每一個詞的詞向量(長度為 512,在圖中為 4 個方框)
矩陣Q、K和V 中的每一行,分別表示Query向量,Key向量和Value 向量(它們的長度都為64,在圖中為3個方框)。
第2步:計算自注意力。由于這里使用了矩陣進行計算,可以將前面的第 2 步到第 6 步壓縮為一步。
矩陣形式的自注意力計算
5、多頭注意力機制(Multi-head Attention)
5.1 多頭注意力機制架構
在Transformer論文中,通過添加一種多頭注意力機制,進一步完善了自注意力層。具體做法:
首先,通過個不同的線性變換對Query、Key 和 Value 進行映射;
然后,將不同的 Attention 拼接起來;
最后,再進行一次線性變換。
基本結構如圖所示:
每一組注意力用于將輸入映射到不同的子表示空間,這使得模型可以在不同子表示空間中關注不同的位置。整個計算過程可表示為:
其中:、、和
在論文中,指定h=8,也就是使用8個注意力頭,和。
在多頭注意力下,我們?yōu)槊拷M注意力單獨維護不同的Query、Key 和 Value 權重矩陣,從而得到不同的 Query、Key和Value 矩陣。
如前所述,我們將 乘以矩陣,得到Query、Key和Value矩陣。
按照上面的方法,使用不同的權重矩陣進行 8 次自注意力計算,就可以得到 8 個不同的 矩陣。
接下來就有點麻煩了。因為前饋神經網絡層接收的是 1 個矩陣(每個詞的詞向量),而不是上面的 8 個矩陣。因此,我們需要一種方法將這 8 個矩陣整合為一個矩陣。具體方法如下:
把8個矩陣拼接起來
把拼接后的矩陣和另一個權重矩陣相乘
得到最終的矩陣,這個矩陣包含了所有注意力頭的信息,這個矩陣會輸入到FFN層。
5.2 Multi-head Attention總結
這差不多就是多頭注意力的全部內容了。下面將所有內容放到一張圖中,以便我們可以統(tǒng)一查看:
現在讓我們重新回顧一下前面的例子,看看在對示例句中的“it”進行編碼時,不同的注意力頭關注的位置分別在哪:
當我們對it進行編碼時,一個注意力頭關注The animal,另一個注意力頭關注tired。從某種意義上來說,模型對it的表示,融入了animal和tired的部分表達。
Multi-head Attention 的本質是:在參數總量保持不變的情況下,將同樣的Query,Key,Value 映射到原來的高維空間的不同子空間中進行Attention的計算,在最后一步再合并不同子空間中的Attention信息。
這樣降低了計算每個 head 的 Attention 時每個向量的維度,在某種意義上防止了過擬合。
由于 Attention 在不同子空間中有不同的分布,Multi-head Attention 實際上是尋找了序列之間不同角度的關聯(lián)關系,并在最后拼接這一步驟中,將不同子空間中捕獲到的關聯(lián)關系再綜合起來。
6、位置前饋網絡(Position-wise Feed-Forward Networks)
位置前饋網絡就是一個全連接前饋網絡,每個位置的詞都單獨經過這個完全相同的前饋神經網絡。
其由兩個線性變換組成,即兩個全連接層組成,第一個全連接層的激活函數為 ReLU 激活函數??梢员硎緸椋?/p>
在每個編碼器和解碼器中,雖然這個全連接前饋網絡結構相同,但是不共享參數。整個前饋網絡的輸入和輸出維度都是,第一個全連接層的輸出和第二個全連接層的輸入維度為
7、殘差連接和層歸一化
編碼器結構中有一個需要注意的細節(jié):每個編碼器的每個子層(Self-Attention 層和 FFN 層)都有一個殘差連接,再執(zhí)行一個層標準化操作,整個計算過程可以表示為:
將向量和自注意力層的層標準化操作可視化,如下圖所示:
上面的操作也適用于解碼器的子層。假設一個 Transformer 是由 2 層編碼器和 2 層解碼器組成,其如下圖所示:
為了方便進行殘差連接,編碼器和解碼器中的所有子層和嵌入層的輸出維度需要保持一致,在 Transformer 論文中
8、位置編碼
到目前為止,我們所描述的模型中缺少一個東西:表示序列中詞順序的方法。為了解決這個問題,Transformer 模型為每個輸入的詞嵌入向量添加一個向量。
這些向量遵循模型學習的特定模式,有助于模型確定每個詞的位置,或序列中不同詞之間的距離。
如果我們假設詞嵌入向量的維度是 4,那么實際的位置編碼如下:
那么位置編碼向量到底遵循什么模式?其具體的數學公式如下:
其中表示位置,表示維度。上面的函數使得模型可以學習到 之間的相對位置關系:任意位置的都可以被的線性函數表示:
在下圖中,我們將這些值進行可視化。每一行對應一個向量的位置編碼。所以第一行對應于輸入序列中第一個詞的位置編碼。每一行包含 64 個值,每個值的范圍在 -1 和 1 之間
需要注意的是,官方提供的示例代碼(TensorFlow 1.x 版本中的 get_timing_signal_1d() 函數和 TensorFlow 2.x 版本 中的 call() 函數)與 Transformer 論文中的方法稍微存在一定差異:
Transformer 論文中,sine 函數和 cosine 函數產生的值交織在一起;
而官方提供的代碼中,左半部分的值全是由 sine 函數產生的,右半部分的值全是由 cosine 函數產生的,然后將它們拼接起來。
官方代碼生成的位置編碼值的可視化圖如下:
這不是唯一一種生成位置編碼的方法。但這種方法的優(yōu)點是:可以擴展到未知的序列長度。例如,當我們訓練后的模型被要求翻譯一個句子,而這個句子的長度大于訓練集中所有句子的長度。
9、解碼器Decoder
現在我們已經介紹了編碼器的大部分概念,我們也了解了解碼器的組件的原理?,F在讓我們看下編碼器和解碼器是如何協(xié)同工作的。
通過上面的介紹,我們已經了解第一個編碼器的輸入是一個序列,最后一個編碼器的輸出是一組注意力向量 Key 和 Value。這些向量將在每個解碼器的 Encoder-Decoder Attention 層被使用,這有助于解碼器把注意力集中在輸入序列的合適位置。
在完成了編碼階段后,我們開始解碼階段。解碼階段的每個時間步都輸出一個元素。
接下來會重復這個過程,直到輸出一個結束符,表示 Transformer 解碼器已完成其輸出。每一步的輸出都會在下一個時間步輸入到下面的第一個解碼器,解碼器像編碼器一樣將解碼結果顯示出來。就像我們處理編碼器輸入一樣,我們也為解碼器的輸入加上位置編碼,來指示每個詞的位置。
Encoder-Decoder Attention 層的工作原理和多頭自注意力機制類似。不同之處是:Encoder-Decoder Attention 層使用前一層的輸出構造 Query 矩陣,而 Key 和 Value 矩陣來自于編碼器棧的輸出。
10、掩碼Mask
Mask 表示掩碼,它對某些值進行掩蓋,使其在參數更新時不產生效果。Transformer 模型里面涉及兩種 mask,分別是 Padding Mask 和 Sequence Mask。
Padding Mask 在所有的 scaled dot-product attention 里面都需要用到
而Sequence Mask 只有在解碼器 Decoder 的 Self-Attention 里面用到。
10.1 Padding Mask
什么是 Padding mask 呢?因為每個批次輸入序列的長度是不一樣的,所以我們要對輸入序列進行對齊。
具體來說:就是在較短的序列后面填充 0(但是如果輸入的序列太長,則是截斷,把多余的直接舍棄)。因為這些填充的位置,其實是沒有什么意義的,所以我們的 Attention 機制不應該把注意力放在這些位置上,所以我們需要進行一些處理。
具體的做法:把這些位置的值加上一個非常大的負數(負無窮),這樣的話,經過Softmax 后,這些位置的概率就會接近0。
10.2 Sequence Mask
Sequence Mask是為了使得 Decoder 不能看見未來的信息。也就是對于一個序列,在時刻,我們的解碼輸出應該只能依賴于時刻之前的輸出,而不能依賴之后的輸出。因為我們需要想一個辦法,把之后的信息給隱藏起來。
具體的做法:產生一個上三角矩陣,上三角的值全為0。把這個矩陣作用在每個序列上,就可以達到我們的目的。
總結:對于Decoder的Self-Attention,里面使用到的scaled dot-product attention,同時需要Padding Mask 和Sequence Mask,具體實現就是兩個Mask相加。其他情況下,只需要Padding Mask。
11、最后的線性層和 Softmax 層
解碼器棧的輸出是一個 float向量。我們怎么把這個向量轉換為一個詞呢?通過一個線性層再加上一個Softmax層實現。
11.1 線性層
線性層是一個簡單的全連接神經網絡,其將解碼器棧的輸出向量映射到一個更長的向量,這個向量被稱為logits向量。
11.2 Softmax層
現在假設我們的模型有 10000 個英文單詞(模型的輸出詞匯表)。因此 logits 向量有 10000 個數字,每個數表示一個單詞的分數。
然后,Softmax 層會把這些分數轉換為概率(把所有的分數轉換為正數,并且加起來等于 1)。最后選擇最高概率所對應的單詞,作為這個時間步的輸出。
12、嵌入層和最后的線性層
在 Transformer 論文,提到一個細節(jié):編碼組件和解碼組件中的嵌入層,以及最后的線性層共享權重矩陣。
需要注意的是:在嵌入層中,會將這個共享權重矩陣乘以
13、正則化操作
為了提高 Transformer 模型的性能,在訓練過程中,使用了以下的正則化操作:
Dropout。對編碼器和解碼器的每個子層的輸出使用Dropout 操作,是在進行殘差連接和層歸一化之前。詞嵌入向量和位置編碼向量執(zhí)行相加操作后,執(zhí)行Dropout操作。Transformer 論文中提供的參數
Label Smoothing(標簽平滑)。Transformer論文中提供的參數是。
編輯:黃飛
?
評論
查看更多