两个月前,老板扔给我一个任务:“把这个 70B 的模型按照我们的业务数据微调一下。”

我当时心里就三个字:得加钱。

70B 模型,全量微调起码要 8 张 A100,一张 A100 租一天就几百块。我们小团队哪烧得起这个钱。

后来一个朋友跟我说:试试 QLoRA 吧,一张 3090 就能跑 70B 的微调。

说实话我当时是不信的。一张卡跑 70B 的微调?这不是扯吗?结果试完之后我发现——不仅真的能跑,效果还不赖。

QLoRA 到底是个什么东西

QLoRA = Quantized LoRA,就是给 LoRA 又加了一层量化。

拆开说:

  • LoRA(Low-Rank Adaptation):把大模型的权重冻结不动,在旁边加两个小的低秩矩阵做训练。原来要更新 1000 万个参数,现在只更新 10 万。显存需求大幅降低。
  • QLoRA:在此基础上,把冻结的权重量化到 4bit(NormalFloat4),进一步砍显存。一张 24G 的 3090,跑 70B 模型的微调不是梦。

QLoRA 的核心创新是 NF4 量化格式。它不是简单的 INT4,而是针对神经网络的权重分布设计的 4bit 量化格式,比普通的 INT4 精度更高,对模型输出影响更小。

另外,QLoRA 还有一个骚操作叫 Paged Optimizer——利用 CPU 内存和 GPU 显存之间的页交换,解决显存不够时的"爆显存"问题。

我的实战环境

先交代硬件配置,方便你对照:

GPU: RTX 3090 (24GB) × 1
CPU: AMD Ryzen 5950X (16核)
内存: 64GB DDR4
系统: Ubuntu 22.04
CUDA: 12.1

就这配置,说实话在 AI 训练圈算寒碜的。但够用。

实操步骤

第一步:环境安装

装 bitsandbytes 和 peft,两个最核心的库。

pip install bitsandbytes
pip install peft transformers accelerate datasets

bitsandbytes 负责 NF4 量化,peft 负责 LoRA 操作。两个是 QLoRA 的黄金搭档。

第二步:加载量化模型

关键代码就这几行:

from transformers import AutoModelForCausalLM, BitsAndBytesConfig
import torch

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16
)

model = AutoModelForCausalLM.from_pretrained(
    "模型名称",
    quantization_config=bnb_config,
    device_map="auto",  # 自动分配到各个设备
    torch_dtype=torch.bfloat16
)

这里 bnb_4bit_use_double_quant=True 开启双重量化——对量化常数再量化一次,进一步省显存。device_map="auto" 让 Transformers 自动分配层到不同的 GPU/CPU,防止某一块显存爆掉。

第三步:配置 LoRA 参数

from peft import LoraConfig, get_peft_model

lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

model = get_peft_model(model, lora_config)

r=16 是 LoRA 的秩,秩越大可学习参数越多但显存也更大。70B 模型我试过 r=16 性价比最高。target_modules 指定在哪些模块上加 LoRA——QKV 投影层是全连上。

第四步:开始训练

训练参数上,我用的是:

per_device_train_batch_size: 1
gradient_accumulation_steps: 8
learning_rate: 2e-4
num_train_epochs: 3
max_seq_length: 2048

batch_size=1 是因为显存真的就那么多。配合 gradient_accumulation_steps=8,等效 batch size 是 8,训练效果其实不差。

关键显存数据

  • 加载模型:约 18GB(NF4 量化+双重量化)
  • 训练峰值:约 22GB(含梯度、优化器状态)
  • 剩余:约 2GB(系统占用)

卡的刚刚好。3090 的 24GB 基本用满。

踩过的三个坑

坑一:CPM 评分上不去

第一次训完,跑评测 CPM 只涨了 2 个点。找了半天原因——学习率太高了

QLoRA 因为权重是量化的,对学习率特别敏感。我一开始用了 1e-4 觉得挺保守,结果还是太高。降到 2e-5 之后,CPM 直接涨了 8 个点。

坑二:中途 OOM

训到一半报 OOM。排查后发现是 max_seq_length 设了 4096。70B 模型 + 4K 上下文 = 显存直接爆掉。降到 2048 之后稳如老狗。

坑三:NF4 反量化成为瓶颈

QLoRA 的原理是 forward 时把 4bit 权重反量化到 16bit 做计算,这导致训练速度比 LoRA 慢 30%-40%。没办法,这是 trade-off。想快就多花钱买更多卡。

效果到底怎么样?

拿我们的场景来说——用 5000 条客服对话数据微调一个 70B 模型。

  • 全量微调:8 张 A100,训练 6 小时,成本约 3000 元
  • QLoRA(我的方案):1 张 3090,训练 12 小时,成本 0 元(自己的卡)

模型输出质量呢?做了 100 条测试集的盲测,QLoRA 的回复质量达到全量微调的 92%。

92% 的效果,0 元的硬件成本。 这笔账不用我算了吧。

写在最后

QLoRA 这个方案,说实话不是银弹。它慢、它有精度损失、它对超参敏感。

但它解决了一个真实的问题——让买不起 A100 的团队也能做大模型微调。

如果你手头也有一张消费级显卡,想试试微调但怕跑不动,直接用 QLoRA 就行。先用一张卡跑起来,效果不行再想办法上多卡。

先把事情做出来,再考虑做完美。这个道理放哪都适用。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐