2. QLoRA微调LLaMA-7B
任务目标
本案例使用 bitsandbytes 将 LLaMA-7B 模型量化为 4-bit NF4(NormalFloat4)格式,并基于 QLoRA 方法在对话数据集上完成微调,最终验证模型在对话生成任务上的效果。核心目标是跑通“4-bit 量化 → QLoRA 微调 → 对话生成测试”的完整闭环。
环境与依赖
需要以下环境(建议使用支持 CUDA 的 GPU,显存 ≥ 10GB):
- Python 3.10+
- PyTorch 2.0+(CUDA 11.8 或更高)
transformers≥ 4.35.0peft≥ 0.7.0bitsandbytes≥ 0.41.0datasets≥ 2.14.0accelerate≥ 0.25.0
安装命令:pip install torch transformers peft bitsandbytes datasets accelerate
实现代码
以下代码完整实现了 4-bit NF4 量化加载、QLoRA 配置与微调、以及微调后的对话生成测试。数据集使用 datasets 库内置的 HuggingFaceH4/ultrachat_200k 的子集(取前 500 条用于演示),训练 1 个 epoch。
import torch
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
TrainingArguments,
Trainer,
DataCollatorForLanguageModeling
)
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from datasets import load_dataset
# ========== 1. 4-bit NF4 量化配置 ==========
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True,
bnb_4bit_compute_dtype=torch.bfloat16
)
# ========== 2. 加载模型与分词器 ==========
model_name = "huggyllama/llama-7b" # 使用可公开访问的 LLaMA-7B 权重
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_ = tokenizer.eos_
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto",
trust_remote_code=True
)
# ========== 3. 准备 QLoRA 训练 ==========
model = prepare_model_for_kbit_training(model)
lora_config = LoraConfig(
r=8,
lora_alpha=16,
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)
# ========== 4. 加载并预处理对话数据集 ==========
dataset = load_dataset("HuggingFaceH4/ultrachat_200k", split="train[:500]")
def format_chat(example):
# 将对话格式化为单轮指令-回复文本
messages = example["messages"]
user_msgs = [m["content"] for m in messages if m["role"] == "user"]
assistant_msgs = [m["content"] for m in messages if m["role"] == "assistant"]
if not user_msgs or not assistant_msgs:
return {"text": ""}
# 取第一轮对话作为训练样本
text = f"User: {user_msgs[0]}\nAssistant: {assistant_msgs[0]}{tokenizer.eos_}"
return {"text": text}
dataset = dataset.map(format_chat, remove_columns=dataset.column_names)
dataset = dataset.filter(lambda x: len(x["text"]) > 0)
def tokenize_function(examples):
return tokenizer(examples["text"], truncation=True, max_length=512)
tokenized_dataset = dataset.map(tokenize_function, batched=True, remove_columns=["text"])
# ========== 5. 训练配置与执行 ==========
training_args = TrainingArguments(
output_dir="./qlora-llama7b-checkpoints",
per_device_train_batch_size=1,
gradient_accumulation_steps=8,
num_train_epochs=1,
learning_rate=2e-4,
fp16=True,
logging_steps=10,
save_steps=100,
report_to=[],
remove_unused_columns=False
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset,
data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
)
trainer.train()
# ========== 6. 保存微调后的模型 ==========
model.save_pretrained("./qlora-llama7b-lora")
tokenizer.save_pretrained("./qlora-llama7b-lora")
# ========== 7. 对话生成测试 ==========
def generate_response(prompt, max_new_tokens=100):
model.eval()
inputs = tokenizer(f"User: {prompt}\nAssistant:", return_tensors="pt").to(model.device)
with torch.no_grad():
outputs = model.generate(
**inputs,
max_new_tokens=max_new_tokens,
do_sample=True,
temperature=0.7,
top_p=0.9,
pad__id=tokenizer.eos__id
)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
# 提取 Assistant 部分
if "Assistant:" in response:
response = response.split("Assistant:", 1)[1].strip()
return response
# 测试示例
test_prompts = [
"What is the capital of France?",
"Explain quantum computing in simple terms."
]
for prompt in test_prompts:
print(f"Prompt: {prompt}")
print(f"Response: {generate_response(prompt)}")
print("-" * 50)
运行方式
- 将上述代码保存为
qlora_llama7b.py。 - 在 GPU 环境下执行:
python qlora_llama7b.py。 - 首次运行会自动下载模型权重(约 13GB,需网络连接),训练过程约需 10-20 分钟(取决于 GPU 性能)。
验证方法与通过标准
- 训练日志检查:训练过程中 loss 应逐步下降(例如从 2.0 左右降至 1.0 以下),且无 NaN 或报错。
- 模型保存检查:训练完成后,
./qlora-llama7b-lora目录下应包含adapter_config.json和adapter_model.bin文件。 - 生成质量测试:运行脚本末尾的测试提示词,观察输出。通过标准为:模型能生成与提示词相关的、语法通顺的英文回复(例如对 “What is the capital of France?” 应回答 “Paris” 或包含 Paris 的完整句子)。
- 显存占用验证:训练时显存占用应低于 10GB(4-bit 量化后约 6-8GB),若显存溢出则说明量化未生效或 batch size 过大。
常见问题
- 模型下载失败:若无法访问
huggyllama/llama-7b,可替换为其他 LLaMA-7B 镜像(如decapoda-research/llama-7b-hf),但需确认该仓库允许访问。 - bitsandbytes 不支持当前 GPU:需 CUDA 11.8+ 且 GPU 算力 ≥ 7.5(如 RTX 30/40 系列)。
- 训练 loss 不下降:检查学习率是否过大(建议 1e-4 至 3e-4),或数据集预处理是否正确(确认
text字段非空)。