跳轉到

9.3 Transformer與大型語言模型簡介#

概念說明#

2017 年,Google 的論文《Attention Is All You Need》提出 Transformer,徹底改寫了 NLP。此前 RNN/LSTM 逐詞處理序列——無法平行(第 i 步要等第 i−1 步),長距離依賴靠隱狀態逐步傳遞而漸漸遺忘。Transformer 用自注意力(self-attention)一步到位:序列中每個位置直接「看」所有其他位置,依相關度加權取用資訊;訓練完全平行,長依賴路徑長度為 1。

自注意力的計算:每個詞向量乘三個矩陣得到 Query、Key、Value。注意力分數 = softmax(QKᵀ/√d)·V——直觀是「拿我的 Query 去和大家的 Key 比對,相關的 Value 加權越多」。例:「牠追著球跑,因為牠很興奮」中,「牠」的 Query 與前句「狗」的 Key 高度匹配,於是「牠」的表示融入「狗」的資訊——一詞多義(7.3 節的 bank 問題)就此解決:同一詞在不同上下文有不同向量。多頭注意力把 Q/K/V 拆成 h 組平行計算,讓不同頭各自學語法、語義、指代等不同關係。位置編碼補上「順序」資訊(注意力本身對位置無感),從正弦編碼演進到旋轉位置編碼(RoPE)。

預訓練範式改變了遊戲規則。BERT(2018)用遮罩語言建模(挖空詞讓模型還原)做雙向編碼器,刷新 11 項任務;GPT 系列用因果語言建模(只看左邊預測右邊)做解碼器,路線一路走到 GPT-4 級模型。公式:先在網路級語料自監督預訓練,再對下游任務微調——「預訓練知識 + 少量標註微調」取代了「每個任務從零訓練」,NLP 進入基礎模型時代。

大型語言模型(LLM)是「資料 × 參數 × 計算」規模化的結果。規模定律(scaling laws)指出損失隨三者平滑下降;GPT-3(2020,175B 參數)展示少樣本學習(in-context learning):不用改參數,提示詞裡給幾個例子模型就能上手。之後的對齊工程——指令微調(SFT)與人類回饋強化學習(RLHF)——把「補全機」變成「聽話的助手」。

LLM 時代的文字演算法並未退場,反而更關鍵:

  • 分詞:LLM 用 BPE/WordPiece 子詞(7.1 節練習),詞表 5–10 萬;token 數直接影響成本與上下文限制。
  • 檢索增強生成(RAG):LLM 知識有截止日且會幻覺,把 8.1–8.2 節的索引+向量檢索接上 LLM(先檢索文件、再讓模型引用作答),是企業落地的標準架構。
  • 上下文管理:上下文視窗有限(數千~數百萬 token),長文件摘要、分塊、滑動視窗都是演算法問題。
  • 推論優化:KV 快取、投機解碼、量化(把 16-bit 權重壓到 4-bit,第 5 章壓縮思想的回歸)。

演算法步驟(縮放點積注意力)#

  1. 輸入詞向量序列 X(n×d),經線性層得 Q、K、V(各 n×dₖ)。
  2. 分數 S = QKᵀ/√dₖ(n×n);因果模型把上三角遮成 −∞(不可偷看未來)。
  3. A = softmax(S)(每列歸一);輸出 O = A·V。
  4. 多頭:h 組平行做 1–3,串接後再線性變換。
  5. 每層 Transformer 區塊 = 多頭注意力 + 前饋網路(逐位置 MLP)+ 殘差連接與層正規化;堆疊 L 層後接輸出層預測下一詞。

Python 程式碼範例#

import numpy as np

rng = np.random.default_rng(0)
n, d_model, d_k = 4, 8, 4      # 4 個詞、模型維度 8、注意力頭維度 4

X = rng.normal(0, 1, (n, d_model))                  # 已含位置編碼的詞向量
Wq, Wk, Wv = [rng.normal(0, 0.5, (d_model, d_k)) for _ in range(3)]

Q, K, V = X @ Wq, X @ Wk, X @ Wv

def attention(Q, K, V, causal=True):
    scores = Q @ K.T / np.sqrt(Q.shape[-1])
    if causal:                                       # 因果遮罩
        mask = np.triu(np.ones_like(scores, dtype=bool), k=1)
        scores = np.where(mask, -1e9, scores)
    A = np.exp(scores - scores.max(-1, keepdims=True))
    A /= A.sum(-1, keepdims=True)
    return A, A @ V

A, out = attention(Q, K, V)
print("注意力權重(列=誰在看、行=被看者):")
print(np.round(A, 3))
print("輸出形狀:", out.shape)

# 驗證:因果模式下第 1 個詞只能看自己
assert A[0, 1:] .max() < 1e-5 and abs(A[0, 0] - 1) < 1e-5
# 驗證:每列權重和為 1
assert np.allclose(A.sum(-1), 1)

# 多頭的骨架
n_heads, out_dim = 2, 8
Wo = rng.normal(0, 0.5, (n_heads * d_k, out_dim))
heads = []
for h in range(n_heads):
    Qh = X @ rng.normal(0, 0.5, (d_model, d_k))
    Kh = X @ rng.normal(0, 0.5, (d_model, d_k))
    Vh = X @ rng.normal(0, 0.5, (d_model, d_k))
    heads.append(attention(Qh, Kh, Vh)[1])
concat = np.concatenate(heads, axis=-1)
print("多頭輸出:", (concat @ Wo).shape)   # (4, 8)

複雜度分析#

  • 注意力:QKᵀ 為 O(n²dₖ)、A·V 為 O(n²dₖ)——序列長度的平方成本是 Transformer 的根本瓶頸;n=百萬 token 時連權重矩陣都存不下,催生 FlashAttention(IO 感知的精確加速)、稀疏/線性注意力、滑動視窗等變體。
  • 前饋層:O(n×d×4d),通常比注意力更耗算(參數占比大)。
  • 訓練/推論:訓練全序列平行 O(n²);推論自回歸逐 token 生成,KV 快取把每步從 O(n²) 降到 O(n)。
  • 模型量級:BERT-base 110M、GPT-2 1.5B、GPT-3 175B;訓練 GPT-3 約 10²³ FLOPs——文字演算法的「常數項」在此規模就是工程核心(混合精度、分散式、資料管線)。

練習#

  1. 把範例的多頭部分重寫成乾淨的 MultiHeadAttention 類別(h=2、4),觀察不同頭的注意力矩陣差異,說明「多頭」為何能學到多種關係。
  2. 實作縮放因子的作用:去掉 1/√dₖ 後用 dₖ=64 重算,觀察 softmax 飽和(接近 one-hot)的現象,解釋為何需要縮放。
  3. 設計一個玩具 RAG:把第 8 章的倒排索引+TF-IDF 接上一個小語料,對查詢先檢索 top-2 文件,再把文件內文與問題拼成提示詞;用任意可用的 LLM API(或手動觀察提示詞結構)比較「有無檢索」時答案的差異,寫 200 字說明 RAG 為何能抑制幻覺。