Transformer基礎—自注意力機制
當我們處理文本、語音這類序列數據時,總會遇到一個老問題:模型到底該怎么理解“前后文”呢?
RNN 和 LSTM 曾經是熱門的答案,它們沿著時間順序一點點地讀數據,但讀得太慢,還容易忘記前面的信息。后來 CNN 被搬了進來,靠卷積核抓住局部模式,可要想看遠處的信息,就得堆一大堆層,效率也不高。
于是研究者開始換個思路:如果模型能直接跳過中間環節,把注意力放到序列中真正相關的位置,不是更聰明嗎? 這就是注意力機制的出發點。而當這種機制被應用到同一個序列內部時,就誕生了今天大名鼎鼎的——自注意力機制(Self-Attention)。
一、基本概念
什么是自注意力機制?
自注意力機制就是找到序列當前詞與序列所有詞之間的關系,也就是說我們的模型要知道這個詞“是誰”、“在哪”。
當我們說“模型要知道這個詞是誰、在哪、該關注誰”時,其實就需要一種可計算的方式來衡量詞和詞之間的關系。
這時候就引出了自注意力的三大主角:Q(查詢向量:Query)、K(鍵向量:Key)、V(值向量:Value)。
我們知道:在傳統的 RNN 模型里,每個詞都會被轉化成一個 詞向量(Embedding),這個向量基本上就代表了“這個詞是誰”。RNN 會把這些向量按照順序依次讀入,再結合隱狀態去理解上下文。
但在自注意力機制中,研究者覺得:光有一個詞向量還不夠。如果我們想讓模型判斷“這個詞應該關注誰”,就得從不同角度去看待它。
于是,同一個詞的詞向量會被投影成三份不同的表示:
- Q(Query):我去發起“提問”,看看我應該關心哪些詞;
- K(Key):我拿出自己的“身份標簽”,告訴別人“我是什么”;
- V(Value):我還準備了一份“內容”,如果有人關注我,就把這份內容貢獻出來。
這樣一來,詞嵌入不再只是一個“靜態身份”,而是被拆解成查詢、標識和內容三種角色,從而讓模型能夠靈活地建立聯系。
我們能夠理解為:我們將一個詞最開始的一個詞向量進行了三次線性變換(也就是乘上三個不同的矩陣),得到的結果就是Q、K、V,他們都是這個這個詞得詞向量。
雖然一個詞從最開始的一個詞向量變為了三個詞向量,但是這三個詞向量僅僅只是表示這一個詞,沒有和上下文建立聯系,那么我們是如何實現上下文聯系的呢?
二、實現過程
1.計算注意力得分
我們將序列當前詞的Q向量與序列任何一個詞的K向量做點積,得到的這個值能夠作為當前詞與另外一個詞的相似度判斷依據,值越大,說明這兩個詞越相似,但是數值可能會過大,所以需要引入一個縮放因子限制數值大小,使得梯度能夠穩定更新。因此就有了注意力得分矩陣公式:
Attention(Q,K)=QKTdk
\text{Attention}(Q, K) = \frac{QK^T}{\sqrt{d_k}}
Attention(Q,K)=dk??QKT?
這個矩陣的形狀為n×nn\times nn×n,其中n表示的是序列的長度,矩陣中的元素(i,j)(i,j)(i,j)表示序列第iii個元素與第jjj個元素的注意力得分,也就是它們的相似度。
圖示:
![]() |
---|
得到QKV向量 |
![]() |
---|
計算第一個詞和序列中所有詞的每個注意力得分α1,i=q1?kidk\alpha_{1,i} = \frac{q^1 \cdot k^i}{\sqrt{d_k}}α1,i?=dk??q1?ki? |
2.歸一化
我們要將得到的注意力得分轉換為概率分布,即將值得范圍控制在[0,1]之間,這個想法我們可以通過softmaxsoftmaxsoftmax函數得到實現,并且它確保了每一行的權重和為1,也就是一個詞對于序列所有詞的注意力權重之和為1。(注意:計算注意力得分和權重的時候,包括詞自己本身,也就是用某個詞的Q向量去乘上自己的V向量)
Attention?Weight=softmax(QKTdk)
\text{Attention Weight} = \text{softmax} \left( \frac{QK^T}{\sqrt{d_k}} \right)
Attention?Weight=softmax(dk??QKT?)
3.加權求和
得到了每個詞對于序列的注意力權重矩陣之后,接下來就是與V矩陣進行相乘,進行加權求和,最終得到的就是帶有上下文聯系的詞向量。
Output=Attention?Weight×V=softmax(QKTdk)×V
\text{Output} =\text{Attention Weight} \times V = \text{softmax} \left( \frac{QK^T}{\sqrt{d_k}} \right) \times V
Output=Attention?Weight×V=softmax(dk??QKT?)×V
計算圖示意:
![]() |
---|
Q和K計算相似度后,經 softmaxsoftmaxsoftmax 得到注意力,再乘V,最后相加得到包含注意力的輸出 |
三、多頭注意力
現在我們已經知道了什么是自注意力機制,那么接下來介紹以下自注意力機制的拓展,也就是transformer所真正運用到的注意力機制——多頭注意力機制
多頭注意力機制顧名思義,將注意力機制中的Q、K、VQ、K、VQ、K、V向量分成了多個“頭”,也就是分成了nnn個組,每個組算出各自的注意力結果,然后將每組的輸出進行拼接,最后再通過線性變換(乘上一個權重矩陣做特征融合)得到最終的輸出。
【這種思路類似于CNN中的分組卷積】
比如將一個512維度的詞分為2個組(也就是兩個頭),那么每組QKV向量的維度就應該是256維度,一共有兩組QKV。
![]() |
---|
aia^iai和aja^jaj為兩個不同的詞,他們分別有兩組QKV向量 |
多頭注意力的目的
總的來說,多頭注意力的目的就是為了提高模型的表達能力。我們可以用多組注意力去關注這個詞的不同特征,比如一個詞有32組注意力,那么一組可以是表示這個詞的情感特征、一組表示這個詞的詞法特征、一組表示這個詞的詞性特征等等…
這就讓我們的模型學習到了更多的上下文信息,能夠在不同場景下表達合適的意思,也就是更有語境。
PyTorch封裝好的多頭注意力層nn.MultiheadAttention
:
import torch
import torch.nn as nnmultihead_atten_layer = nn.MultiheadAttention(embed_dim=512,num_heads=8,batch_first=True
)
embedding_layer = nn.Embedding(10, 512)
X = torch.randint(0, 10, (1, 10))X = embedding_layer(X)atten_out, atten_weights = multihead_atten_layer(# 內部自動用可學習的 W^Q, W^K, W^V 把 X 投影成 QKVquery=X,key=X,value=X,
)# 打印注意力得分以及權重矩陣
print(atten_out.shape, atten_weights.shape)# torch.Size([1, 10, 512]) torch.Size([1, 10, 10])
以上是博主對transformer注意力機制的一些總結筆記,若文章中出現錯誤請及時指正博主,感謝瀏覽☆嚕~☆