Transformer詳解

B站視頻講解php

Transformer是谷歌大腦在2017年末發表的論文attention is all you need中所提出的seq2seq模型。如今已經取得了大範圍的應用和擴展,而BERT就是從Transformer中衍生出來的預訓練語言模型html

這篇文章分爲如下幾個部分python

  1. Transformer直觀認識
  2. Positional Encoding
  3. Self Attention Mechanism
  4. 殘差鏈接和Layer Normalization
  5. Transformer Encoder總體結構
  6. Transformer Decoder總體結構
  7. 總結
  8. 參考文章

0. Transformer直觀認識

Transformer和LSTM的最大區別,就是LSTM的訓練是迭代的、串行的,必需要等當前字處理完,才能夠處理下一個字。而Transformer的訓練時並行的,即全部是同時訓練的,這樣就大大增長了計算效率。Transformer使用了位置嵌入(Positional Encoding)來理解語言的順序,使用自注意力機制(Self Attention Mechanism)和全鏈接層進行計算,這些後面會講到git

Transformer模型主要分爲兩大部分,分別是EncoderDecoderEncoder負責把輸入(語言序列)隱射成隱藏層(下圖中第2步用九宮格表明的部分),而後解碼器再把隱藏層映射爲天然語言序列。例以下圖機器翻譯的例子(Decoder輸出的時候,是經過N層Decoder Layer才輸出一個token,並非經過一層Decoder Layer就輸出一個token)github

本篇文章大部份內容在於解釋Encoder部分,即把天然語言序列映射爲隱藏層的數學表達的過程。理解了Encoder的結構,再理解Decoder就很簡單了markdown

上圖爲Transformer Encoder Block結構圖,注意:下面的內容標題編號分別對應着圖中1,2,3,4個方框的序號網絡

1. Positional Encoding

因爲Transformer模型沒有循環神經網絡的迭代操做, 因此咱們必須提供每一個字的位置信息給Transformer,這樣它才能識別出語言中的順序關係app

如今定義一個位置嵌入的概念,也就是Positional Encoding,位置嵌入的維度爲[max_sequence_length, embedding_dimension], 位置嵌入的維度與詞向量的維度是相同的,都是embedding_dimensionmax_sequence_length屬於超參數,指的是限定每一個句子最長由多少個詞構成ide

注意,咱們通常以爲單位訓練Transformer模型。首先初始化字編碼的大小爲[vocab_size, embedding_dimension]vocab_size爲字庫中全部字的數量,embedding_dimension爲字向量的維度,對應到PyTorch中,其實就是nn.Embedding(vocab_size, embedding_dimension)svg

論文中使用了sin和cos函數的線性變換來提供給模型位置信息:

P E ( p o s , 2 i ) = sin ( p o s / 1000 0 2 i / d model ) P E ( p o s , 2 i + 1 ) = cos ( p o s / 1000 0 2 i / d model ) PE{(pos,2i)} = \sin(pos / 10000^{2i/d_{\text{model}}}) \\ PE{(pos,2i+1)} = \cos(pos / 10000^{2i/d_{\text{model}}})

上式中 p o s pos 指的是一句話中某個字的位置,取值範圍是 [ 0 , max_sequence_length ) [0, \text{max\_sequence\_length}) i i 指的是字向量的維度序號,取值範圍是 [ 0 , embedding_dimension / 2 ) [0, \text{embedding\_dimension}/2) d model d_{\text{model}} 指的是embedding_dimension​的值

上面有 sin \sin cos \cos 一組公式,也就是對應着embedding_dimension維度的一組奇數和偶數的序號的維度,例如0,1一組,2,3一組,分別用上面的 sin \sin cos \cos 函數作處理,從而產生不一樣的週期性變化,而位置嵌入在embedding_dimension​維度上隨着維度序號增大,週期變化會愈來愈慢,最終產生一種包含位置信息的紋理,就像論文原文中第六頁講的,位置嵌入函數的週期從 2 π 2 \pi 10000 2 π 10000 * 2 \pi 變化,而每個位置在embedding_dimension​維度上都會獲得不一樣週期的 sin \sin cos \cos 函數的取值組合,從而產生獨一的紋理位置信息,最終使得模型學到位置之間的依賴關係和天然語言的時序特性

若是不理解這裏爲什麼這麼設計,能夠看這篇文章Transformer中的Positional Encoding

下面畫一下位置嵌入,縱向觀察,可見隨着embedding_dimension​序號增大,位置嵌入函數的週期變化愈來愈平緩

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import math

def get_positional_encoding(max_seq_len, embed_dim):
    # 初始化一個positional encoding
    # embed_dim: 字嵌入的維度
    # max_seq_len: 最大的序列長度
    positional_encoding = np.array([
        [pos / np.power(10000, 2 * i / embed_dim) for i in range(embed_dim)]
        if pos != 0 else np.zeros(embed_dim) for pos in range(max_seq_len)])
    
    positional_encoding[1:, 0::2] = np.sin(positional_encoding[1:, 0::2])  # dim 2i 偶數
    positional_encoding[1:, 1::2] = np.cos(positional_encoding[1:, 1::2])  # dim 2i+1 奇數
    return positional_encoding

positional_encoding = get_positional_encoding(max_seq_len=100, embed_dim=16)
plt.figure(figsize=(10,10))
sns.heatmap(positional_encoding)
plt.title("Sinusoidal Function")
plt.xlabel("hidden dimension")
plt.ylabel("sequence length")
複製代碼

plt.figure(figsize=(8, 5))
plt.plot(positional_encoding[1:, 1], label="dimension 1")
plt.plot(positional_encoding[1:, 2], label="dimension 2")
plt.plot(positional_encoding[1:, 3], label="dimension 3")
plt.legend()
plt.xlabel("Sequence length")
plt.ylabel("Period of Positional Encoding")
複製代碼

2. Self Attention Mechanism

對於輸入的句子 X X ,經過WordEmbedding獲得該句子中每一個字的字向量,同時經過Positional Encoding獲得全部字的位置向量,將其相加(維度相同,能夠直接相加),獲得該字真正的向量表示。第 t t 個字的向量記做 x t x_t

接着咱們定義三個矩陣 W Q , W K . W V W_Q,W_K.W_V ,使用這三個矩陣分別對全部的字向量進行三次線性變換,因而全部的字向量又衍生出三個新的向量 q t , k t , v t q_t,k_t,v_t 。咱們將全部的 q t q_t 向量拼成一個大矩陣,記做查詢矩陣 Q Q ,將全部的 k t k_t 向量拼成一個大矩陣,記做鍵矩陣 K K ,將全部的 v t v_t 向量拼成一個大矩陣,記做值矩陣 V V (見下圖)

爲了得到第一個字的注意力權重,咱們須要用第一個字的查詢向量 q 1 q_1 乘以鍵矩陣K(見下圖)

[0, 4, 2]
[1, 0, 2] x [1, 4, 3] = [2, 4, 4]
            [1, 0, 1]
複製代碼

以後還須要將獲得的值通過softmax,使得它們的和爲1(見下圖)

softmax([2, 4, 4]) = [0.0, 0.5, 0.5]
複製代碼

有了權重以後,將權重其分別乘以對應字的值向量 v t v_t (見下圖)

0.0 * [1, 2, 3] = [0.0, 0.0, 0.0]
0.5 * [2, 8, 0] = [1.0, 4.0, 0.0]
0.5 * [2, 6, 3] = [1.0, 3.0, 1.5]
複製代碼

最後將這些權重化後的值向量求和,獲得第一個字的輸出(見下圖)

[0.0, 0.0, 0.0]
+ [1.0, 4.0, 0.0]
+ [1.0, 3.0, 1.5]
-----------------
= [2.0, 7.0, 1.5]
複製代碼

對其它的輸入向量也執行相同的操做,便可獲得經過self-attention後的全部輸出

矩陣計算

上面介紹的方法須要一個循環遍歷全部的字 x t x_t ,咱們能夠把上面的向量計算變成矩陣的形式,從而一次計算出全部時刻的輸出

第一步就不是計算某個時刻的 q t , k t , v t q_t,k_t,v_t 了,而是一次計算全部時刻的 Q , K Q,K V V 。計算過程以下圖所示,這裏的輸入是一個矩陣 X X ,矩陣第 t t 行爲第 t t 個詞的向量表示 x t x_t

接下來將 Q Q K T K^T 相乘,而後除以 d k \sqrt{d_k} (這是論文中提到的一個trick),通過softmax之後再乘以 V V 獲得輸出

Multi-Head Attention

這篇論文還提出了Multi-Head Attention的概念。其實很簡單,前面定義的一組 Q , K , V Q,K,V 可讓一個詞attend to相關的詞,咱們能夠定義多組 Q , K , V Q,K,V ,讓它們分別關注不一樣的上下文。計算 Q , K , V Q,K,V 的過程仍是同樣,只不過線性變換的矩陣從一組 ( W Q , W K , W V ) (W^Q,W^K,W^V) 變成了多組 ( W 0 Q , W 0 K , W 0 V ) (W^Q_0,W^K_0,W^V_0) ( W 1 Q , W 1 K , W 1 V ) (W^Q_1,W^K_1,W^V_1) ,…以下圖所示

對於輸入矩陣 X X ,每一組 Q Q K K V V 均可以獲得一個輸出矩陣 Z Z 。以下圖所示

Padding Mask

上面Self Attention的計算過程當中,咱們一般使用mini-batch來計算,也就是一次計算多句話,即 X X 的維度是[batch_size, sequence_length],sequence_length​是句長,而一個mini-batch是由多個不等長的句子組成的,咱們須要按照這個mini-batch中最大的句長對剩餘的句子進行補齊,通常用0進行填充,這個過程叫作padding

但這時在進行softmax就會產生問題。回顧softmax函數 σ ( z i ) = e z i j = 1 K e z j \sigma(z_i)=\frac{e^{z_i}}{\sum_{j=1}^K e^{z_j}} e 0 e^0 是1,是有值的,這樣的話softmax中被padding的部分就參與了運算,至關於讓無效的部分參與了運算,這可能會產生很大的隱患。所以須要作一個mask操做,讓這些無效的區域不參與運算,通常是給無效區域加一個很大的負數偏置,即

Z i l l e g a l = Z _ i l l e g a l + b i a s i l l e g a l b i a s i l l e g a l \begin{aligned} &Z_{illegal}=Z\_{illegal}+bias_{illegal}\\ &bias_{illegal}→-∞ \end{aligned}

3. 殘差鏈接和Layer Normalization

殘差鏈接

咱們在上一步獲得了通過self-attention加權以後輸出,也就是 Self-Attention ( Q ,   K ,   V ) \text{Self-Attention}(Q, \ K, \ V) ,而後把他們加起來作殘差鏈接

X e m b e d d i n g + Self-Attention ( Q ,   K ,   V ) X_{embedding} + \text{Self-Attention}(Q, \ K, \ V)

Layer Normalization

Layer Normalization的做用是把神經網絡中隱藏層歸一爲標準正態分佈,也就是 i . i . d i.i.d 獨立同分布,以起到加快訓練速度,加速收斂的做用

μ j = 1 m i = 1 m x i j \mu_{j}=\frac{1}{m} \sum^{m}_{i=1}x_{ij}

上式以矩陣的列(column)爲單位求均值;

σ j 2 = 1 m i = 1 m ( x i j μ j ) 2 \sigma^{2}_{j}=\frac{1}{m} \sum^{m}_{i=1}(x_{ij}-\mu_{j})^{2}

上式以矩陣的列(column)爲單位求方差

L a y e r N o r m ( x ) = x i j μ j σ j 2 + ϵ LayerNorm(x)=\frac{x_{ij}-\mu_{j}}{\sqrt{\sigma^{2}_{j}+\epsilon}}

而後用每一列每個元素減去這列的均值,再除以這列的標準差,從而獲得歸一化後的數值,加 ϵ \epsilon 是爲了防止分母爲0

下圖展現了更多細節:輸入 x 1 , x 2 x_1,x_2 經self-attention層以後變成 z 1 , z 2 z_1,z_2 ,而後和輸入 x 1 , x 2 x_1,x_2 進行殘差鏈接,通過LayerNorm後輸出給全鏈接層。全鏈接層也有一個殘差鏈接和一個LayerNorm,最後再輸出給下一個Encoder(每一個Encoder Block中的FeedForward層權重都是共享的)

4. Transformer Encoder總體結構

通過上面3個步驟,咱們已經基本瞭解了Encoder的主要構成部分,下面咱們用公式把一個Encoder block的計算過程整理一下:

1). 字向量與位置編碼

X = Embedding-Lookup ( X ) + Positional-Encoding X = \text{Embedding-Lookup}(X) + \text{Positional-Encoding}

2). 自注意力機制

Q = Linear q ( X ) = X W Q K = Linear k ( X ) = X W K V = Linear v ( X ) = X W V X a t t e n t i o n = Self-Attention ( Q , K , V ) Q = \text{Linear}_q(X) = XW_{Q}\\ K = \text{Linear}_k(X) = XW_{K}\\ V = \text{Linear}_v(X) = XW_{V}\\ X_{attention} = \text{Self-Attention}(Q,K,V)

3). self-attention殘差鏈接與Layer Normalization

X a t t e n t i o n = X + X a t t e n t i o n X a t t e n t i o n = LayerNorm ( X a t t e n t i o n ) X_{attention} = X + X_{attention}\\ X_{attention} = \text{LayerNorm}(X_{attention})

4). 下面進行Encoder block結構圖中的第4部分,也就是FeedForward,其實就是兩層線性映射並用激活函數激活,好比說 R e L U ReLU

X h i d d e n = Linear ( ReLU ( Linear ( X a t t e n t i o n ) ) ) X_{hidden} = \text{Linear}(\text{ReLU}(\text{Linear}(X_{attention})))

5). FeedForward殘差鏈接與Layer Normalization

X h i d d e n = X a t t e n t i o n + X h i d d e n X h i d d e n = LayerNorm ( X h i d d e n ) X_{hidden} = X_{attention} + X_{hidden}\\ X_{hidden} = \text{LayerNorm}(X_{hidden})

其中

X h i d d e n R b a t c h _ s i z e     s e q _ l e n .     e m b e d _ d i m X_{hidden} \in \mathbb{R}^{batch\_size \ * \ seq\_len. \ * \ embed\_dim}

5. Transformer Decoder總體結構

咱們先從HighLevel的角度觀察一下Decoder結構,從下到上依次是:

  • Masked Multi-Head Self-Attention
  • Multi-Head Encoder-Decoder Attention
  • FeedForward Network

和Encoder同樣,上面三個部分的每個部分,都有一個殘差鏈接,後接一個 Layer Normalization。Decoder的中間部件並不複雜,大部分在前面Encoder裏咱們已經介紹過了,可是Decoder因爲其特殊的功能,所以在訓練時會涉及到一些細節

Masked Self-Attention

具體來講,傳統Seq2Seq中Decoder使用的是RNN模型,所以在訓練過程當中輸入 t t 時刻的詞,模型不管如何也看不到將來時刻的詞,由於循環神經網絡是時間驅動的,只有當 t t 時刻運算結束了,才能看到 t + 1 t+1 時刻的詞。而Transformer Decoder拋棄了RNN,改成Self-Attention,由此就產生了一個問題,在訓練過程當中,整個ground truth都暴露在Decoder中,這顯然是不對的,咱們須要對Decoder的輸入進行一些處理,該處理被稱爲Mask

舉個例子,Decoder的ground truth爲"<start> I am fine",咱們將這個句子輸入到Decoder中,通過WordEmbedding和Positional Encoding以後,將獲得的矩陣作三次線性變換( W Q , W K , W V W_Q,W_K,W_V )。而後進行self-attention操做,首先經過 Q × K T d k \frac{Q\times K^T}{\sqrt{d_k}} 獲得Scaled Scores,接下來很是關鍵,咱們要對Scaled Scores進行Mask,舉個例子,當咱們輸入"I"時,模型目前僅知道包括"I"在內以前全部字的信息,即"<start>"和"I"的信息,不該該讓其知道"I"以後詞的信息。道理很簡單,咱們作預測的時候是按照順序一個字一個字的預測,怎麼能這個字都沒預測完,就已經知道後面字的信息了呢?Mask很是簡單,首先生成一個下三角全0,上三角全爲負無窮的矩陣,而後將其與Scaled Scores相加便可

以後再作softmax,就能將-inf變爲0,獲得的這個矩陣即爲每一個字之間的權重

Multi-Head Self-Attention無非就是並行的對上述步驟多作幾回,前面Encoder也介紹了,這裏就很少贅述了

Masked Encoder-Decoder Attention

其實這一部分的計算流程和前面Masked Self-Attention很類似,結構也一摸同樣,惟一不一樣的是這裏的 K , V K,V 爲Encoder的輸出, Q Q 爲Decoder中Masked Self-Attention的輸出

6. 總結

到此爲止,Transformer中95%的內容已經介紹完了,咱們用一張圖展現其完整結構。不得不說,Transformer設計的十分巧奪天工

下面有幾個問題,是我從網上找的,感受看完以後能對Transformer有一個更深的理解

Transformer爲何須要進行Multi-head Attention?

原論文中說到進行Multi-head Attention的緣由是將模型分爲多個頭,造成多個子空間,可讓模型去關注不一樣方面的信息,最後再將各個方面的信息綜合起來。其實直觀上也能夠想到,若是本身設計這樣的一個模型,必然也不會只作一次attention,屢次attention綜合的結果至少可以起到加強模型的做用,也能夠類比CNN中同時使用多個卷積核的做用,直觀上講,多頭的注意力有助於網絡捕捉到更豐富的特徵/信息

Transformer相比於RNN/LSTM,有什麼優點?爲何?

  1. RNN系列的模型,沒法並行計算,由於 T 時刻的計算依賴 T-1 時刻的隱層計算結果,而 T-1 時刻的計算依賴 T-2 時刻的隱層計算結果
  2. Transformer的特徵抽取能力比RNN系列的模型要好

爲何說Transformer能夠代替seq2seq?

這裏用代替這個詞略顯不穩當,seq2seq雖已老,但始終仍是有其用武之地,seq2seq最大的問題在於將Encoder端的全部信息壓縮到一個固定長度的向量中,並將其做爲Decoder端首個隱藏狀態的輸入,來預測Decoder端第一個單詞(token)的隱藏狀態。在輸入序列比較長的時候,這樣作顯然會損失Encoder端的不少信息,並且這樣一股腦的把該固定向量送入Decoder端,Decoder端不可以關注到其想要關注的信息。Transformer不但對seq2seq模型這兩點缺點有了實質性的改進(多頭交互式attention模塊),並且還引入了self-attention模塊,讓源序列和目標序列首先「自關聯」起來,這樣的話,源序列和目標序列自身的embedding表示所蘊含的信息更加豐富,並且後續的FFN層也加強了模型的表達能力,而且Transformer並行計算的能力遠遠超過了seq2seq系列模型

7. 參考文章

相關文章
相關標籤/搜索