无显卡也能微调大模型:Qwen3-0.6B + QLoRA 低配实战全记录
无显卡也能微调大模型:Qwen3-0.6B + QLoRA 低配实战全记录
摘要:本文记录了一台无独显、仅8~16GB内存的Windows电脑,从零开始完成Qwen3-0.6B大模型QLoRA微调的完整过程。涵盖环境配置、数据准备、CPU训练脚本、推理验证、常见误区澄清,以及"原模型是否被修改"的核心原理解析。适合所有想入门大模型微调但硬件有限的开发者参考。
标签:大模型微调 QLoRA Qwen3 低配电脑 CPU训练 Peft 博客园实战
一、写在前面:为什么要写这篇
大模型微调的教程遍地都是,但绝大多数默认你有一张A100或者至少24GB显存的卡。对于一个只有核显、8~16GB内存的普通Windows电脑用户来说,那些教程看完只能叹气。
这篇博客的目的很单纯:证明一件事——你不需要高端显卡,也能跑通大模型微调的完整流程,并真正理解它在干什么。
我会用一台无独显的机器 + 本地已有的 Qwen3-0.6B 模型,走完从环境搭建到训练、推理、合并的全流程。所有代码可直接复制运行。
二、我的硬件与环境
| 项目 | 配置 |
|---|---|
| 系统 | Windows 11 |
| CPU | 无独显(核显) |
| 内存 | 8~16GB |
| Python | 3.14(默认 C:\Python314\python.exe) |
| 模型 | 本地 D:\models\Qwen3-0.6B-Instruct |
| 训练数据 | 约100~300条 Alpaca 格式 |
Python 环境确认
Windows 下确认默认 Python:
where python
输出类似:
C:\Python314\python.exe
C:\Users\xxx\AppData\Local\Microsoft\WindowsApps\python.exe
排在第一行的就是默认解释器。 后续所有 python 命令都走这一个,避免环境混乱。
验证版本:
python --version
验证 PyTorch 是否可用(CPU 模式):
python -c "import torch; print(torch.__version__)"
三、核心结论先给:原模型不会被修改
这是整个过程中最容易误解、也最关键的一点。
训练完成后,你本地 D:\models\Qwen3-0.6B-Instruct\model.safetensors 文件原封不动,没有任何修改。
QLoRA 的训练机制决定了这一点:
最终权重 = 原始权重(全程冻结) + 低秩矩阵 A × B(仅训练这部分)
训练过程只产生一个新的、体积很小的 LoRA 适配器目录:
D:\qwen_lora\qwen3_lora_output\
├── adapter_config.json # LoRA 配置
├── adapter_model.safetensors # LoRA 权重(通常几 MB ~ 几十 MB)
├── tokenizer.json
├── tokenizer_config.json
└── special_tokens_map.json
形象类比:
- 原始模型 = 一本印刷好的教科书
- LoRA 权重 = 你在书页边缘写的笔记
- 推理 = 一边看书,一边参考笔记
写了笔记,书本身没有被涂改。删掉 LoRA 目录,模型立刻恢复原样。
四、环境准备
安装依赖
CPU 模式不需要 bitsandbytes(那是 GPU 4-bit 量化用的),也不需要 trl(除非做 DPO)。只装最小集:
python -m pip install --upgrade pip
python -m pip install torch transformers peft datasets accelerate
目录结构
建议按以下结构组织,路径清晰不容易出错:
D:\qwen_lora\
├── train_qlora_cpu.py # 训练脚本
├── train_data.json # 训练数据
└── qwen3_lora_output\ # 训练后自动生成
D:\models\
└── Qwen3-0.6B-Instruct\ # 原始模型(只读)
├── model.safetensors
├── config.json
├── tokenizer.json
└── ...
五、训练数据:Alpaca 格式
train_data.json,每行一条 JSON,无需表头:
{"instruction": "你是一个礼貌的中文客服助手,请简洁回复", "input": "我的快递三天没动了", "output": "非常抱歉给您带来不便,我帮您查询一下物流状态,请稍等。"}
{"instruction": "请总结以下文本的核心观点", "input": "人工智能正在改变医疗、教育和交通行业,提高了效率但也带来隐私挑战。", "output": "AI正在深刻影响医疗、教育和交通,效率提升的同时也带来隐私问题。"}
{"instruction": "将以下句子翻译成英文", "input": "今天天气很好,我们去公园散步吧。", "output": "The weather is nice today. Let's go for a walk in the park."}
{"instruction": "判断下列评论的情感倾向并给出理由", "input": "这家餐厅的服务态度极差,等了一个小时才上菜。", "output": "负面情感。理由是顾客抱怨服务态度差和等待时间过长,表达了明显的不满。"}
字段说明:
instruction(必填):任务指令,定义模型要做什么input(可空):附加输入内容output(必填):标准答案
数据质量 > 数据数量。100条高质量数据远胜1000条垃圾数据。格式统一、覆盖多样场景、留20%做测试集,是基本要求。
六、完整训练脚本(CPU 低显存优化版)
保存为 D:\qwen_lora\train_qlora_cpu.py。
使用前只需改两个路径:MODEL_PATH 和 DATA_PATH。
"""
Qwen3-0.6B + QLoRA 微调脚本(CPU / 低显存优化版)
适用:无独显、8~16GB 内存、Windows
"""
import torch
from datasets import load_dataset
from transformers import (
AutoTokenizer,
AutoModelForCausalLM,
TrainingArguments,
Trainer,
DataCollatorForSeq2Seq,
)
from peft import LoraConfig, get_peft_model, TaskType
# ============================================================
# 【必改】路径配置
# ============================================================
MODEL_PATH = r"D:\models\Qwen3-0.6B-Instruct" # ← 改为你的模型路径
DATA_PATH = r"D:\qwen_lora\train_data.json"
OUTPUT_DIR = r"D:\qwen_lora\qwen3_lora_output"
# ============================================================
# 训练超参(CPU 已调小)
# ============================================================
NUM_EPOCHS = 3
LEARNING_RATE = 1e-4
PER_DEVICE_BATCH_SIZE = 1
GRADIENT_ACCUMULATION_STEPS = 4
MAX_SEQ_LENGTH = 512 # CPU 不宜过大
# LoRA 参数(0.6B 模型很小,rank 不用大)
LORA_R = 8
LORA_ALPHA = 16
LORA_DROPOUT = 0.05
def main():
# ---------- 1. Tokenizer ----------
tokenizer = AutoTokenizer.from_pretrained(
MODEL_PATH, trust_remote_code=True,
)
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
# ---------- 2. 模型(CPU 模式)----------
model = AutoModelForCausalLM.from_pretrained(
MODEL_PATH,
trust_remote_code=True,
torch_dtype=torch.float32, # CPU 用 float32 最稳
device_map=None, # CPU 不要 device_map
)
# ---------- 3. LoRA 配置 ----------
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=LORA_R,
lora_alpha=LORA_ALPHA,
lora_dropout=LORA_DROPOUT,
target_modules="all-linear",
bias="none",
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters() # 打印可训练参数量
# ---------- 4. 数据预处理 ----------
dataset = load_dataset("json", data_files=DATA_PATH, split="train")
def format_example(example):
"""Alpaca → Chat 格式"""
content = example.get("instruction", "")
if example.get("input"):
content += "\n" + example["input"]
messages = [{"role": "user", "content": content}]
if example.get("output"):
messages.append({"role": "assistant", "content": example["output"]})
text = tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=False,
)
return {"text": text}
dataset = dataset.map(format_example, remove_columns=dataset.column_names)
def tokenize_fn(examples):
return tokenizer(
examples["text"],
max_length=MAX_SEQ_LENGTH,
truncation=True,
padding=False,
)
tokenized = dataset.map(tokenize_fn, batched=True)
# ---------- 5. 训练参数 ----------
training_args = TrainingArguments(
output_dir=OUTPUT_DIR,
num_train_epochs=NUM_EPOCHS,
per_device_train_batch_size=PER_DEVICE_BATCH_SIZE,
gradient_accumulation_steps=GRADIENT_ACCUMULATION_STEPS,
learning_rate=LEARNING_RATE,
lr_scheduler_type="linear",
warmup_ratio=0.05,
logging_steps=5,
save_strategy="epoch",
fp16=False,
bf16=False,
gradient_checkpointing=True, # 省内存
use_cpu=True, # 强制 CPU
report_to="none",
)
# ---------- 6. 训练 ----------
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized,
data_collator=DataCollatorForSeq2Seq(
tokenizer=tokenizer, padding=True, return_tensors="pt",
),
)
trainer.train()
# ---------- 7. 保存 ----------
model.save_pretrained(OUTPUT_DIR)
tokenizer.save_pretrained(OUTPUT_DIR)
print(f"✅ 训练完成,LoRA 权重已保存到: {OUTPUT_DIR}")
if __name__ == "__main__":
main()
启动训练
cd /d D:\qwen_lora
python train_qlora_cpu.py
CPU 训练速度参考
| 内存 | 100条数据 / 3 epoch | 说明 |
|---|---|---|
| 8GB | 30~60 分钟 | 能跑,关闭其他程序 |
| 16GB | 15~30 分钟 | 比较稳定 |
七、推理验证:加载 LoRA 看效果
训练完成后,用以下脚本验证 LoRA 是否生效:
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import PeftModel
# 加载原始模型(原文件,未被修改)
base = AutoModelForCausalLM.from_pretrained(
r"D:\models\Qwen3-0.6B-Instruct",
torch_dtype=torch.float32,
trust_remote_code=True,
)
tok = AutoTokenizer.from_pretrained(r"D:\models\Qwen3-0.6B-Instruct")
# 叠加 LoRA 适配器
model = PeftModel.from_pretrained(base, r"D:\qwen_lora\qwen3_lora_output")
model.eval()
# 测试
messages = [{"role": "user", "content": "我的快递三天没动了,怎么办?"}]
inputs = tok.apply_chat_template(messages, return_tensors="pt")
with torch.no_grad():
out = model.generate(inputs, max_new_tokens=128)
print(tok.decode(out[0], skip_special_tokens=True))
对比方法:分别用「原始模型」和「LoRA 模型」回答同一个问题,差异就是微调效果。
八、进阶:合并 LoRA 为独立模型
如果想把 LoRA 合并进原模型,生成一个可以单独部署的完整模型文件:
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
import torch
base = AutoModelForCausalLM.from_pretrained(
r"D:\models\Qwen3-0.6B-Instruct",
torch_dtype=torch.float32,
trust_remote_code=True,
)
model = PeftModel.from_pretrained(base, r"D:\qwen_lora\qwen3_lora_output")
model = model.merge_and_unload() # 合并
model.save_pretrained(r"D:\qwen_lora\qwen3_merged")
tok = AutoTokenizer.from_pretrained(r"D:\models\Qwen3-0.6B-Instruct")
tok.save_pretrained(r"D:\qwen_lora\qwen3_merged")
print("✅ 合并完成,输出目录: D:\qwen_lora\qwen3_merged")
⚠️ 合并会生成一个新目录,原模型仍然不动。合并后模型体积 ≈ 原模型大小(0.6B 约 1.2GB)。
九、常见误区与排坑
| 误区 | 真相 |
|---|---|
| 训练会修改原模型文件 | ❌ 原模型全程只读,只生成 LoRA 补丁 |
| CPU 不能微调大模型 | ✅ 0.6B + LoRA 完全可行,只是慢 |
| 需要很多数据才能微调 | ❌ 100~300 条高质量数据就能看到效果 |
| LoRA 和全量微调效果一样 | ❌ LoRA 参数量少,上限低于全量,但性价比极高 |
| 微调能记住新知识 | ❌ 微调擅长改风格/格式,灌知识用 RAG |
| Python 版本越新越好 | ⚠️ 3.14 太新,部分库兼容性滞后,3.11 最稳 |
十、小结
走完这一遍,你应该建立了以下认知:
- 微调 ≠ 修改原模型,而是生成一份轻量补丁(LoRA)
- 低配电脑完全能跑通,0.6B 是入门最佳尺寸
- 数据质量远比数量重要,格式统一、场景多样是关键
- CPU 训练慢但可行,适合学习和验证流程
- 同一份原模型可以挂多个 LoRA,分别对应不同任务
下一步可以探索的方向:
- 用更多数据训练不同任务(客服话术、摘要、翻译)
- 尝试 DPO 偏好对齐优化语气
- 合并后用 Ollama 本地部署
- 有条件时升级 GPU,体验全量微调和更大模型
大模型微调的门槛,远比你想象的低。
附录:完整文件清单
| 文件 | 用途 |
|---|---|
train_qlora_cpu.py |
QLoRA 训练脚本(CPU 优化) |
train_data.json |
Alpaca 格式训练数据 |
qwen3_lora_output/ |
训练产物(LoRA 适配器) |
qwen3_merged/(可选) |
合并后的完整模型 |
如果这篇博客帮到了你,欢迎转发。有任何问题欢迎在评论区交流。

浙公网安备 33010602011771号