最近审阅:2026-10 · 前置:一次训练、模型适配

你想让模型按固定格式整理客服记录。数据有了,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 参数。可以粗略写成:

几种微调方式和各自的显存需求:QLoRA 在 LoRA 的基础上把 Transformer 量化到 4 bit,并用分页优化器应对显存峰值。
原文图几种微调方式和各自的显存需求:QLoRA 在 LoRA 的基础上把 Transformer 量化到 4 bit,并用分页优化器应对显存峰值。图源:Dettmers et al., 2023 · QLoRA · Figure 1 · CC BY 4.0 · 转为 WebP

$$ 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
先用大量数据学习通用表示和能力,再适配具体任务