跳到主要內容

LV.12

秩之神殿:LoRA 與 QLoRA

加修次專科,不必重讀醫學院

BOSS
全參數巨人
時間
約 45 分鐘
建議先過
LV.06 、LV.11

先看 Boss:全參數巨人

想像要教一個已經讀完醫學院的畢業生「如何做病歷去識別化」。你會把整套醫學院課程重教一遍嗎?當然不會,只要幾週的專項訓練。

模型也是一樣。Gemma 4 E2B 這類模型本身有數十億個參數(作者實測載入時顯示總計約 46.3 億,包含大量給每一層用的 embedding)。如果每次微調都要更新全部參數,記憶體要裝的東西包含:模型本身、每個參數的梯度(gradient,告訴你該往哪調)、優化器狀態(optimizer state,例如 Adam 的動量)。總量會是模型本身的好幾倍。這就是全參數巨人(full fine-tuning):筆電裝不下。

LoRA:只改一點點

LoRA(Low-Rank Adaptation,低秩適配)的核心想法是:原本的權重凍結,不動;旁邊加兩個很小的矩陣 A 和 B,只訓練這兩個。

假設某一層的權重是一個 d × k 的大矩陣 W。全參數微調要更新 d × k 個數字。LoRA 改成:

  • A:d × r 的小矩陣
  • B:r × k 的小矩陣
  • 推論時用 W + (A × B) 的結果

其中 r 就是 rank(秩),通常只有 8、16、32 這種小數字。可訓練的參數量是 r × (d + k)。

用實際數字感受一下:一個 2048 × 2048 的矩陣,原本有 4,194,304 個數字。rank 8 的 LoRA 只有 8 × (2048 + 2048) = 32,768 個,約 0.78%。

作者在 M5 32GB 的實測(mlx-lm 0.32 預設設定:rank 8、只在最後 16 層加 LoRA;Gemma 4 E2B 4-bit):可訓練參數 6,815,744(約 6.8M),總參數 4,628M,約 0.147%。可以看到「只訓練很小一部分」是真的。Gemma 4 E2B 後段的層共用前面層的 KV,這些層沒有 k_proj / v_proj,所以也沒有對應的 LoRA;逐項明細見下方計算器。Colab notebook 用的是 Unsloth 的 r = 16,並同時套在注意力與 MLP 模組上,設定與 Mac 不同,數字不能直接相比;用 model.print_trainable_parameters() 會印出實際數字【實測數據待補】。

為什麼這樣有效?直覺上,微調要學的是「在原本能力上做小幅調整」,這種調整往往可以用低秩(資訊量很少)的方式表達。LoRA 的原始論文就是這個假設。

類比:

  • pre-training(預訓練) 像醫學院:讀海量資料、打下通識。
  • SFT(supervised fine-tuning,監督式微調) 像住院醫師訓練:用標好答案的例子教它做某類特定工作。
  • LoRA 是做 SFT 的一種省資源方式,像在既有訓練上加修一個次專科,不必重讀醫學院。

這是教學用的比喻,不是嚴格對應,例如 LoRA 之後可以拆掉 adapter 回到原本的模型,現實中的訓練就沒辦法這麼乾脆。

QLoRA:底座壓縮成 4-bit

QLoRA 是在 LoRA 的基礎上,把凍結的底座模型先量化(quantize)成 4-bit,再接上 LoRA adapter。底座不需要被更新,壓縮之後對記憶體的負擔大幅降低。Unsloth 官方文件說明 QLoRA 可省下約 75% 的記憶體(截至 2026-10,出處見 Unsloth fine-tuning guide)。

作者在 Mac 上用 gemma-4-E2B-it-MLX-4bit 做的就是 QLoRA(4-bit 底座 + LoRA)。

但要記得兩件事:

  1. 量化會損失一點精度。對多數任務影響不大,但有些模型不建議這麼做。例如 Unsloth 文件指出 Qwen3.5 不建議 QLoRA,建議用 16-bit 的 LoRA(截至 2026-10)。選模型前先查最新建議。
  2. Colab 免費版的 T4 沒有 bf16(一種常用的 16-bit 格式),只能用 fp16。本站 notebook 預設 load_in_4bit = False,若遇到 CUDA out of memory 再改成 True。

超參數:旋鈕有哪些

參數意義類比
rank (r)adapter 的容量次專科訓練的深度
alphaLoRA 輸出的縮放係數,常設為與 rank 相同或 2 倍這份次專科訓練影響日常判斷的權重
learning rate每次調整的步伐修正診斷偏差時的力道
epoch完整讀過一遍訓練資料的次數同一份病例集複習幾輪
batch size一次看幾筆再調整一次討論幾個病人再更新作法
gradient accumulation累積幾個小 batch 才更新記憶體不夠時,分幾次看再一起結算

文獻中的設定可作參考,但不要照抄:

  • 澳洲皮膚病理報告研究用 rank 8、alpha 16、3 epochs、4-bit(PLOS Digit Health,PMID 42424371)。
  • 法國 Bordeaux 急診病歷去識別化研究用 rank 32、alpha 64(JMIR AI,PMID 40605780)。

兩者任務、模型大小、資料量都不同,數字只是「別人這樣設過」。Unsloth 對初學者的建議是 1–3 個 epoch,並留約 20% 的資料做測試。若訓練 loss 一路逼近 0,通常是死背的訊號(下一關會看到曲線)。

互動道具:LoRA Rank 計算器

下面這個計算器可以輸入 hidden size、層數、要套用 LoRA 的模組與 rank,看可訓練參數量與占整體的比例。試試看:rank 從 8 調到 64,可訓練參數量如何變化?

LoRA 不改動原模型,只在選定的矩陣旁訓練兩個小矩陣 A(r × 輸入維度)與 B(輸出維度 × r)。 每個被套用的矩陣新增 r × (d_in + d_out) 個參數。

LoRA 可訓練參數
可訓練參數
1.57 M
佔全模型
0.034%
Adapter 檔案(fp16)
3.1 MB

實測對照

作者在 M5 32GB 的實測(mlx-lm 0.32 預設:rank 8、只訓練最後 16 層,Gemma 4 E2B 4-bit):可訓練 6.8M / 4,628M = 0.147%。 上面的快速估算假設每個矩陣都是 hidden × hidden 的方陣,只適合抓數量級。下表是從實際存下的 adapter 檔讀出的真實矩陣尺寸,用 rank 8 逐項相加:

矩陣輸入 → 輸出個數參數
q_proj(局部注意力層)1536 → 204812344,064
q_proj(全域注意力層)1536 → 40964180,224
o_proj(局部注意力層)2048 → 153612344,064
o_proj(全域注意力層)4096 → 15364180,224
gate_proj1536 → 12288161,769,472
up_proj1536 → 12288161,769,472
down_proj12288 → 1536161,769,472
per_layer_input_gate1536 → 25616229,376
per_layer_projection256 → 153616229,376
合計6,815,744

rank 8 時合計 6,815,744,與訓練紀錄完全一致。沒有 k_proj / v_proj,是因為 Gemma 4 E2B 後段的層共用前面層的 KV;MLP 寬度 12,288 也是這些層特有的設計。換別的模型時,維度請看該模型的 config.json。

🍎 Mac 與 ☁️ Colab 實作

🍎 Mac:用計算器試算 Gemma 4 E2B 在你的 Mac 上要用什麼設定。作者在 32GB 上實測 batch 4、max seq 2048、開 gradient checkpointing,peak memory footprint 為 14.8GB。16GB Mac 的建議降配見下一關(標示【待實測】)。

☁️ Colab:在 notebook 的 get_peft_model 之後加一行 model.print_trainable_parameters(),把印出來的數字與計算器的估計值對照。數字有差距是正常的,因為 Gemma 4 的結構與計算器的簡化假設不完全相同。

本關重點

  • LoRA 凍結原權重,只訓練旁邊兩個低秩小矩陣 A、B,可訓練參數量為 r × (d + k),通常只占整體不到 1%。作者實測 Gemma 4 E2B 為 0.147%。
  • QLoRA = 4-bit 量化的底座 + LoRA;省記憶體,代價是些許量化誤差,部分模型(如 Qwen3.5)官方不建議。
  • pre-training、SFT、LoRA 的醫學教育類比有助記憶,但只是比喻。
  • rank、learning rate、epoch 都有「過猶不及」;文獻設定只供參考,要用 valid 集自己驗證。

BOSS 戰:全參數巨人

HP0/4
  1. 一個 2048 × 2048 的權重矩陣,若用 rank 8 的 LoRA,可訓練參數量大約是多少?

  2. 「QLoRA」和「LoRA」最主要的差別是什麼?

  3. 以「醫學教育」作類比,pre-training、SFT、LoRA 各最接近什麼?

  4. 下列哪一項對 LoRA 超參數的敘述較恰當?