Skip to content

Relative Positional Encoding

1、圖書館管理員的困境:書本沒有頁碼

在一座巨大的圖書館裡,新來了一位名叫 Attentio 的AI管理員。他的工作是理解讀者借書單上的順序,例如讀者寫下:「先給我《人工智慧導論》,然後是《Python 程式設計》,最後是《深度學習實戰》。」

Attentio 有一個特殊能力:他可以瞬間理解每一本書的內容,無論是書名、作者還是摘要,他都能完美掌握。但是,他有一個嚴重的缺陷——他分不清楚「先後順序」。

當他看到借書單時,對他來說:

[《人工智慧導論》, 《Python 程式設計》, 《深度學習實戰》]

[《深度學習實戰》, 《Python 程式設計》, 《人工智慧導論》]

是完全一樣的。因為他只看到「有一堆書」,卻看不到「誰先誰後」。

有一天,一位讀者氣沖沖地跑來投訴:「我要的是先讀基礎理論,再學程式,最後學實戰。你怎麼給我反過來的順序?我完全看不懂啊!」

Attentio 很委屈:「我看每本書都認識啊,但我不知道它們的順序有什麼意義。」

圖書館館長這時走過來,嘆了一口氣說:「孩子,這就是你最大的缺陷——你看得見內容,卻看不見順序。而順序,往往決定了意義。」

2、第一次嘗試:貼上座位號碼

2-1 絕對位置編碼的誕生

館長想出了一個解決辦法:「我們在每本書上貼一個座位號碼吧!」

於是,每當讀者開出借書單,館長就在第一本書貼上「座位 0」,第二本書貼上「座位 1」,第三本書貼上「座位 2」。

這樣一來,Attentio 看到的不只是書的內容,還有一個額外的標籤。他開始學會:「喔,原來『座位 0』的書要先讀,『座位 1』的書第二讀。」

這個方法一開始運作得很好,Attentio 終於能夠正確地按照順序理解讀者的需求。

2-2 隱藏的危機:從未見過的座位號碼

然而,問題很快就出現了。

有一天,一位讀者開出了一張超長的借書單,總共有 200 本書。Attentio 看著最後一本書上的標籤,困惑地說:「『座位 199』?這是什麼?我從來沒見過這麼大的數字。」

原來,圖書館的座位號碼只準備到 100 號,因為館長認為沒有人會一次借超過 100 本書。但現實是,讀者們的需求越來越多樣化。

更糟的是,當 Attentio 看到「座位 150」時,他不知道這個位置和「座位 0」的距離有多遠,也不知道和「座位 149」的關係是什麼。對他來說,「座位 150」只是一個陌生的數字,沒有任何意義。

3、相對位置編碼的革命:從地址到地圖

3-1 老讀者的智慧

正當館長苦惱時,一位經常來圖書館的老教授走了過來。他聽了問題後,笑著說:

「你們這些年輕人,為什麼要記座位號碼呢?我活了這麼多年,從來不記門牌號碼。我在城市裡找路,靠的是『關係』。」

老教授繼續說: - 我知道「便利商店的隔壁是郵局」 - 我知道「郵局往前走三間是學校」 - 我知道「學校的對面是我的家」

「你看,我不需要知道郵局的門牌是 100 號還是 200 號。只要知道這些相對關係,就算城市擴大一倍,我照樣能找到路。」

館長恍然大悟:「對啊!我們不需要讓 Attentio 記住『座位 0』、『座位 1』這些絕對數字。我們應該讓他學會『前一本書』、『後一本書』、『相隔三本書』這些相對關係!」

3-2 相對位置編碼的實作

於是,館長設計了一套新的標籤系統。現在,當 Attentio 在看一本書時,他會同時知道這本書和其他書的相對關係。

舉例來說,當他在看第三本書時,他會知道:

  • 第一本書:在我前面兩本的位置
  • 第二本書:在我前面一本的位置
  • 第三本書:就是我自己
  • 第四本書:在我後面一本的位置
  • 第五本書:在我後面兩本的位置

這種關係可以用一個矩陣來表示:

當前書 關係對象 相對距離
書 3 書 1 -2
書 3 書 2 -1
書 3 書 3 0
書 3 書 4 +1
書 3 書 5 +2

3-3 解決的痛點:位置外推

痛點一:絕對位置的陌生感

原本的絕對位置編碼,讓模型只認識「看過的數字」。當出現更大的數字時,模型就無法處理。

解決方式:相對位置編碼關注的是「距離」而不是「絕對值」。無論句子長度是 100 還是 1000,「相鄰」的關係永遠存在且意義相同。

假設模型學會了「相鄰的兩個詞關係緊密」這個規律: - 在 10 個詞的句子中,詞 5 和詞 6 是相鄰 - 在 1000 個詞的句子中,詞 500 和詞 501 也是相鄰 - 兩種情況的「相鄰」概念完全相同

因此,模型可以輕易地將學到的規律,應用到任意長度的序列中。

3-4 解決的痛點:距離的語義

痛點二:距離感的缺失

在絕對位置編碼中,模型只知道「位置 5」和「位置 6」是不同的,但它不知道這兩個位置的「關係強度」應該等於「位置 100」和「位置 101」的關係強度。

解決方式:相對位置編碼直接建模「距離」這個概念。模型會學習到:

  • 距離 0:自己和自己,關係最強
  • 距離 1:相鄰的詞,關係很強
  • 距離 2:隔一個詞,關係中等
  • 距離 3 以上:距離越遠,關係越弱

這個規律與絕對位置無關,只與相對距離有關。

在數學上,注意力機制的計算會加入一個代表相對距離的項:

\[ \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T + R}{\sqrt{d_k}}\right)V \]

這裡的 \(R\) 是一個矩陣,其中 \(R_{ij}\) 代表位置 \(i\) 和位置 \(j\) 的相對距離所對應的權重。

3-5 生活中的例子:學習文法

讓我們用一個實際的文法例子來說明:

句子:「我今天早上吃了一顆蘋果」

如果模型只學絕對位置: - 它知道「蘋果」在位置 5 - 但如果遇到「我昨天晚上吃了一顆蘋果」,「蘋果」變成了位置 6,模型就覺得陌生

如果模型學相對位置: - 它知道「蘋果」出現在「吃了」的後面一個位置 - 它知道「一顆」出現在「吃了」的後面一個位置,且在「蘋果」的前面一個位置 - 這些關係在任何長度的句子中都成立

當模型看到一個全新的句子:「昨天下午我在公園裡悠閒地吃了一顆又大又紅的蘋果」

雖然句子變長了,但「吃了」→「一顆」→「蘋果」的相對關係依然存在,模型可以輕鬆地識別出這個結構。

3-6 從數學看本質

在 Transformer 的數學表達中,相對位置編碼體現了這樣的思想:

給定兩個位置 \(i\)\(j\),我們關心的是它們的相對距離 \(i-j\),而不是它們各自的絕對值。

如果把位置看作一個函數 \(f(pos)\),相對位置編碼要求:

\[ \text{Relation}(f(i), f(j)) = g(i-j) \]

也就是說,兩個位置編碼的關係,只應該由它們的差決定,而與 \(i\)\(j\) 本身無關。這正是人類理解序列的方式——我們在乎的是「距離」,而不是「編號」。

4、圖書館的新氣象

經過這次改革,Attentio 終於成為了一位出色的圖書館管理員。

現在,當讀者拿來一份從未見過的超長書單時,Attentio 不再慌張。他知道:

  • 第 1 本書和第 2 本書的關係,和任何長度書單中的第 1、2 本書關係都一樣
  • 倒數第 1 本書和倒數第 2 本書的關係,也具有相同的模式
  • 無論書單多長,只要掌握了「相鄰」、「隔一個」、「隔兩個」這些基本關係,就能理解整個結構

館長看著煥然一新的圖書館,欣慰地說:

「真正的智慧,不在於記住每個東西的絕對位置,而在於理解萬事萬物之間的相對關係。這不只是圖書館管理的道理,也是理解語言、理解世界的道理。」

從此,圖書館的讀者們再也沒有投訴過順序錯誤的問題。而 Attentio 的故事,也成為了 AI 世界裡關於位置編碼的經典教材。

---

5、故事的開端:一個沒有順序感的句子

想像我們有一句非常簡單的話:「我 愛 你」。這句話有三個詞,每個詞我們都用一個 4 維的向量來表示(為了計算簡單,我們用很小的維度)。

在現實中,這些向量是透過詞嵌入(Word Embedding)得到的,代表每個詞的語義。

假設我們的輸入矩陣 \(X\) 如下:

\[ X\ (shape=3\times 4)= \begin{bmatrix} 1 & 0 & 1 & 0 \\ 0 & 1 & 0 & 1 \\ 1 & 1 & 0 & 0 \end{bmatrix} \]

這裡: - 第一行 [1,0,1,0] 代表「我」 - 第二行 [0,1,0,1] 代表「愛」 - 第三行 [1,1,0,0] 代表「你」

現在,我們要把這個句子送進 Transformer 模型裡。但問題來了:Transformer 本身沒有循序漸進的結構(像 RNN 那樣),它是一次性看到所有詞的。

如果我們直接把 \(X\) 送進去,模型會認為「我 愛 你」和「你 愛 我」是一樣的,因為詞的集合相同。

痛點:原始 Transformer 缺乏序列順序資訊,無法區分詞序不同的句子。

6、第一次嘗試:Sinusoidal 絕對位置編碼

為了解決這個問題,我們先試試看最經典的方法:加上一個絕對位置編碼矩陣 \(P\)

對於位置 0(第一個詞)、位置 1(第二個詞)、位置 2(第三個詞),我們用正弦和餘弦函數產生它們的位置編碼。

為了簡化計算,我們直接用預先算好的位置編碼矩陣:

\[ P\ (shape=3\times 4)= \begin{bmatrix} 0 & 1 & 0 & 1 \\ 1 & 0 & 1 & 0 \\ 0 & 1 & 0 & 1 \end{bmatrix} \]

現在,我們把詞嵌入和位置編碼相加:

\[ X_{\text{with\_pos}} = X + P \]
\[ X_{\text{with\_pos}}\ (shape=3\times 4)= \begin{bmatrix} 1 & 0 & 1 & 0 \\ 0 & 1 & 0 & 1 \\ 1 & 1 & 0 & 0 \end{bmatrix} + \begin{bmatrix} 0 & 1 & 0 & 1 \\ 1 & 0 & 1 & 0 \\ 0 & 1 & 0 & 1 \end{bmatrix} = \begin{bmatrix} 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 \\ 1 & 2 & 0 & 1 \end{bmatrix} \]

現在,每個詞的向量都帶有位置訊息了。模型可以透過這些數值知道哪個詞在前面。

痛點:為每個詞加上獨一無二的位置標籤,讓模型能夠區分不同位置的詞。

7、進入注意力機制:計算查詢、鍵、值

接下來,我們要計算注意力。首先,我們需要三個權重矩陣 \(W_Q\)\(W_K\)\(W_V\),用來將輸入轉換成查詢(Query)、鍵(Key)、值(Value)。

為了計算簡單,我們設定所有權重矩陣都是 \(4\times 4\) 的單位矩陣(實際上它們是訓練出來的)。

\[ W_Q = W_K = W_V = I\ (shape=4\times 4)= \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \]

計算查詢矩陣 \(Q\)

\[ Q = X_{\text{with\_pos}} \cdot W_Q = X_{\text{with\_pos}} \cdot I = X_{\text{with\_pos}} \]
\[ Q\ (shape=3\times 4)= \begin{bmatrix} 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 \\ 1 & 2 & 0 & 1 \end{bmatrix} \]

計算鍵矩陣 \(K\)

\[ K = X_{\text{with\_pos}} \cdot W_K = X_{\text{with\_pos}} \]
\[ K\ (shape=3\times 4)= \begin{bmatrix} 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 \\ 1 & 2 & 0 & 1 \end{bmatrix} \]

計算值矩陣 \(V\)

\[ V = X_{\text{with\_pos}} \cdot W_V = X_{\text{with\_pos}} \]
\[ V\ (shape=3\times 4)= \begin{bmatrix} 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 \\ 1 & 2 & 0 & 1 \end{bmatrix} \]

痛點:將輸入轉換成三種不同角色的表示,讓模型能分別從「我要找什麼」(Q)、「我有什麼」(K)、「我提供什麼」(V)的角度處理資訊。

8、標準注意力分數計算(尚未加入相對位置)

現在我們計算注意力分數矩陣 \(S = Q \cdot K^T\)

首先計算 \(K^T\)

\[ K^T\ (shape=4\times 3)= \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 2 \\ 1 & 1 & 0 \\ 1 & 1 & 1 \end{bmatrix} \]

然後計算 \(Q \cdot K^T\)

\[ S\ (shape=3\times 3)= \begin{bmatrix} 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 \\ 1 & 2 & 0 & 1 \end{bmatrix} \cdot \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 2 \\ 1 & 1 & 0 \\ 1 & 1 & 1 \end{bmatrix} \]

計算過程(只寫結果): - 第一行 [1,1,1,1] 點乘各列 = [1+1+1+1, 1+1+1+1, 1+2+0+1] = [4, 4, 4] - 第二行 [1,1,1,1] 點乘各列 = [4, 4, 4] - 第三行 [1,2,0,1] 點乘各列 = [1+2+0+1, 1+2+0+1, 1+4+0+1] = [4, 4, 6]

所以:

\[ S\ (shape=3\times 3)= \begin{bmatrix} 4 & 4 & 4 \\ 4 & 4 & 4 \\ 4 & 4 & 6 \end{bmatrix} \]

這裡 \(S_{ij}\) 代表第 \(i\) 個詞對第 \(j\) 個詞的注意力分數。

但這裡有個問題:這些分數只反映了詞義的相似度,完全沒有考慮詞之間的距離關係。

痛點:標準注意力分數只考慮內容相似性,忽略了詞與詞之間的相對距離對注意力的影響。

9、引入相對位置偏誤矩陣

為了解決這個問題,我們要加入相對位置編碼。在這裡,我們用一種簡化的相對位置方法:直接加上一個「距離偏誤矩陣」\(B\)

這個矩陣的規則是:兩個詞距離越遠,分數扣越多。我們設定: - 自己對自己(距離 0):加 0 - 相鄰詞(距離 1):扣 1 - 距離 2:扣 2

對於三個詞的句子,相對距離矩陣如下:

\[ B\ (shape=3\times 3)= \begin{bmatrix} 0 & -1 & -2 \\ -1 & 0 & -1 \\ -2 & -1 & 0 \end{bmatrix} \]

現在,我們把注意力分數加上這個偏誤矩陣:

\[ S_{\text{relative}} = S + B \]
\[ S_{\text{relative}}\ (shape=3\times 3)= \begin{bmatrix} 4 & 4 & 4 \\ 4 & 4 & 4 \\ 4 & 4 & 6 \end{bmatrix} + \begin{bmatrix} 0 & -1 & -2 \\ -1 & 0 & -1 \\ -2 & -1 & 0 \end{bmatrix} = \begin{bmatrix} 4 & 3 & 2 \\ 3 & 4 & 3 \\ 2 & 3 & 6 \end{bmatrix} \]

看看發生了什麼變化: - 原本第一詞對第三詞的分數是 4,現在變成 2(因為距離遠,扣分多) - 原本第三詞對第一詞的分數是 4,現在變成 2(對稱性) - 自己對自己的分數保持不變

痛點:透過加入距離懲罰,讓模型在計算注意力時考慮詞與詞之間的相對距離,距離越遠的詞影響力越小,符合語言學中「遠距離依賴較弱」的直覺。

10、縮放與 Softmax 標準化

接下來,我們要對分數進行縮放(除以 \(\sqrt{d_k}\),這裡 \(d_k=4\),所以 \(\sqrt{4}=2\))和 Softmax 轉換成機率。

先縮放:

\[ S_{\text{scaled}} = \frac{S_{\text{relative}}}{2} \]
\[ S_{\text{scaled}}\ (shape=3\times 3)= \begin{bmatrix} 2 & 1.5 & 1 \\ 1.5 & 2 & 1.5 \\ 1 & 1.5 & 3 \end{bmatrix} \]

現在對每一行做 Softmax。Softmax 公式為 \(\frac{e^{x_i}}{\sum e^{x_j}}\)

計算第一行: - \(e^2 = 7.39\) - \(e^{1.5} = 4.48\) - \(e^1 = 2.72\) - 總和 \(= 7.39 + 4.48 + 2.72 = 14.59\) - 機率:\([7.39/14.59, 4.48/14.59, 2.72/14.59] = [0.51, 0.31, 0.18]\)

第二行(對稱): - \(e^{1.5} = 4.48\) - \(e^2 = 7.39\) - \(e^{1.5} = 4.48\) - 總和 \(= 4.48 + 7.39 + 4.48 = 16.35\) - 機率:\([4.48/16.35, 7.39/16.35, 4.48/16.35] = [0.27, 0.46, 0.27]\)

第三行: - \(e^1 = 2.72\) - \(e^{1.5} = 4.48\) - \(e^3 = 20.09\) - 總和 \(= 2.72 + 4.48 + 20.09 = 27.29\) - 機率:\([2.72/27.29, 4.48/27.29, 20.09/27.29] = [0.10, 0.16, 0.74]\)

得到注意力權重矩陣 \(A\)

\[ A\ (shape=3\times 3)= \begin{bmatrix} 0.51 & 0.31 & 0.18 \\ 0.27 & 0.46 & 0.27 \\ 0.10 & 0.16 & 0.74 \end{bmatrix} \]

痛點:將注意力分數轉換成機率分佈,讓模型可以決定「要關注多少比例」在每個詞上,同時透過縮放避免數值過大導致梯度不穩定。

11、加權求和得到輸出

最後,我們用注意力權重對值矩陣 \(V\) 進行加權求和:

\[ \text{Output} = A \cdot V \]

先回顧 \(V\)

\[ V\ (shape=3\times 4)= \begin{bmatrix} 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 \\ 1 & 2 & 0 & 1 \end{bmatrix} \]

計算 \(A \cdot V\)

第一行輸出 \(= 0.51 \times [1,1,1,1] + 0.31 \times [1,1,1,1] + 0.18 \times [1,2,0,1]\) \(= [0.51,0.51,0.51,0.51] + [0.31,0.31,0.31,0.31] + [0.18,0.36,0,0.18]\) \(= [1.00, 1.18, 0.82, 1.00]\)

第二行輸出 \(= 0.27 \times [1,1,1,1] + 0.46 \times [1,1,1,1] + 0.27 \times [1,2,0,1]\) \(= [0.27,0.27,0.27,0.27] + [0.46,0.46,0.46,0.46] + [0.27,0.54,0,0.27]\) \(= [1.00, 1.27, 0.73, 1.00]\)

第三行輸出 \(= 0.10 \times [1,1,1,1] + 0.16 \times [1,1,1,1] + 0.74 \times [1,2,0,1]\) \(= [0.10,0.10,0.10,0.10] + [0.16,0.16,0.16,0.16] + [0.74,1.48,0,0.74]\) \(= [1.00, 1.74, 0.26, 1.00]\)

最終輸出矩陣:

\[ \text{Output}\ (shape=3\times 4)= \begin{bmatrix} 1.00 & 1.18 & 0.82 & 1.00 \\ 1.00 & 1.27 & 0.73 & 1.00 \\ 1.00 & 1.74 & 0.26 & 1.00 \end{bmatrix} \]

痛點:根據學習到的注意力權重,聚合所有詞的資訊到每個位置的表示中,讓每個詞的向量都包含上下文資訊,同時保留相對位置造成的影響差異。

12、對比:如果沒有相對位置編碼

如果我們沒有加入相對位置偏誤 \(B\),直接用原始的 \(S\) 做 Softmax:

原始 \(S\) 縮放後:

\[ \frac{S}{2} = \begin{bmatrix} 2 & 2 & 2 \\ 2 & 2 & 2 \\ 2 & 2 & 3 \end{bmatrix} \]

Softmax 結果(對每一行):

第一行:\([e^2, e^2, e^2] = [7.39, 7.39, 7.39]\),總和 22.17,機率 \([0.33, 0.33, 0.33]\)

第二行:同樣 \([0.33, 0.33, 0.33]\)

第三行:\([e^2, e^2, e^3] = [7.39, 7.39, 20.09]\),總和 34.87,機率 \([0.21, 0.21, 0.58]\)

得到注意力權重 \(A_{\text{no\_relative}}\)

\[ A_{\text{no\_relative}}\ (shape=3\times 3)= \begin{bmatrix} 0.33 & 0.33 & 0.33 \\ 0.33 & 0.33 & 0.33 \\ 0.21 & 0.21 & 0.58 \end{bmatrix} \]

對比 \(A\)\(A_{\text{no\_relative}}\)

有相對位置時,第一詞關注自己的權重是 0.51,關注第三詞只有 0.18 沒有相對位置時,第一詞均勻關注所有詞(各 0.33)

這代表:相對位置編碼讓模型知道「離我遠的詞不要那麼關注」,而沒有相對位置時,模型只憑內容決定關注程度,可能會關注到不該關注的遠距離詞。

痛點:相對位置編碼防止模型被遠距離但內容相似的詞誤導,讓注意力分佈更符合語言的真實結構——通常重要的關係發生在相鄰或相近的詞之間。