上个月我用 LLaMA-Factory 跑通了第一次 LoRA 训练,配置里的 lora_rank: 8 是照抄官方示例的。能跑,心里其实没底:为什么是 8?改成 16 会不会更好?后来翻教程,发现这个数字忽大忽小,有写 4 的,也有写 64 的,把账摊开算的文章很少。这篇就补上这笔账。
先看全参微调有多贵
拿 Qwen3-8B 做例子。我从 ModelScope 拉了它的官方 config.json:36 层,隐藏维度 4096,总参数 8.2B。
全参微调就是这 82 亿个参数全部参与梯度更新。听着霸气,代价也霸气。微调的基本原理之前写过,这里只算钱。LLaMA-Factory 官方 README 有一张硬件需求表:7B 模型全参 bf16 训练要 120GB 显存,就算切到 pure_bf16 也要 60GB。普通人的显卡,连门都摸不到。这条路走不通。
存储是另一笔账:每微调一个任务就存一份完整模型,8B 权重按 bf16 算 16GB 上下,真要接十个活儿,160GB 硬盘就这么没了。
LoRA 的做法:冻住原来的,另开一条小路
LoRA 出自微软 Edward J. Hu 等人 2021 年的论文《LoRA: Low-Rank Adaptation of Large Language Models》。想法两句话能说完。把原权重 W 冻住不动,在旁边加一条通路。这条通路用两个小矩阵 A 和 B 的乘积表示要补的改动,也就是 ΔW = BA。训练时只更新 A 和 B,W 原地不动。
「低秩」说的是这条通路的形状:A 是 r 行、B 是 r 列,r 远小于原权重矩阵的边长。补丁矩阵的秩撑死只有 r,所以叫低秩分解。r 就是 rank。所有争论都围绕它。论文摘要的原话是「injects trainable rank decomposition matrices into each layer of the Transformer architecture」,结果是「drastically reducing the number of trainable parameters for downstream tasks」,大幅砍掉下游任务要训的参数。
有个细节我是看源码才知道的:B 矩阵初始化为 0。PEFT 官方文档原话是「the LoRA B weight being set to 0」,训练开始之前 LoRA 层什么都不干,模型行为和原版完全一样。改动从零开始学。这设计挺讲究。
把参数量算给你看
基于 Qwen3-8B 的官方 config(hidden 4096,中间层 12288,8 个 KV 头、每组 128 维),我把 lora_target: all 的账算了一遍。每层 7 个线性层(q、k、v、o、gate、up、down)各挂一对 A 和 B,r=8 时:
- q_proj:8×4096 + 4096×8 = 65,536 个参数
- k_proj、v_proj:各 40,960(KV 维度只有 1024,沾了 GQA 的光)
- o_proj:65,536
- gate、up、down:各 131,072
先算单层。每层合计 606,208,乘 36 层,约 21.8M。8.2B 的模型,可训参数只有 21.8M。占比 0.27%。千分之三。
数量级能交叉验证:PEFT 官方 README 举的例子是 bigscience/mt0-large,只训练 0.19% 的参数。两套模型分开算,落在同一个量级,这账没算错。
存下来也轻。21.8M 参数按 bf16 两个字节算,适配器文件 44MB 上下。对比 16GB 的完整权重,差不多是 1/370。训练完落盘的就是这么一个小文件,网盘都能装下,拷给朋友毫无压力。
rank 怎么选
先说结论。r 决定这条通路的容量。r 翻倍,可训参数跟着翻倍:r=16 是 43.6M,r=32 是 87.3M,显存和过拟合风险都往上走。实操结论几条。
第一,8 是经过验证的起点。LLaMA-Factory 0.9.5 的 Qwen3 LoRA 官方示例,用的就是 lora_rank: 8 配 lora_target: all,学习率 1.0e-4,跑 3 个 epoch。官方都这么配,照抄不丢人,跑通再调。我上次也是这么来的。
第二,任务离原模型越近,rank 越可以小。改文风、固定格式输出、让模型学会你的行话,这类任务 8 完全够用,我上次跑的就是 8。要灌新领域的知识、做行为差异大的迁移,8 可能不够,先试 16,有卡再上 32。
第三,怎么判断 rank 够不够?我的做法看两头:训练 loss 和验证 loss 一起降,说明容量还有富余。训练 loss 降了,输出却还是原来的腔调,多半是 rank 不够,或者数据太少。loss 不降反升,先查学习率,别急着怪 rank。
第四,alpha 是缩放系数,实际生效的改动是 (alpha ÷ r) × BA。PEFT 里 lora_alpha 默认 8。单独调大 alpha 和调大 rank 的效果有重叠,新手别同时动两个,先动 rank。另外 PEFT 还提供了一个 rsLoRA 开关,把缩放公式从 alpha/r 换成 alpha/√r,官方文档里引用的论文称高 rank 场景下这样更稳,属于进阶选项,新手可以先不管。
顺带说两件小事。一是 target:只挂 q、v 是早年 4090 时代的老配方,现在显存不紧张就挂 all,参数多三倍,换来的容量不亏。二是 lora_dropout,PEFT 默认 0,我数据少于 1000 条时会手动设 0.05,给自己买个保险,代价是训练慢一点点。
把我自己的选型习惯摊开写在这里,仅供参考:改格式、调文风、加一套行话,rank 8 起步;灌一个垂直领域的基本概念和术语,rank 16;行为大改、数据量上万条,才考虑 32 往上。每次只动一个数字,跑完和上一版对比,别一口气调三个参数然后不知道功劳归谁。
显存到底省在哪
一个常见误会:LoRA 省的不是权重那份显存。8B 模型 bf16 装进显存还是 16GB 左右,一份不少。省的是梯度和优化器状态。全参微调时每个可训参数都要带一份梯度,外加 Adam 优化器的一阶和二阶动量,按 fp32 算,8.2B 参数光动量就要 64GB,再加上权重和梯度本身,总数奔着 100GB 去了,和官方表里 120GB 的量级正好对得上。
LoRA 的账就不同了:21.8M 个参数,梯度 44MB,动量 176MB,九牛一毛。省的就是这里。
官方硬件表的数字也印证了:LoRA 16bit 训 7B 要 16GB;把底座量化成 4bit 再挂 LoRA,也就是 QLoRA,只要 6GB。LLaMA-Factory README 里写的 QLoRA 支持覆盖 2 到 8 bit,靠 AQLM、AWQ、GPTQ、LLM.int8 这些量化方案实现。所以 24GB 的消费卡训 7B、8B 很从容。14B?上 QLoRA 也行。本地机器和云 API 怎么取舍,之前写过一篇对比。
什么时候不该用 LoRA
两类场景要想清楚。一是任务量大、想彻底改模型行为,比如让模型换一种语言写作、能力全面升级,那全参训练更合适,LoRA 的容量上限摆在那里。二是只是想让模型用上你的资料,那 RAG 或长上下文更对路,根本不用训,三者的取舍我专门写过一篇选型。
我个人吃过一次亏的教训是:别指望 LoRA 给模型加它从没见过的全新能力。它能激活和引导已有的本事。从零造一门本事?这点参数不够看。
还有个坑:把 LoRA 合并回原模型时,底座不能是量化模型。LLaMA-Factory 的 merge 示例第一行注释就是「DO NOT use quantized model or quantization_bit when merging lora adapters」,官方原话,不是我踩的坑。
结尾
把上个月那次训练的配置翻译一下:lora_rank 8,等于只训练了 0.27% 的参数,一张消费级卡跑 1000 条样本 3 个 epoch,半小时出头。82 亿参数里动了 2180 万,落盘 44MB,模型就学会了我的活儿。这大概就是 LoRA 到 2026 年还稳坐普通人微调首选位置的原因。