算清 LoRA 参数量与微调资源开销
文章以 16GB Apple Silicon 上的 Qwen2.5-1.5B-Instruct、rank 16 配置为例,拆解适配层、秩、冻结权重精度与训练步数。通过低秩矩阵公式说明可训练参数如何随 rank 和层宽增长,补充“只训练约 1% 参数”背后的资源细节。
AI 深度解读
LoRA 到底训练了什么,不能只用「模型的 1%」回答。作者拿 Qwen2.5-1.5B-Instruct 在 16GB Apple Silicon Mac 上的配置算了一遍:训练参数约占 1.2%,但内存大头仍是冻结的基础模型;200 条样本跑 3 个 epoch,也只有约 39 次参数更新。
这篇最有用的地方,是把参数量、内存和训练步数连起来了。准备在本地微调模型时,这些账比一句「消费级设备也能训练」更能帮你判断方案是否可行。
这 1.2% 的参数,具体加在哪里
作者使用 osFoundry 的本地训练默认配置,底层是 transformers + PEFT + TRL。模型为 Qwen2.5-1.5B-Instruct,LoRA rank 为 16,alpha 为 32。

对一个形状为 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 线性增长。
但 rank 相同,挂载位置不同,参数量仍能差很多。作者的配置覆盖每个 transformer 块里的七个线性投影:
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"]
要看后面三个 MLP 投影,它们贡献了约四分之三的 adapter 参数。
这个模型有 28 个块,hidden size 为 1536,MLP 维度为 8960。分组查询注意力(GQA)使用 2 个 KV head,每个维度为 128,因此 k、v 的输出维度只有 256,给它们加 adapter 相对便宜。
rank 16 下,每块新增 659,456 个参数,合计 18,464,768,约为 1.54B 总参数的 1.2%。若只适配 q、v,就降到约 2.2M,只剩当前参数规模的八分之一。
讨论 LoRA 的规模,必须同时报 rank 和 target_modules。
训练参数很少,为什么内存还是不够
冻结只是停止更新权重,权重仍要加载进内存。作者的 trainer 按设备选择精度:
torch_dtype = torch.float16 if device == "cuda" else torch.float32
关键是 else torch.float32:这个配置在 Apple GPU 上以 fp32 加载模型。作者给出的理由是,MPS 半精度容易出现 loss NaN,因此选择更稳妥的 32 位路径。
于是,冻结的基础权重就占了 1.54B × 4 byte ≈ 6.2 GB。相比之下,18.5M 可训练参数的权重约 74 MB,梯度再占 74 MB,AdamW 的两份矩估计占 148 MB,总计约 0.3 GB。
剩余空间还要放激活值,其规模受 batch size 和序列长度影响。trainer 的序列上限是 2048 token,短聊天回复通常远低于这个长度。
按作者约 12 GB 可供 GPU 使用的预算,16GB Mac 能容纳这个 1.5B 模型;7B 基础权重若用 fp32,训练前就接近 30 GB。QLoRA 通过把冻结权重量化为 4-bit 缩小这一部分,但原文所述的 bitsandbytes 4-bit 路径需要 NVIDIA GPU,所以这套 Mac 配置使用普通 LoRA。
跑完 3 个 epoch,其实只更新约 39 次
作者设置 batch size 为 4,梯度累积为 4 步,每次 optimizer 更新合计处理 16 个样本。200 对数据对应:
- 每个 epoch 有
200 ÷ 4 = 50次前向和反向计算。 - 每个 epoch 约有
50 ÷ 4 ≈ 13次 optimizer 更新。 - 3 个 epoch 合计约 39 次更新,其中前 10 次用于学习率 warmup。
学习率为 2e-4,随后线性下降。这个取整结果也依赖 trainer 如何处理 epoch 末尾不足一次累积的批次。

作者观察到,几百条回复可以改变写作风格,却不足以教会模型新知识。至少在这个配置里,「跑了三轮」并不代表经历了大量优化。
训练完成后,只保存 196 个适配层的 A、B,文件为数十 MB。应用把它转换为 LoRA GGUF,再由 llama.cpp 加载到 Q4_K_M 量化的 qwen2.5-1.5b-instruct 上。多个风格或任务 adapter 可以共用基础模型。

这里还有一道精度落差:训练面对 fp32 基础权重,推理面对 4-bit 权重。作者认为小型风格 adapter 通常感受不到明显差异,但先合并再量化,与运行时挂载 adapter,仍可能产生不同输出。
我的判断
这篇最可靠的是可复核的参数量和内存账。它也解释了为什么只看「可训练参数占比」容易误判设备需求。
但「39 次更新不能教新知识」应当视为这套配置下的经验判断。原文没有给知识测试集、对照实验或统计结果,不能推成 LoRA 的普遍能力边界。只适配 q、v 虽然参数少,也不代表效果必然按比例下降,作者没有提供质量对比。
同样,MPS 半精度出现 NaN、约 12 GB GPU 可用预算,都有环境前提。原文没交代完整软件版本,不能当作所有 Mac 的固定结论;bitsandbytes 的限制也只对应文中使用的路径。
如果目标是统一回复风格,可以比较提示词、少量示例和 LoRA 的效果;如果目标是回答持续变化的项目资料,检索方案更值得先评估。原文没有这些对照,选型仍要靠自己的任务验证。
能拿来做什么
- 本地训练前,先列出基础模型精度、target_modules、rank 和序列长度,再估算内存,别只看 adapter 文件有多小。
- 准备用几百条技术问答调整回复风格时,先算有效 batch 和总更新次数,同时检查 warmup 占比,避免只凭 epoch 数判断训练是否充分。
- 部署到 llama.cpp 时,用相同提示比较基础模型、运行时 adapter 和合并后量化模型,检查格式、风格及事实回答是否偏移。