QLoRA:4-bit 量化与显存账

02-PEFT原理 核心≈ 25 分钟 #QLoRA#量化#NF4 reviewed
我的状态:

前置知识点

一句话定义

QLoRA = 把冻结的基座权重量化成 4-bit 存储(NF4 格式),再在其上训练常规 LoRA 适配器,让单张消费级显卡也能微调大模型。

为什么重要

它把微调的显卡门槛从「A100 集群」拉到「一张 24G 的 4090」:70B 模型 QLoRA 约需 40-48G 显存,7B 模型 5-7G 即可开训。绝大多数个人与小团队的第一次微调就发生在 QLoRA 上;它同时给出了「量化不伤微调质量」的关键结论。

前置知识

kp-004 的显存四大件与 LoRA 显存公式;kp-005 的 LoRA 原理。

核心概念

  • NF4(4-bit NormalFloat):专为正态分布权重设计的信息论最优 4-bit 格式,比普通 INT4 量化误差更小。
  • 双重量化(Double Quantization):把量化用的缩放常数本身也量化一次,再省约 0.4 位/参数。
  • 分页优化器(Paged Optimizer):优化器状态显存不足时借道 CPU 内存,避免长序列尖峰导致的 OOM 崩溃。
  • 计算精度与存储精度分离:权重以 4-bit 存储,前向/反向时按需反量化为 BF16 参与矩阵乘法。

原理与机制

存储账(参数量 P,十亿计):fp16 权重 2P 字节 → NF4 约 0.5P 字节 + 双重量化开销约 0.06P。梯度与 AdamW 状态只存在于 LoRA 参数上(沿用 kp-005 的 16·P_lora)。合成公式:

M_qlora ≈ 0.5P + 16·Plora + M_act

数值直觉:7B → 权重约 3.5G,总训练显存约 5-8G;13B → 约 8-11G;70B → 约 40-48G。代价是速度:每步都要做 4-bit → BF16 反量化,QLoRA 通常比同配置 LoRA(fp16 权重)慢 20%-40%。

质量来源在于「冻结权重只读、误差不累积」:4-bit 误差是固定的前向偏差,而可训练的 LoRA 分支会学着补偿这个偏差——这是 QLoRA 论文的核心洞察,也是它不能反向推广到「4-bit 上做全参微调」的原因(那样误差会被梯度更新放大)。

图示

fp16 权重 (2B/参数)          NF4 权重 (0.5B/参数)
▓▓▓▓▓▓▓▓▓▓▓▓ 7B=14G   →    ▓▓▓ 7B=3.5G
        训练时: NF4 ─反量化→ BF16 参与计算 → 梯度只更新 LoRA 的 B/A

直观类比

把图书馆藏书(冻结权重)做成缩微胶片入库(4-bit 存储),要看哪页再放大成原尺寸阅读(反量化计算);你在书页边写的批注(LoRA 参数)始终用全尺寸保存。

实例或案例

在单张 4090 上 QLoRA 微调 Qwen2.5-14B(4000 条领域数据):权重约 7.4G,LoRA 状态约 0.4G,梯度检查点后激活约 6G,峰值约 15G,全程无 OOM;fp16 权重方案则因 28G 权重无法加载,代价是每 epoch 时间多约 35%。

操作步骤

from transformers import BitsAndBytesConfig
import torch
bnb = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",            # NF4 格式
    bnb_4bit_use_double_quant=True,       # 双重量化
    bnb_4bit_compute_dtype=torch.bfloat16 # 计算精度 BF16
)
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen2.5-14B", quantization_config=bnb, device_map="auto")

再对量化模型 prepare_model_for_kbit_training 后注入 LoRA(kp-005 的三行代码);优化器选 paged_adamw_32bit 以启用分页。

排错清单

  • 加载即 OOM:确认 load_in_4bit=True 生效、device_map="auto";排除误以 fp16 先加载再量化。
  • 训练速度慢得离谱:NF4 反量化开销正常存在;检查是否误用 fp32 计算精度(compute_dtype 应为 bf16)。
  • loss 出现 NaN:Ampere 之前的卡不支持 BF16,改 torch.float16 并配 kp-018 的 loss scaling。
  • 效果明显差于预期:优先怀疑数据与超参,而不是量化本身;同数据先跑一版 LoRA 对照。
  • bitsandbytes 报 CUDA 错误:版本与 CUDA 不匹配,按框架文档核对版本矩阵。

常见误区

  • QLoRA 是新算法:它只是「NF4 存储 + LoRA + 分页优化器」的工程组合,数学核心仍是 LoRA。
  • 4-bit 计算也 4-bit:存储 4-bit、计算 BF16,两层精度要分开配置。
  • 量化收益可以叠加到全参微调:冻结只读是误差不累积的前提,全参更新会把量化误差放大。
  • QLoRA 锁定部署精度:导出时可按需另选精度(见 kp-028),训练侧量化不约束部署形态。

与其他知识点的关系

显存优化的其他手段(梯度检查点等)见 kp-017;量化导出与部署侧量化(GPTQ/AWQ/GGUF)见 kp-028 与 kp-029。

延伸阅读

Dettmers et al. 2023《QLoRA: Efficient Finetuning of Quantized LLMs》;Dettmers et al. 2022《8-bit Optimizers via Block-wise Quantization》(bitsandbytes 的量化基础)。

自测题

  1. QLoRA 显存公式中每一项分别是什么?

答:约 0.5P 的 NF4 冻结权重 + 16×LoRA 参数的梯度与 AdamW 状态 + 激活值。

  1. 为什么 4-bit 存储的误差不会毁掉微调效果?

答:冻结权重只读,量化误差是固定前向偏差不随训练累积;可训练的 LoRA 分支会适应并补偿该偏差。

  1. QLoRA 比 LoRA 慢的原因是什么?

答:每次矩阵乘法前要把 NF4 权重反量化为 BF16,带来约 20%-40% 的额外计算开销。

相关知识点

来源

  • Dettmers et al. 2023《QLoRA: Efficient Finetuning of Quantized LLMs》

基于模型知识整理,建议按需核对原文。