版权与内容来源声明
本文为原创整理。文中涉及官方文档、开源仓库、论文与公开报道的内容,均在附表 A 中标注来源;引用官方原文保持原样,不作改写。文中命令、版本号与界面截图以本文成文时的实测/核验结果为准,标注「待验证」的部分请以你本地环境实际输出为判断依据。本文不推荐任何不合规的软件获取方式,也不对任何收益结果作承诺。转载请注明出处。
一、先把两件事拆开:秩和适配范围根本不是同一个坐标
把 LoRA 的r从 8 改成 64、只适配 q/v,可训练参数从 4,194,304 涨到 33,554,432,涨了 8 倍;而r保持 8 不动、只把适配范围从 q/v 扩到全部线性层,参数从 4,194,304 涨到 19,988,480,涨了约 4.8 倍。两个数字都在涨,涨的却是完全不同的东西——前者抬高每个被适配矩阵的表达上限,后者把被改动的层铺开。把它们当成同一个「LoRA 大小」来调,是超参排查绕远路的最大来源。
现场:一次几乎人人犯过的误判
我见过的典型操作是这样的:微调完效果不理想,第一反应是把r从 8 加到 64,跑完发现显存吃紧或者过拟合,再往下调;整个过程里target_modules从来没动过,一直停在注意力块的 q/v 上。如果真实需求是「让模型记住一批行业术语并稳定输出」,需要的并不是更宽的秩,而是更多层被覆盖到。两个旋钮共用一个模糊的名字,但作用点不重合。
先把参数账的公式钉死
LoRA 的参数量算法很朴素,一句话就能记住:每层每个被适配的权重矩阵,新增一对低秩矩阵 A 和 B,参数量 = r × (d_in + d_out)。d_in、d_out是这个权重矩阵的输入维与输出维,r就是所谓的秩。整个模型的 LoRA 参数量,就是把所有被适配的矩阵按这条公式加总。
这条公式是下文所有数字的基础。你拿自己模型的hidden_size、层数和 MLP 中间维,就能复算一遍,不用装任何框架。
实测块 1:参数账跑一遍
🧪 实测环境:Python 3.13.12 / macOS / 仅标准库
L,D=32,4096f=lambdar,ms:sum(r*(i+o)for_,i,oinms)*L qv=[("q_proj",D,D),("v_proj",D,D)]all_linear=qv+[("k_proj",D,D),("o_proj",D,D),("gate_proj",D,11008),("up_proj",D,11008),("down_proj",11008,D)]base=6.74e9print(f"{'rank':>4}|{'只适配 q/v':>16}|{'占基座':>8}|{'适配全部线性层':>16}|{'占基座':>8}")print("-"*74)forrin(4,8,16,64):n1,n2=f(r,qv),f(r,all_linear)print(f"{r:>4}|{n1:>16,}|{n1/base*100:>7.3f}% |{n2:>16,}|{n2/base*100:>7.3f}%")print()print(f"rank 从 8 提到 16(只适配 q/v):参数翻倍 →{f(8,qv):,}→{f(16,qv):,}")print(f"rank=16 时,把适配范围从 q/v 扩到全部线性层:参数放大{f(16,all_linear)/f(16,qv):.1f}倍")print(f"rank=16 全线性层占比{f(16,all_linear)/base*100:.2f}% —— 仍不到基座的 3%")print()print(f"对照:全量微调 7B ≈ 6.74e9 可训练参数;rank=16 只适配 q/v ≈{f(16,qv):,}(约{base/f(16,qv):,.0f}分之一)")原样输出:
rank | 只适配 q/v | 占基座 | 适配全部线性层 | 占基座 -------------------------------------------------------------------------- 4 | 2,097,152 | 0.031% | 9,994,240 | 0.148% 8 | 4,194,304 | 0.062% | 19,988,480 | 0.297% 16 | 8,388,608 | 0.124% | 39,976,960 | 0.593% 64 | 33,554,432 | 0.498% | 159,907,840 | 2.373% rank 从 8 提到 16(只适配 q/v):参数翻倍 → 4,194,304 → 8,388,608 rank=16 时,把适配范围从 q/v 扩到全部线性层:参数放大 4.8 倍 rank=16 全线性层占比 0.59% —— 仍不到基座的 3% 对照:全量微调 7B ≈ 6.74e9 可训练参数;rank=16 只适配 q/v ≈ 8,388,608(约 803 分之一)这段脚本不加载模型、不装依赖,纯按公式和公开结构参数算,跑一次不到一秒。它给出的第一个反直觉结论已经在表里了:在 7B 这个量级上,「把适配范围扩到全部线性层」比「把秩从 8 提到 64」更贵。
二、LoRA 的内核:它只动权重更新量的一小块,但缩放挂在秩上
LoRA 省参数量,靠的是不去重训整个权重矩阵:冻结原始权重,只学一个低秩的「更新量」,再加回到原权重上。这件事论文摘要说得很直白,下面逐字引原文。
论文口径:省下来的到底是什么
LoRA 论文(arXiv:2106.09685)摘要里的原句是:
Compared to GPT-3 175B fine-tuned with Adam, LoRA can reduce the number of trainable parameters by 10,000 times and the GPU memory requirement by 3 times.
也就是可训练参数减少约 1 万倍、显存需求减少约 3 倍。这个结论的限定条件必须一起读:它说的是「相比用 Adam 全量微调同一个 175B 模型」,不是「LoRA 在任何模型任何配置上都省 3 倍显存」。做参数账时把限定条件丢掉,账就会算歪。
QLoRA(arXiv:2305.14314)摘要里的两句原句是:
QLoRA backpropagates gradients through a frozen, 4-bit quantized pretrained language model into Low Rank Adapters~(LoRA).
reduces memory usage enough to finetune a 65B parameter model on a single 48GB GPU while preserving full 16-bit finetuning task performance
翻译过来:QLoRA 把基座冻结并量化到 4-bit,梯度穿过量化后的基座、只回到 LoRA 适配器上,因此能在单张 48GB 显存的卡上微调 65B 参数模型,并且保持与 16-bit 全量微调相当的训练任务表现。它解决的是「显存不够」这个前置条件,不是「效果不够」。
官方配置项里的三个名字
Hugging Face PEFT 是目前落地这套方法最常用的库,官方文档对三个关键参数的定义如下(逐字引用,出处见附表 A):
r:Lora attention dimension (the "rank").target_modules:The names of the modules to apply the adapter to.传all-linear时,all linear/Conv1D modules are chosen (if the model is a PreTrainedModel, the output layer excluded)。lora_alpha:The alpha parameter for Lora scaling.
文档里还有两句对本文的判断最关键的话:
A higher rank means the model has more parameters to train, but it also means the model has more learning capacity.
The resulting number of trainable parameters in a LoRA model depends on the size of the update matrices, which is determined mainly by the rank
rand the shape of the original weight matrix.
「主要由秩和原权重形状决定」这句把第一件易混的事说穿了:在参数量这个数字里,r只是一个乘数,被适配矩阵的形状是另一个乘数,而形状由target_modules决定。
一个 PEFT 的最小配置长这样:
⚠️代码待验证
frompeftimportLoraConfig config=LoraConfig(r=16,lora_alpha=32,target_modules="all-linear",lora_dropout=0.05,bias="none",)这是官方文档给出的参数组合形式,本地环境没有安装 peft,所以没有跑过;参数含义以附表 A 的出处为准。PEFT 当前发布版本为 v0.21.2(截至 2026-10-13,取自 PyPI 官方接口)。
一个容易被忽略的耦合:改秩就改了有效缩放
PEFT 文档说明,LoRA 的缩放系数在原实现里是lora_alpha/r;如果打开 rsLoRA,则变成lora_alpha/math.sqrt(r)。这句话的后果很直接:你把r从 8 改成 64、lora_alpha不动,有效缩放就变成了原来的八分之一。此时做对比评测,测出来的差异到底来自「秩变宽」还是「等效缩放变小」,是分不清的。
于是有了本文的第一条判据:比较不同秩之前,先把lora_alpha/r的比值固定住,或者统一改用 rsLoRA,让缩放只跟sqrt(r)相关。不固定这个比值,后面扫出来的r曲线不可信。
三、把两个坐标都摆上桌,才看清四个真问题
算完账会发现,「r取 8 还是 64」这个问题本身就问偏了——它只在一个坐标上挪动。
差距悬殊的四个档,没有一个超过 3%
🧪 实测环境:Python 3.13.12 / macOS / 仅标准库(离线复算,不加载任何模型)
| rank | 只适配 q/v | 占基座 | 适配全部线性层 | 占基座 | q/v 相对全量微调 |
|---|---|---|---|---|---|
| 4 | 2,097,152 | 0.031% | 9,994,240 | 0.148% | 约 1/3214 |
| 8 | 4,194,304 | 0.062% | 19,988,480 | 0.297% | 约 1/1607 |
| 16 | 8,388,608 | 0.124% | 39,976,960 | 0.593% | 约 1/803 |
| 64 | 33,554,432 | 0.498% | 159,907,840 | 2.373% | 约 1/201 |
口径:按 32 层、隐藏维 4096、MLP 中间维 11008 的公开 7B 量级结构自算;基座参数量按 6.74e9 记;公式为「每层每适配矩阵 = r × (d_in + d_out)」;「只适配 q/v」指每层适配 q_proj 与 v_proj 两个矩阵,「适配全部线性层」指每层适配 q/k/v/o 与 gate/up/down 共 7 个矩阵;取数日期 2026-10-13。
四个档里最大的 2.373%,最小的 0.031%,相差 76 倍,但没有一档超过 3%。也就是说,只要不碰全量微调,参数量占比这个数字从头到尾都「很好看」。正因为都好看,它就不能当效果指标——它是成本指标,只回答「要多存多少参数、多算多少梯度」。
真正拉开差距的是层覆盖了哪些能力面
由这两个坐标衍生出的四个问题,按重要性排:
- 0.124% 和 0.593% 都不到 1%,效果却可能差出一个档次。差的那 4.8 倍不是均匀撒出去的,而是全压在 MLP 的 gate/up/down 上。这几层动与不动,改的是不同的能力面。
- 被适配的层决定覆盖面,秩只决定单层表达上限。只适配 q/v,改的是注意力里「信息怎么被重新加权」;把 k/o 和 MLP 三层纳进来,才有机会改「信息怎么被写进中间表示」。
- 显存和训练时间跟着参数量走。全线性层的参数是 q/v 的 4.8 倍,优化器状态与梯度也按同比例上涨。「扩范围」比「提秩」更贵,这正是 QLoRA 要用 4-bit 量化基座把这个前提压下去的原因。
- 缩放耦合会污染评测结论。上一条已经拆过,但它是评测里最容易漏的一环,值得单独记一笔。
把系数摊开看更清楚。这段两行代码就能算出来:
D=4096print("q/v 每层每 rank 系数 =",2*(D+D))print("全线性层每层每 rank 系数 =",4*2*D+2*(D+11008)+(11008+D))输出两行:q/v 每层每 rank 系数 = 16384、全线性层每层每 rank 系数 = 78080。前者是 2 个矩阵 × (4096 + 4096),后者是 4 个 4096×4096 加上 gate/up/down 三项,两者比值 4.77——这就是「4.8 倍」的来源,把维度换成你自己模型的就能复算。
所以第一件事永远是:先定范围,再定秩
顺序倒过来会怎样?你会先花几天时间扫r = 8/16/32/64,每个配置的适配范围都停在 q/v,最后发现四个配置之间的差异都落在波动范围里,于是误判成「LoRA 调参没效果」。实际上你一直在同一个坐标上左右挪,另一个坐标一次都没动。
四、坐标系:四类常见配置分别落在哪一格
把「每层每秩的参数量系数」当横轴、「覆盖的能力面」当纵轴,四类配置的落点就清楚了。下面四行覆盖了绝大多数 7B 级微调会真实用到的组合。
先把坐标轴定下来
- 横轴是每层每秩的参数量系数:q/v = 16,384;q/k/v/o = 32,768;含 MLP 的全部线性层 = 78,080。
- 纵轴是能力面:q/v 只覆盖注意力的重加权路径;加上 k/o 覆盖注意力的读与写;再加 MLP 三层,才覆盖到信息写进中间表示这一段。
坐标系表
| 配置 | 每层每秩系数 | 覆盖的能力面 | 建议起始秩 | 什么条件下别用 |
|---|---|---|---|---|
| q/v | 16,384 | 注意力重加权,不碰 MLP | 8 | 任务需要注入大批领域术语时,覆盖面不够 |
| q/k/v/o | 32,768 | 注意力的读侧与写侧 | 8 到 16 | 任务瓶颈在 MLP 表达时,扩到这里也不够 |
| 全线性层(含 MLP) | 78,080 | 注意力 + MLP 三层 | 8 | 显存只够极小的 batch 且不能用量化基座时 |
| 全线性层 + 分层秩 | 78,080 起 | 关键层加宽,其余保持 | 8(局部 16 到 32) | 没做过分层验证时,先别上分层秩 |
口径同上:每层每秩系数按 32 层、隐藏维 4096、MLP 中间维 11008 的结构自算,取数日期 2026-10-13。
这张表的读法是先横后纵:任何一行的起始秩都可以是 8,先看自己需要哪条能力面,再决定要不要往上加秩。把行选错、只在那行里加秩,是效率最低的一种调参方式。
这份资料里有什么:本文的参数账脚本、7B 与 13B 两种结构的系数对照表,以及四类配置的 PEFT 配置模板都在这个资料包里,扫码即可获取:
五、选型建议:先定范围再定秩,定完用两个条件验收
选型这件事收敛到两句话:横轴先用任务性质拍定,纵轴用验证集数据和显存余量拍定。下面把常见情形对号入座。
按现象决定先动哪个坐标
| 你观察到的现象 | 先动哪个坐标 | 建议起始配置 | 验收条件 |
|---|---|---|---|
| 格式、语气、输出结构不对,知识其实是有的 | 范围(先),秩(后) | q/v,秩取 8 | 格式类样例在验证集上稳定通过 |
| 模型不认识领域术语,答案和术语对不上 | 范围 | 全线性层,秩取 8 | 领域问答样例不再出现术语张冠李戴 |
| 上面都试过仍不足,且训练数据量够 | 秩 | 全线性层,秩取 16 再上 32 | 秩翻倍后验证集指标稳定超出波动范围 |
| 显存不够,batch 只能压到很小 | 先降秩,不降范围 | 全线性层,秩取 4 加 4-bit 基座 | 训练能稳定跑完,再谈效果 |
口径:表中的配置都指 PEFT 里LoraConfig的target_modules与r取值,缩放参数按前面的要求固定lora_alpha/r比值;取数日期 2026-10-13。
什么时候该停手
三条可以直接执行的停手判断:
- 秩翻倍(8 到 16、16 到 32)之后,验证集指标的变化落在波动范围里,就停手。继续加秩是在给成本表加数字,不是在给效果表加数字。此时应该先去扩适配范围,或者回头查数据。
- 全线性层 + 秩取 64 在 7B 上约 1.6 亿可训练参数、占基座 2.373%。如果按这个配置算出来的显存余量撑不住一个完整 epoch,就降到秩取 16,或者先上 4-bit 量化基座,不要靠砍 batch 硬撑——参数账在这里是硬约束。
- 只适配 q/v 且秩已经到 64(3355 万参数、占基座 0.498%),效果仍不达标,基本能说明问题不在容量。此时把范围扩到全线性层,比继续加秩更值得试。
回到标题那个问题:秩取 8 还是 64,答案取决于你先在哪一行。只适配 q/v 时,秩取 8 就够起步,往上加秩的边际收益要靠验证集来证明;选了全线性层时,秩取 8 到 16 的起点已经比「q/v + 秩取 64」覆盖了更多能力面,而参数量还更低。把两个坐标分开看,这个选择就不再是二选一。
这份资料里有什么:配套的学习路线图和微调实操课都在同一个资料包里,路线图里标了「哪些微调前置知识可以先跳过」,扫码即可获取:
附表 A:本文引用事实与出处对照表
| # | 事实 | 出处 | 本文位置 |
|---|---|---|---|
| 1 | LoRA 相比用 Adam 全量微调 175B 量级模型,可将可训练参数减少约 1 万倍、显存需求减少约 3 倍(原句:reduce the number of trainable parameters by 10,000 times and the GPU memory requirement by 3 times) | 论文摘要页《LoRA: Low-Rank Adaptation of Large Language Models》,作者 Hu 等,arXiv:2106.09685v2(2021-10-16 修订),https://arxiv.org/abs/2106.09685 | 第二章「论文口径」 |
| 2 | QLoRA 通过冻结的 4-bit 量化基座把梯度传回 LoRA;可在单张 48GB 显存卡上微调 65B 参数模型,并保持与 16-bit 全量微调相当的训练任务表现 | 论文摘要页《QLoRA: Efficient Finetuning of Quantized LLMs》,作者 Dettmers 等,arXiv:2305.14314v1(2023-05-23),https://arxiv.org/abs/2305.14314 | 第二章「论文口径」 |
| 3 | r的官方定义为Lora attention dimension (the "rank"). | Hugging Face PEFT 官方仓库src/peft/tuners/lora/config.py中LoraConfig文档字符串,https://github.com/huggingface/peft/blob/main/src/peft/tuners/lora/config.py | 第二章「官方配置项」 |
| 4 | target_modules用于指定被适配的模块名;传all-linear时选中全部 linear/Conv1D 模块(PreTrainedModel 会排除输出层) | 同第 3 条出处 | 第二章「官方配置项」 |
| 5 | lora_alpha的官方定义为The alpha parameter for Lora scaling. | 同第 3 条出处 | 第二章「官方配置项」 |
| 6 | 秩越高可训练参数越多、学习容量越大;LoRA 可训练参数量主要由秩r与原权重矩阵形状决定;默认给注意力块的 query/value 层加可训练权重,QLoRA 则加到所有线性层且官方文档称其可提供等同全量微调的表现 | Hugging Face PEFT 官方文档源文件docs/source/package_reference/lora.md(即官网 huggingface.co/docs/peft 的 LoRA 页面内容来源),https://github.com/huggingface/peft/blob/main/docs/source/package_reference/lora.md | 第二、三章 |
| 7 | 原实现的 LoRA 缩放为lora_alpha/r,rsLoRA 使用lora_alpha/math.sqrt(r) | 同第 3 条与第 6 条出处 | 第二章「缩放耦合」 |
| 8 | PEFT 当前发布版本为 v0.21.2 | PyPI 官方 JSON 接口 https://pypi.org/pypi/peft/json,取数日期 2026-10-13 | 第二章「官方配置项」 |
核验说明:第 3 至 7 条引文的官网页面(huggingface.co/docs/peft)在核验时返回空白页(前端渲染),因此逐字引文取自同一项目的官方仓库源文件;两者为同一份内容,仓库文件为目标页面「待验证」之外的可靠替代。第 1、2 条的英文原句已逐字核对 arXiv 摘要页。第 3、4、5 条引文中的英文原样保留,未做拼写改写。
写在最后:这篇用到的资料
写这篇文章时,把相关的官方文档和源码又翻了一遍,顺手也整理了几份配套的东西:
- 大模型学习路线图:从零基础到能自己动手做 Agent,按阶段说明每一步该学什么、哪些可以先跳过
- 《LangChain + LangGraph + MCP 智能体开发实战》视频课:7 个模块,从私有化部署、Embedding+RAG 到 MCP+Agent 全流程
- AI 大模型知识库(在线可查):Agent Skills 从入门到落地、Claude Skills 完全指南等专题,按目录浏览即可
- 640 套 AI 大模型行业报告 + 经典 PDF 书籍:看行业落地案例和别人怎么做的时候用得上
- 大模型零基础到精通教学视频:跟着敲一遍,比只读文档快得多
资料是我自己整理的,放在下面这个码上,扫码即可获取:
添加时备注「AI」,优先通过。
资料按「先路线、再动手、最后查漏」的顺序整理好了,建议先看学习路线那一份,照着它挑一条适合自己当前基础的路径再往下看。