参数高效微调:LoRA、QLoRA 与一笔算得清的显存账

T4-2模块 4 · 微调与对齐面试权重 更新于 2026-08-19
前置T4-1T0-1
关联题目Q4-04Q4-05Q4-06

这篇学完你能回答什么

  1. LoRA 的原理是什么?为什么在原权重旁边挂两个低秩矩阵就能顶替全参微调?
  2. r 和 alpha 到底在控制什么?2026 年这两个值该怎么设,QLoRA 又省在哪一块?
  3. 微调一个 7B 模型,全参、LoRA、QLoRA 各要多少显存?这笔账怎么当场算出来?

从一个真实故障讲起

一个做法律文书助手的团队要给模型灌"本所的行文风格"。他们做了正确的判断——这属于写不出规则、只能给例子的隐性风格,该微调。数据也准备得不错:1800 条精挑的(客户问题,本所标准回复)对。

他们用 peft 起了一轮 LoRA SFT,配置基本抄的社区教程:

LoraConfig(r=16, lora_alpha=32, target_modules=["q_proj", "v_proj"])

训完评测,结果很难看:在自建的风格一致性评分上,微调后的模型 打不过直接在 prompt 里塞 8 个例子的 few-shot 基线。团队试了加大 r 到 64、加大 epoch 到 5、换学习率,曲线抖来抖去,就是过不去基线。

结论写进了周报:"LoRA 在我们这个场景上不行,建议评估全参微调。"

这个结论是错的,而且错得很典型。

问题出在 target_modules=["q_proj", "v_proj"]。这是 2021 年 LoRA 论文里的实验配置,也是很多老教程的默认写法。但截至 2026-08 的共识是:LoRA 必须加在所有线性层上,尤其是 MLP 层。 只加注意力的 Q、V 投影,实测效果差一大截——一个 r=256 的 attention-only LoRA,打不过 r=128 的 MLP LoRA,两者可训参数量还差不多

他们把配置改成 target_modules="all-linear"、学习率从 2e-5 提到 2e-4(后面会讲为什么要提十倍),重跑一轮,直接超过 few-shot 基线一大截。

一个抄来的默认值,差点让团队得出"该上全参微调"的结论,成本差着两个数量级。

抄来的默认值,差点换来两个数量级的账单
r 加到 64、epoch 加到 5、学习率换了个遍,曲线就是过不去基线

  1. 1800 条精挑的样本

    (客户问题,本所标准回复)对

  2. 判断是对的:该微调

    行文风格写不出规则,只能给例子

  3. 配置基本抄社区教程断点

    r=16lora_alpha=32,只挂 Q、V

  4. 打不过 few-shot 基线

    对手只是 prompt 里塞 8 个例子

  5. 周报写「建议评估全参」

    成本差着两个数量级

target_modulesq_projv_projall-linear,必须覆盖 MLP
学习率2e-52e-4,提了十倍
风格一致性评分微调后打不过基线改完超过基线一大截
那份配置的出处2021 年 LoRA 论文的实验配置被老教程抄到了 2026
「LoRA 在我们这个场景上不行」错得很典型。实测里一个 r=256 的 attention-only LoRA,打不过 r=128 的 MLP LoRA,两者可训参数量还差不多 —— 效果不好时先查挂在哪,别先加 r

核心概念:先打比方,再给定义

想象基座模型的每个权重矩阵 W 是一张已经画满的巨幅设计图。全参微调(full fine-tuning)是在原图上直接改线——改哪都行,但你得把整张图连同所有修改痕迹、所有撤销记录都带在手上,代价极大。

LoRA(Low-Rank Adaptation,低秩适配)的做法是:原图锁死不动,在上面盖一张透明描图纸,你所有的改动只画在描图纸上。最终效果 = 原图 + 描图纸。

关键在于这张描图纸是"压缩"的:它不是一张同样大的纸,而是两个细长条的乘积。一个 4096×4096 的矩阵,用两个 4096×64 和 64×4096 的矩阵相乘来近似——参数量从 1600 万降到 52 万,压掉了 97%。

为什么这么粗暴的压缩还能用?因为有一个经验事实:微调带来的权重变化本身就是低"内在秩"的(intrinsic rank)——你在教模型一种行文风格,这件事需要的信息量,本来就远小于整个权重矩阵的容量。描图纸只要装得下你要改的那点东西就够了。

QLoRA(Quantized LoRA)再往前一步:既然原图锁死了不再改,那原图就没必要用高精度存。把它压成 4 bit 存着,只在计算时临时还原。描图纸仍然是高精度的。

原图锁死不动,改动全画在描图纸上
为什么在权重旁边挂两个细长条,就能顶替在原图上直接改线

在原图上直接改线

改哪都行,改完就是最终稿

整张图连同所有修改痕迹、撤销记录都得带在手上

对应
全参微调 · full fine-tuning

每个参数都要带三件套

权重、梯度、优化器状态,一个都躲不掉 —— 代价直接写在显存账上

梯度优化器状态fp32 主权重
盖一张透明描图纸

原图锁死,最终效果 = 原图 + 描图纸

这张纸还是压缩的:不是同样大的一张,而是两个细长条的乘积

对应
LoRA · 低秩适配

基座冻结,旁边挂 A、B 两个低秩矩阵

4096×4096 用 4096×64 与 64×4096 相乘来近似,1600 万参数降到 52 万,压掉 97%

ralphatarget_modules
QLoRA 是同一张描图纸,配一张压缩过的原图:既然原图锁死了不再改,就用 NF4 存成 4 bit,算的时候临时还原成 BF16,描图纸仍是高精度。省的是原图那一块,赔的是速度和一点精度。

原理拆解

基座冻结之后,那笔账只按可训参数算
B 初始化为全 0,接上瞬间不扰动模型;显存差别全在梯度和优化器状态跟谁走

x同一份输入进两条路
两条路并行
冻结W₀ · d×k基座权重一步不动
可训练A · r×k → B · d×rA 高斯初始化,B 全 0
旁路先缩放
× α/rr 时让量级保持可比
两路相加
h = W₀x + (α/r)BAx起步 BA=0,等于基座输出
推理时可合并
并回一个普通权重W = W₀+(α/r)BA,零额外延迟
手算一遍:7B、r=64all-linear
方案基座可训参数三件套激活合计
全参 · 12 bytes/param14 GB70 GB2–20 GB约 88 GB
全参 · 16 bytes/param14 GB98 GB2–20 GB约 116 GB
LoRA r=6414 GB · BF16 冻结约 1.9 GB(160M × 12)2–20 GB约 19 GB
QLoRA r=643.5 GB · NF4 冻结约 1.9 GB2–20 GB约 9 GB

12 和 16 只差一份 fp32 主权重副本。经典口径:BF16 权重 2 + BF16 梯度 2 + FP32 主权重 4 + 一阶动量 4 + 二阶动量 4 = 16 bytes/param;现代纯 BF16 口径不留主权重:2 + 2 + 8 = 12

160M 从哪来:hidden 4096、intermediate 11008、32 层,r=64all-linear 每层 = q,k,v,o 2.10M + gate,up 1.93M + down 0.97M ≈ 5.0M,×32 ≈ 160M,占基座 2.3%;r=16 约 40M。

表里唯一会浮动的是激活:它跟 batch × seq_len × hidden × 层数 走,也是「我算出来 20 G,80 G 卡还是 OOM」的头号原因。压它的标准手段只有梯度检查点 —— 前向少存、反向重算,慢 20%–30%。

LoRA 的前向与初始化

原文示意
                    冻结
              ┌──────────────┐
        x ───►│   W₀ (d×k)   │───────────┐
        │     └──────────────┘           ▼
        │                              ( + ) ───► h
        │     ┌────┐    ┌────┐           ▲
        └────►│ A  │───►│ B  │──× α/r ───┘
              │r×k │    │d×r │
              └────┘    └────┘
              可训练      可训练
        A ~ 高斯初始化 ,  B = 全 0

前向公式:

h = W₀·x + (α/r) · B·A·x

三个设计细节,每个都能当面试追问点:

  1. B 初始化为全 0,所以训练刚开始时 BA = 0,h 完全等于基座输出。这保证了接上适配器的瞬间不扰动模型,训练从基座的原始行为平滑出发。如果两个矩阵都随机初始化,第一步就把模型打乱了。
  2. α/r 是一个缩放系数(scaling factor),不是"学习强度"这种玄学。它的作用是:当你改变 r 时,让适配器输出的量级保持可比。所以比较不同 r 的实验时必须固定 α/r,否则你分不清变化来自容量还是来自缩放。
  3. 推理时可以合并W = W₀ + (α/r)·B·A,算完就是一个普通权重矩阵,推理零额外延迟。这是 LoRA 相对 Adapter、Prefix-Tuning 这些前辈的决定性优势——那些方法在推理时会多出实打实的计算层。反过来,不合并也有价值:一个基座可以同时挂多个 LoRA,按请求热切换,做多租户/多任务服务。

参数量怎么算(这是显存账的基础)

对一个 d×k 的权重矩阵,LoRA 新增可训参数 = r × (d + k)

拿一个典型 7B 结构举例(hidden 4096、intermediate 11008、32 层),all-linear 且 r=64:

原文示意
每层:
  q,k,v,o   4×  64×(4096+4096)  = 4 × 524,288   ≈ 2.10 M
  gate,up   2×  64×(4096+11008) = 2 × 966,656   ≈ 1.93 M
  down      1×  64×(11008+4096) =     966,656   ≈ 0.97 M
  ────────────────────────────────────────────────────
  小计                                          ≈ 5.0 M
32 层合计 ≈ 160 M 可训参数 ≈ 基座的 2.3%

记住这个量级:r=64 的 all-linear LoRA 在 7B 上约 160M 可训参数。r=16 就是约 40M。你能当场把这个数算出来,面试官基本可以确认你自己配过。

QLoRA 省在哪

QLoRA 有三个组件,很多人只记得第一个:

  1. NF4(4-bit NormalFloat):一种针对"神经网络权重近似服从正态分布"这个先验设计的 4 bit 数据类型,在该假设下是信息论意义上更优的量化格式(优于普通 int4)。基座权重以 NF4 存储,前向计算时临时反量化到 BF16。
  2. 双重量化(double quantization):量化本身会产生一堆量化常数(scale),这些常数也占显存。QLoRA 把量化常数再量化一次,每个参数再省约 0.4 bit。
  3. 分页优化器(paged optimizers):借助 NVIDIA 统一内存,在梯度检查点造成显存尖峰时把优化器状态临时换出到主机内存,避免尖峰直接 OOM。

三段式评价 QLoRA:

  • 解决什么:把基座的显存占用压到 1/4,让 7B 级别的微调塞进消费级显卡。
  • 代价是什么:(每次前向都要反量化,训练吞吐通常下降三成上下),精度略降
  • 什么时候不该用:显存够的时候。截至 2026-08,QLoRA 的定位是显存不足时的降级选项,不是默认选择——很多人把它当"更先进的 LoRA",这是个误解。

显存三档账

先记一句总纲:三种方案的差别,几乎全在「梯度和优化器状态跟谁走」。

全参微调时,每个参数都要带:权重、梯度、优化器状态。用 Adam 且混合精度训练:

经典口径(含 fp32 主权重副本,ZeRO 论文的算法):
  BF16 权重 2 + BF16 梯度 2 + FP32 主权重 4 + FP32 一阶动量 4 + FP32 二阶动量 4 = 16 bytes/param

现代纯 BF16 口径(不保 fp32 主权重):
  BF16 权重 2 + BF16 梯度 2 + FP32 双动量 8                              = 12 bytes/param

面试就答"12 到 16 之间,取决于优化器实现有没有留 fp32 主权重副本"——能说清这句话本身就是分水岭。

LoRA / QLoRA 时,基座冻结,所以基座只占"权重"那一项,没有梯度也没有优化器状态;那 12~16 bytes 的账只按可训参数算。

7B 模型的完整对照(r=64,all-linear):

基座 可训参数三件套 激活 合计
全参(12B/param) 14 GB 70 GB 2–20 GB 约 88 GB
全参(16B/param) 14 GB 98 GB 2–20 GB 约 116 GB
LoRA r=64 14 GB(BF16 冻结) 约 1.9 GB(160M × 12) 2–20 GB 约 19 GB
QLoRA r=64 3.5 GB(NF4 冻结) 约 1.9 GB 2–20 GB 约 9 GB

那个最容易被漏掉的加项:激活显存。 它跟 batch × seq_len × hidden × 层数 走,是 2–20 GB 的浮动项,也是"我算出来 20 G,结果 80 G 卡还是 OOM"的头号原因。压它的标准手段是梯度检查点(gradient checkpointing)——前向时只存少数几个中间结果,反向时重算,拿时间换显存,典型代价是训练慢 20%–30%。

工程实践(截至 2026-08)

超参速查表

最重要的时效锚点是 Thinking Machines 的《LoRA Without Regret》(2025-09),到 2026 已被 HuggingFace TRL 收进官方文档,事实上成为社区共识口径。

超参 2026 共识 常见的 2023 化石答案
target_modules "all-linear",必须覆盖 MLP ["q_proj","v_proj"]
学习率 约为全参微调的 10 倍(约 100 步的短训练约 15 倍)。SFT 场景 LoRA 用 2e-4,全参用 1e-5~1e-6;RL/GRPO 场景 LoRA 用 5e-5 沿用全参的 2e-5
有效 batch size < 32。LoRA 对大 batch 的容忍度差于全参,且这个差距与 r 无关 不区分,能开多大开多大
r 数据信息量定,见下 "8 或 16,玄学"
α α=r 或 α=2r 皆可;比较不同 r 时保持 α/r 不变 "alpha 设两倍 rank 就完事"
epoch 1–3。超过 3 收益递减且过拟合风险陡增 跑到 loss 不降为止
dropout 0 起步。短训练里 dropout 作为正则手段并不可靠 默认 0.1

r 到底怎么选:两套数字不矛盾

社区里有两套看似打架的建议,值得说清楚,这本身就是一个很好的分水岭点:

  • TRL / Thinking Machines 口径:SFT 用 r=256,RL/GRPO 用 r=1~32
  • Unsloth 等实用口径16 或 32 起步,常见 8/16/32/64/128。

两者不矛盾,因为说的不是一个数据规模。统一的原理是:

LoRA 的可训参数量必须大于"数据集要装进去的信息量"。容量够时,LoRA 能打平全参微调——同样的样本效率、同样的最终性能;容量不够时,性能会随数据量增大而逐步落后(不是断崖,是效率变差)。

TRL 说的是 post-training 规模的数据(百万 token 级),所以要 256。你手上 1800 条法律文书,16 或 32 绰绰有余。而 RL 场景之所以 r=1 就够,是因为强化学习每个 episode 只带回约 1 bit 信息,rank-1 的三百万参数早就超容量了。

实操建议:从 r=16 或 32 起步;如果训练 loss 明显欠拟合(降不下去)再往上加;不要在效果不好时第一反应就加 r,先检查 target_modules 对不对。

避坑清单

  1. target_modules 是本篇第一号坑。抄教程前先确认它是不是 all-linear
  2. 学习率忘了提十倍是第二号坑。用全参的 2e-5 跑 LoRA,表现为 loss 降得极慢、效果平淡,很容易被误判成"LoRA 不行"。
  3. 别用 QLoRA 当默认。显存够就用 LoRA,快且准。
  4. 算显存时把激活单列出来,并且明确写出你的 batch 和 seq_len。只报一个总数的估算是不可信的。
  5. 合并(merge)前后各评测一次。量化基座上训的 QLoRA 适配器合并回 BF16 基座时会有精度损失,值得确认没掉点。
  6. 多适配器场景不要合并。要热切换就保持适配器独立加载,牺牲一点推理开销换灵活性。
共识只有三条:全线性层、十倍学习率、小 batch
左栏是 2026 的共识口径,右栏是至今还在被教程抄来抄去的答案

超参速查
超参2026 共识2023 化石答案
target_modules本篇一号坑all-linear,必须覆盖 MLP 层q_projv_proj
学习率约为全参的 10 倍(约 100 步的短训练约 15 倍);SFT 场景 LoRA 用 2e-4、全参 1e-5~1e-6,RL/GRPO 场景 LoRA 用 5e-5沿用全参的 2e-5
有效 batch size< 32;LoRA 对大 batch 的容忍度差于全参,且这个差距与 r 无关不区分,能开多大开多大
r按数据信息量定:TRL / Thinking Machines 口径 SFT 用 256、RL/GRPO 用 1~32;Unsloth 等实用口径 16 或 32 起步「8 或 16,玄学」
alphaα=rα=2r 皆可;比较不同 r 时必须保持 α/r 不变「alpha 设两倍 rank 就完事」
epoch1–3,超过 3 收益递减且过拟合风险陡增跑到 loss 不降为止
实操与避坑
QLoRA 的定位
显存不足时的降级选项,不是默认:慢三成上下、精度略降,显存够就该用 LoRA
dropout
0 起步 —— 短训练里 dropout 作为正则手段并不可靠
r 怎么起步
16 或 32;训练 loss 明显欠拟合再往上加,别在效果不好时第一反应就加 r
算显存要单列激活
并写明你的 batchseq_len;只报一个总数的估算不可信
合并前后各评一次
量化基座上训的适配器合并回 BF16 基座会有精度损失,值得确认没掉点
多适配器就别合并
要按请求热切换就保持独立加载,牺牲一点推理开销换灵活性
时效锚点是 Thinking Machines 的《LoRA Without Regret》(2025-09),2026 已被 HuggingFace TRL 收进官方文档。r 的两套数字不打架 —— 可训参数量只要大过数据要装进去的信息量就够

面试视角

报账本,别报数字 —— 换个规模也能重算
算法工程向二面的经典压轴题(Q4-06):换规模、换优化器、换精度,全得现场推

  1. 先分三块基座、可训参数三件套、激活
  2. 全参那档给区间12~16 bytes/param,7B 就是 84 到 112 G
  3. LoRA 只按可训参数算基座剩 2 字节共 14 G,160M 不到 2 G
  4. QLoRA 再换 4 bit基座那 14 G 变 3.5 G
  5. 把激活单独列出来batch × seq_len 走,梯度检查点换
只读过:这些回答会暴露你
  • 「LoRA 加在 q_projv_proj 上」—— 停在 2021 年论文的配置
  • 「LoRA 学习率和全参差不多」—— 于是 loss 降得极慢,被误判成方法不行
  • 「alpha 一般设成 rank 的两倍」—— 讲不出 α/r 是个缩放系数
  • 「7B 全参微调要 80 G 显存」—— 报一个死数,换个规模就重算不出来
  • 「QLoRA 是更好的 LoRA」—— 把降级选项当成了升级选项
真做过:这些细节骗不了人
  • 「现在的共识是 all-linearMLP 层比注意力层更关键
  • 「LoRA 的学习率要比全参高一个数量级,大概 10 倍」
  • 「比较不同 rank 时保持 α/r 不变,否则分不清变的是容量还是缩放」
  • 「12 到 16 字节每参数,看有没有 fp32 主权重;再加激活」
  • 「容量足够时 LoRA 能打平全参,掉点通常是配置问题不是方法上限」
Adapter、Prefix-Tuning 在推理时会多出实打实的计算层,LoRA 不会 —— 能主动说出「可合并、零额外延迟」和「一个基座挂多个适配器热切换」的人,通常真在服务侧部署过

面试官怎么问

Q4-04(LoRA 原理)是一二面高频送分题;Q4-05(r 和 alpha、QLoRA 省在哪)开始筛人;Q4-06(显存估算)是算法工程向二面的经典压轴,因为它没法背——面试官会临时换模型规模、换优化器、换精度,逼你现场推。

答题结构建议(尤其是 Q4-06

不要报数字,报账本

"我分三块算:基座权重、可训参数的三件套(权重+梯度+优化器状态)、激活。 全参的话每个参数 12 到 16 字节,取决于有没有 fp32 主权重副本,7B 就是 84 到 112 G。 LoRA 把基座冻结,基座只剩权重那 2 字节共 14 G,三件套只按可训参数算——r=64 的 all-linear 在 7B 上大概 160M 参数,不到 2 G。 QLoRA 再把基座换成 4 bit,14 G 变 3.5 G。 剩下的是激活,跟 batch 乘序列长度走,2 到 20 G 浮动,这块最容易漏,也是实际 OOM 的主因,用梯度检查点拿时间换。"

这套讲法的价值在于:面试官换任何参数你都能重算一遍。

分水岭信号

只读过 真做过
"LoRA 加在 q_proj 和 v_proj 上" "现在的共识是 all-linear,MLP 层比注意力层更关键;只加 attention 是 2021 年论文的配置"
"LoRA 学习率和全参差不多" "LoRA 的学习率要比全参高一个数量级,大概 10 倍"
"alpha 一般设成 rank 的两倍" "α/r 是缩放系数,重点是比较不同 rank 时保持这个比值不变,否则分不清变的是容量还是缩放"
"7B 全参微调要 80 G 显存" "12 到 16 字节每参数,看有没有 fp32 主权重;再加激活,激活跟 batch 和序列长度走"
"QLoRA 是更好的 LoRA" "QLoRA 是显存不够时的降级选项,慢三成、精度略降,显存够就该用 LoRA"
"LoRA 是全参微调的近似,会掉点" "容量足够时 LoRA 能打平全参;掉点通常是配置问题,不是方法上限"
(不提) "LoRA 推理时能合并回权重,零额外延迟;这是它比 Adapter 强的关键,不合并还能一个基座挂多个适配器做热切换"

最后一行经常是加分项:能主动说出"可合并"和"多适配器热插拔"这两个工程价值的候选人,通常是真在服务侧部署过的。

小结与延伸

  • LoRA 冻结基座、在旁边挂两个低秩矩阵,h = W₀x + (α/r)BAx;B 初始化为 0 保证接上瞬间不扰动模型;推理可合并,零额外延迟。
  • 2026 的三条硬共识:加在所有线性层(含 MLP)、学习率约为全参的 10 倍、有效 batch 小于 32。抄旧教程的 q_proj/v_proj 是最常见的翻车原因。
  • r 按数据信息量选,不是玄学:容量够就能打平全参,容量不够是效率变差而非断崖。
  • QLoRA 用 NF4 + 双重量化 + 分页优化器把基座压到 1/4,代价是慢和精度略降,是降级选项不是默认
  • 显存账三块:基座 + 可训参数三件套(12~16 bytes/param)+ 激活。激活是最容易漏也最容易导致 OOM 的一块。

延伸:会算这笔账只解决了"怎么做"。下一篇 T4-3 处理更值钱的问题——这件事到底该不该做:prompt、RAG、微调、蒸馏之间怎么选,以及 2026 年微调还剩哪几条护城河。

关联题目Q4-04(LoRA 原理)、Q4-05(r/alpha 与 QLoRA)、Q4-06(显存估算)

继续深入

本篇归属第 4 章「微调与对齐」,去做这一章的题