Chapter 02

LoRA 与 QLoRA 原理

为什么只训练一小撮参数就能微调好大模型?搞懂低秩分解与 4bit 量化,才能调好 rank、alpha 这些关键超参。

2.1 全参微调 vs PEFT

全参微调更新模型的每一个权重,效果上限最高,但显存与存储代价巨大——每微调一个任务就得存一份完整的 7B/13B 权重。PEFT(参数高效微调)的思路是:冻结原始权重,只训练极少量新增参数,用 1% 甚至更少的可训练参数逼近全参微调的效果。

维度全参微调LoRA (PEFT)QLoRA (PEFT)
可训练参数100%~0.1%-1%~0.1%-1%
原权重精度16bit16bit(冻结)4bit(冻结)
7B 显存需求~80GB~16GB~6-8GB
产物大小全量权重几十 MB adapter几十 MB adapter
效果最高接近全参接近全参

2.2 LoRA:低秩分解

LoRA(Low-Rank Adaptation)的核心观察:微调对权重的改变量 ΔW,虽然是个大矩阵,但它的"内在维度"很低——可以用两个瘦长的小矩阵相乘来近似。

设原权重为 W₀(形状 d×k),LoRA 不直接改它,而是学一个增量:ΔW = B · A,其中 A 形状 r×k、B 形状 d×r,r(秩)远小于 d、k。前向变为:

# 伪代码:LoRA 的前向
h = x @ W0.T                 # 原始权重,冻结不训练
h = h + (x @ A.T @ B.T) * (alpha / r)   # 只训练 A、B

假设 d=k=4096、r=16,全参要训练 4096×4096 ≈ 1678 万参数,LoRA 只需 (4096×16)×2 ≈ 13 万——不到 1%。训练完 A/B 可合并回 W₀,推理时零额外开销。

2.3 QLoRA:4bit 量化 + LoRA

QLoRA 在 LoRA 基础上更进一步:把冻结的原权重量化成 4bit 存储(用 NF4 数据类型),显存再降一大截,而 LoRA 的 A/B 仍用较高精度训练。计算时权重反量化到 bf16 参与运算,梯度只流向 A/B。这是消费级显卡微调 7B/8B 模型的关键技术,Unsloth 对这条路径做了深度内核优化。

什么时候用 QLoRA

显存紧张(< 24GB)→ 用 QLoRA(load_in_4bit=True);显存充裕、追求极致效果 → 用 16bit 的 LoRA。多数个人开发者选 QLoRA。

2.4 关键超参名词解释

rank (r)
低秩矩阵的秩,即 A/B 的"瘦"维度。常用 8/16/32/64。越大表达力越强、越占显存;一般任务 16 起步。
lora_alpha
缩放系数,实际缩放为 alpha / r。经验做法是让 alpha = r 或 2×r。它控制 LoRA 增量对模型的影响强度。
lora_dropout
对 LoRA 分支施加的 dropout 概率,防过拟合。Unsloth 优化路径下推荐设 0(更快且效果好)。
target_modules(目标模块)
指定给哪些线性层加 LoRA。通常是 attention 的 q/k/v/o 投影和 MLP 的 gate/up/down 投影。
NF4(4-bit NormalFloat)
QLoRA 使用的 4bit 量化数据类型,针对正态分布权重做了优化,比普通 int4 精度更高。
bias
是否训练偏置项。LoRA 通常设 "none",不训练 bias 以省参数。
use_rslora
Rank-Stabilized LoRA,用 alpha/√r 缩放,在大 rank 时更稳定,可选开启。
可训练参数占比
可训练参数 / 总参数。LoRA 常见 0.1%-1%,是 PEFT 省显存的直接体现。

2.5 在 Unsloth 里配置 LoRA

Unsloth 通过 get_peft_model 一步注入 LoRA(第 3 章会在完整上下文里再讲):

from unsloth import FastLanguageModel

model = FastLanguageModel.get_peft_model(
    model,
    r = 16,                    # rank
    target_modules = [
        "q_proj", "k_proj", "v_proj", "o_proj",      # attention
        "gate_proj", "up_proj", "down_proj",          # MLP
    ],
    lora_alpha = 16,             # 建议 = r
    lora_dropout = 0,            # Unsloth 下设 0 最优
    bias = "none",
    use_gradient_checkpointing = "unsloth",   # 省显存,长上下文更省
    random_state = 3407,
    use_rslora = False,
)

2.6 如何选 rank 与 target_modules

alpha/r 不是越大越好

把 alpha 调得远大于 r 会放大 LoRA 增量,容易训崩或过拟合。稳妥起点:r=16、alpha=16、dropout=0,先跑通再调。

2.7 小结与下一步