用 LoRA 与 QLoRA 微调
微调调的是行为、不是知识。当模型懂材料却跳错舞时它是正确的工具:错的输出格式、错的语气、错的领域方言、错的拒答校准。对“懂我的文档”它是错误的工具——那是检索:RAG。
微调还是不微调
| 目标 | 用什么 |
|---|---|
| 回答我自己文档里的问题 | RAG |
| 永远输出我精确的 JSON/XML 格式 | LoRA——或语法约束解码 |
| 以一致的自家风格写作 | LoRA |
| 停止拒绝合法的领域请求 | LoRA、配谨慎的数据 |
| 流利说我的领域方言 | LoRA、上面再叠 RAG |
| 更好地推理 | 更大或更好的基座模型——调优不加智商 |
如果一条提示词或一个 schema 能做到、优先提示词或 schema。当你发现自己在每次调用粘贴同样 300 词元指令时、再调优。
LoRA 一段话讲完
冻结每个基座权重。对每个目标权重矩阵、加两个小的可训练矩阵——A(r×d)和 B(d×r)——只训练它们。更新是低秩的:
W' = W + (alpha / r) · B·A # A 是 r×d,B 是 d×r,秩 r << d
具体:d = 4096 的矩阵在秩 r = 16 下需要 2 × 4096 × 16 = 131k 个适配器参数、而不是 4096² ≈ 16.8M 个稠密参数——那张矩阵的 0.8%。整个 7–8B 模型上、适配器共 ~40–80M 参数:基座的 0.5–1%、几百 MB。那足以硬移风格和格式、因为这些行为住在强低秩方向上。
QLoRA:一张消费级卡
QLoRA 让冻结基座在训练期间保持 4-bit(NF4)量化、并以 16-bit 跑适配器。当前栈上的实用数字:7–8B 模型 QLoRA 训练在单张 24GB GPU 上;3B 在 8GB 里舒适训练。梯度检查点和分页优化器由工具处理——你提供的是预算数学:显存计算。
数据胜过一切
500–5,000 对高质量样本每次都赢 100k 对爬来的。要紧的规则:
- 一个一致的格式。 用你将来服务时用的那个确切对话模板——训练/服务模板错配毁掉整轮。
- 质量高于数量。 每对都应该是你会从模型接受的那种输出。去重;丢掉懒惰样本。
- 覆盖。 包含你希望模型拒绝或特殊处理的情形——否则它把新行为过度泛化到一切上。
- 污染检查。 确保评估问题不出现在训练数据里——否则你在给死记硬背打分。
- 保留评估集。 50–100 条你从不训练的样本、前后各评一次。
一对长什么样(多数工具消费的 messages 格式):
{"messages": [{"role": "system", "content": "You are a 1998-era equipment manual assistant."},
{"role": "user", "content": "How do I reset the service counter?"},
{"role": "assistant", "content": "Press MENU and hold for 3 seconds..."}]}
工具
| 工具 | 为什么选它 |
|---|---|
| Unsloth | 最快的单 GPU 训练器、免费社区笔记本——轻松起步 |
| Axolotl | 配置驱动、广泛的数据集格式支持、可复现配方 |
| LLaMA-Factory | GUI 加 CLI、强多语种数据集生态 |
截至本文写作三者都在积极维护:unsloth、axolotl、llama-factory。
真正要紧的超参数
按影响力排序:
- 学习率——QLoRA 的 1e-4 到 2e-4 是清醒区间;过高通常是糊掉的常见原因。
- 轮数——1–3。更多就是应声虫的来源。
- 秩 / alpha——r 8–32 配 alpha 16–32 覆盖多数行为微调;领域重的转向用更大秩。
- 上下文长度——设成你最长的真实样本、不是训练器默认。
- 批大小——单卡 QLoRA 正常在 1–8;它是吞吐旋钮、不是质量旋钮。
一轮令人失望时、先修数据、再学习率、最后秩。
时间与成本
2,000 对、3 个 epoch、7–8B 模型上的 QLoRA:预期在一张 RTX 3090/4090 级卡上 1–3 小时。那是电费、不是 API 账单、迭代最坏过一夜。这就是为什么本地微调是个爱好、不是一个采购流程。
为迭代做预算:第一轮教你数据问题、第二轮才是你留下的。
发布前评估
跑一组固定的 30–50 条提示词——含保留集——前后各一次;并排 diff 输出。然后回归检查通用聊天:经典失败是领域调优的模型用 bug 报告格式回答一切。如果通用质量掉了、用更少轮数、更低学习率、或往训练里掺 10–30% 通用指令数据。
损失曲线用于发现发散、不用于打分:训练损失应该下降并走平。仲裁者是评估套件。
导出与服务
从一个训练好的适配器出发的两条路:
- 合并——把 LoRA 以 fp16 合进基座、再转 GGUF 给 llama.cpp——论坛友好的制品:一个文件、任何引擎:模型格式、量化。
- 适配器单独保留——给 transformers/vLLM、它们在运行时加载基座 + 适配器——迭代更便宜、引擎特定。
失败模式
- 过拟合 / “应声虫”——回声你的提示词、附和一切;训练损失低、评估更差。修:更少轮数、更低学习率、更多样数据。
- 灾难性遗忘——领域技能升、通用能力降。修:掺通用数据;降学习率。
- 模板漂移——用一个对话模板训练、用另一个服务;症状是 故障排查 里的那些经典。
SFT 之后的 DPO
当格式对了但偏好不对——太啰嗦、错语气、过度拒答——在偏好对(chosen 对 rejected 回答)上跑一小轮 DPO、无需再过一遍 SFT 就调整行为。便宜、稳定、是 SFT-then-DPO 配方的标准第二阶段。