微调实操:LoRA/QLoRA 单卡跑通、参数选择、过拟合判断
硬件前提
- QLoRA(4bit 底座 + LoRA):单卡 12~16GB 可训 7B,24GB 舒服
- LoRA(FP16 底座):7B 需要 24GB 以上
- 数据准备已在上一篇完成,这一步只需要算力与时间
先确认可用显存:nvidia-smi。训练前把显存预算写下来:底座权重 + LoRA 参数 + 优化器状态 + 激活值(随 batch 与序列长度增长)。爆显存几乎总是最后一项。
先确认该不该微调
| 需求 | 该用 |
|---|---|
| 补知识、要出处 | RAG(别微调) |
| 稳定格式、字段、话术、风格 | LoRA 微调 |
| 提升推理能力 | 微调帮助有限,先改提示与流程 |
| 私有数据完全不能出内网 | 自托管 + 微调 |
跑通流程(用现成训练框架,别自己写循环)
LLaMA-Factory、unsloth、PEFT + Transformers Trainer 都能做。第一次的目标是跑通,不是训好:
- 数据:
train.jsonl/val.jsonl(格式见上一篇) - 底座:选一个指令模型,别选基座
- 配置起点(7B / QLoRA):
| 参数 | 起点 | 说明 |
|---|---|---|
| 量化 | 4bit | QLoRA 的前提 |
LoRA r | 8~16 | 容量太小学不动,太大易过拟合;先 8 |
alpha | 2×r | 常见配比 |
| target modules | 全部线性层(q/k/v/o + mlp) | 只训 attention 效果常不够 |
| learning rate | 1e-4 ~ 2e-4 | LoRA 的典型区间;全参微调要小一个数量级 |
| epochs | 2~3 | 超过 3 轮先看是否过拟合 |
| batch size | 显存允许下尽量大 | 不够就 gradient accumulation 补 |
| max length | 按数据实际长度设 | 直接决定显存 |
| 优化器 | AdamW + warmup 3%~5% | 没有悬念 |
- 先跑 100 步看 loss 是否下降、显存是否稳定,再跑完整训练。
显存不够的降级顺序
- 减
max length(最有效) - 减 batch size + 加 gradient accumulation
- 底座换 4bit(QLoRA)
- 减 LoRA
r与 target modules - 换更小的底座模型
怎么判断训好了
必须有一组「业务评测集」(几十到几百条,带期望输出),训练前后各跑一遍。只看训练 loss 是最常见的自欺。
| 信号 | 含义 | 处理 |
|---|---|---|
| 训练 loss 降、验证 loss 也降 | 正常 | 继续 |
| 训练 loss 降、验证 loss 升 | 过拟合 | 减 epochs、减 r、加数据 |
| 业务集变好,但通用任务变差 | 灾难性遗忘 | 降 lr、混入 5%~10% 通用数据、减 epochs |
| 输出过度套模板 | 数据格式太单一 | 增加输入多样性、加「不需要该格式」的样本 |
| 分数没变 | 数据太少/太脏,或任务本来就该用 RAG | 回到数据那一步 |
遗忘探针:固定 20 道通用题(简单算术、常识、代码),每次训练后跑。这是发现「训傻了」最便宜的办法。
常见失败与排查
| 现象 | 原因 | 处理 |
|---|---|---|
| 一开始就 OOM | 序列长度/batch 太大 | 按上面的降级顺序 |
| loss 不降 | 数据格式错、lr 太小、system 不一致 | 先检查 10 条样本的拼接结果 |
| loss NaN | lr 太大、精度问题 | 降 lr、开梯度裁剪 |
| 输出乱码/复读 | 数据里有坏样本 | 重跑格式与去重校验 |
| 换底座就白训 | LoRA 与底座绑定 | 记录底座版本,底座升级需重训 |
| 效果无法复现 | 没固定 seed 与数据版本 | 数据、提示、配置全部版本化 |
完成标志
- 一个可复现的训练配置(含 seed、数据版本号);
- 训练前后在同一业务集上的分数对比;
- 遗忘探针分数没有明显下降。
三条齐了才叫「微调成功」,否则只是「跑完了一次训练」。