运营上周提了个需求。客服机器人要能答一批内部产品术语,通用模型答得含糊。想全量微调,一算显存就放弃了,6B 的模型全参训练,优化器状态加梯度缓存,80GB 的卡都紧张。最后用 LoRA 在单卡 24GB 上跑通。从装环境到出第一个 adapter 用了两天,大头全在排错。这篇把配置和三个坑整理出来,照着走能少绕路。
先给结论
| 方案 | 可训练参数占比 | 显存占用(6B,bf16) | 适用场景 |
|---|---|---|---|
| 全量微调 | 100% | 80GB 起,需多卡 | 预算充足,追求极限 |
| LoRA | 1%~2% | 16~22GB | 通用指令微调,性价比首选 |
| QLoRA | 1%~2%(基座 4bit) | 10~14GB | 消费级显卡 |
QLoRA 会略微增加推理延迟。快速验证领域适配效果时,LoRA 更划算。
环境先锁版本
微调代码死于版本不兼容的,比死于调参的多。transformers、peft、torch 三者的接口一直在动,老代码在新环境里经常直接报错。我锁的组合是 torch 2.1.2、transformers 4.38、peft 0.8,装完先跑一行确认 CUDA 可用,再往下走。
基座模型要单独跑通一次推理。ChatGLM 这类模型需要 trust_remote_code=True,模型结构和特殊 token 都在官方远程脚本里定义,缺了这个参数加载直接失败。推理用 bf16,fp16 在小数值上容易溢出,生成会出乱码。
三个真实的坑
坑一,target_modules 配错是静默失败。 ChatGLM 的注意力层把 Q、K、V 合在一个线性层里,名字是 query_key_value。照网上 Llama 的写法填 q_proj、v_proj,PEFT 找不到目标层,不报错,照样开训,只是什么都没学。跑训练前先看 print_trainable_parameters() 的输出,可训练参数占比应该在 1% 上下,打印出来是 0 就回头查配置。
坑二,padding 的标签没置 -100。 症状是 loss 长期降不动,曲线来回震荡。Trainer 默认对所有 token 算交叉熵,padding 位置要手动设成 -100 让损失计算跳过。这个坑在数据预处理阶段埋下,很多人以为是学习率的问题,往小调了半天没效果。
坑三,训练几百步后 OOM。 显存曲线本来平稳,某一步突然跳涨爆掉。排查下来是 DataLoader 的 num_workers 大于 0,子进程共享 CUDA context,collate 时产生隐式显存拷贝,攒到阈值就爆。处理顺序是先设 num_workers=0 验证归因,再开 pin_memory 和 persistent_workers。手动 empty_cache() 只能临时腾出一点空间,稳当的做法是检查张量生命周期,别让它们跨 batch 泄漏。
训练参数这么设
| 参数 | 取值 | 说明 |
|---|---|---|
| per_device_train_batch_size | 2 | 显存吃紧时先动它 |
| gradient_accumulation_steps | 8 | 等效 batch 16,不增加峰值显存 |
| learning_rate | 2e-4 | LoRA 用比全量大一档的 lr |
| r / lora_alpha | 8 / 16 | alpha 取 r 的两倍 |
| gradient_checkpointing | true | 峰值再降 20%~30%,训练时间加 15% |
我用 24GB 卡、等效 batch 16,峰值显存 19.3GB。梯度累积是关键,它把峰值压在单个 micro batch 上,显存不够就加累积步数,慢一点但能跑。
数据量少于 2000 条时,max_steps 控制在 1000 以内,调度器换 linear,防止后期把参数拖进平坦区。
训练完怎么部署
产物是 adapter_model.bin,只有几十 MB,两种用法。
动态挂载走 PeftModel.from_pretrained,基座不动,随时换 adapter,适合灰度和多任务切换。合并走 merge_and_unload(),把 LoRA 权重算回基座,推理快 5%~8%。合并时 dtype 要和训练时一致,bf16 训的就 bf16 存,强转 fp32 会放大量化误差。
结合系列
- 训练前后的显存估算和量化版本选型,见《模型量化部署实战》
- 微调数据里的 JSON 类输出,先过结构化校验再进训练集,见《结构化输出实战》
- LoRA 和 prompt 模板是绑定的,换模板等于换任务,上线策略参考《Prompt 管理实战》
- 微调效果好不好,要和通用模型跑同口径评测,见《LLM 评测》篇
写在最后。LoRA 本身是成熟技术,时间都花在周边工程细节上。版本对齐、标签掩码、显存峰值,每一处都能让训练白跑。开跑前逐项过一遍,省下的都是排查的时间。
下一篇写 RAG 和微调混合的实践,检索召回为主,模型训练为辅。觉得有用的话点个关注,有问题评论区聊。
参考《从零开始大模型微调(基于 PyTorch 与 ChatGLM 的 LoRA 实践)》,作者 打工仔折腾 AI。结构借鉴,配置和数据结论经过独立验证。