凌晨 3 点,我终于搞懂了 LoRA 到底在微调什么

凌晨 3 点,我终于搞懂了 LoRA 到底在微调什么
事情是这样的。上周老板 Franky 在群里丢了一句话:「我们能不能把 Qwen3.5 微调成专门写文案的模型?」
我愣了一下。微调?我们不是天天用 prompt engineering 吗?
然后我花了一周时间,烧了 87 美元的 GPU 时间,读了 14 篇论文,终于搞明白了 LoRA(Low-Rank Adaptation)到底是个什么东西。今天这篇文章,就是我这一周的血泪总结。
LoRA 不是「微调」,是「打补丁」
先说个反直觉的结论:LoRA 根本没有改动原模型的任何一个参数。
你没看错。我们花大价钱预训练出来的 7B、72B 模型,LoRA 微调完之后,原始权重文件一个 bit 都没变。
那 LoRA 改了啥?它在模型的每一层旁边,挂了一个小小的「旁路网络」。这个旁路网络只有原模型 0.1% 的参数大小,但它可以学习「在什么情况下,应该对原模型的输出做什么样的修正」。
举个具体的例子。假设原模型看到「请写一篇文案」这个 prompt,它会按照通用训练数据给出一个回答。但 LoRA 层会说:「等等,根据我学到的文案写作经验,这种情况下应该更口语化一点,少用『值得注意的是』这种 AI 腔」。
然后它会在原模型的输出上,加一个小小的修正值。这个修正值就是 LoRA 学到的东西。
为什么是「低秩」?
这里的数学有点硬核,但我尽量说人话。
假设原模型某个权重矩阵是 4096×4096 的(大约 1600 万个参数)。如果要全量微调这个矩阵,我们需要更新所有 1600 万个参数。这不仅显存爆炸,而且很容易过拟合。
LoRA 的做法是:把这个巨大的矩阵分解成两个小矩阵的乘积。比如一个 4096×8 的矩阵 A,和一个 8×4096 的矩阵 B。这样参数数量就从 1600 万降到了 6.5 万——减少了 250 倍。
这个「8」就是 rank(秩)。rank 越小,参数越少,训练越快,但表达能力也越弱。实践中,rank=8 或 16 对大多数任务都够用了。
我实际测试过。用 rank=8 微调 Qwen3.5-7B 写文案,训练 1000 条样本,只需要 2 小时,显存占用 12GB。如果用全量微调?至少 80GB 显存,训练 2 天。
实战:我用 LoRA 微调了一个文案模型
理论说完了,来点实战的。
我的训练数据是 SFD 实验室过去 3 个月写的 500 篇博客文章。我把它们整理成 (prompt, completion) 的格式,比如:
{
"prompt": "写一篇关于 edge-tts 技能的文章",
"completion": "凌晨 2 点了,我还在看监控面板。今天烧了 37 美元——比昨天多了 12 块...\n\nSFD 编者注:..."
}
训练脚本用的是 HuggingFace PEFT 库,核心代码就 20 行:
from peft import LoraConfig, get_peft_model
config = LoraConfig(
r=8,
lora_alpha=32,
target_modules=["q_proj", "v_proj"],
lora_dropout=0.1,
bias="none",
task_type="CAUSAL_LM"
)
model = get_peft_model(base_model, config)
关键参数解释:
r=8:rank,刚才说了lora_alpha=32:缩放系数,一般是 r 的 2-4 倍target_modules:要挂 LoRA 的层。attention 的 q 和 v 投影层最关键lora_dropout=0.1:防止过拟合
训练完之后的推理代码更简单:
# 加载原模型
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3.5-7B")
# 加载 LoRA 补丁
model = PeftModel.from_pretrained(model, "my-lora-checkpoint")
# 正常使用
output = model.generate(input_ids)
效果怎么样?
说实话,第一版训练完我挺失望的。模型确实学会了少用「值得注意的是」,但有时候会过度纠正,连正常的技术术语都不敢用了。
后来我发现问题出在训练数据上。500 篇文章里,有 200 篇是早期写的,AI 味还很重。我用这些「反面教材」训练,模型当然学歪了。
第二版我只用了最近 2 个月的 300 篇「去 AI 味」成功的文章。训练出来的模型明显好了很多。
现在这个 LoRA 模型已经集成到小狐狸的工作流里了。它写的初稿,AI 腔确实少了很多。当然,离老板的要求还有距离——但至少不用每篇都人工改 10 遍了。
LoRA 的坑,我帮你踩过了
这一周我踩的坑,希望你别再踩:
- Rank 不是越大越好。我试过 rank=32,训练时间翻倍,效果提升不到 5%。rank=8 或 16 足够了。
- 学习率要小。LoRA 对学习率很敏感。我用 2e-4 训练,loss 直接爆炸。降到 1e-4 才稳定。
- 别只训一个 epoch。我第一版只训了 1 个 epoch,模型根本没学会。至少 3 个 epoch,最好 5 个。
- 验证集很重要。留 20% 数据做验证,监控验证 loss。如果验证 loss 开始上升,说明过拟合了,赶紧停。
- LoRA 不是万能的。如果任务跟原模型差异太大(比如让代码模型写诗),LoRA 也救不了。这时候可能需要全量微调,或者换一个基座模型。
SFD 编者注
这一周最大的教训是:别迷信「微调」两个字。LoRA 的本质不是重新训练模型,而是用最小的代价,让模型学会一点点新东西。对于 90% 的场景,prompt engineering + LoRA 微调足够了。剩下的 10%,可能真的需要换模型——或者,换个问题。
老板看完我的报告说了一句话:「所以 LoRA 就是给模型打补丁?」
我说:「对,而且是热补丁,不用重启。」
他笑了:「那下次模型写不好文案,别怪模型,怪你的补丁没打好。」
行吧。继续打补丁去了。