1.3 参数高效微调
掌握 LoRA 和 QLoRA 的原理与实践,理解参数高效微调的必要性和显存优化策略
为什么需要参数高效微调
全参数微调的显存瓶颈
以 Qwen3-8B 为例,全参数微调(Full Fine-Tuning)的显存需求远超单张 GPU 容量:
| 组件 | 计算方式 | 显存需求 |
|---|---|---|
| 模型参数(FP16) | 8B × 2 bytes | ~16 GB |
| 梯度(FP16) | 8B × 2 bytes | ~16 GB |
| 优化器状态(AdamW, FP32) | 8B × 8 bytes(动量 + 方差) | ~64 GB |
| 激活值(估计) | 取决于 batch size 和 seq len | ~4–16 GB |
| 总计 | ~100–112 GB |
单张 A100-80G 无法完成 8B 模型的全参数微调!即便是 A100-80G 也仅有 80GB 显存,而全参数微调需要约 100GB。这使得全参数微调对于大多数研究者来说是不切实际的。
显存构成分析
训练时的显存主要由四部分构成:
其中 优化器状态 是最大的开销——AdamW 需要为每个参数维护一阶动量(momentum)和二阶动量(variance),各占 FP32(4 bytes),共 8 bytes/参数。
参数高效微调(Parameter-Efficient Fine-Tuning, PEFT) 的核心思路:冻结大部分原始参数,仅训练少量新增参数,从而大幅降低梯度和优化器状态的显存需求。
LoRA:低秩适配
核心思想
LoRA(Low-Rank Adaptation,Hu 等,2021)基于一个关键假设:预训练模型在微调时的权重更新具有低秩结构。
对于预训练权重矩阵 ,LoRA 不直接更新 ,而是将权重更新分解为两个低秩矩阵的乘积:
其中:
- ,
- 是秩(rank),通常取 16–64
- 被冻结,不参与梯度计算
- 仅 和 参与训练
前向传播
LoRA 修改后的前向传播:
其中 是缩放因子(scaling factor), 控制了 LoRA 更新的幅度。
输入 x ─────┬──────── W₀x ──────────┬──── 输出 h
│ │
└── A ──→ B ──→ (α/r)BAx ┘
r×k d×r
(可训练) (可训练)参数效率
以 Qwen3-8B 中一个典型的线性层()为例:
| 方法 | 训练参数量 | 相对占比 |
|---|---|---|
| 全参数微调 | 100% | |
| LoRA(r=16) | 0.78% | |
| LoRA(r=64) | 3.13% |
关键超参数
秩 r 决定了 LoRA 的表达能力:
- r 太小(如 4-8):模型表达能力受限,可能欠拟合
- r 太大(如 128-256):接近全参数微调,失去效率优势
- 推荐范围:16-64,通常 r=32 是一个好的起点
经验法则:
- 简单任务(风格调整):r=8-16
- 中等任务(指令跟随):r=32
- 复杂任务(领域适配):r=64
alpha (α) 与 rank 共同决定 LoRA 更新的缩放:
常见设置:
alpha = 2 * r:缩放因子为 2,更新幅度较大(Qwen3 推荐)alpha = r:缩放因子为 1,更新幅度适中alpha = r / 2:缩放因子为 0.5,更新幅度较小
实践建议:先固定 alpha = 2 * rank,通过调整学习率来控制训练强度。
LoRA 可以应用于 Transformer 中的不同线性层:
| 层 | 说明 | 优先级 |
|---|---|---|
q_proj | Query 投影 | 高 |
k_proj | Key 投影 | 高 |
v_proj | Value 投影 | 高 |
o_proj | Output 投影 | 高 |
gate_proj | FFN 门控层 | 中 |
up_proj | FFN 上投影 | 中 |
down_proj | FFN 下投影 | 中 |
推荐:应用到所有线性层(all linear layers),即同时覆盖注意力层和 FFN 层。Qwen3 的实验表明,覆盖所有线性层的效果最好。
from peft import LoraConfig
lora_config = LoraConfig(
r=32,
lora_alpha=64,
target_modules=[
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"
],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)初始化策略
LoRA 的初始化确保训练开始时不改变原始模型行为:
- 矩阵 A:使用 Kaiming 均匀分布初始化
- 矩阵 B:初始化为全零
这保证了 ,即训练开始时 。
QLoRA:量化低秩适配
核心思想
QLoRA(Dettmers 等,2023)在 LoRA 基础上增加了 4-bit NormalFloat(NF4)量化,将基座模型的权重从 FP16(16 bit)量化到 4 bit,进一步将显存需求减半。
NF4 量化原理
NormalFloat 量化基于一个关键观察:预训练模型的权重近似服从正态分布。NF4 将正态分布的分位数作为量化级别,使得量化误差在信息论意义上最优。
QLoRA 还引入了双重量化(Double Quantization):对量化常数本身再做一次量化,额外节省约 0.4 bit/参数。
QLoRA 训练流程
冻结 (4-bit NF4) 可训练 (FP16/BF16)
┌──────────┐ ┌──────────────┐
输入 x ────────→│ W₀(NF4) │───────────→│ │
│ ↑反量化↑ │ │ 加法求和 │──→ 输出 h
│ W₀(FP16) │ │ │
└──────────┘ └──────────────┘
↑
┌──────────┐ │
输入 x ────────→│ BA(FP16) │─────── (α/r) ───┘
│ 可训练 │
└──────────┘- 前向传播: 从 NF4 反量化到 FP16 后参与计算
- LoRA 部分(, )始终保持 FP16 精度
- 反向传播仅经过 LoRA 参数, 不计算梯度
BitsAndBytesConfig 配置
from transformers import BitsAndBytesConfig
import torch
bnb_config = BitsAndBytesConfig(
load_in_4bit=True, # 启用 4-bit 加载
bnb_4bit_quant_type="nf4", # 使用 NF4 量化
bnb_4bit_compute_dtype=torch.bfloat16, # 计算时使用 BF16
bnb_4bit_use_double_quant=True, # 启用双重量化
)显存对比
以 Qwen3-8B 模型为例,不同微调方法的显存对比:
| 方法 | 模型加载 | 可训练参数 | 优化器状态 | 总显存 | GPU 需求 |
|---|---|---|---|---|---|
| 全参数微调(FP16) | 16 GB | 8B (16 GB) | ~64 GB | ~100 GB | 2× A100-80G |
| LoRA(FP16, r=32) | 16 GB | ~40M (80 MB) | ~320 MB | ~20 GB | 1× A100-40G |
| QLoRA(NF4, r=32) | 5 GB | ~40M (80 MB) | ~320 MB | ~10 GB | 1× RTX 4090 |
显存经验法则(7B-8B 模型):
- 全参数微调:~100 GB(需多卡)
- LoRA(FP16):~20 GB(A100-40G 或 RTX 4090)
- QLoRA(NF4):~10 GB(T4 16GB 勉强可用)
QLoRA 使大模型微调真正走向了消费级 GPU!
近期进展简介
DoRA:权重分解 LoRA
DoRA(Weight-Decomposed Low-Rank Adaptation,2024)将权重矩阵分解为幅度(magnitude)和方向(direction)两个分量,LoRA 仅作用于方向分量:
其中 是可学习的幅度向量。DoRA 在多项基准上略优于标准 LoRA,但增加的计算开销很小。
Spectrum:基于信噪比的层选择
Spectrum(2024)提出了一种更智能的层选择策略:
- 计算每一层的信噪比(Signal-to-Noise Ratio)
- 只对信噪比高的层应用 LoRA,跳过信噪比低的层
- 效果:在相同参数预算下,Spectrum 优于对所有层统一应用 LoRA
这种方法的直觉是:不同层在微调中的贡献是不均等的,集中资源到"关键层"可以获得更好的效果。
实践建议总结
| 决策 | 推荐选择 | 说明 |
|---|---|---|
| 全参数 vs. PEFT | PEFT(LoRA/QLoRA) | 除非资源充裕且数据极多 |
| LoRA vs. QLoRA | QLoRA(显存有限时) | A100-40G 上 LoRA 亦可 |
| 秩 r | 32 | 通用起点,可按需调整 |
| Alpha | 2 × r | 如 r=32 则 alpha=64 |
| 目标层 | 所有线性层 | q/k/v/o_proj + gate/up/down_proj |
| Dropout | 0.05 | 防止过拟合 |
| 计算精度 | BF16 | 比 FP16 更稳定,A100 原生支持 |
本节小结
| 概念 | 要点 |
|---|---|
| 全参数微调瓶颈 | 8B 模型需 ~100GB 显存,单卡无法完成 |
| LoRA | 冻结 ,训练低秩 ,仅 ~0.2-1% 参数 |
| LoRA 公式 | |
| QLoRA | LoRA + NF4 4-bit 量化,显存再减半 |
| 显存对比 | 全参 ~100GB → LoRA ~20GB → QLoRA ~10GB |
| DoRA | 权重分解,幅度+方向,略优于 LoRA |
| Spectrum | 信噪比层选择,集中资源到关键层 |