你想让模型按固定格式整理客服记录。数据有了,SFT 的 loss 也写好了,但全参数训练放不进显存。于是换成 LoRA,只训练很少的参数。听起来应该一下就轻了,结果把序列拉长,还是 OOM。
这并不矛盾。LoRA 主要减少需要更新的权重和相应的梯度、优化器状态;模型做前向和反向时用到的中间结果,没有因此全部消失。我们从一层线性变换算起。
SFT 和 LoRA 不在回答同一个问题
SFT 说的是“用示范回答来训练”;LoRA 说的是“允许哪些参数变化”。所以正确的比较是 full-parameter SFT 和 LoRA-SFT,而不是“LoRA 还是 SFT”。LoRA 同样可以用于其他目标。
如果任务只是输出格式偶尔不合法,先考虑校验或 constrained decoding。如果缺的是经常变化的事实,先考虑检索(retrieval)。只有确认需要改变模型行为以后,才轮到选择参数更新方式。
把一块大更新拆成两块小矩阵
线性层原本是 $y=W_0x$。LoRA 冻结 $W_0$,另学一条小分支:
$$ y=W_0x+sBAx,\qquad s=\alpha/r. $$
若输入和输出维度分别为 $d_{in},d_{out}$,则:
| 对象 | 形状 | 是否更新 |
|---|---|---|
| $W_0$ | $d_{out}\times d_{in}$ | 不更新 |
| $A$ | $r\times d_{in}$ | 更新 |
| $B$ | $d_{out}\times r$ | 更新 |
| $BA$ | $d_{out}\times d_{in}$ | 由两者组成,不必单独作为参数存储 |
“低秩”限制的是增量 $BA$,不是声称原来的 $W_0$ 低秩。$A$ 先把输入投到 $r$ 维,$B$ 再映回输出维度;训练可以改变这条分支,但不能在一层里任意改动所有方向。LoRA 原论文提出了这套参数化。
例如一个 4096 × 4096 的权重有 16,777,216 个参数。取 $r=8$,LoRA 只有:
$$ 8\times4096+4096\times8=65{,}536, $$
是原矩阵参数量的 0.390625%。这是单个目标矩阵的比例,不是整次训练的显存比例。
用一个小输入看它究竟改了什么
暂时取 $s=1$,只看增量分支:
$$ A=\begin{bmatrix}1&0&-1\end{bmatrix},\quad B=\begin{bmatrix}2\\-1\end{bmatrix},\quad x=\begin{bmatrix}3\\1\\1\end{bmatrix}. $$
先算 $Ax=2$,再算 $B(Ax)=[4,-2]^\top$。最后把这两个数加到原输出 $W_0x$ 上。
x=[3,1,1] ─────────────→ 原来的 W₀ ──────→ 原输出
│ + → 新输出
└→ A:压到 1 维,得到 2 → B:[4,-2] ───┘
输入变了,这条分支的修正也会变;它不是给所有输入加同一个常数。这个 rank-1 例子只有一个中间方向。增大 rank 会放宽约束,但不保证测试集更好:数据不足时,也可能更容易拟合噪声。
为什么不能把 A、B 都初始化成零?
设输出梯度为 $g=\partial\mathcal L/\partial y$,则单样本有:
$$ \frac{\partial\mathcal L}{\partial B}=s\,g(Ax)^\top,\qquad \frac{\partial\mathcal L}{\partial A}=s\,B^\top g x^\top. $$
如果 $A=B=0$,两边梯度也都是零,增量分支就学不动了。常见初始化让 A 随机、B 为零:开始时 $BA=0$,模型行为保持原样;第一步 B 可以收到梯度,之后 A 也能更新。其他初始化有不同设计,不要把某一种当作唯一规范。
“冻结”也别理解成“后面不用反向传播”。为了训练较早层的 LoRA,梯度仍可能需要穿过中间冻结的层。冻结通常是不更新这些权重、不存它们的参数梯度;不是把整段计算放进 no_grad() 就完事了。
显存到底花在哪儿?
可以先用这份账检查,而不是只盯着 trainable parameters:
| 项目 | 普通 LoRA 带来的变化 |
|---|---|
| 基础权重 | 仍然要存,普通 LoRA 不自动量化它 |
| 基础权重的参数梯度 | 冻结时通常不需要 |
| 基础权重的优化器状态 | 通常不需要 |
| LoRA 权重、梯度、优化器状态 | 需要,但规模较小 |
| 反向所需的激活 | 仍可能很大,取决于长度、batch、实现 |
| 临时工作区、通信 buffer | 取决于 kernel 和并行配置 |
如果激活是主要开销,减 microbatch、缩短或分桶序列、使用 activation checkpointing,可能比再减一点 rank 更有效。Checkpointing 用重算换存储,会增加计算,不能只看显存下降。
QLoRA 再省掉哪一块?
QLoRA 把冻结的基础权重以低比特形式存储,同时训练较高精度的 LoRA 参数。可以粗略写成:

$$ y=\operatorname{dequant}(W_q)x+sBAx. $$
这不是说训练期间所有张量都变成 4-bit。存储 dtype、计算 dtype、梯度与优化器状态的 dtype 可以不同;矩阵运算时通常要在更高精度下使用恢复出的权重值。原始 QLoRA 论文包含 NF4、double quantization 与 paged optimizers,分别处理权重表示、量化常数和内存峰值问题。
做一个理想化估算:7B 参数的权重若每个用 2 bytes,约 14 GB;若每个恰好 4 bits,原始码值约 3.5 GB。3.5 GB 不是训练总显存:还没算量化元数据、非量化层、adapter、激活与工作区,也不能由此推出训练速度一定更快。
NF4、双重量化、分页优化器分别省什么?
这三个名字经常一起出现,但改的不是同一块:
| 技术 | 存的是什么 | 需要留意什么 |
|---|---|---|
| NF4 | 用按正态分布设计的非均匀码值表示权重 | 不是均匀 INT4,也不意味着每层权重都严格正态 |
| Double quantization | 连各个权重块的缩放常数也量化 | 常数还要有自己的缩放信息,不是免费消失 |
| Paged optimizer | 用 unified memory 在 CPU / GPU 之间迁移优化器状态页 | 缓解显存峰值,但迁移有成本;不是 KV cache 的分页 |
例如,每 64 个权重共用一个 FP32 缩放常数,光常数就占 $32/64=0.5$ bit/weight。若先把这些常数变成 8-bit,第一层开销降到 $8/64=0.125$ bit/weight,但还要加第二层常数等元数据。这笔账解释了为什么“4-bit 权重”不等于整个 checkpoint 恰好每参数 4 bits。
机制见 QLoRA 第 3 节。显存是否够用,还得带上实际长度、batch 和 checkpointing 配置测试。
部署时能直接合并吗?
对普通线性 LoRA,在推理时可计算 $W_{merged}=W_0+sBA$,再按普通线性层运行。实数运算下它与两分支计算等价;浮点舍入会带来小差异。若多个任务需要切换 adapter,不合并也可能更方便。
量化权重更麻烦:先反量化、加增量、再量化,可能产生新的误差;工具和后端也不一定支持同样的合并方式。不能把“QLoRA 训得动”当作“任意 4-bit 引擎都能无损加载”。部署前用目标后端检查输出与显存。PEFT 文档可用于核对具体实现支持,版本变化时要重查。
怎么做一个能解释结果的实验?
不用一口气扫几十组配置。先固定数据、split、模板、loss mask 和训练 token 预算,再分别比较:
| 想知道什么 | 只改变什么 | 一起记录什么 |
|---|---|---|
| rank 是否太小 | rank,例如 8 → 16;明确 scaling 规则 | 验证集任务成功率、回归、显存 |
| 改哪些层更有效 | 仅 attention 投影 vs 再加 MLP 投影 | 参数量、吞吐、质量 |
| 量化代价多大 | 同一配置的 LoRA vs QLoRA | 质量、峰值显存、每秒有效 token |
| 瓶颈是否在激活 | 长度或 microbatch,一次改一个 | OOM 边界、耗时、实际 token 数 |
前两行已有公开对照可参考。LoRA Without Regret(Schulman 等,Thinking Machines,2025-09-29)报告:只加在 attention 上的 LoRA 明显不如只加在 MLP 上的,在 MLP 之外再给 attention 加 LoRA 也没有额外收益;LoRA 的最佳学习率稳定在同一任务全参数微调(fine-tuning)的约 10 倍;做策略梯度 RL 时,rank 低到 1 也能追平全参数微调。同一篇也提醒:数据量超过 LoRA 的容量(接近预训练(pre-training)那种规模)时它会落后,而且它比全参数微调更怕大 batch,加大 rank 也补不回来。这些是作者在自己设置下的结果,换了模型和数据,仍要按上表自己测。
别把训练 loss 更低直接写成用户体验更好。客服例子至少检查格式是否合法、字段是否正确、信息不足时会不会编造,以及原来会做的任务有没有退化。
LoRA 让一些实验更便宜,但不会自动修复坏标签。要换监督来源,继续读蒸馏:学生到底向老师学什么;要选示范,回到 SFT。
本页术语 3
- 检索 retrieval
- 从外部语料里找出相关内容
- 微调 fine-tuning
- 在预训练权重上继续训练以适配具体任务
- 预训练 pre-training
- 先用大量数据学习通用表示和能力,再适配具体任务