# LoRA 与 QLoRA 微调大模型
简介
在大模型时代,微调(Fine-tuning)是让预训练模型适应特定任务的关键技术。然而,传统全参数微调需要消耗巨大的计算资源——一个 7B 参数的模型全量微调需要约 60GB 显存,这让大多数研究者和开发者望而却步。
**LoRA(Low-Rank Adaptation)** 和 **QLoRA(Quantized LoRA)** 的出现彻底改变了这一局面。通过低秩矩阵分解和量化技术的结合,我们可以在单张 24GB 显存的 GPU 上完成 7B 参数模型的微调,大幅降低了定制大模型的门槛。
LoRA 核心原理
什么是低秩适配?
LoRA 的核心思想源于一个关键假设:**大模型在微调过程中,权重矩阵的更新本质上处于一个低秩空间**。换句话说,我们不需要调整全部参数,只需要学习一小部分“增量信息”即可实现有效的任务适配。
LoRA 对预训练权重矩阵 $W_0 \in \mathbb{R}^{d \times k}$ 进行低秩分解:
$$W = W_0 + \Delta W = W_0 + BA$$
其中:
LoRA 的优势
QLoRA 核心原理
QLoRA 在 LoRA 基础上引入了**NF4(4-bit NormalFloat)量化**技术,进一步降低显存占用:
| 优化技术 | 描述 | 显存节省 |
|---------|------|---------|
| 4-bit NF4 量化 | 将权重压缩到 4-bit | ~4x |
| 双重量化 | 对量化常数再次量化 | ~2x |
| 分页注意力 | 处理内存峰值 | 稳定性 |
**关键洞察**:LoRA 参数仍使用 fp16/bf16 训练,但基座模型的 4-bit 量化大幅减少了 **模型权重** 的显存占用,使得 7B 模型从 ~14GB 降至 ~3.5GB。
环境准备与依赖安装
硬件要求
依赖安装
# 创建虚拟环境
conda create -n qlora python=3.10
conda activate qlora
# 安装核心依赖(以 PEFT 库为例)
pip install transformers accelerate peft datasets bitsandbytes
pip install flash-attn --no-build-isolation # 可选,加速注意力计算
# 验证安装
python -c "import peft, transformers, bitsandbytes; print('环境配置成功')"
完整实操流程
以下代码演示使用 QLoRA 在中文指令数据集上微调 ChatGLM3-6B:
1. 数据准备
from datasets import load_dataset
# 加载alpaca格式的中文数据
dataset = load_dataset("yahma/alpaca-chinese", split="train")
dataset = dataset.shuffle(seed=42).select(range(1000)) # 演示用少量数据
def format_instruction(sample):
"""构建指令微调格式"""
return {
"prompt": f"指令: {sample['instruction']}\n输入: {sample['input']}\n输出: ",
"response": sample['output']
}
dataset = dataset.map(format_instruction, remove_columns=dataset.column_names)
2. 模型加载(4-bit 量化)
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
# QLoRA 量化配置
quantization_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type="nf4"
)
model_name = "THUDM/chatglm3-6b"
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=quantization_config,
device_map="auto",
trust_remote_code=True
)
3. LoRA 配置与模型准备
from peft import LoraConfig, get_peft_model, TaskType
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=8, # 秩,越大越强但更慢
lora_alpha=16, # 缩放因子
lora_dropout=0.05,
target_modules=[ # 指定要添加 LoRA 的层
"query_key_value",
"dense",
"dense_h_to_4h",
"dense_4h_to_h"
],
bias="none"
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# 输出示例: trainable params: 4,194,304 || all params: 6,383,874,560 || trainable%: 0.0657
4. 训练配置与启动
from transformers import TrainingArguments
training_args = TrainingArguments(
output_dir="./chatglm3-lora",
per_device_train_batch_size=4,
gradient_accumulation_steps=4, # 等效 batch_size=16
learning_rate=1e-4,
num_train_epochs=3,
fp16=True,
logging_steps=10,
save_strategy="epoch",
optim="paged_adamw_8bit", # 节省优化器显存
max_grad_norm=0.3,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset,
data_collator=data_collator,
)
trainer.train()
5. 模型推理与权重合并
# 加载 LoRA 权重进行推理
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained(
model_name, quantization_config=quantization_config
)
model