这篇学完你能回答什么
- LoRA 的原理是什么?为什么在原权重旁边挂两个低秩矩阵就能顶替全参微调?
- r 和 alpha 到底在控制什么?2026 年这两个值该怎么设,QLoRA 又省在哪一块?
- 微调一个 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 基线一大截。
一个抄来的默认值,差点让团队得出"该上全参微调"的结论,成本差着两个数量级。
1800 条精挑的样本
(客户问题,本所标准回复)对
判断是对的:该微调
行文风格写不出规则,只能给例子
配置基本抄社区教程断点
r=16、lora_alpha=32,只挂 Q、V打不过 few-shot 基线
对手只是 prompt 里塞 8 个例子
周报写「建议评估全参」
成本差着两个数量级
target_modulesq_proj、v_projall-linear,必须覆盖 MLPr=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 存着,只在计算时临时还原。描图纸仍然是高精度的。
改哪都行,改完就是最终稿
整张图连同所有修改痕迹、撤销记录都得带在手上
每个参数都要带三件套
权重、梯度、优化器状态,一个都躲不掉 —— 代价直接写在显存账上
原图锁死,最终效果 = 原图 + 描图纸
这张纸还是压缩的:不是同样大的一张,而是两个细长条的乘积
基座冻结,旁边挂 A、B 两个低秩矩阵
4096×4096 用 4096×64 与 64×4096 相乘来近似,1600 万参数降到 52 万,压掉 97%
原理拆解
B 初始化为全 0,接上瞬间不扰动模型;显存差别全在梯度和优化器状态跟谁走r 时让量级保持可比W = W₀+(α/r)BA,零额外延迟r=64、all-linear| 方案 | 基座 | 可训参数三件套 | 激活 | 合计 |
|---|---|---|---|---|
| 全参 · 12 bytes/param | 14 GB | 70 GB | 2–20 GB | 约 88 GB |
| 全参 · 16 bytes/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 |
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=64 的 all-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
三个设计细节,每个都能当面试追问点:
- B 初始化为全 0,所以训练刚开始时 BA = 0,
h完全等于基座输出。这保证了接上适配器的瞬间不扰动模型,训练从基座的原始行为平滑出发。如果两个矩阵都随机初始化,第一步就把模型打乱了。 - α/r 是一个缩放系数(scaling factor),不是"学习强度"这种玄学。它的作用是:当你改变 r 时,让适配器输出的量级保持可比。所以比较不同 r 的实验时必须固定 α/r,否则你分不清变化来自容量还是来自缩放。
- 推理时可以合并:
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 有三个组件,很多人只记得第一个:
- NF4(4-bit NormalFloat):一种针对"神经网络权重近似服从正态分布"这个先验设计的 4 bit 数据类型,在该假设下是信息论意义上更优的量化格式(优于普通 int4)。基座权重以 NF4 存储,前向计算时临时反量化到 BF16。
- 双重量化(double quantization):量化本身会产生一堆量化常数(scale),这些常数也占显存。QLoRA 把量化常数再量化一次,每个参数再省约 0.4 bit。
- 分页优化器(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 对不对。
避坑清单
target_modules是本篇第一号坑。抄教程前先确认它是不是all-linear。- 学习率忘了提十倍是第二号坑。用全参的 2e-5 跑 LoRA,表现为 loss 降得极慢、效果平淡,很容易被误判成"LoRA 不行"。
- 别用 QLoRA 当默认。显存够就用 LoRA,快且准。
- 算显存时把激活单列出来,并且明确写出你的 batch 和 seq_len。只报一个总数的估算是不可信的。
- 合并(merge)前后各评测一次。量化基座上训的 QLoRA 适配器合并回 BF16 基座时会有精度损失,值得确认没掉点。
- 多适配器场景不要合并。要热切换就保持适配器独立加载,牺牲一点推理开销换灵活性。
| 超参 | 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 | 按数据信息量定:TRL / Thinking Machines 口径 SFT 用 256、RL/GRPO 用 1~32;Unsloth 等实用口径 16 或 32 起步 | 「8 或 16,玄学」 |
alpha | α=r 或 α=2r 皆可;比较不同 r 时必须保持 α/r 不变 | 「alpha 设两倍 rank 就完事」 |
| epoch | 1–3,超过 3 收益递减且过拟合风险陡增 | 跑到 loss 不降为止 |
- QLoRA 的定位
- 显存不足时的降级选项,不是默认:慢三成上下、精度略降,显存够就该用 LoRA
- dropout
- 0 起步 —— 短训练里 dropout 作为正则手段并不可靠
r怎么起步- 16 或 32;训练 loss 明显欠拟合再往上加,别在效果不好时第一反应就加
r - 算显存要单列激活
- 并写明你的
batch和seq_len;只报一个总数的估算不可信 - 合并前后各评一次
- 量化基座上训的适配器合并回 BF16 基座会有精度损失,值得确认没掉点
- 多适配器就别合并
- 要按请求热切换就保持独立加载,牺牲一点推理开销换灵活性
r 的两套数字不打架 —— 可训参数量只要大过数据要装进去的信息量就够。面试视角
- 先分三块基座、可训参数三件套、激活
- 全参那档给区间
12~16 bytes/param,7B 就是 84 到 112 G - LoRA 只按可训参数算基座剩 2 字节共 14 G,160M 不到 2 G
- QLoRA 再换 4 bit基座那 14 G 变 3.5 G
- 把激活单独列出来跟
batch × seq_len走,梯度检查点换
- 「LoRA 加在
q_proj和v_proj上」—— 停在 2021 年论文的配置 - 「LoRA 学习率和全参差不多」—— 于是 loss 降得极慢,被误判成方法不行
- 「alpha 一般设成 rank 的两倍」—— 讲不出
α/r是个缩放系数 - 「7B 全参微调要 80 G 显存」—— 报一个死数,换个规模就重算不出来
- 「QLoRA 是更好的 LoRA」—— 把降级选项当成了升级选项
- 「现在的共识是
all-linear,MLP 层比注意力层更关键」 - 「LoRA 的学习率要比全参高一个数量级,大概 10 倍」
- 「比较不同 rank 时保持
α/r不变,否则分不清变的是容量还是缩放」 - 「12 到 16 字节每参数,看有没有 fp32 主权重;再加激活」
- 「容量足够时 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 年微调还剩哪几条护城河。
继续深入
本篇归属第 4 章「微调与对齐」,去做这一章的题。