PEFT LoRA 微調 LLM 實作指南
這篇教你用 PEFT 和 LoRA 只訓練小型 adapter,完成 LLM 微調、保存與部署。

這篇教你用 PEFT 和 LoRA 只訓練小型 adapter,完成 LLM 微調、保存與部署。
這篇給想在不重訓整個 LLM 的前提下,快速做領域微調的開發者。照著做完,你會得到一個可訓練的 LoRA adapter、可重複使用的訓練流程,以及一份能確認只有少量參數在更新的檢查結果。
你也會知道 PEFT 為什麼適合 production,adapter 和 full fine-tuning 的差別是什麼,還能把訓練出的 adapter 掛回同一個 base model 做推論。
開始之前
訂閱 AI 趨勢週報
每週精選模型發布、工具應用與深度分析,直送信箱。不定期,不騷擾。
不會寄垃圾信,隨時可取消。
- Python 3.10+
- PyTorch 2.1+
- Hugging Face Transformers
- Hugging Face PEFT
- CUDA GPU,至少 16 GB VRAM,適合跑小型 LoRA 範例
- Hugging Face 帳號與 access token,用於下載 gated model
- 一個 pretrained causal LLM,例如 Llama、Mistral 或較小的開源模型
- Git 與終端機,環境可在 macOS、Linux 或 Windows Subsystem for Linux
Step 1: 選定基礎模型
這一步的產出是「凍結的 base model」。PEFT 的核心是保留既有語言能力,只對任務相關行為做小幅調整,所以你要先選一個已經懂語言的 pretrained model。

先用較小的開源模型驗證流程,再往更大的模型擴充。這樣你可以先確認資料載入、訓練與儲存都正常,再處理更高的顯存需求。
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id = "mistralai/Mistral-7B-v0.1"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto")
for param in model.parameters():
param.requires_grad = False你應該看到模型成功載入,而且所有原始權重都被標記為 frozen。若你印出幾個參數,requires_grad 應該是 False。
Step 2: 掛上 LoRA adapter
這一步的產出是「可訓練的 LoRA 模組」。LoRA 會在指定投影層加入低秩矩陣,讓模型只更新很小一部分參數,就能學到新任務行為。

初學時先鎖定 attention projection,例如 q_proj 和 v_proj。這樣 adapter 夠小,訓練成本也低,通常已經能看到明顯效果。
from peft import LoraConfig, get_peft_model
config = LoraConfig(
r=16,
lora_alpha=32,
lora_dropout=0.05,
target_modules=["q_proj", "v_proj"],
task_type="CAUSAL_LM",
)
model = get_peft_model(model, config)
model.print_trainable_parameters()你應該看到 trainable parameter 的報告,而且可訓練比例遠低於整個模型。健康的 LoRA 設定通常只會更新不到 1% 的參數。
Step 3: 整理任務資料
這一步的產出是「一致格式的訓練資料集」。PEFT 不能取代資料品質,它只是把需要更新的參數變少,所以資料仍然要能清楚對應你要的行為。
把資料寫成固定模板,例如 prompt 和 ideal response。若你要做客服助理,就放客服問題與標準回覆;若你要做程式助手,就放指令與修正版輸出。
格式要穩定,因為模型會從重複模式中學習。如果每幾筆資料的提示詞結構都不同,adapter 會更難收斂,評估也會變得模糊。
你應該看到每筆樣本都能直接看出任務目標,而且輸入與輸出邊界清楚。只要人類一眼能判斷這筆資料在教什麼,資料集就算合格。
Step 4: 執行 adapter 訓練
這一步的產出是「只更新 LoRA 權重的訓練結果」。PEFT 的主要價值就在這裡:顯存壓力更低、可訓練參數更少、checkpoint 也更小。
你可以用 Transformers 的 Trainer,或自己寫訓練迴圈。重點不是訓練框架,而是確認 base model 沒有被解凍,只有 adapter 在接收梯度。
from transformers import Trainer, TrainingArguments
args = TrainingArguments(
output_dir="./peft-output",
per_device_train_batch_size=2,
num_train_epochs=3,
learning_rate=2e-4,
fp16=True,
)
trainer = Trainer(
model=model,
args=args,
train_dataset=train_dataset,
)
trainer.train()你應該看到 loss 逐步下降,而且 GPU 記憶體用量明顯低於 full fine-tuning。如果記憶體還是像整模型更新一樣暴增,先回頭檢查 base model 是否真的 frozen。
Step 5: 匯出並重載 adapter
這一步的產出是「可攜式 adapter 檔案」。這也是 PEFT 很適合 production 的原因之一,因為你通常只要保存小型 adapter,不必重新分發整個 base checkpoint。
把 adapter 單獨存起來,之後在推論時再掛回同一個 base model。這樣你就能維持一份共同的基礎模型,同時切換多個不同任務的專用版本。
model.save_pretrained("./customer-support-lora")
tokenizer.save_pretrained("./customer-support-lora")
# Later
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto")
adapted_model = PeftModel.from_pretrained(base_model, "./customer-support-lora")你應該看到 adapter 很快載入,推論結果也開始帶有任務特徵。如果輸出還是很泛用,通常是 adapter 和 base model 版本不一致。
Step 6: 比較 PEFT 方法
這一步的產出是「方法選擇判斷」。LoRA 很常是第一選擇,但 adapter、prompt tuning、prefix tuning 和 IA³ 都是在不同限制下解同一類問題。
如果你要一個品質與部署平衡都不錯的預設方案,先選 LoRA。若你想把更新量再壓低,可以考慮 prompt tuning 或 prefix tuning;若你偏好模組化架構,adapter 會更直觀。
你現在應該能解釋 PEFT 為什麼有效:多數任務只需要調整模型行為,不需要重寫整個模型。這就是它能在有限算力下完成 LLM 微調的原因。
| 指標 | 基準/優化前 | 結果/優化後 |
|---|---|---|
| 可訓練參數 | 7B 全量微調 | 約 5M 到 20M,LoRA 套在 7B 模型 |
| 可訓練參數 | 13B 全量微調 | 約 10M 到 40M,LoRA 套在 13B 模型 |
| 可訓練參數 | 70B 全量微調 | 約 50M 到 200M,LoRA 套在 70B 模型 |
| Adapter 大小 | 完整模型 checkpoint | 常見 production 情境下約 50 MB 到 200 MB |
常見錯誤
- 忘記凍結 base model。修法:在訓練前檢查 pretrained weights 的
requires_grad=False。 - 選錯 target modules。修法:先看模型結構,確認 attention projection 的實際名稱,再套用 LoRA。
- base 與 adapter 版本不一致。修法:adapter 一律掛回訓練時使用的同一個 base model family 與 revision。
接下來可以看什麼
如果你已經能順利跑 LoRA,下一步可以看 adapter merging、QLoRA 的量化微調,以及把 adapter-only 模型和 full fine-tuning 在同一組任務上做評估比較。