LoRA 与参数高效微调

全量微调的问题

最直接的微调方式是全量微调(Full Fine-tuning)——更新模型的所有参数。

但这有一个大问题:一个 7B 参数的模型,全量微调需要大约 60GB 显存(FP16)。这远超大多数消费级 GPU 的容量。70B 的模型?你可能需要一个 GPU 集群。

有没有办法用更少的资源达到接近的效果?

LoRA:低秩适配

LoRA(Low-Rank Adaptation)是目前最流行的参数高效微调方法。它的核心思想非常优雅:

不修改原始模型的权重,而是在旁边加一小组可训练的参数。

直觉理解

想象模型的权重矩阵 W 是一个巨大的矩阵(比如 4096×4096)。全量微调要更新整个矩阵的 1600 万个参数。

LoRA 的做法:把更新分解为两个小矩阵的乘积。

原始矩阵 W: 4096 × 4096 (16M 参数)

LoRA 更新 ΔW = A × B
  A: 4096 × 16  (65K 参数)
  B: 16 × 4096  (65K 参数)
  总共: 130K 参数 ← 只有原来的 0.8%!

这里的 16 就是秩(rank)——LoRA 的关键超参数。秩越大,可训练参数越多,表达能力越强,但训练成本也越高。

为什么这能工作

研究发现,微调时权重的实际变化具有低秩特性——也就是说,虽然模型有数十亿参数,但微调时真正需要改变的"有效自由度"远小于参数总量。LoRA 正是利用了这一特性。

QLoRA:更进一步

QLoRA 结合了量化和 LoRA,进一步降低内存需求:

  1. 把基础模型量化到 4bit(大幅减少内存)
  2. 在量化模型上应用 LoRA
  3. 训练时只更新 LoRA 参数(用 FP16 精度)
全量微调 7B 模型: ~60 GB 显存
LoRA 微调 7B 模型: ~16 GB 显存
QLoRA 微调 7B 模型: ~6 GB 显存  ← 一块 RTX 4060 就行!

QLoRA 让你在消费级硬件上微调 7B 甚至 13B 的模型成为可能。

三种方式的对比

全量微调LoRAQLoRA
可训练参数100%0.1-1%0.1-1%
7B 模型显存~60 GB~16 GB~6 GB
训练速度最慢
效果最好(理论上)接近全量略低于 LoRA
硬件要求多 GPU单 GPU (16GB+)单 GPU (8GB+)
推荐场景资源充足、追求极致大多数场景资源有限

对于大多数开发者,QLoRA 是最实用的选择。

LoRA 的关键超参数

Rank (r)

秩,决定了 LoRA 的"容量"。

Rank可训练参数适用
8最少简单任务(风格调整)
16适中大多数任务
32较多复杂任务
64+很多接近全量微调

推荐从 16 开始。 效果不好再提高。

Alpha (α)

缩放因子,控制 LoRA 更新的强度。通常设为 rank 的 2 倍(即 alpha = 2 × rank)。

实际更新 = ΔW × (alpha / rank)

alpha/rank = 2 意味着 LoRA 的更新会被放大 2 倍。

Target Modules

LoRA 应用到哪些模块。Transformer 中有多种权重矩阵:

target_modules = [
    "q_proj",  # Query 投影
    "k_proj",  # Key 投影
    "v_proj",  # Value 投影
    "o_proj",  # Output 投影
    "gate_proj",  # FFN 门控
    "up_proj",    # FFN 上投影
    "down_proj",  # FFN 下投影
]

推荐:至少包含 q_proj 和 v_proj。 对效果有显著影响的是注意力层的投影矩阵。如果资源允许,可以加上所有线性层。

Dropout

防止过拟合的正则化手段。通常设为 0.05-0.1。数据量少时可以适当提高。

一个完整的 LoRA 配置

from peft import LoraConfig

lora_config = LoraConfig(
    r=16,                    # 秩
    lora_alpha=32,           # 缩放因子
    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 权重的使用

训练完成后,LoRA 会保存为一个很小的文件(通常几十 MB):

base_model/           # 原始模型(几 GB)
lora_adapter/         # LoRA 权重(几十 MB)
  adapter_config.json
  adapter_model.safetensors

使用时有两种方式:

1. 动态加载(推理时叠加)

from peft import PeftModel

model = load_base_model("meta-llama/Llama-3.1-8B")
model = PeftModel.from_pretrained(model, "path/to/lora_adapter")

优势:一个基础模型可以搭配多个 LoRA,按需切换。

2. 合并权重(发布前合并)

merged_model = model.merge_and_unload()
merged_model.save_pretrained("merged_model/")

优势:推理时没有额外开销,可以直接量化为 GGUF 部署。

要点总结

  1. LoRA 是当前最主流的微调方法——用不到 1% 的参数达到接近全量微调的效果。
  2. QLoRA 进一步降低门槛——一块 8GB 显卡就能微调 7B 模型。对大多数开发者最实用。
  3. 关键超参数:rank=16, alpha=32 是好的起点。 目标模块至少包含 q_proj 和 v_proj。
  4. LoRA 权重小(几十 MB)且可热切换——一个基础模型可以搭配不同任务的 LoRA。