QLoRA 4bit 微调 1.5B 编码模型实战: 15015 条样本 / 4G 显存

在 RTX 3050 4G 显存上, 用 QLoRA 4bit (NF4) 微调 Qwen-Coder-1.5B-Instruct, 15015 条样本 / 102 步 / 2 epoch, A-B 提升 +69.5pp。详解训练参数、显存优化、坑点总结。

📅 2026/7/5 📂 tutorial
QLoRA微调QwenRTX 30504bit NF4

QLoRA 4bit 微调 1.5B 编码模型实战

背景

在 RTX 3050 4G 显存 (笔记本入门级) 上微调 1.5B 模型, 看似不可能:

  • 1.5B 模型 fp16 需要 3GB 显存 (仅权重)
  • 加上优化器 / 激活 / 梯度, 至少 12GB
  • 4G 显存根本跑不动

QLoRA 4bit 让这件事变成现实: 4bit 量化 + LoRA adapter, 4G 显存跑 1.5B 模型训练

核心参数

from peft import LoraConfig, get_peft_model
from transformers import BitsAndBytesConfig
from trl import SFTTrainer

# 4bit 量化配置
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",            # NF4 (NormalFloat 4-bit)
    bnb_4bit_compute_dtype=torch.float16,  # 计算用 fp16
    bnb_4bit_use_double_quant=True,       # 双量化
)

# LoRA 配置
lora_config = LoraConfig(
    r=8,                    # rank: 越大越能拟合, 但显存/速度都增
    lora_alpha=16,          # alpha = 2 * r 是惯例
    lora_dropout=0.05,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],  # 只调 attention
    bias="none",
    task_type="CAUSAL_LM",
)

训练命令

trainer = SFTTrainer(
    model=model,
    train_dataset=dataset,        # 15015 条
    peft_config=lora_config,
    args=TrainingArguments(
        per_device_train_batch_size=1,    # ★ 关键: 4G 显存只能 batch=1
        gradient_accumulation_steps=8,    # 累积 8 步 = 有效 batch 8
        max_length=256,                    # ★ 关键: 短序列省显存
        learning_rate=2e-4,                # LoRA 适合较高 LR
        num_train_epochs=2,
        fp16=True,
        save_strategy="epoch",
        logging_steps=10,
        warmup_ratio=0.03,
    ),
    data_collator=DataCollatorForLanguageModeling(tokenizer, mlm=False),
)
trainer.train()

数据准备

我的训练数据来自 38 个项目源码 + 合成 ChatML Q&A:

  • 样本数: 15015 条 (推荐 ≥ 10000, 我之前 800 条效果差)
  • 格式: ChatML
  • 长度: 平均 200 tokens, 最大 256
  • 来源: D:\llm 39 个项目源码
def format_chatml(messages):
    parts = []
    for m in messages:
        parts.append(f"<|im_start|>{m['role']}\n{m['content']}<|im_end|>\n")
    parts.append("<|im_start|>assistant\n")
    return "".join(parts)

训练过程

指标数值
总步数102
单步时间18.2s
总耗时31 分钟
峰值显存3.4GB / 4GB
最终 loss1.42 → 0.68
学习率2e-4 (cosine)

合并 + GGUF 量化

训练完的 LoRA adapter 很小 (几十 MB), 需要合并回 base 模型才能部署:

# 1. 合并 LoRA
python -m peft.merge_and_unload \
    --base_model Qwen/Qwen2.5-Coder-1.5B-Instruct \
    --adapter_path output/ \
    --output_path merged/

# 2. 转 GGUF Q4_K_M
python convert-hf-to-gguf.py merged/ --outfile qwen-coder-1.5b-q4_k_m.gguf

# 3. 量化
./llama-quantize qwen-coder-1.5b-f16.gguf qwen-coder-1.5b-q4_k_m.gguf Q4_K_M

最终模型 850MB, 在 4G 显存上能跑, CPU 也能跑 (但慢 20x)。

A/B 评估

最关键的一步: 用量化指标证明微调有效

维度基座微调后提升
关键词命中率28.5%98.0%+69.5pp
Jaccard 相似度-0.639-
平均 Token 数1,6283,016+85%
平均延迟4.2s5.1s+21%

命中率从 28.5% → 98.0%, 证明微调后模型完全”吸收”了私域代码库知识。

踩过的坑

  1. OOM 在 batch_size: 默认 per_device_train_batch_size=8 在 4G 显存直接 OOM, 必须显式传 =1
  2. 多模型加载显存碎片: 训练完再启动 8013 服务时 GPU 内存被占, 需 torch.cuda.empty_cache()
  3. max_length 默认 512: 我的数据平均 200, 显式传 =256 显存直接省一半
  4. 量化类型选 NF4: 比 FP4 训练稳定, loss 收敛更快
  5. 样本量: 800 条训练后命中率从 49% 降到 40% (欠拟合 + 过拟合), 15000 条才能真正学到

写在最后

QLoRA 是 4G 显存的救星。但要量化效果, 不能靠”感觉”, 必须 A/B 测试。

面试经常被问”你微调过什么模型”, 答这一套: 1.5B / 15015 样本 / +69.5pp, 面试官立刻知道你是真干过。

完整代码

🔗 相关项目

📖 相关文章

tutorial

QLoRA 微调 RTX 3050 4GB 也能跑 - 完整实战指南

QLoRA 微调 RTX 3050 4GB 也能跑 - 完整实战指南 TL;DR - 主题 - QLoRA 微调 RTX 3050 4GB 也能跑 - 技术栈 - Python 3.10+ / PyTorch / Transformers / PEFT - 难度 - 中级 - 高级 - 阅读时长 - 8-12 分钟 - 可运行 -

tutorial

QLoRA 微调技术 - 完整实战指南

QLoRA 微调技术 - 完整实战指南 TL;DR - 主题 - QLoRA 微调技术 - 技术栈 - Python 3.10+ / PyTorch / Transformers / PEFT - 难度 - 中级 - 高级 - 阅读时长 - 8-12 分钟 - 可运行 - 全部代码均已验证 前言 最近 "QLoRA 微调

🤖

人工智能AI大模型智能体应用交流群

1000+ 人在线 · 长沙 AI 工程师聚集地

+ 988+

🎁 群里 1000+ 人在聊这些:

  • 🚀 开源项目源码 · D:\llm 38 个项目持续更新
  • 💼 AI 工程师内推 · 长沙 / 远程 / 大厂机会
  • 📚 学习路线 / 资料 · LLM/RAG/Agent 全套
  • 🛠️ 踩坑分享 · 微调 / 部署 / 性能调优
  • 🎁 每周精选 · 实战资料 / 论文 / 工具
💬 立即加入 QQ 群 群号 306671879 · 5 秒加入

链接打不开? 直接搜群号 306671879

💬
AI 全栈交流群
1000+ 人在线 · 长沙
立即加入