← LLMOps
LLMOps

LoRA 這件事你只需要搞清楚一次

2026-05-20 · — views

Fine-tuning 一個 7B 的模型,Full Fine-tune 需要大約 84GB VRAM。這個數字意味著,大多數人根本跑不起來。

LoRA 解決的就是這個問題——但理解它的方式不只是「記憶體比較省」,而是搞清楚它背後的假設是什麼、哪些決策是真正重要的、什麼情況下它根本不是正確選項。

讀完這篇,你會理解:

  • LoRA、Full FT、RAG 三者在解決什麼不同的問題
  • LoRA 在做什麼,以及 r 和 alpha 這兩個參數的物理意義
  • 為什麼 target_modules 通常選 Q 和 V,而不是 K 和 O
  • QLoRA 是什麼,以及什麼時候該用 LoRA、什麼時候不該

這篇是地圖,不是教學。


Full Fine-tune 為什麼跑不起來,LoRA 解決了什麼問題

Full Fine-tune 的問題很單純:它要更新模型的所有參數,這代表你需要儲存每個參數的梯度和 optimizer state,記憶體需求大約是模型本身的 3-4 倍。一個 7B 模型在 BF16 精度下大約 14GB,Full FT 就需要 ~84GB VRAM。

方法7B 模型所需 VRAM
Full Fine-tune(BF16)~84 GB
LoRA(BF16)~28 GB
QLoRA(4-bit + LoRA)~10-12 GB

LoRA 的切入點是一個觀察:fine-tuning 的過程中,weight 的更新方向其實是低維的。你不需要在全部的參數空間上移動,大多數任務只需要在一個遠比原始維度小的子空間裡調整就夠了。這個觀察有論文實驗作為支撐(Aghajanyan et al. 2020, Hu et al. 2021),而且即使 rank 只有 4 或 8,LoRA 在大多數任務上的效果都接近 Full FT。


LoRA、Full FT、RAG:先把定位搞清楚

在進入參數細節之前,值得先把這三個工具的定位說清楚,否則很容易用錯。

三者解決的是不同層次的問題:

Full Fine-tune 更新所有參數,適合任務和 base model 的差距非常大、或需要根本性改變模型行為的情況。需要最多資源,但彈性也最高。

LoRA 只訓練一個小的「差值矩陣」,凍結原始 weight。適合調整模型的行為、風格、輸出格式,前提是 base model 已經有基礎能力,只是需要引導。

RAG 完全不訓練,而是在 inference 時把外部知識注入 context。適合需要即時資訊、特定文件內容、或頻繁更新的知識。

這三者的核心區別在一個維度上:你要解決的是知識問題還是行為問題

模型不知道某件事(例如你公司內部的 FAQ、最新的新聞),這是知識問題,RAG 是正確選項。模型知道,但表現方式不對(輸出格式不穩定、語氣跑掉、在特定任務上判斷不一致),這是行為問題,LoRA 才有用。

用 LoRA fine-tune 之後,模型不會「學到」新的 factual knowledge。這是 LoRA 最常被誤解的地方。


LoRA 在做什麼:低秩更新的機制與初始化設計

LoRA 不更新原始的 weight 矩陣 W,而是在旁邊加一個旁路:訓練兩個小矩陣 B 和 A,讓 B×A 近似那個「如果 Full FT 的話,W 會移動多少」的差值。

原始:h = W · x
加上 LoRA 之後:h = W · x + (α/r) · B · A · x

W 在訓練過程中完全凍結,只有 B 和 A 在更新。兩個矩陣的維度設計讓參數量大幅縮小:

原始 W:4096 × 4096 = 16,777,216 個參數
LoRA A:r × 4096
LoRA B:4096 × r
當 r=8:A + B = 65,536 個參數(節省 99.6%)

初始化設計有一個細節值得注意:B 初始化為全零。這讓訓練開始時 B×A = 0,也就是說 LoRA 旁路一開始對輸出沒有任何影響,模型從 base model 的能力出發,穩定地學習差值。A 則用隨機值初始化,給整個系統一個出發點。


r 和 alpha:兩個參數的物理意義

LoRA 有兩個主要超參數,理解它們的物理意義遠比記住建議值更重要。

r(rank):adapter 的容量

r 控制 B 和 A 的「寬度」,也就是這個差值矩陣能表達多複雜的更新。r 越大,capacity 越高,能學到的 weight update 越豐富;r 越小,強迫模型用更低維的表示去近似那個差值。

r適合場景
4–8輕量任務:輸出格式調整、語氣固化
16大多數 NLP 任務的起點
32–64複雜任務,或任務和 base model 差距較大

不是越大越好。r 過大,訓練更慢、容易 overfit,同時失去低秩的效率優勢。大多數情況下,r=16 是夠用的起點。

alpha(α):更新的音量控制

真正影響 LoRA 輸出強度的是 α/r 這個比值,不是 alpha 本身。可以把它想成 LoRA 更新相對於原始 W 的「音量」:

  • α/r = 1(例如 alpha=r=16):LoRA 和原始 weight 同等比例更新
  • α/r = 2(例如 alpha=32, r=16):LoRA 更新放大 2 倍,學習更激進

常見的起點是 alpha = 2r,讓 LoRA 的更新稍微強一點。如果發現模型學太快、容易 overfit,可以降回 alpha = r。


為什麼 target_modules 偏偏選 Q 和 V,而不是 K 和 O

設定 LoRA 的時候,target_modules 決定了哪些 weight 要被替換成 LoRA 旁路。標準建議是從 ["q_proj", "v_proj"] 開始,但這背後有具體的理由。

Attention 有四個投影矩陣(Q、K、V、O),它們在計算流程裡做的事情完全不同:

輸入 x
q_proj
Query
注意哪裡?
k_proj
Key
被查詢的索引
v_proj
Value
帶走什麼?
o_proj
Output
多頭整合
LoRA 重點
LoRA 重點
Q × Kᵀ → Softmax → 注意力分數
注意力分數 × V → Context 向量
多頭 Context 拼接 → o_proj → 輸出
■ LoRA 核心目標 ■ 通常不加或效益低

Q 決定「注意力的方向」

q_proj 把輸入 x 變成 Query,本質上是在問:「這個 token 應該去關注序列裡的哪些位置?」注意力模式(什麼詞關注什麼詞)是任務之間差異最大的地方。翻譯任務、摘要任務、程式碼補全,它們關注序列的方式根本不同。修改 Q 就是在直接調整模型的「注意力策略」,對下游任務的影響最直接。

V 決定「輸出帶什麼內容」

v_proj 把輸入 x 變成 Value,是 Attention 加權求和後真正「被搬走」的資訊。注意力分數只決定搬多少、從哪裡搬,但搬的東西是什麼、以什麼表示空間呈現,完全由 V 決定。不同任務需要不同的資訊表示方式,修改 V 是在調整「每個位置能提供的資訊內容」。

那 K 和 O 呢?

k_proj 產生 Key,是「被查詢的索引」,和 Q 是一對。但實驗上發現,只要 Q 改了,模型就能重新學習匹配關係,K 不一定需要同步修改。兩個都改當然更充分,但如果要節省參數,K 的邊際貢獻比 V 低得多。

o_proj 是把多個 attention head 的輸出拼接後做線性整合,更像是「後處理匯流排」,對特定任務的適應性貢獻相對有限。

用一句話總結:Q 改變模型「看哪裡」,V 改變模型「帶走什麼」,這兩件事是任務適應的核心,K 和 O 更像配合者而非主導者。原始 LoRA 論文(Hu et al. 2021)的消融實驗也確認了這點:只注入 Q+V 和注入全部四個的效果差距很小,但參數量少了一半。


QLoRA 是什麼:在 LoRA 之上再壓一層記憶體

LoRA 把 VRAM 需求從 ~84GB 降到 ~28GB,但在消費級 GPU(如 RTX 4090 的 24GB)上跑 7B 模型還是吃緊。QLoRA 解決的是這個問題。

QLoRA 的做法是在 LoRA 的基礎上,把 base model 以 **4-bit NF4(Normally distributed Float 4)**量化並完全凍結,然後在這個 4-bit frozen base 上附加 BF16 精度的 LoRA adapter。計算時,base model 的 weight 動態 dequantize 回 BF16 進行乘法,adapter 的梯度照常回傳。

效果:7B 模型所需 VRAM 從 ~28GB 降到 ~10-12GB,一張 RTX 4090 可以跑 QLoRA 13B 模型。

代價:量化和 dequantize 有少量計算開銷,訓練速度比純 LoRA 慢一點。


場景判斷:什麼時候用 LoRA,什麼時候不用

面對一個新需求,建議的判斷順序是:

先試 Prompt Engineering(零成本)
    │ 能解決 → 停在這裡
    │ 不能解決 ↓
需要即時 / 外部知識?
    │ 是 → RAG
    │ 否 ↓
問題是行為 / 格式 / 風格,不是知識?
    │ 否 → 更好的 RAG 或更強的 base model
    │ 是 → 考慮 LoRA
        │ VRAM < 16GB → QLoRA
        │ 需要部署多個任務 → 多個 adapter,共用 base model
        │ 確定部署一個任務 → 訓練完 merge_and_unload()

LoRA 適合的場景

  • 穩定的輸出格式(永遠輸出 JSON、特定結構)
  • 品牌語氣、客服口吻的固化
  • 領域術語和表達方式的習慣
  • 用小模型複製大模型對特定任務的能力(成本優化)

LoRA 不適合的場景

  • 需要注入最新資訊或外部知識 → RAG
  • 訓練資料少於 50 筆 → 先去收集資料
  • 任務需求頻繁改變 → Prompt Engineering
  • 需要根本性改變模型推理能力 → 換 base model

LoRA 的天花板:它能調整行為、格式、風格,但不能讓模型「學到」它在 pre-training 階段沒見過的 knowledge。把 LoRA 用在知識問題上是最常見的誤用。