LLM 面试备考
首页/后训练

LoRA 与参数高效微调(Low-Rank Adaptation / Parameter-Efficient Fine-Tuning)

所属:01-fundamentals / 02-post-training
面试权重:★★
来源:通用领域知识;未做一手考证
相关项目:Own — QueWI(Qwen2.5-4B SFT 做意图识别,典型的小数据窄任务,正是 PEFT 的适用场景);HKGAI / Race Bot 的全参微调方案可作为对照

一句话#

LoRA 冻结全部预训练权重,只在每层线性变换旁并联一对低秩矩阵 B ⁣⋅ ⁣AB\!\cdot\!A,把可训练参数量从 d×kd\times k 降到 r(d+k)r(d+k),从而让优化器状态(显存的大头)和训练成本大幅下降;推理时既可以把增量合并进原权重(零额外开销),也可以作为可热插拔的 adapter 保留。

为什么重要(面试角度)#

这是一个「看起来简单、细节很能拉开差距」的题:

  • 大家都会说「LoRA 就是低秩矩阵」,但能说清它省的主要是优化器状态而不是权重的人不多。
  • rank / alpha / target modules 三个参数的相互关系、以及 alpha/r 这个缩放因子的意义,是标准的深挖点。
  • 「什么时候不该用 PEFT」 是最能体现判断力的一问 —— 只会背优点的答案会被当成「没用过」。
  • 你在 QueWI 用 Qwen2.5-4B 做过窄任务微调,这是 PEFT 的对口经验;同时 HKGAI/Race Bot 是全参微调,正好能讲清为什么两个场景选了不同方案。

核心内容#

低秩分解(Low-Rank Decomposition)#

对某个线性层 W0∈Rd×kW_0\in\mathbb{R}^{d\times k},LoRA 把它替换为

W=W0+ΔW=W0+αrBA,B∈Rd×r, A∈Rr×k, r≪min⁡(d,k)W = W_0 + \Delta W = W_0 + \frac{\alpha}{r}BA,\qquad B\in\mathbb{R}^{d\times r},\ A\in\mathbb{R}^{r\times k},\ r\ll\min(d,k)

训练时 W0W_0 冻结(requires_grad=False),只有 A,BA,B 可训练。参数量从 d⋅kd\cdot k 降到 r(d+k)r(d+k) —— 当 d=k=4096d=k=4096、r=16r=16 时,约从 1670 万降到 13 万,低了两个数量级。

两个必须提的初始化细节:

  • AA 用高斯随机初始化,BB 初始化为全零,于是 ΔW=BA=0\Delta W=BA=0。训练起点与基座模型完全一致 —— 这保证了「微调不会一开始就把模型带偏」,也让 LoRA 训练的前几步是温和的。
  • 因为 BABA 是乘积,AA 与 BB 之间存在尺度冗余(BA=(cB)(A/c)BA=(cB)(A/c))。缩放因子 α/r\alpha/r 的作用就是把这种冗余的口径固定下来,使得调整 rr 时不至于让有效学习率跟着漂移。

Rank / Alpha / Target Modules#

Rank(rr)—— 容量旋钮

  • rr 决定低秩子空间的维度,也就是「允许模型改变多少」。
  • 任务偏移小(改格式、改风格、窄任务分类)→ 小的 rr 就够;任务偏移大(新领域知识、新语言)→ 需要更大的 rr。
  • 存在边际递减:把 rr 加得很大并不会一直变好,收益很快饱和(这与「微调发生的内在维度通常远小于参数量」这一观察一致)。所以 rr 不是越大越好,大 rr 只带来更多参数、更慢的训练和更高的过拟合风险。
  • ⚠️ 起点要按训练阶段分开,不要只记一个数。此前本文写「常见起点是个位数到十几」,那是偏 RL / 小任务一侧的旧惯例,直接套到 SFT 上会显著欠参数化。经过验证的经验口径是:
    • SFT:中高 rank,64–256 —— SFT 每步注入的信息量大,需要足够容量去承载。
    • RL:小 rank,8–32,甚至 r=1r=1 就够 —— RL 每轮参数更新的信息量很小,大 rank 纯属浪费(还更容易过拟合)。
    • 反直觉但值得记:RL 用小 rank 不是妥协,是够用。
  • 无论哪个阶段,这个值都必须实测 —— 它取决于数据量、任务偏移和基座。

Alpha(α\alpha)—— 缩放

  • 实际参与前向的是 αrBA\frac{\alpha}{r}BA,所以真正有意义的是比值 α/r\alpha/r,而不是 α\alpha 的绝对值。
  • 惯例是让 α\alpha 取 rr 的一个小常数倍(如 α=r\alpha=r 或 α=2r\alpha=2r),这样改变 rr 时有效缩放大致不变,两个参数可以分开调。
  • 如果只放大 rr 而不动 α\alpha,α/r\alpha/r 会变小,等于同时把 LoRA 分支的输出缩小了 —— 这是「加了 rank 反而没变好」的常见原因。
  • 反向的常见做法:想用更大的学习率时,把 α\alpha 调大(因为它等效于放大 LoRA 分支的梯度尺度)。

Target Modules(作用在哪些层)—— 影响最大的参数

选择 特点
只做 attention 的 q/v 最原始的默认,参数量最小,对格式/风格类任务往往够用
attention 的全部投影(q/k/v/o) 常见的平衡选择,明显强于只做 q/v
attention + MLP(gate/up/down) 参数量更大,容量更强,是「效果优先」的常用配置;大任务上通常明显更好
全部线性层 容量最大,最接近全参微调的效果,但参数与开销也最高

选择逻辑:作用模块比 rank 更影响效果上限。 在预算固定时,「加宽作用范围(更多模块)+ 较小的 rank」通常比「只做一个模块 + 大 rank」更划算。注意不同框架的默认值不一样(有的默认只挂 q/v),迁移到新框架时一定要显式确认 target modules,这是静默掉效果的高频事故点。

⚠️ 把「通常更好」升级成「必须」:上有出处的经验规则是 —— 必须把 LoRA 应用到所有主要权重矩阵,尤其是参数占比最大的 MLP 层;只加在注意力层会掉点。 原因很直白:MLP 占了参数的绝大部分,只挂注意力等于把容量旋钮拧在一个小得多的子空间上。所以「作用模块比 rank 重要」不只是排序,它在 MLP 这一项上是硬要求,不是可选项。

学习率:LoRA 要开大,不是开小

一条非常实用且常被答反的迁移规则:LoRA 的最优学习率约是全参微调的 10 倍,而且 SFT 和 RL 都成立。原因是 LoRA 只更新一小部分参数、梯度尺度天然更小,沿用全参微调的学习率会训得过慢。⚠️ 这与上面「容量变大后可以适当降学习率」不矛盾 —— 后者是在同一方法内部调容量,前者是方法之间的基线差异;面试里说清这一点,比只报一个数可信得多。

⚠️ 不要背具体数值当结论。rr、α\alpha、target modules 的最优组合高度依赖任务与数据量,任何「r=8r=8 就是标准答案」的说法都是错的。答题时给出选择逻辑 + 实测口径才有说服力。

QLoRA#

在 LoRA 之上再加一层量化:把冻结的基座量化到 4-bit 存储,前向时反量化到 bf16 计算,LoRA adapter 本身用 bf16。

  • 量化格式通常用 NF4(面向正态分布权重设计的信息论最优 4-bit 数据类型),并配合双重量化(对量化常数本身再量化,进一步省显存)和分页优化器(把优化器状态换页到 CPU 内存以扛住显存尖峰)。
  • 收益:显存占用大幅下降,可以直接在单卡上微调原本放不下的模型。
  • 代价:
    • 反量化引入额外计算开销 → 每步更慢(省显存不省时间)。
    • 量化本身有精度损失,效果通常接近但不等同于 16-bit LoRA。不要声称 QLoRA 与全精度 LoRA 效果完全一致。
    • 4-bit 基座不能直接合并,需要先反量化到 fp16/bf16 再加 LoRA 增量(此时产物是一个 16-bit 模型,量化带来的显存优势在部署时不再保留 —— 除非另做一次量化)。

Merge 还是 Adapter#

不合并(adapter 形态) 合并进原权重
推理开销 需要额外计算 LoRA 分支(或运行时合并),有额外延迟 零额外开销,与基座模型同构
部署 一个基座 + N 个 adapter,可热插拔 每个任务一份完整权重
多租户 ✅ 一套基座服务多个任务/客户 ❌ 每个任务各一份,显存不可共享
后续训练 ✅ adapter 可独立加载、卸载、继续训 ⚠️ 合并后 A,BA,B 的分解关系被抹掉,无法"解开"
适合 多任务、多客户、频繁切换 单任务生产部署、追求最低延迟

合并的关键操作细节:

  • 必须在高精度下合并(fp16/bf16 起),低精度合并会引入不必要的舍入误差。
  • 合并是有损的:W′+BAW'+BA 一旦算成一个矩阵,就再也不能精确还原出原来的 AA 和 BB,因此「合并后继续训这个 adapter」在语义上不成立(会退化成一个新的全参微调)。生产流程通常是先留一份 adapter 存档,再合并出部署版本。
  • QLoRA 的合并要先反量化基座。
  • 多个 adapter 合并到同一个模型时会互相干扰(参数空间的线性叠加不等于能力的叠加),且不同 adapter 的 α/r\alpha/r 口径要统一。

什么时候 PEFT 是错的选择(必答部分)#

场景 为什么不该用 PEFT
需要注入大量新知识 / 新语言 低秩瓶颈限制了可改变的幅度。知识与词汇层面的分布大偏移,通常需要全参微调(这也是为什么继续预训练/领域自适应阶段大多用全参)
需要扩词表 / 训练 embedding LoRA 一般只挂在 attention/MLP 的线性层上,embedding 与 LM head 不在默认作用范围内 —— 新语言、新特殊 token 的场景必须显式训练这些层,不能指望 LoRA
任务偏移极大、且数据充足、算力允许 低秩自由的表达力有限。广泛的经验是「格式/指令类任务上 LoRA 能追平全参,需要新知识的任务上会落后」—— 这是一个倾向而非定律,但足以让你在选型时提高警惕
需要模型行为发生大幅变化(如强对齐、长链推理能力跃升) 策略需要远离起点时,低秩子空间可能成为瓶颈。RL 场景用 LoRA 是可行的(也确实常见),但要意识到这是在用表达力换成本,务必用评测验证效果上限
基础框架不支持多 adapter 服务 如果不合并就要付出额外推理开销、合并又要多份权重,而你的服务栈又不支持多租户 adapter —— 此时 PEFT 的工程收益可能是负的
只是调 prompt 能解决的问题 顺序错误:先试 prompt / few-shot / RAG,再考虑微调。格式问题往往不需要训练

判断准则(可以直接说出口):PEFT 适合「改变行为」,不适合「改变知识」。 前者是调用既有表征的重新组合,低秩足够;后者需要改写或新增表征,低秩不够。

为什么 LoRA 省显存:真正的账要算对#

很多人答「因为可训练参数少,所以显存少」—— 方向对但没算到点上。真正的省在于优化器状态:

全参微调时,一个 NN 参数、用 Adam 的模型大约需要:权重 + 梯度 + 优化器一阶矩 + 优化器二阶矩(若用混合精度还有 fp32 主权重副本),合计可达权重本身的数倍。这些开销只与可训练参数挂钩。

LoRA 下 W0W_0 的梯度不存在、优化器状态也不存在,这些大头全部消失,只剩 adapter 那一小份。所以显存节省幅度远大于参数量比例所暗示的程度 —— 这才是 LoRA 能在消费级显卡上微调大模型的根本原因。

其他 PEFT 方法(知道名字和差异即可)#

  • Prefix / Prompt Tuning:在输入前拼一段可训练向量,参数量极小,但表达力与稳定性通常弱于 LoRA,对模型规模敏感。
  • Adapter(bottleneck):在层间插入小的下投影—上投影模块,会增加推理时的层数与串行深度。
  • IA³:用可学习的缩放向量调制激活,参数极少。
  • DoRA:把权重的幅度与方向分解,方向用 LoRA 更新、幅度单独学,是 LoRA 的一个改进变体。
  • Bias-only / 分层冻结:只训 bias 或部分层,比 LoRA 更弱但更省。

面试时不必逐一展开,但**能说出「LoRA 不是唯一的 PEFT、且在同等参数预算下通常比 prefix/prompt tuning 更强」**就够了。

常见面试问法#

Q:LoRA 的原理是什么?为什么它能省这么多显存? A:冻结 W0W_0,并联低秩增量 αrBA\frac{\alpha}{r}BA,只训 A,BA,B(AA 随机初始化、BB 零初始化,保证起点与基座一致)。省显存的关键不是权重本身,而是优化器状态:全参微调下权重、梯度、Adam 的一阶/二阶矩、混合精度的 fp32 主权重副本都是权重本身的数倍,而 LoRA 下这些只与 adapter 参数挂钩,W0W_0 的部分全部消失。

Q:rank 和 alpha 分别控制什么?它们怎么相互影响? A:rank 是容量旋钮(低秩子空间的维度),alpha 是缩放。实际生效的是 α/r\alpha/r,所以有意义的是比值:只加 rr 不动 α\alpha 会让 α/r\alpha/r 变小,等于把 LoRA 分支的输出缩小,这是「加了 rank 没变好」的常见原因。惯例上让 α\alpha 取 rr 的常数倍,使两者可以分开调。另外作用模块(target modules)通常比 rank 更影响效果上限。

Q:QLoRA 是什么?它和 LoRA 有什么取舍? A:把冻结基座量化到 4-bit(常用 NF4),配合双重量化和分页优化器,前向反量化到 bf16 计算,adapter 保持 bf16。收益是显存大幅下降,可以在单卡上微调更大的模型;代价是反量化带来额外计算(每步更慢)、量化有精度损失(效果接近但不等于全精度 LoRA)、且 4-bit 基座不能直接合并(要先反量化)。

Q:训练完的 LoRA 是合并好还是不合并好? A:取决于服务形态。合并 → 零推理开销、单一模型文件,适合单任务生产部署;不合并 → adapter 可热插拔,一套基座服务多任务/多客户,显存共享,适合多租户。取舍的关键是你是否需要在一份基座上切换多个任务。注意两点:合并在高精度下做(否则有舍入损失)、合并有损(抹掉 A,BA,B 的分解,之后不能"解开"继续训这个 adapter);生产上通常留 adapter 存档再合并出部署版本。

Q:什么情况下你会放弃 LoRA 选择全参微调? A:① 需要注入大量新知识或新语言(改变知识而非改变行为,低秩不够);② 需要扩词表/训练 embedding 与 LM head(不在 LoRA 的默认作用范围内);③ 任务偏移极大、数据充足、算力允许,且验证过 LoRA 的效果确实有瓶颈;④ 需要策略远离起点的大幅行为改变(强对齐、复杂推理能力跃升)。判断准则可以概括为:PEFT 适合改变行为,不适合改变知识。

Q:如果我们给每个客户训一个 LoRA,你觉得会踩什么坑? A:① adapter 的服务栈支持:不合并则推理要额外算 LoRA 分支或运行时合并,合并则每客户一份完整权重 —— 需要确认框架(如 vLLM 的多 LoRA 支持)能撑住;② 隔离与安全:不同客户的数据训出的 adapter 必须有严格的加载隔离,避免串号;③ 口径一致:所有 adapter 的 α/r\alpha/r、target modules、基座版本必须统一,否则无法共享基座;④ 评测:每个 adapter 都要单独跑目标能力评测,而通用能力回归只需测基座(adapter 通常不改变通用能力,但仍要抽验);⑤ 版本管理:基座一升级,所有 adapter 都要重新验证甚至重训。

易错点#

  • ❌ 说「LoRA 省显存是因为参数少」而不提优化器状态才是大头。
  • ❌ 孤立地谈 rank,不知道真正生效的是 α/r\alpha/r,也不知道只加 rank 会缩小有效缩放。
  • ❌ 忽略 target modules —— 它在实践中比 rank 更影响效果;且不同框架默认值不同,迁移时容易静默掉效果。
  • ❌ 声称 LoRA「一定不会灾难性遗忘」—— 它降低风险,但不保证。
  • ❌ 忘记 BB 零初始化的意义(保证训练起点等价于基座)。
  • ❌ 声称 QLoRA 与全精度 LoRA 效果完全一致。
  • ❌ 把合并说成无损可逆的操作。
  • ❌ 在所有场景无脑推荐 PEFT,讲不出它失败的场景(新知识、扩词表、大幅行为改变)。
  • ❌ 给出一个具体的 rr 值当作普适最优。

自测#

1. LoRA 大幅降低显存占用的真正原因是什么?请把「训练一个 NN 参数模型」的显存构成拆开说明。

答案

训练显存大致由四部分构成:① 模型权重;② 梯度;③ 优化器状态(Adam 为每个可训练参数各存一阶矩和二阶矩,即两份);④ 混合精度训练下的 fp32 主权重副本。后三项都只与可训练参数挂钩,合计可达权重本身的数倍。

LoRA 里 W0W_0 被冻结:它的梯度不存在(不参与反向传播的存储)、优化器状态不存在、也不需要主权重副本。这些大头一次性消失,只剩下 adapter 的极小一份。所以显存节省幅度远大于「可训练参数量比例」所暗示的程度 —— 例如参数量降到千分之几,显存节省却可能是一半以上。这就是 LoRA 能在有限显存下微调大模型的根本原因。

2. 你把 rank 从 8 提到 64,效果却没有提升。列出至少三个可能原因。

答案

① α\alpha 没跟着调:实际生效的是 α/r\alpha/r,只加 rr 会让 α/r\alpha/r 缩小,LoRA 分支的输出被压小 —— 相当于同时降低了有效学习率,两件事的效果互相抵消。应当把 α\alpha 同步放大(保持 α/r\alpha/r 或按惯例取常数倍)。

② 瓶颈不在容量,而在作用模块:如果 target modules 只挂了 q/v,增加 rank 只是让一个小范围更有表达力,而效果上限受限于作用范围。通常「扩大作用模块 + 较小 rank」比「单一模块 + 大 rank」更有效。

③ 数据量或任务本身不支持更大容量:小数据集上更大的容量只会更快过拟合(表现为训练 loss 更低但评测不升),这也是「内在维度」直觉的体现 —— 任务真正需要的改变可能远小于 rr。

④ (补充)学习率未随容量调整:容量变大后常需要更低的学习率。以及库/kernel 的兼容性问题导致配置未生效 —— 应先用参数量打印确认配置真的被应用。

3. 「PEFT 适合改变行为,不适合改变知识」——请把这个准则展开成三个具体场景的判断。

答案

① 改变行为(LoRA 合适):让模型按固定 JSON schema 输出工具调用参数、统一回复语气与格式、把回答风格对齐到某客户的话术、窄任务分类(如 QueWI 里的意图识别)。这些任务本质是重新组合模型已有的能力,改变的是在什么条件下输出什么,低秩子空间足够表达。

② 改变知识(LoRA 不合适):把某领域的私有知识注入模型、适配一门模型没充分见过的新语言、大幅改变领域词汇分布。这需要新增或改写表征,低秩瓶颈会限制可改变的幅度,通常该用全参微调(或先做领域继续预训练)。

③ 结构性变化(LoRA 做不到):需要扩词表、新增特殊 token、训练 embedding 与 LM head。LoRA 一般只作用于 attention/MLP 的线性层,这些参数不在它的默认作用范围内,必须显式训练。

补充判断依据:如果任务能用「明确的指令 + 上下文」描述清楚,先试 prompt/RAG 而不是微调;如果 LoRA 与全参微调的效果差距明显,且数据与算力允许,就说明这个任务的偏移已经超出「行为」范畴。

4. 合并 LoRA 权重时有哪些坑?

答案

① 精度:必须在高精度(bf16/fp16 起)下合并,低精度合并会引入舍入误差;QLoRA 的 4-bit 基座必须先反量化再加增量。

② 不可逆:合并后 ΔW\Delta W 变成一个完整矩阵,无法再精确还原出 A,BA,B,所以"合并后继续训这个 adapter"在语义上不成立;生产流程应保留 adapter 存档,合并产物只用于部署。

③ α/r\alpha/r 口径:合并时用的是训练时的缩放系数,如果加载 adapter 时配置的 α\alpha 或 rr 与训练时不一致,合并结果会整体尺度错误 —— 这是静默掉效果的常见事故。

④ 多 adapter 叠加:多个 adapter 合并到同一模型时是参数空间线性叠加,不等于能力叠加,会互相干扰;且它们的基座版本与作用模块必须一致。

⑤ 部署形态的真正取舍:合并换来零推理开销,但失去热插拔与显存共享;多租户服务通常选「不合并 + 框架的多 LoRA 支持」。另外注意「合并后在量化部署」与「量化基座 + LoRA」是两条不同的技术路线,数值行为不同,需要各自验证。

5. 给定一个「用 4 张卡把 32B 模型微调成垂域客服助手,训练数据 2 万条,主要是话术与格式」的需求,你会怎么选方案?

答案

先判断任务性质:话术与格式属于「改变行为」,不是「改变知识」,所以 PEFT 是对的选择 —— 这决定了不需要上全参微调。

方案要点:① 选 LoRA(或 QLoRA,如果 4 卡显存扛不住 32B 的优化器状态);② target modules 覆盖 attention 全部投影 + MLP,用中等偏小的 rank(作用模块比 rank 更影响上限);③ α\alpha 取 rr 的常数倍,保证有效缩放正常;④ 数据侧做去重、按主题切分、并预留一套通用能力回归集(2 万条话术数据是典型的窄分布场景,要盯灾难性遗忘 —— 这是个重要提醒,见 catastrophic-forgetting.md);⑤ 评测用双尺:目标侧是话术/格式遵循,通用侧是冻结的通用能力切片,两者画在同一横轴上;⑥ 部署形态:如果只有一个客服场景,合并出单一模型最省延迟;如果是多客户多场景,保留 adapter 形态并用支持多 LoRA 的推理框架。

风险提示要主动说:如果上线后发现模型答不出业务事实性问题,说明这已经是「知识」而非「行为」的问题 —— 正确的做法不是继续加大 rank,而是引入 RAG 或全参领域微调。