讓模型理解並且處理帶有順序的資料,一直是 NLP 的核心挑戰,因為文字是有順序的,前後文會改變語意,因此對於提高 NLP 處理的準確度,是相當重要的一部分。
因此早期深度學習方法經常會使用循環神經網路(RNN)或是基於 RNN 改良的長短期記憶(LSTM)來處理語言,因為兩者都具有記憶性,會記得前面的內容,但隨著應用規模的擴大,RNN 已經無法滿足需求了,這才產生了注意力機制(Attention)這個技術,再利用注意力機制打造出了 Transformer。
無法並行處裡,效率不夠高
RNN 的輸入需要逐步依序處理:
第 1 個 token 輸出 → 餵給第 2 個 token → 餵給第 3 個 token...,以此類推的依序輸出,這讓 GPU 的並行能力幾乎浪費掉,訓練速度很慢。
難以捕捉長句的語意
雖然 LSTM 加入門控機制(遺忘門、輸入門、輸出門),讓 LSTM 有比 RNN 更好的效果,但遇到很長的句子時,遠距離詞語之間的關聯還是很難學到。
注意力機制的靈感來自於人類專注的方式,當我們在閱讀一篇文章的時候,不會每個字都看得很仔細,而是會特別注意某些關鍵詞,而在 NLP 裡,注意力機制讓模型能夠判斷 目前要處理的詞(Query) 應該要去注意句子中的哪些詞(Key),與對應詞的資訊(Value)比此相關聯,再依照關聯的程度分配「權重」,之後再加權的組合計算,得到更有意義的結果。
我們可以把注意力機制想像成字典查找:
當 Query =「成長」,模型可能會分配較多的注意力(權重)給「幫助」、「學習」兩詞,次要注意力給「鐵人賽」,幾乎不會去注意「我」和「愛」,這樣模型就能正確理解「成長」是在說「鐵人賽帶來的效果」,而不是「愛」或「我」。
import torch
import torch.nn.functional as F
import math
# Query, Key, Value
Q = torch.tensor([[1.0, 0.0]]) # Query: 想找 "時間"
K = torch.tensor([[1.0, 0.0], # token1 (相關)
[0.0, 1.0]]) # token2 (不相關)
V = torch.tensor([[10.0], # token1 的資訊
[20.0]]) # token2 的資訊
# 計算注意力分數
dk = Q.size(-1)
scores = torch.matmul(Q, K.T) / math.sqrt(dk)
# 轉換成權重
attn_weights = F.softmax(scores, dim=-1)
# 加權求和得到輸出
output = torch.matmul(attn_weights, V)
print("注意力權重:", attn_weights)
print("輸出結果:", output)
輸出結果
注意力權重: tensor([[0.6698, 0.3302]])
輸出結果: tensor([[13.3024]])
可以從輸出結果看到,模型認為 token1 更重要(67%的注意力),所以最終輸出會比較接近他的值,顯示出了 Attention 能幫助模型聚焦於更相關的資訊。