1287 words
6 minutes
【八股】QLoRA

1. 啥是 QLoRA#

QLoRA(Quantized Low-Rank Adapters)是一种参数高效微调方法,先把预训练大模型的基座权重以 4-bit 量化后冻结不更新,然后在关键线性层上插入并只训练 LoRA 的低秩适配器,让梯度穿过量化的冻结模型但参数更新仅发生在少量 LoRA 权重上,从而把显存占用压到足以在单张 GPU 上微调(论文展示了 65B 模型可在 48GB GPU 上微调),同时尽量保持接近 16-bit 全量微调的效果。其关键工程点包括 NF4 4-bit 量化格式、double quantization 进一步压缩量化常量,以及 paged optimizers 用来缓解训练时的显存峰值。

在提出 QLoRA 的时候,模型量化 + LoRA 并不是没有人做,个人认为 QLoRA 的提出更大的贡献不是提出了一个全新的 LoRA 方法,而是提出了一种更适配 LoRA 的量化方式,也就是 NF4。

(关于 LoRA 可以看上一篇笔记。)

2. 简单说下模型量化#

模型量化就是把模型里的数值表示从高精度(FP32/FP16)换成更低比特(常见 INT8、INT4,或 4-bit 浮点/码本等),以减少模型体积与显存占用、降低内存带宽压力,并在支持低精度算力的硬件上提升推理速度。

2. NF4#

NF4(NormalFloat 4-bit)是 QLoRA 里用来做 4-bit 权重量化的一种非均匀量化数据类型,预训练模型的权重分布大多近似零均值的正态分布,所以量化时应该把更多的表示能力分配到 00 附近,而不是像 int4 那样等间隔。

先用标准正态分布 N(0,1)N(0,1) 的分位数预先算出 2k2^kk=4k=4,所以 1616 个)代表值,再把这些代表值归一化到 [1,1][-1,1],实际量化某个权重块时,用该块的绝对最大值做 rescale(把权重映射到 [1,1][-1,1]),然后把每个权重映射到最接近的 NF4 码本值并用 4-bit 存索引。

用人话说就是,可以把 NF4 理解成一种更聪明的 4-bit 记数方式,专门用来存大模型的权重,让 44 位(1616 个档位)尽量少损失信息。

普通的 4-bit,比如 int4 更像尺子刻度,是等间隔的,不管权重值常不常出现,都平均分 1616 个格子。NF4 的出发点是大模型权重大多集中在 00 附近,所以 00 附近应该刻得更密,远离 00 可以刻得更稀,把宝贵的 1616 个格子优先用在最常出现的范围,从而同样 4-bit 下误差更小、效果更稳。QLoRA 把 NF4 描述为对“近似正态分布的权重”更合适的 4-bit 数据类型,并作为其 4-bit 微调效果接近 16-bit 的关键点之一。

假设某一小块权重里有这些值:

0.12, 0.05, 0.02, 0, 0.01, 0.03, 0.08, 0.20-0.12,\ -0.05,\ -0.02,\ 0,\ 0.01,\ 0.03,\ 0.08,\ 0.20

如果用等间隔 int4 ,想象:区间 [0.2,0.2][-0.2, 0.2] 平均分 1616 档,步长大约是 0.4/150.02670.4/15≈0.0267。那 0.010.01 会被四舍五入到 0.000.000.02670.02670.030.03 会到 0.02670.02670.05330.0533。也就是说,00 附近一堆很小的数,会被同一个粗刻度糊在一起,误差相对更明显。

如果用 NF4 风格的非均匀刻度,想象:把更多档位挤在 00 附近,这样 0.010.01 可以精确落在 0.010.01 档,0.030.03 可能落在 0.020.020.040.04 档,误差就更小,而像 0.200.20 这种大值,本来就少见,刻度稀一点对整体影响没那么大。

3. 双重量化(Double Quantization)#

4-bit 量化本身还需要存每个 block 的量化尺度/常量,例如 scale、absmax 一类的元数据。QLoRA 进一步把这些“量化常量”再量化一遍,从而继续压缩显存占用。

4. 分页优化器(Paged Optimizers)#

训练时显存会出现峰值,尤其是优化器状态、梯度等瞬时占用导致 OOM。QLoRA 引入 paged optimizer 的思路,用“分页/统一内存”的方式把一部分优化器状态在需要时换入/换出,降低显存峰值带来的崩溃风险。

使用 NVIDIA 统一内存特性,在CPU和GPU之间进行页传输。当GPU内存不足时,将部分状态转移到CPU RAM 中,并在优化器更新步骤需要内存时分页回到GPU内存中。

5. QLoRA 训练方式本身#

QLoRA 的训练方式和普通 LoRA 在核心逻辑上是一样的,都把基座模型冻结,只训练插进去的低秩适配器(LoRA 的 A、B 矩阵),梯度会穿过基座模型的前向计算,但参数更新只发生在 LoRA 上。

但 QLoRA 是在量化后的模型上做微调,所以做前向(矩阵乘)时通常会把 4-bit 权重在算子内部解码/反量化到 BF16/FP16 去算,然后再继续反传到 LoRA 参数。

从参数形式上看,QLoRA 训练出来的 A、B 矩阵和普通 LoRA 是同一种东西,通常仍然以 BF16/FP16 保存;QLoRA 只是把基座模型的线性层权重量化成 4-bit(比如 NF4)来省显存,训练时只更新适配器。

【八股】QLoRA
https://fuwari.vercel.app/posts/note/qlora/
Author
P19E99
Published at
2026-02-15
License
CC BY-NC-SA 4.0