Skip to content

CMU 11-868 L23 大模型的高效微調:LoRA、CIAT 與 QLoRA

2026年9月30日1 分鐘
TL;DR11-868 第 23 講把微調當成記憶體問題來算:LLaMA-8B 全參數半精度微調約要 80GB,換成 LoRA 約 33GB,再把凍結權重存成 4-bit 的 QLoRA 壓到約 9.2GB。這講的主線是三步:只訓練低秩的 A、B 兩個小矩陣(投影片說這招最早出自 CIAT);用 NF4 查表與雙重量化把凍結權重壓到約 0.52 bytes/參數;用 paged optimizer 在 GPU 快爆時把 optimizer state 換到 CPU。

🌏 English version

版本說明:本文依據 CMU 11-868 LLM Systems 2026 春季版。主要材料是 4/8 的 第 23 講投影片 Parameter Efficient Fine-Tuning for LLM(Lei Li,PDF 共 46 頁;下文頁碼指 PDF 頁序,不是投影片角落的編號),以及 Syllabus 列的三篇 reading:CIAT、LoRA、QLoRA。事實皆於 2026-09-30 打開官方材料核對。存取等級 A3:投影片公開;拿不到的是課堂錄影(本課沒有公開錄影)與 Canvas 上的課後 Quiz。

系列位置:上一篇 L12–L13 TPU、JAX 與 Pallas/Splash Attention|下一篇 L22、L24 LLM 服務:排程、RadixAttention 與 PagedAttention|系列總覽

前幾講一直在問「怎麼把一次訓練跑快、跑得下」。第 23 講換一個場景:模型已經預訓練好了,你只想讓它學會一個新任務或新領域,手上卻只有一兩張卡。

這講的回答分兩層。第一層是 LoRA:凍結原權重,只訓練一個低秩的增量。第二層是 QLoRA:連凍結的權重也壓成 4-bit。兩層加起來,投影片把 LLaMA-8B 的微調記憶體從約 80GB 算到約 9.2GB。

投影片第 2 頁先回顧上一講的量化(absmax、zero-point、LLM.int8()、GPTQ),因為 QLoRA 會直接用到。沒讀過的話,先看本系列的 L19–L20 模型量化。

先算帳:全參數微調為什麼貴

投影片第 4–6 頁用同一張「每個參數要花多少 bit」的表,比較三種做法:

做法權重權重梯度optimizer stateadapter 權重LLaMA-8B 工作記憶體
半精度全參數(Adam)16 bit16 bit2 × 16 bit—約 80GB
LoRA16 bit約 0.4 bit約 0.8 bit約 0.4 bit約 33GB,單張 A100 放得下
QLoRA4 bit約 0.4 bit約 0.8 bit約 0.4 bit約 9.2GB

三列的 activation 都寫成「約參數量的 1–2 倍」,不因方法而變。這張表的讀法是:全參數微調最貴的不是權重本身,是梯度加上 Adam 的兩份 moment;LoRA 砍的就是這兩塊。

第 7 頁把 PEFT 分三類,引自 Lialin et al. 的綜述:

  • Selective:只微調挑出來的一部分參數。
  • Reparameterization:用低秩表示權重的更新。LoRA 在這一類。
  • Additive:加上可訓練的新層或新參數,例如 adapter、soft prompt。

LoRA:凍結 W,只學 A·B

第 9–10 頁的式子就一行:凍結預訓練權重 W,學一個低秩增量。

W′ = W + A·B,其中 A 是 d×r、B 是 r×d,r 遠小於 d。

第 10 頁特別寫了這個想法的來歷:最早出現在多語翻譯的 Counter-Interference Adapter(CIAT,EMNLP 2021),後來由 LoRA(ICLR 2022)「re-invented」。兩篇的 arXiv 首版分別是 2021 年 4 月與 6 月。之後投影片一律寫成「LoRA/CIAT」。

放在哪幾個矩陣。第 11 頁的建議是 rank 取 8 或 16,套在 attention 的 W_Q、W_K、W_V、W_O,不套在 FFN 的線性層;投影片的理由是 FFN「storing knowledge」。同一頁也補了一句:CIAT 把它同時套在 embedding 與 FFN 上,效果有提升。這兩句放在一起,代表「只套 attention」是一個預設,不是定律。

推論時怎麼用(第 12 頁)。直接算出 W′ = W + A·B 當成一般權重用,額外只需要存 A、B。要換任務時,減掉舊的、加上新的:W″ = W′ − A·B + A″·B″。一個底座模型因此可以掛很多組領域專用的小 adapter。

反向傳播只算兩個小梯度(第 13 頁)。W₀ 固定,只需要對 A、B 求導:

  • ∂L/∂A = g_out · (Bx)ᵀ
  • ∂L/∂B = (g_out · A) · xᵀ(照投影片的寫法;把轉置按維度寫清楚是 (Aᵀ · g_out) · xᵀ)

如果你做過本系列的 HW2 MiniTorch,這就是把 matmul 的反向規則套兩次。

要存什麼(第 14 頁):原參數本身,加上 adapter 權重、adapter 梯度、adapter 的兩份 Adam moment(各 2×d×r),以及 activation。原參數不需要梯度與 optimizer state。

第 15 頁把數字放在一起看:LLaMA 8B 的 80 億參數在 BF16 下是 16GB,Adam 的 optimizer state 是 48GB;換成 LoRA,可訓練參數只剩約 4M,對應 8MB 權重與 24MB optimizer state。第 16 頁的結論是記憶體與訓練時間都下降,推論則跟一般 LLM 一樣。

rank 要取多大

第 17–21 頁整理 LoRA 論文的實驗:NLU 用 RoBERTa、DeBERTa 跑 GLUE 的八個子任務,NLG 用 GPT-2、GPT-3,和全參數微調、BitFit、兩種 prefix tuning、adapter tuning 比較。投影片擷取的要點有兩個:

  • 第 19 頁:把 rank 調高並不會涵蓋更多有意義的子空間,r=8 的低秩矩陣就夠。
  • 第 20 頁:把規模拉到 175B 的 GPT-3 做壓力測試,不是每種方法都會隨可訓練參數增加而單調變好。

第 21 頁另外放了一張 LoRA 在 GSM8K 數學題上的表現圖,投影片沒有配文字說明結論,這裡不替它下結論。

QLoRA:連凍結的權重也壓成 4-bit

第 23 頁先分清兩種量化。上一講的 GPTQ 是 post-training quantization:模型訓練完才轉低精度,不再訓練。QLoRA 則被歸在 quantization-aware training:量化發生在訓練階段,通常效果較好。

第 24 頁列出 QLoRA(NeurIPS 2023) 的三項創新:4-bit NormalFloat 儲存、double quantization、paged optimizer;計算一律用 BF16。投影片引論文的結果:65B 模型的微調記憶體平均需求從 780GB 降到單張 GPU 的 48GB,表現與 16-bit 微調相當。

第 25 頁的演算法是一條「存 4-bit、算 16-bit」的管線:

  1. 用雙重量化把權重存成 NF4。
  2. 用到時反量化成 BF16。
  3. 前向與反向都在 BF16 做。
  4. 只對 LoRA 參數算 BF16 權重梯度。

NF4:為什麼不用等寬分箱

4-bit 只有 16 個值。第 26 頁指出,absmax 那種等寬分箱遇到分布不均的資料會很吃虧:大量彼此差很少的小數值會被量化到同一格。

第 27 頁的 NF4 做法:

  1. 每 64 個權重一組。
  2. 找組內最大絕對值當 scale。
  3. 把 64 個數除以 scale,落到 [−1, 1]。
  4. 在一張 16 值的查表裡找最近的值,輸出它的索引(−7 到 8)。

這張查表不是等距的:靠近 0 的格子密,靠近 ±1 的格子疏。第 29 頁說明這些值取自分位數(probably quantile)。

第 28 與 30 頁手算一個例子,值得跟著算一次:

  • 原值 0.0045,組內 scale 0.0071,正規化後約 0.63。
  • 查表最近的是 0.5626,索引是 6。
  • 反量化:0.5626 × 0.0071 ≈ 0.00399,誤差約 0.0005。

Double quantization:scale 本身也要壓

第 31 頁點出小 block 的代價:每 64 個參數配一個 32-bit 常數,平均每個參數多花 32/64 = 0.5 bit。

第 32 頁的解法是再量化一次:每 64 個值做一次 NF4,產生的 scale 每 256 個一組用 FP8 量化,第二層的 scale 才用 FP32 存。投影片算出的結果是每個參數約 0.52 bytes。

第 33 頁把 QLoRA 的完整配置收在一起:預訓練權重存 NF4 加雙重量化,LoRA 權重存 BF16,輸入與所有計算(前向、反向、optimizer)都用 BF16。

Paged optimizer:快爆時先換到 CPU

第 34–36 頁處理的是訓練中偶發的 OOM。做法是用 NVIDIA unified memory 配置 optimizer state:GPU 記憶體不夠時,這些 state 自動逐頁移到 CPU,到 optimizer 更新那一步需要時再搬回 GPU。投影片把它比作 CPU RAM 與硬碟之間的一般分頁。

第 37–38 頁引論文的兩個結果:LoRA 的預設超參數追不上 16-bit 的表現;NF4 比 4-bit float(FP4)好;調好之後,4-bit QLoRA 可以對上 16-bit 全參數微調與 16-bit LoRA。

程式碼導覽

第 40–42 頁是 LoRA 層的實作截圖,重點有三個:初始化 A、B 兩層;凍結預訓練權重;前向時把兩條分支(原權重、低秩分支)的結果加起來,訓練完可以把 LoRA 權重併回原權重。

第 43 頁示範 QLoRA 的用法:用帶 quantization config 的方式載入模型,再照常套 LoRA;底層的 CUDA 量化運算由 bitsandbytes 的 wrapper 提供。投影片上的設定大致如下(模型名稱照投影片):

AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-2-70b",
    quantization_config=BitsAndBytesConfig(
        load_in_4bit=args.bits == 4,
        load_in_8bit=args.bits == 8,
        llm_int8_threshold=6.0,
        llm_int8_has_fp16_weight=False,
        bnb_4bit_compute_dtype=compute_dtype,
        bnb_4bit_use_double_quant=args.double_quant,
        bnb_4bit_quant_type=args.quant_type,
    ),
)

同頁附了 QLoRA repo 的 Guanaco 7B Colab 範例。

這講跟作業的關係

LoRA 會在 HW6 直接用到:作業要你在 DeepSpeed ZeRO 上打開 LoRA,讓 Llama-2-7B 的訓練塞進 2 張 16GB 的 V100。這講的記憶體帳,就是你在作業裡調參數時要心算的那張表;ZeRO 那一半請先讀 L18 ZeRO。

第 44–45 頁的總結:LoRA/CIAT 用少量低秩參數就能便宜地適配大模型,對 GPT-3 這種規模也有效,低資料量時表現更好;QLoRA 用 NF4 雙重量化存權重、用 BF16 計算,表現與原本的 LoRA 相當,投影片稱它是第一個能在單張消費級 GPU 上微調 33B LLM 的方法。

自學怎麼做

  1. 讀投影片第 4–6 頁,自己用「每參數 bit 數 × 參數量」重算一次三列記憶體,確認你知道哪一塊被砍掉。
  2. 跟著第 28、30 頁手算 NF4 的量化與反量化,再換一個數字算一次。
  3. 讀 LoRA 論文談 rank 的實驗段落,對照投影片第 19 頁。
  4. 有 GPU 的話,用第 43 頁的設定載入一個小模型,比較開關 bnb_4bit_use_double_quant 前後的顯存。

延伸閱讀

參考資料