← LING5006 講義 Lectures Lecture 05

Lecture 05 · Transformer、微調與對齊

Transformer 入門Transformers from analogy to formula

謝舒凱 · 大型語言模型的語言學基礎 · 更新於 2026-10-13

導讀

Transformer 要解決的核心問題只有一個:讓同一個詞的向量,隨語境而改變。本文依照本週投影片(Jurafsky & Martin,Speech and Language Processing 第三版草稿)的順序和記號來編。每一節先給比喻,再給式子,最後附上例子或程式。下表先把五個常見術語翻成白話:

術語 白話 生活類比
向量 一串數字,代表空間中一個點的座標 地圖上的經緯度,只是維度多達上千
矩陣 排成表格的一大堆數字 一張 Excel 試算表
內積 兩串數字逐項相乘再加總;數值越大,兩者越相似 兩人問卷答案的吻合程度
softmax 把任意分數換成加總為 100% 的比例 把各候選人的票數換成得票率
參數(權重) 模型從資料中學到、可以調整的數字 收音機上可以轉動的旋鈕

整體流程可以一句話說完:詞元先查出詞嵌入,加上位置嵌入,再經過 𝐿 個 Transformer 區塊逐層修改,最後由語言模型頭輸出下一個詞元的機率分布。

示意圖 · 一個詞元走過的五站

真正的「理解」發生在第④站:前三站只是把字變成數字,第⑤站只是把數字換回詞。

貫穿全文的例句是一組 Winograd 型照應句:「獎盃放不進行李箱,因為它太大了」與「……因為它太小了」。一字之差,「它」就從獎盃改指行李箱。投影片用的是英文版:The chicken didn't cross the road because it was too tired / wide.

進階・記號約定(第一次讀可以跳過):向量一律寫成列向量(row vector),所以是「向量乘矩陣」而非「矩陣乘向量」。

符號 意義 形狀
𝐱ᵢ 第 𝑖 個詞元的輸入向量 [1 × 𝑑]
𝐗 整段輸入的 𝑁 個向量疊成的矩陣 [𝑁 × 𝑑]
𝐄 詞嵌入矩陣,每個詞元一列 [詞彙表大小 × 𝑑]
𝐖(上標 Q、K、V) 查詢、鍵、值的投影矩陣 [𝑑 × 𝑑ₖ]、[𝑑 × 𝑑ₖ]、[𝑑 × 𝑑ᵥ]
𝐴 注意力頭的數量 純量
𝐡ᵢᴸ 第 𝐿 層在位置 𝑖 的輸出,即上下文詞向量 [1 × 𝑑]

1. 詞元與詞嵌入

電腦不認得字,只認得數字。所以先把句子切成小塊,再替每一塊查出一串代表它的數字。

比喻:一本座標辭典。 斷詞器(tokenizer)先把句子切成辭典裡查得到的條目,再把每個條目換成編號;詞嵌入矩陣就是一本「座標辭典」,每個編號對應一列座標,也就是高維空間中的一個點。

進階:式子(可跳過)。 詞嵌入矩陣 𝐄 的形狀為 [|𝑉| × 𝑑],|𝑉| 為詞彙表大小。以 BPE 等方法把字串切成長度為 𝑁 的詞元編號序列 𝐰 = [𝑤₁, 𝑤₂, …] 之後,查表等同於用 one-hot 向量乘上 𝐄:

算算看。 假設詞彙表只有 4 個詞元、𝑑 = 3:

編號 詞元 𝐄 的那一列
0 獎盃 [0.9, 0.1, 0.4]
1 行李箱 [0.8, 0.3, 0.1]
2 它 [0.2, 0.7, 0.5]
3 大 [0.6, 0.2, 0.9]

「它」的編號是 2。表從 0 開始數,one-hot 向量是 [0, 0, 1, 0]。那個 1 對上的是由上往下數的第 3 列,也就是「它」,不是第 2 列的「行李箱」:

所以「乘上 one-hot」,其實就是查出編號 2 的那一列。兩個例句的「它」都拿到 [0.2, 0.7, 0.5]。

限制。 這張表是固定的。在「太大」與「太小」兩句中,「它」查出的是同一列向量,並不知道自己指向誰。投影片把這稱為靜態詞向量(如 word2vec)的問題;後面的注意力,就是要把這個向量依照語境推向對的方向。

示意圖 · 色塊只表示兩句的「它」查到同一列,顏色不必對上表裡的數字

另外要留意:切分本身並不中立。書寫系統和構詞類型不同的語言,同樣的內容可能被切成數量差很多的詞元,成本和用得到的上下文長度都會不一樣(Petrov et al. 2023)。

2. 位置嵌入 position embeddings

光知道有哪些詞還不夠,還得告訴模型每個詞排第幾,否則「狗咬人」與「人咬狗」無從分辨。

比喻:座位號碼。 注意力本身只看「誰和誰相似」,不看「誰坐在哪裡」。若不加處理,「狗咬人」與「人咬狗」對它而言是同一袋詞。位置嵌入就像在每個詞身上別一張座位號碼牌,讓詞序重新進入計算。

互動示意 · 點按鈕交換主詞與受詞

進階:式子(絕對位置)。 另學一個位置嵌入矩陣 𝐄ₚₒₛ,每個位置一列,從隨機初始化開始訓練。輸入向量是詞嵌入與位置嵌入相加:

算算看。 若「它」坐在第 11 號,而 𝐄ₚₒₛ 的第 11 列是 [0.1, −0.2, 0.0],則:

同一個「它」換到別的座位,加上的是另一列,得到的向量也就不同。

限制。 不加位置的話,「狗咬人」和「人咬狗」對模型來說是同一袋詞。上面的圖只是把主詞和受詞對調:詞還是那三個,座位卻換了。為什麼這樣就分不出誰咬誰,下一節先把注意力分數定義好,後面的進階節再算一次。

絕對位置還有一個實際限制:訓練時沒見過的位置,沒有向量可以查,上下文長度因此受到限制。正弦編碼和 RoPE 不必查表,放在自注意力之後;第一次讀可以先跳過。

3. 自注意力 Self-attention

每個詞環顧整句,挑出對自己最要緊的幾個詞,把它們的意思混進來,更新自己。

比喻:在圖書館找書。 你帶著一個問題(Query)走進書庫;每本書的書背貼著標籤(Key);問題與標籤越吻合,你就越仔細讀那本書的內容(Value)。每個詞同時扮演這三個角色:提出問題、貼出標籤、提供內容。讀完之後,你把各書的內容依投入程度加權,寫成一份筆記,這份筆記就是該詞的新表示。

投影片的定義更簡潔:注意力就是一種向量的加權總和,權重取決於相似度。

互動示意 · 點右上角按鈕切換「大/小」

這就是「加權總和」的意思:「它」的新意思,約有一半來自先行詞,其餘零星來自其他詞。這張圖看得到整句。讀到「它」的時候,後面的「大」或「小」已經出現,權重就可以整片轉去獎盃,或整片轉去行李箱。下面的式子和手算只看左邊,而且手算的三個詞裡還沒有「大」和「小」。

進階:式子(單一注意力頭)。 先以三個可學習矩陣把 𝐱 投影成三種角色:

再以內積衡量吻合度、softmax 換成權重、對值向量加權求和。softmax 只加總 𝑗 ≤ 𝑖 的位置,也就是只看左邊的因果注意力。多頭最後用來彙整的 𝐖ᴼ 留到下一節;這一節的 𝐚ᵢ 就是值向量的加權總和:

算算看。 只取三個詞元(獎盃、行李箱、它),𝑑ₖ = 2。假設投影後得到:

詞元 鍵 𝐤ⱼ 值 𝐯ⱼ
獎盃 [2, 1] [1, 0]
行李箱 [1, 0] [0, 1]
它 [0, 1] [0.5, 0.5]

「它」是第 3 個詞元,查詢向量為 𝐪₃ = [1, 2]。分四步算完:

  1. 內積 𝐪₃·𝐤ⱼ:獎盃 1×2 + 2×1 = 4;行李箱 1×1 + 2×0 = 1;它 1×0 + 2×1 = 2。
  2. 除以 √𝑑ₖ = √2 ≈ 1.414:得 2.83、0.71、1.41。
  3. softmax:exp(2.83) ≈ 16.9、exp(0.71) ≈ 2.0、exp(1.41) ≈ 4.1,總和約 23.1,所以 𝛼₃ⱼ ≈ 0.73、0.09、0.18。
  4. 加權總和:𝐚₃ = 0.73×[1, 0] + 0.09×[0, 1] + 0.18×[0.5, 0.5] ≈ [0.82, 0.18]。

結果有八成來自「獎盃」的值向量。「它」被拉向獎盃,在數學上就是這麼一回事。這三個詞裡沒有「大」,也沒有「小」。這裡的 0.73,是「它」分給前面「獎盃」的權重,和圖上那個會跟著「大」或「小」翻轉的數字不是同一回事。

進階:為何除以 √𝑑ₖ。 若 𝐪 與 𝐤 的各分量獨立、變異數為 1,內積的變異數就是 𝑑ₖ。維度越高,分數越極端,softmax 會把幾乎全部權重壓在單一詞元上,梯度也隨之消失。除以 √𝑑ₖ 把變異數拉回 1:

算算看。 設 𝑑ₖ = 64,三個分數原本是 [8, 4, 0]。不縮放與除以 √64 = 8 的結果對照如下:

前者幾乎全押在第一個詞;縮放之後,其他詞也分得到注意力。

進階:矩陣形式與遮罩。 實作時把 𝑁 個詞元一次算完。生成式模型不能偷看答案,因此把 𝐐𝐊ᵀ 上三角(未來位置)設為 −∞,softmax 後即為 0:

算算看。 沿用上例的順序(獎盃、行李箱、它)。加上遮罩後,「獎盃」那一列只剩自己,softmax 結果必為 [1, 0, 0];「它」排在最後,本來就看得到全部,權重仍是 [0.73, 0.09, 0.18]。

回到例句。 圖上那種整片轉過去的樣子,得要模型讀到「它」時就看得到「大」或「小」,也就是雙向注意力。加上因果遮罩之後,處理「它」時還看不到「大」或「小」,照應要等到後面的位置,再由那些詞把訊息帶回來。所以那張圖不是 GPT 在「它」這個位置上的注意力。

代價。 𝐐𝐊ᵀ 有 𝑁 × 𝑁 個分數,計算和記憶體都隨長度平方成長。長上下文這麼貴,原因就在這裡。

進階・程式(NumPy,單頭、含遮罩):

import numpy as np

def softmax(z, axis=-1):
    z = z - z.max(axis=axis, keepdims=True)   # 數值穩定
    e = np.exp(z)
    return e / e.sum(axis=axis, keepdims=True)

def causal_self_attention(X, WQ, WK, WV):
    Q, K, V = X @ WQ, X @ WK, X @ WV           # [N×dk], [N×dk], [N×dv]
    N, dk = K.shape
    scores = Q @ K.T / np.sqrt(dk)              # [N×N]
    future = np.triu(np.ones((N, N), dtype=bool), k=1)
    scores[future] = -np.inf                    # 遮住未來
    alpha = softmax(scores)                     # 每列和為 1
    return alpha @ V, alpha

rng = np.random.default_rng(0)
N, d, dk = 5, 8, 4
X = rng.normal(size=(N, d))
WQ, WK, WV = (rng.normal(size=(d, dk)) for _ in range(3))
out, alpha = causal_self_attention(X, WQ, WK, WV)
print(alpha.round(2))   # 下三角矩陣
print(out.shape)        # (5, 4)

進階・位置寫進內積

這一節補上第 2 節留下的兩件事:座位號碼怎麼改變注意力分數,以及怎麼不把位置加成向量,而是寫進內積裡。第一次讀可以整節跳過。

算算看:少了位置,「誰咬誰」就消失。 取 𝑑 = 2,詞嵌入為 狗 = [1.0, 0.2]、咬 = [0.0, 1.0]、人 = [0.8, 0.6];位置嵌入為 第 1 號 [0.4, 0.0]、第 2 號 [0.0, 0.2]、第 3 號 [−0.4, 0.0]。為了算起來簡單,假設三個投影矩陣 𝐖 都是單位矩陣,而且模型看得到整句。這裡只追蹤「咬」這個詞元。

以「狗咬人」加上位置為例:「咬」是第 2 個詞元,𝐱₂ = [0.0, 1.2],它對三個詞的分數為

不加位置的時候,softmax 可以手算。分數 0.2、1.0、0.6 的指數大約是 1.22、2.72、1.82,加起來約 5.76,權重約 0.21、0.47、0.32。加權之後,就是下面那張表的 [0.465, 0.704]。加上位置之後的 0.24、1.44、0.72,同樣算出表裡的 0.168、0.559、0.272。「人咬狗」只是把這三個分數左右對調。

兩句的完整結果如下:

步驟 狗咬人 人咬狗
不加位置:「咬」對第 1、2、3 個詞的分數 狗 0.2、咬 1.0、人 0.6 人 0.6、咬 1.0、狗 0.2
不加位置:「咬」的輸出 [0.465, 0.704] [0.465, 0.704]
加位置後的 𝐱₁、𝐱₃ 狗 [1.4, 0.2]、人 [0.4, 0.6] 人 [1.2, 0.6]、狗 [0.6, 0.2]
加位置:分數 0.24、1.44、0.72 0.72、1.44、0.24
加位置:softmax 權重 0.168、0.559、0.272 0.272、0.559、0.168
加位置:「咬」的輸出 [0.345, 0.868] [0.428, 0.868]

不加位置時,兩句只是同一組「詞與分數」換了排列;加權總和不分先後,輸出一模一樣,模型確實分不出誰咬誰。這個性質稱為置換等變(permutation equivariance)。加上位置之後,「狗」當主詞時是 [1.4, 0.2],當受詞時是 [0.6, 0.2],兩種角色拿到不同向量,「咬」的輸出也就分開了。

兩種常見變體。 原始論文(Vaswani et al. 2017)用固定的正弦函數,不需學習,波長由短到長,像一組時針、分針、秒針同時報時:

算算看。 取 𝑑 = 4。𝑘 = 0 那一組的分母是 10000⁰ = 1,轉得快,像秒針;𝑘 = 1 那一組的分母是 10000 的 2/4 次方,即 √10000 = 100,轉得慢,像時針:

位置 𝑝 sin(𝑝) cos(𝑝) sin(𝑝/100) cos(𝑝/100)
0 0.000 1.000 0.000 1.000
1 0.841 0.540 0.010 1.000
2 0.909 −0.416 0.020 1.000
3 0.141 −0.990 0.030 1.000
7 0.657 0.754 0.070 0.998
100 −0.506 0.862 0.841 0.540

從第 1 號移到第 2 號,前兩格變化明顯,後兩格幾乎不動;要等位置相隔夠遠,慢的那一組才會拉開差距。

再看第 7 號:快的一組 [0.657, 0.754] 已轉回接近第 1 號的 [0.841, 0.540],因為秒針約每 2π ≈ 6.28 個位置轉一圈;這時要靠慢的一組(0.070 對 0.010)才分得開。到了第 100 號,慢的一組也轉了 1 弧度,四個數合起來仍是獨一無二的座標。

相對位置藏在內積裡。 利用 sin 𝑎 sin 𝑏 + cos 𝑎 cos 𝑏 = cos(𝑎 − 𝑏),兩個位置向量的內積只取決於距離:

代入數字:

只要相隔兩格,內積就相同。RoPE 正是把這個性質直接用在 𝐪 與 𝐤 上。

現在的大型語言模型多半使用旋轉位置編碼 RoPE(Su et al. 2024):位置不加在 𝐱 上,而是讓 𝐪 和 𝐤 依所在位置旋轉一個角度。兩個向量轉完之後,內積只看角度差,也就是相對距離 𝑗 − 𝑖。換句話說,模型在意的是「隔幾個詞」,不是「坐在第幾號」。

算算看。 以二維為例,設每往後一個位置就多轉 30°,且 𝐪 與 𝐤 轉動前都是 [1, 0]。位置 1 與位置 3 分別轉 30° 與 90°,夾角 60°,內積為 cos 60° = 0.5;位置 5 與位置 7 分別轉 150° 與 210°,夾角仍是 60°,內積仍是 0.5。只要相隔兩個詞,分數就相同。

再算一例:換成真正的 𝐪 與 𝐤。 沿用第 3 節「它」的 𝐪 = [1, 2] 與「獎盃」的 𝐤 = [2, 1],轉動前內積為 4。把向量 [𝑥, 𝑦] 轉 𝛼 度的公式,以及轉動後內積的一般形式如下(𝜑 為兩者原本的夾角,此例 cos 𝜑 = 0.8):

設「它」在位置 𝑚 = 3、「獎盃」在位置 𝑛 = 1,每個位置轉 𝜃 = 30°,則 𝐪 轉 90°、𝐤 轉 30°:

換幾組位置:

「它」位置 𝑚 「獎盃」位置 𝑛 轉後 𝐪 轉後 𝐤 內積
1 1 [−0.134, 2.232] [1.232, 1.866] 4.000
2 1 [−1.232, 1.866] [1.232, 1.866] 1.964
3 1 [−2.000, 1.000] [1.232, 1.866] −0.598
7 5 [0.134, −2.232] [−2.232, 0.134] −0.598

後兩列轉完的向量完全不同,內積卻一樣,因為兩種情況都相隔 2 個位置。相隔 0 個、1 個、2 個位置時,分數各不相同,模型因此可以學到自己比較在意隔多遠的詞。這個例子每一步轉 30°,只是為了讓變化看得清楚。實際的 RoPE 把 𝑑 維切成 𝑑/2 組,各組的角速度和正弦編碼的 𝜔ₖ 相同,多數組轉得很慢,不會像這個例子一樣,轉幾步就繞回原處。

進階・程式(NumPy,驗證本節數字):

import numpy as np

def sinusoidal_pe(p, d):
    k = np.arange(d // 2)
    omega = 1 / 10000 ** (2 * k / d)            # 每組的角速度
    pe = np.empty(d)
    pe[0::2], pe[1::2] = np.sin(p * omega), np.cos(p * omega)
    return pe

def rope_2d(v, pos, theta=np.pi / 6):           # 每往後一個位置多轉 30°
    a = pos * theta
    R = np.array([[np.cos(a), -np.sin(a)],
                  [np.sin(a),  np.cos(a)]])
    return v @ R.T                              # 講義用列向量,旋轉寫在右邊

print(sinusoidal_pe(1, 4).round(3))             # [0.841 0.54  0.01  1.   ]
for p, p2 in [(1, 3), (5, 7), (40, 42)]:
    print(p, p2, round(sinusoidal_pe(p, 4) @ sinusoidal_pe(p2, 4), 3))  # 皆 0.584

q, k = np.array([1., 2.]), np.array([2., 1.])  # 第 3 節的 q_它、k_獎盃
for m, n in [(1, 1), (2, 1), (3, 1), (7, 5)]:
    print(m, n, round(rope_2d(q, m) @ rope_2d(k, n), 3))  # 4.0、1.964、-0.598、-0.598

4. 多頭注意力與 Transformer 區塊

同時請好幾組「讀者」從不同角度讀句子,再把意見彙整;這樣的步驟疊上幾十層,就是一個 Transformer。

比喻:審稿委員會。 一組 𝐐、𝐊、𝐕 只能問一種問題,而語言中的關係不只一種:誰是主詞、哪個修飾語修飾哪個名詞、代名詞指向誰。多頭注意力就像請 𝐴 位審稿人各看一個面向,最後由主編(𝐖ᴼ)整合成一份意見。

其中 ⊕ 為串接;通常取 𝑑ᵥ = 𝑑 / 𝐴,使串接後仍是 𝑑 維,𝐖ᴼ 的形狀為 [𝑑 × 𝑑]。

算算看。 設 𝑑 = 8、𝐴 = 2,每個頭輸出 𝑑ᵥ = 4 維。兩個頭串接成 4 + 4 = 8 維,再乘上 [8 × 8] 的 𝐖ᴼ,輸出仍是 8 維,形狀和輸入一樣。

比喻:殘差流是一份共筆筆記。 每個詞元有自己的一條「殘差流」(residual stream),由下往上傳遞。每一層都不重寫整份筆記,只在上面加註。注意力是唯一能讀別人筆記的元件,負責在詞元之間搬運資訊;前饋網路則在各自的筆記上做加工(Elhage et al. 2021)。所以剛才那個 8 維的輸出,可以整段加回這份筆記,不必把原來的筆記換掉。

互動示意 · 點「下一步」逐層加註

進階・一個區塊的五個步驟(pre-norm,投影片所用):

算算看。 沿用第 2 節「它」的 𝐱₁₁ = [0.3, 0.5, 0.5]。若注意力算出 𝐭² = [0.2, −0.1, 0.4],則第三步為

原本的筆記還在,只是每一格多了一點註記。

前饋網路提供非線性,通常先把維度放大約四倍再縮回:

算算看。 ReLU 把負數歸零、正數照留:ReLU([−1.2, 0.5, 3.0, −0.3]) = [0, 0.5, 3.0, 0]。至於維度,以 GPT-2 小型版為例,𝑑 = 768,𝐖₁ 先放大到 3072 維,𝐖₂ 再縮回 768 維。

LayerNorm 就是統計學的 z 分數,套用在單一向量的 𝑑 個分量上,再以可學習的 𝛾、𝛽 還原尺度。比喻是把各科原始分數換成標準分數,避免某一科只因分數尺度較大就主宰總分。這裡的標準差用全部 𝑑 個分量去除,分母是 𝑑。這和統計課的樣本標準差不同,樣本標準差要除以 𝑑 − 1:

算算看。 取 𝐱 = [2, 4, 6, 8],並設 𝛾 = 1、𝛽 = 0:

不論原始數字多大,正規化後平均都是 0、標準差都是 1。

因為輸入與輸出都是 𝑑 維,區塊可以一層層疊上去。以 GPT-3 為例,共 96 層、每層 96 個頭(Brown et al. 2020)。

5. 上下文詞向量、語言模型頭與預訓練

疊完所有層,每個詞都換上一組「讀過上下文」的新數字;模型用它來猜下一個詞,並靠反覆猜、反覆修正來學習。

比喻:辭典釋義與讀者的當下理解。 靜態詞向量像辭典:一詞一條,羅列所有可能的意思。上下文詞向量像讀者讀到某一句時腦中的理解:一詞一例,只留下此刻成立的那個意思。

定義。 詞元 𝑖 在第 𝐿 層的輸出 𝐡ᵢᴸ,就是它的上下文詞向量。「太大」與「太小」兩句裡的「它」,起點 𝐱ᵢ 相同,經過 𝐿 層注意力之後的 𝐡ᵢᴸ 卻不同。投影片的總結是:注意力讓每個詞的嵌入在不同語境中各不相同。

互動示意 · 切換「大/小」看「它」的走向

語言模型頭。 最後一層的向量要換回詞彙表上的機率。解嵌入(unembedding)層通常直接借用 𝐄 的轉置,稱為權重共享(weight tying):

算算看。 沿用第 1 節的 4 詞元 𝐄,設最後一層正規化後的向量為 𝐡 = [0.8, 0.2, 0.6]。乘上 𝐄ᵀ,等於拿 𝐡 和每個詞元那一列做內積:

詞元 內積 𝐮 softmax 後 𝐲
獎盃 0.8×0.9 + 0.2×0.1 + 0.6×0.4 = 0.98 0.280
行李箱 0.76 0.225
它 0.60 0.192
大 0.8×0.6 + 0.2×0.2 + 0.6×0.9 = 1.06 0.303

模型認為下一個詞最可能是「大」,但把握不高;這是因為示範用的數字很小。

預訓練:預測下一個詞。 拿大量文本,在每個位置 𝑡 要求模型猜 𝑤ₜ₊₁,以交叉熵懲罰錯誤。因為正確分布是 one-hot,損失就等於正確詞元的負對數機率。訓練時無論模型猜什麼,下一步一律餵入正確的詞,稱為 teacher forcing:

算算看。 若正確的下一個詞是「大」,上表給它 0.303。比較三種把握程度:

依序對應現況、更有把握(給到 0.9)、幾乎猜錯(只給 0.01)。訓練就是不斷調整參數,讓這個數字變小。

生成與溫度。 貪婪解碼每一步都選機率最高的詞,結果平淡、容易重複。實務上改成抽樣,再用溫度 𝜏 調整分布有多尖。𝜏 越小越保守;𝜏 趨近 0 的時候,就變成貪婪解碼。𝜏 越大,選詞越分散:

算算看。 同一組分數 𝐮 = [0.98, 0.76, 0.60, 1.06],「大」是第 4 個詞元:

𝜏 = 0.5 等於把分數加倍,「大」從 0.303 升到 0.357,其餘都下降,分布變得更尖。

下面這張圖用的是「太_了」這個空格的示意分數,不必和上面那四個詞的內積對上。兩邊的算法一樣,都是 softmax(分數/𝜏)。

互動示意 · 點選溫度,機率由 softmax(分數/τ) 即時計算

三種架構。 同一套區塊,換個遮罩與訓練目標,就成了不同家族:

架構 注意力範圍 訓練目標 代表模型 典型用途
僅解碼器 只看左側(因果遮罩) 預測下一個詞 GPT 系列、Llama 生成、對話
僅編碼器 雙向,左右皆可見 遮蔽語言模型(填空) BERT 分類、序列標記、取上下文詞向量
編碼器-解碼器 編碼雙向,解碼因果並交叉注意 序列到序列 原始 Transformer、T5 翻譯、摘要

若目的是取上下文詞向量做詞義分析,雙向的 BERT 類模型較直接,因為「它」的向量同時看得到「大/小」。

6. 評估

困惑度問的是:模型每一步平均在幾個詞之間拿不定主意?數字越小越好。

比喻:每一步在幾個選項之間猶豫。 困惑度(perplexity)可以讀成模型的「等效分支數」。困惑度為 4,表示模型平均而言像在 4 個等可能的詞之間擲骰子;越低,代表它對真實文本越不意外。

互動示意 · 圖上的柱子來自程式裡那組含有 0.05 的機率;下面先算一個正好等於 4 的例子

進階:式子(可跳過)。 測試集的機率會隨長度變小,無法跨文本比較,因此取幾何平均再倒數,也就是對長度正規化:

算算看。 一段三個詞元的文本,模型給正確詞元的機率依序是 0.5、0.25、0.125:

改用最右邊的寫法,三個 −ln 𝑝 分別是 0.693、1.386、2.079,結果相同:

也就是說,這個模型平均像在 4 個詞之間挑一個。

最右邊一式顯示,困惑度正是第 5 節交叉熵損失的指數。

import numpy as np

def perplexity(p_true):
    """p_true:模型給每個正確下一詞元的機率"""
    return float(np.exp(-np.mean(np.log(p_true))))

print(perplexity([0.25] * 8))             # 4.0:每步四選一
print(perplexity([0.9, 0.5, 0.05, 0.6]))  # 約 2.93;一個 0.05 就拉高不少

使用限制。 困惑度以詞元為單位,只有斷詞器相同的時候才能比較。換模型或換語言時,最好改用每個位元組的位元數(bits per byte),這類和切分方式無關的指標。

困惑度之外。 投影片最後一頁提醒,評估不只是預測準確:

面向 問的問題 常見做法
語言模型品質 對沒看過的文本預測得多好 困惑度、每個位元組的位元數
下游任務 能否完成分類、問答、推理 準確率、F1、標準基準測驗
生成品質 輸出是否忠實、通順、有用 BLEU、ROUGE、人工評估、以 LLM 擔任評審
表示品質 上下文詞向量是否編碼語言結構 探測分類器、結構探測(Hewitt & Manning 2019)、詞義消歧
跨語言與類型涵蓋 能否泛化到陌生的語言系統 多語基準、類型學平衡的推理題(如 LOBSTER,Lian et al. 2025)
規模與能耗 訓練與部署要付出多少 參數量、GPU 時數、kWh 或 CO2 排放
公平性 是否強化刻板印象、對特定群體表現較差 偏見與群體差異基準

基準測驗另有資料汙染的風險:測驗題若已出現在預訓練語料中,高分只說明記憶,不說明能力。

7. 語言學回望與小結

分布語意學的動態化。 Firth(1957)說,要認識一個詞,就看它和誰作伴。靜態詞向量把「作伴」累積成一個平均值;注意力則把它改寫成當下的計算:詞義不是查表查出,而是由此刻身旁的詞共同決定。

語序與位置。 漢語這類缺乏詞形變化、倚重語序的語言,「狗咬人」與「人咬狗」的差別幾乎全落在位置上。RoPE 只編碼相對距離,與語言學中「依存距離」的觀念相近;但模型是否因此學到類型學意義上的語序規律,仍是開放問題。

注意力是線索,不是解釋。 部分注意力頭的行為與句法關係相當吻合,例如受詞注意其動詞、代名詞注意其先行詞(Clark et al. 2019)。然而權重高,不代表模型就依那個詞做判斷(Jain & Wallace 2019;Wiegreffe & Pinter 2019)。結構究竟是模型自己長出來,還是我們讀進去,需要探測與介入實驗共同檢驗。

困惑度與驚奇度。 −log 𝑃(𝑤ₜ ∣ 𝑤₁, …, 𝑤ₜ₋₁) 在心理語言學中稱為驚奇度(surprisal),能預測人類的閱讀時間(Hale 2001;Levy 2008)。困惑度因而不只是工程指標,也是連接模型與人類處理歷程的橋樑。

回到那一句。 「獎盃放不進行李箱,因為它太大了」可以沿著導讀的五站再走一遍。斷詞之後,詞嵌入讓兩個「它」查出同一列。加上位置之後,它才帶上自己的座位,向量就和句子裡其他位置的「它」不一樣。注意力再依照當下的詞改寫它:雙向模型看得到「大」,權重會轉去獎盃;只看左邊的生成式模型,讀到「它」時還沒看到「大」或「小」,要等後面的詞把先行詞的訊息帶回來。區塊疊了 𝐿 層之後,兩句裡的「它」雖然從同一個向量出發,最後卻分開了。語言模型頭只做一件事:把最後一個向量換回下一個詞的機率。

一句話小結。 詞嵌入給每個詞一個起點,位置嵌入標出它坐在哪裡,注意力讓它聽取鄰座的意見,層層堆疊後得到上下文詞向量,最後以困惑度與各種基準檢驗它說得好不好。

參考文獻