LoRA微调需确保模型支持PEFT、正确配置target_modules、验证梯度更新并规范推理部署;关键步骤包括检查nn.Linear层、使用正则匹配线性模块、设置合理超参、调用print_trainable_parameters验证、merge_and_unload导出或set_adapter热切换。

微调 LLaMA 类模型不推荐直接全参数训练——显存炸、速度慢、容易过拟合;用 PEFT + LoRA 是当前最可行的轻量方案,但关键不在“能不能跑”,而在“怎么让 LoRA 真正生效且不破坏原始推理行为”。
确认模型是否支持 PEFT 的 LoRA 注入
不是所有 LLaMA 变体都开箱即用。Hugging Face 的 LlamaForCausalLM(如 meta-llama/Llama-2-7b-hf)支持,但社区魔改版(比如某些 llama.cpp 适配或自定义 forward 的 fork)可能跳过 nn.Linear 层,导致 peft.get_peft_model 静默失败。
- 检查模型中关键模块是否为标准
nn.Linear:model.model.layers[0].self_attn.q_proj、v_proj、o_proj、up_proj、down_proj等必须是torch.nn.Linear实例,否则LoRAConfig中的target_modules会匹配不到 - 用
print(type(model.model.layers[0].self_attn.q_proj))快速验证;若输出类似<class></class>,说明该模块被替换过,需手动 patch 或换回官方 HF 版本 -
transformers >= 4.35和peft >= 0.7.0是底线版本,低版本对Llama-2的qkv分离结构支持不完整
LoRA 配置里 target_modules 别硬写 "q_proj,v_proj" 就完事
LLaMA-2 的注意力层实际把 Q/K/V 合并在一个 q_proj 后接 k_proj 和 v_proj,但不同 tokenizer 或模型变体命名略有差异;盲目指定会导致部分权重没被注入,训练时梯度不更新,loss 下降但生成质量无提升。
- 推荐用正则自动发现:
target_modules = ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"]—— 这是 LLaMA-2 官方结构的全部线性层 - 若用的是
Llama-3,注意新增了lm_head,但通常不建议对它加 LoRA(会干扰 logits 分布),除非你明确要做指令微调中的分类头对齐 -
r=8、lora_alpha=16、lora_dropout=0.05是较稳起点;r=64在 7B 模型上已接近全参微调显存占用,没必要
训练时 model.train() 不等于 LoRA 参数在更新
PEFT 默认冻结 base model,只训练 LoRA 的 A/B 矩阵;但如果误调用了 model.base_model.model.train() 或漏掉 model.enable_input_require_grads()(尤其在使用 DeepSpeed 或自定义梯度逻辑时),会出现 loss 下降但 lora_A 的梯度为 0 的现象。
立即学习“Python免费学习笔记(深入)”;
- 务必用
model.print_trainable_parameters()—— 正常输出应类似trainable params: 3,932,160 || all params: 3,195,492,352 || trainable%: 0.123;若显示0或远低于预期,说明 LoRA 没挂上 - 使用
Trainer时,确保model = get_peft_model(model, peft_config)在Trainer初始化之前完成,且不要在data_collator或compute_loss中重新 wrap 模型 - 如果用了
gradient_checkpointing=True,必须同时设model.gradient_checkpointing_enable(),否则反向传播时 LoRA 梯度会断掉
推理时别忘了 merge_and_unload 或 set_adapter
训练完的 PeftModel 不能直接拿去 generate——它默认走 LoRA 路径,但没做权重融合;而直接 model.merge_and_unload() 又会丢失原始 base 权重的可复用性。
- 部署阶段推荐保留 adapter:用
model.set_adapter("default")切换,再调model.generate(...);这样多个 LoRA adapter 可热切换,适合 A/B 测试不同微调任务 - 若要导出纯 HF 格式供其他框架加载,必须先
model = model.merge_and_unload(),再model.save_pretrained("merged_model");否则保存的是 PEFT 配置 + delta,非标准 checkpoint - 合并后务必用
torch.allclose(base_model_output, merged_model_output)对比相同输入的 logits,验证 merge 是否正确;常见错误是merge_and_unload后没model.eval(),导致 dropout 影响输出
LoRA 微调真正难的不是跑通代码,而是判断哪些层该加、哪些不该加,以及如何验证 adapter 确实参与了梯度更新——光看 loss 曲线会骗人,得进 model.base_model.model.layers[0].self_attn.q_proj.lora_A 里亲手 print(param.grad) 看一眼。


















