拆解 LoRA 参数量与本地微调资源开销
文章以16GB苹果芯片设备微调Qwen2.5-1.5B为例,说明LoRA实际训练的矩阵及参数量计算。结合适配层、秩、冻结权重精度和优化步数,解释影响资源需求与训练耗时的因素。
AI 深度解读
LoRA 常被概括成「只训练模型约 1% 的参数」,但这句话不足以判断电脑能不能跑、训练出来能改变什么。作者用一组具体配置拆开计算:在 16GB Apple Silicon Mac 上,对 Qwen2.5-1.5B-Instruct 做 rank 16 的微调,实际训练约 1850 万个参数,占模型的 1.2%。
更有用的结论是:内存主要花在冻结的基础模型上,小数据集提供的参数更新次数也可能远少于直觉。理解这两笔账,才能判断本地微调是否适合自己的任务。
LoRA 的参数到底加在哪里
对于形状为 d_out × d_in 的权重矩阵 W,LoRA 冻结 W,另外训练两个较薄的矩阵:A 的形状是 r × d_in,B 是 d_out × r。输出变成:
W·x + (α/r)·B·A·x
可以把它理解为:原来的计算保留,再叠加一项可训练的修正。B 初始化为零,因此训练开始时,输出与基础模型一致。单层新增参数量为 r × (d_in + d_out),随 rank 和层宽线性增长。
作者使用 osFoundry 本地训练器,底层是 transformers + PEFT + TRL,默认 rank 为 16、alpha 为 32。

下面的配置决定了哪些线性层参与微调:
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"]
要看的是第二行:三个 MLP 投影层也在训练范围内,它们占了约四分之三的适配器参数。
这个模型有 28 个 Transformer 块,隐藏维度为 1536,MLP 维度为 8960。分组查询注意力(GQA)使用 2 个 KV 头,每个头 128 维,因此 k、v 的投影输出只有 256 维,对应的适配器较小。
在 r = 16 时,每块新增 659,456 个参数,28 块共 18,464,768 个;相对约 1.54B 的总参数,比例为 1.2%。若只适配 q 和 v,参数会降到约 2.2M,约为完整配置的八分之一。
「用了 LoRA」还不够,必须同时看 rank 和 target_modules。
为什么只训练 1.2%,仍然需要大量内存
冻结只代表不更新参数,模型权重仍然需要加载。作者的训练器这样选择精度:
torch_dtype = torch.float16 if device == "cuda" else torch.float32
关键在 else torch.float32:这个实现会在 Apple 的 MPS 后端使用 fp32。作者给出的理由是,MPS 半精度训练容易出现 NaN loss,因此选择更保守的精度。
基础模型的内存账是 1.54B × 4 bytes ≈ 6.2 GB。适配器反而小得多:18.5M 个 fp32 参数约 74 MB,梯度再占 74 MB,AdamW 的两份矩估计约 148 MB,合计约 0.3 GB。
剩余开销还包括激活值,它会随批大小和序列长度增长。训练器将序列限制为 2048 tokens,短聊天回复通常用不到这个上限。
按作者约 12 GB 可供 GPU 使用的估算,16GB Mac 能为这个 1.5B 模型留出训练空间;7B 模型仅 fp32 权重就约需 30 GB。QLoRA 通过冻结的 4-bit 权重缓解这类压力,但原文使用的 bitsandbytes 4-bit 路径需要 NVIDIA GPU,因此这套 Mac 配置采用普通 LoRA。
这里需要区分:这是特定训练器和依赖路径的选择,不能据此推断所有 Mac 微调方案都只能使用 fp32。
200 条数据,实际只更新约 39 次
作者设置 batch size 为 4,梯度累积为 4 步,相当于每次优化器更新处理 16 条样本。对于 200 对训练数据,原文的估算是:
- 每轮进行
200 ÷ 4 = 50次前向和反向计算。 - 每轮约有
50 ÷ 4 ≈ 13次优化器更新。 - 训练 3 epochs,合计约 39 次更新,其中前 10 次用于学习率预热。
这组数字提醒我们:看到模型遍历数据三遍,不代表参数更新了几百次。约 39 次仍是估算,末尾不足 4 个批次时如何处理,原文没有展开。
作者使用 2e-4 学习率和线性衰减,判断这类训练更容易调整语气,而非教授新知识。不过,原文没有给出知识测试或不同数据量的对照实验,这应视为经验判断。
训练结束后,只保存 196 个适配层中的 A、B,文件为几十 MB。推理时,应用将其转成 GGUF LoRA,由 llama.cpp 加载到 Q4_K_M 量化的 qwen2.5-1.5b-instruct 上。基础模型可以共享,每种语气或任务分别保存适配器。

这里还有一个容易漏掉的差别:训练面对的是 fp32 基座,推理面对的是 4-bit 基座。作者认为小型风格适配器通常不受明显影响,但没有提供量化评测;合并适配器后重新量化,也可能与运行时加载产生略有不同的行为。
我的判断
这篇最有价值的是把参数量、内存和更新次数分开算清楚。它也解释了为什么两份都叫 LoRA 的训练配置,资源消耗可能相差很大。
但参数多八倍,不代表效果好八倍;只训练 q、v 是否足够,需要任务评测。类似地,「200 条数据只能改语气」也不是严格边界,结果还取决于数据内容、模型已有能力和评估方法。
我的取舍是:固定表达风格可以考虑小规模 LoRA;需要持续更新、能追溯来源的知识时,优先比较检索增强方案。后者是站内建议,并非原文做过的对照实验。
能拿来做什么
- 准备本地微调前,先记录基础模型精度、rank、target_modules、批大小和序列长度,再估算内存,别只看可训练参数比例。
- 整理日常 AI 编程助手的回复样本时,先明确要调整的是表达格式还是事实知识,并按有效批大小计算实际更新次数。
- 使用量化基座部署适配器时,保留一组固定提示,对比基础模型与加载适配器后的输出,重点检查目标风格和代码正确性,避免只凭单个示例判断效果。