大模型微调实战:LoRA 微调与显存优化
通用大模型什么都懂一点,但不懂你公司的业务。微调就是用自己的数据教它专业技能,LoRA 是性价比最高的微调方法:只训练一小部分参数,效果接近全量微调,显存和时间都省一个数量级。这篇把 LoRA 微调讲透:方法对比、原理、数据准备、训练实战、显存优化、监控、评估、部署、常见问题。
一、微调方法对比:先选对方法
| 方法 | 训练参数 | 7B 显存 | 效果 | 适用 |
|---|---|---|---|---|
| 全量微调 | 100% | 60GB+ | 最好 | 数据多、预算足、效果优先 |
| LoRA | 不到 1% | 24GB | 接近全量 | 通用,推荐默认 |
| QLoRA | 不到 1% | 12GB | 接近 LoRA | 显存紧张,消费级显卡 |
| Adapter | 约 1% | 24GB | 略低于 LoRA | 多任务切换 |
| Prefix Tuning | 不到 0.1% | 16GB | 一般 | 简单任务、快速验证 |
原则:数据少于 1 万条用 LoRA,数据多、预算足才考虑全量。QLoRA 是 LoRA 的省钱版:底座先 4-bit 量化再训 LoRA,24GB 显存能训 13B,效果损失很小。
二、LoRA 原理:为什么只训一点就够
LoRA 的核心思想是:微调时权重的变化量是低秩的。也就是说,不用改整个权重矩阵,只需要在旁边加两个小矩阵(A 和 B),它们的乘积就是权重变化量。训练时冻结原模型,只训 A 和 B;推理时把 A×B 加回原权重,速度不受影响。
- r(rank,秩):小矩阵的维度,16 是常用值。任务复杂可以加到 32,简单任务 8 就够。r 越大参数越多,效果越好也越容易过拟合。
- alpha:缩放系数,通常设成 r 的 2 倍(r=16 时 alpha=32)。实际学习率效果是 alpha/r 倍,别只调学习率不看 alpha。
- target_modules:LoRA 加在哪些层上。通常加在注意力层的 q_proj 和 v_proj,有时加上 k_proj、o_proj 和 MLP 层。加得越多效果越好,参数也越多。
- 合并:训完把 LoRA 权重合并回底座,得到一个完整的模型文件,部署时和普通模型一样用,不用额外加载 LoRA。
三、数据准备:质量比数量重要
[
{
"instruction": "把这段运维报错翻译成处理步骤",
"input": "FATAL ERROR: Function otb_init() cannot be called multiple times.",
"output": "该初始化函数在同一进程内被调用了两次。请检查测试平台,确认 init 只在仿真开始时调用一次,排查重复调用点。"
},
{
"instruction": "解释这个命令的作用",
"input": "nvidia-smi --query-gpu=memory.used --format=csv",
"output": "查询 GPU 的显存使用量,输出为 CSV 格式,适合脚本解析和监控采集。"
}
]
指令数据三件套:instruction(任务说明)、input(输入)、output(期望输出)。数据量不用大,几百到几千条高质量样本就能见效;数据质量差,越多越糟。
- 先人工写标杆:先人工写 100 条标杆样本,定下格式和质量标准,再用模型辅助扩写,最后人工抽查。标杆质量决定整批数据的上限。
- 清洗:去掉重复、格式错乱、答案错误的样本。数据里混进错误答案,模型会把错误学进去。
- 多样性:覆盖主要场景,别全是同一种问题。场景覆盖不全,模型在没见过的场景上表现会断崖式下跌。
- 数据版本:数据和模型版本对应,留好记录。业务变了数据要更新,模型要定期重训,没有版本记录就不知道哪版数据训出了哪版模型。
四、训练实战(LLaMA-Factory)
# 装 LLaMA-Factory
git clone https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e ".[torch,metrics]"
# 准备数据:放进 data 目录,格式是 Alpaca 式 JSON
# 在 dataset_info.json 里注册数据集
# {
# "my_ops_data": {
# "file_name": "my_ops_data.json",
# "formatting": "alpaca"
# }
# }
# 启动训练(单卡 4090,7B 模型,LoRA)
CUDA_VISIBLE_DEVICES=0 python src/train.py \
--stage sft \
--model_name_or_path Qwen/Qwen2.5-7B-Instruct \
--dataset my_ops_data \
--finetuning_type lora \
--lora_rank 16 \
--lora_alpha 32 \
--lora_target q_proj,v_proj \
--output_dir output/lora-qwen2.5-7b \
--per_device_train_batch_size 4 \
--gradient_accumulation_steps 4 \
--num_train_epochs 3 \
--learning_rate 1e-4 \
--lr_scheduler_type cosine \
--warmup_ratio 0.03 \
--bf16 True \
--logging_steps 10 \
--save_steps 100
| 超参 | 常用值 | 说明 |
|---|---|---|
| learning_rate | 1e-4 到 2e-4 | LoRA 比全量微调大一个数量级,只训一小部分参数 |
| num_train_epochs | 3 | 数据少就多跑两轮,配合验证集看,别硬跑 |
| lora_rank | 16 | 任务复杂加到 32,简单任务 8 就够 |
| per_device_train_batch_size | 4 | 显存不够就降,用梯度累积补 |
| gradient_accumulation_steps | 4 | 等效 batch = 4 × 4 = 16 |
| warmup_ratio | 0.03 | 前 3% 的步数线性升温,防一开始 loss 炸掉 |
| lr_scheduler_type | cosine | 余弦衰减,收尾平滑 |
五、显存优化:组合拳
# 显存不够时的组合拳
# 1. 梯度检查点:拿时间换显存,重算代替存储
# --gradient_checkpointing True
# 显存省 30-50%,训练慢 20-30%
# 2. 8-bit 优化器:AdamW 换成 adamw_bnb_8bit
# 优化器状态显存省 75%,效果几乎不变
# 3. 梯度累积:batch_size 降到 2,accumulation 提到 8
# 等效大 batch,显存占用小
# 4. 量化底座:4-bit 量化加载底座再训 LoRA(QLoRA)
# 24GB 显存能训 13B,消费级显卡也能玩
# 5. Flash Attention:注意力计算优化
# 显存和速度都受益,长上下文必开
# 显存估算(7B LoRA,BF16)
# 权重 14GB + LoRA 参数 0.1GB + 梯度 0.1GB
# + 优化器状态(8-bit)约 2GB + 激活(看序列长度和 batch)
# 总计约 20GB 左右,24GB 的 4090 刚好能跑
# 看训练时的显存占用
nvidia-smi --query-gpu=memory.used,memory.total --format=csv -l 2
六、训练监控:loss 曲线会说话
- loss 正常下降:前几十步快速下降,之后缓慢下降,最后趋平。loss 不降先看学习率是不是太小,loss 炸掉先看学习率是不是太大。
- 过拟合判断:训练 loss 一直降,验证 loss 开始升,就是过拟合了。数据少、epoch 多容易过拟合,解决办法是加数据、降 epoch、加 dropout。
- checkpoint:每 100 步存一个 checkpoint,训坏了能回滚。别只存最后一个,中间某个 checkpoint 可能效果最好。
- 监控工具:接 W&B 或者 TensorBoard,loss 曲线、学习率、显存占用都能看,出了问题第一时间发现。
七、评估:能不能上线,评估说了算
- 评估集设计:准备 100 到 200 条测试问题,覆盖主要场景,人工写标准答案。评估集和训练集不能重叠,重叠了等于开卷考试。
- 对比基线:微调前后都跑一遍评估集,看准确率和格式遵守率提升了多少。只看微调后的分数没有意义,要看提升。
- 人工评测:自动指标只能看格式和关键词,语义对不对要人工看。抽 50 条人工打分,通过率 90% 以上再上线。
- A/B 测试:上线后先切 10% 流量到新模型,对比用户反馈,没问题再全量。
八、合并与部署
# 合并 LoRA 权重回底座(LLaMA-Factory)
python src/export_model.py \
--model_name_or_path Qwen/Qwen2.5-7B-Instruct \
--adapter_name_or_path output/lora-qwen2.5-7b \
--template qwen \
--finetuning_type lora \
--export_dir output/merged-qwen2.5-7b \
--export_size 5 \
--export_device cpu
# 部署:用 vLLM 跑合并后的模型
python -m vllm.entrypoints.openai.api_server \
--model output/merged-qwen2.5-7b \
--gpu-memory-utilization 0.9 \
--port 8000
# 多 LoRA 切换:不合并也行,vLLM 支持动态加载多个 LoRA
# --enable-lora --max-lora-rank 16 --lora-modules ops=output/lora-qwen2.5-7b
# 一个底座挂多个 LoRA,按请求切换,省显存
九、常见问题
- loss 不降:先看学习率,再看数据格式是不是对的,最后看模型是不是加载错了。数据格式错是最常见的,Alpaca 格式的字段名错一个字,训练就白跑。
- 灾难性遗忘:新技能学会了,旧本事忘了。解决办法是训练数据里混一部分通用数据,或者降低学习率、减少 epoch。
- 格式漂移:微调后模型输出格式乱了,不按要求的格式回。原因是训练数据格式不统一,先统一格式再训。
- 过拟合:训练集上表现很好,测试集上很差。加数据、降 epoch、加 dropout、早停,四招一起上。
微调就三句话:数据质量决定上限,LoRA 决定成本,评估决定能不能上线。先小规模验证,再放大投入,别一上来就全量训大模型。
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。






