在消费级 GPU 上微调 LLM:QLoRA 实用指南

发布: (2025年12月10日 GMT+8 10:20)
3 min read
原文: Dev.to

Source: Dev.to

介绍

在消费级 GPU 上微调大语言模型(LLM)现在已经可行。使用 QLoRA(量化低秩适配)可以在单块 RTX 3090(24 GB 显存)上容纳一个 7 B 模型,并在几小时内完成训练,无需任何云计算额度。

  • 量化:将模型权重从 32 位压缩到 4 位。
  • LoRA:训练小型适配层,而不是整个模型。

结果:一个通常需要约 28 GB 显存的 7 B 模型,压缩后只需约 6 GB。

硬件与系统要求

组件最低要求推荐配置
GPURTX 3090(24 GB)– 也可在 RTX 3080 上运行RTX 3090
系统内存16 GB32 GB
可用存储空间50 GB50 GB 以上
操作系统Linux/macOS/Windows(支持 CUDA)Linux

安装

pip install torch transformers peft bitsandbytes trl datasets

模型加载与量化

from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
import torch

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

model = AutoModelForCausalLM.from_pretrained(
    "mistralai/Mistral-7B-Instruct-v0.3",
    quantization_config=bnb_config,
    device_map="auto",
)

tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-Instruct-v0.3")

LoRA 配置

from peft import LoraConfig, get_peft_model

lora_config = LoraConfig(
    r=16,                     # 秩
    lora_alpha=32,            # 缩放因子
    target_modules=[
        "q_proj", "k_proj", "v_proj", "o_proj",
        "gate_proj", "up_proj", "down_proj"
    ],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)

model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# trainable params: 20,971,520 || all params: 7,261,749,248
# trainable%: 0.29%

数据集

本指南使用巴西客服对话数据集:

from datasets import load_dataset

dataset = load_dataset("RichardSakaguchiMS/brazilian-customer-service-conversations")

格式化

def format_example(example):
    return {
        "text": f"""[INST] {example['input']} [/INST]
{example['output']}"""
    }

dataset = dataset.map(format_example)

训练

from trl import SFTTrainer
from transformers import TrainingArguments

training_args = TrainingArguments(
    output_dir="./output",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    bf16=True,
    logging_steps=10,
    save_strategy="epoch",
)

trainer = SFTTrainer(
    model=model,
    train_dataset=dataset["train"],
    args=training_args,
    tokenizer=tokenizer,
    max_seq_length=2048,
    dataset_text_field="text",
)

trainer.train()

可选的显存节省

model.gradient_checkpointing_enable()   # 大约慢 20% 但节省显存

更快的注意力(若受支持)

model = AutoModelForCausalLM.from_pretrained(
    model_name,
    attn_implementation="flash_attention_2"
)

训练概览

指标数值
数据集规模10 000 条示例
轮数3
批量大小(实际)4 × 4(梯度累积)
训练时长~4 小时
峰值显存18 GB
最终损失0.82

推理

from peft import PeftModel

base_model = AutoModelForCausalLM.from_pretrained(
    "mistralai/Mistral-7B-Instruct-v0.3",
    quantization_config=bnb_config,
)

model = PeftModel.from_pretrained(base_model, "./output")

prompt = "[INST] Cliente: Quero saber do meu pedido [/INST]"
outputs = model.generate(
    tokenizer.encode(prompt, return_tensors="pt"),
    max_new_tokens=200,
)

print(tokenizer.decode(outputs[0]))

简短、领域特定的查询使用简单的提示工程即可取得良好效果。

实践技巧

  • 数据质量 比数量更重要:1 000 条高质量示例往往优于 100 000 条噪声数据。
  • 清洗:在训练前确保格式统一。
  • 学习率调整
    • 损失停滞 → 提高学习率。
    • 损失突升 → 降低学习率。
    • 损失振荡 → 降低批量大小或学习率。
  • 何时进行微调
Back to Blog

相关文章

阅读更多 »