参数高效微调

F18
概念 · AI 基础

参数高效微调。

LoRA 之所以能一统天下,不是因为它把训练变便宜了——在它流行起来之前,全参微调对多数团队其实已经付得起。真正的原因是:特化的产物是一个 50 MB 的文件,而不是 140 GB 的一整份权重,于是上百个特化模型可以共用显存里的同一份基座,在它们之间切换从一次部署降格成一次路由。它的其余一切性质都由此推出——包括几乎人人都会在秩(rank)这个设置上犯的那个错。

STEP 1

究竟改了什么,又有什么没改。

全参微调会更新模型里的每一个权重。参数高效微调(PEFT)把它们全部冻住,另外训练一小撮新参数。LoRA——低秩适配,也是多数团队唯一需要的变体——是其中的主流形态:对一个权重矩阵 W,它学两个瘦长矩阵 AB,计算 y = Wx + (α/r)·BAx。基座毫发无损,适配器就是那个差值。

  • 参数量直接塌缩。对一个 4096×4096 的投影矩阵,全参微调要训练 1680 万个权重。秩取 16 时,LoRA 训练的是 16 × (4096 + 4096) = 131,072 个——约为 0.8%。放到整个模型上,通常落在被训练参数占比 0.1% 到 2% 之间。
  • 省下的显存主要来自优化器,而不是权重本身。Adam 会为每一个可训练参数保存两份动量估计。只训练 1% 的权重,就等于去掉了 99% 的优化器状态和 99% 的梯度缓冲——而这才是全参微调非得动用一整个集群的大头。QLoRA 更进一步,把冻住的基座压到 4 比特、适配器保持 bf16;正是这个组合,让在单卡上微调 70B 模型成为现实。
  • 产物是一个文件,不是一个模型。训练好的适配器只有几十到几百兆。你可以存下上千个、用普通对象存储做版本管理,也可以把它分发出去,而不必分发那些你未必有权再分发的权重。
  • 推理成本基本不变。适配器每层多一次小矩阵乘法——延迟增加个位数百分比;若把它合并回基座,则为零。PEFT 省的是训练与存储,服务阶段并不向你收税。

PEFT 不是"因为穷才将就"的低配微调。在多数团队真正会跑的指令遵循与风格适配任务上,配置得当的 LoRA 与全参微调的差距,小到很难在评估噪声之上被识别出来。它真正落后的地方是大规模知识注入,以及在新领域或新语种上的继续预训练——这正是下一步要讲的内容,也是那么多微调项目被判定为失败的原因。

STEP 2

秩是容量旋钮,它决定了你能教会什么。

r 决定适配器能装下多少信息。这是最常解释"结果令人失望"的那一个设置,因为它的失败看起来像"微调没用",而不是"容器太小了"。

  • 秩 8–16 教的是行为。输出格式、语气、拒绝边界、一个模型老是跑偏的 schema、一套文风、一种工具调用惯例。绝大多数上生产的 LoRA 干的都是这件事,也是这项技术最可靠的地带——模型本来就会做这个任务,你只是在挪动它落点的位置。
  • 秩 64–256 才开始教内容。一套新的领域词汇、一种不常见的推理模式、一门基座掌握得很差的语言。它训练更贵、存储更大,而且开始需要真正的数据量,而不是几百条样本。
  • 没有哪个秩能经济地教会事实。如果模型需要知道你的商品目录、你的故障历史,或任何会变的东西,答案是检索而不是权重——这正是微调、RAG 还是提示词通篇在论证的事。团队把秩拉到 128 想硬塞事实进去,结果得到一个以新方式自信出错的模型,然后断定这套方法坏掉了。
  • alpha 是缩放系数,不是第二个容量旋钮。α/r 这个因子缩放的是适配器的贡献量。常见约定是 α = 2r;改了秩却不调 alpha,等于悄悄改掉了有效学习率——"秩 16 时好好的,换到 64 就崩了"多半是这么来的。
  • 挂在哪些层上,比多数人以为的更要紧。最初的配方只适配注意力的 query 与 value 投影。当前实践则覆盖包括前馈块在内的每一个线性层,参数多花一些,但能稳定地把与全参微调的差距再抹掉一截。

诊断方法很便宜:拿同一份数据分别按秩 8 和秩 64 训一遍再对比。如果秩 64 明显更好,说明你想教的是内容,那就要么认下这份容量,要么把这个需求挪进检索。如果两者难分伯仲——通常都是如此——就取秩 8,把省下的力气花在数据集上,回报真正在那儿。

STEP 3

真正改变系统设计的那条性质:一个基座,多个适配器。

下面这部分,对做智能体的人比对管训练预算的人更要紧。因为基座权重是共享且未被改动的,服务栈可以在显存里只放一份模型,然后按请求施加不同的适配器。多适配器服务已是现代推理引擎的标准能力,底下是能让使用不同适配器的请求共享同一次前向的批处理算子。

  • 特化不再是一次部署。过去十个微调变体意味着十套模型部署和十倍显存。现在它意味着十个文件、一套部署,用哪一个是在请求时决定的——形状与模型路由相同,只是低了一层。
  • 按租户、按任务的适配器变得付得起。当边际成本只是一个文件加几百兆共享显存时,为每个客户、每种文档类型、或智能体循环的每个阶段各配一个适配器,是合理的设计;而当边际成本是一张 GPU 时,这个设计荒唐。
  • 合并还是不合并,是一个真实的取舍。把适配器合并进基座能去掉那次额外乘法,得到一个普通模型——当你只有一种特化、又想要最大吞吐时最合适。保持分离则保住了热切换,让一支机队服务所有人。同一支机队上,两者不可兼得。
  • 秩必须互相兼容。服务集群会配置一个适配器秩的上限,超过它的适配器加载不进去。训练团队和服务团队各自选默认值时,这是第一天最常见的失败。
  • 基座版本现在成了共享依赖。每个适配器都是针对确切的基座权重训出来的,换一个 checkpoint 就不可用。基座一旦被弃用,所有适配器同时作废——就是模型弃用与迁移里描述的那次重训事件,再乘上一个倍数。
STEP 4

什么时候它是对的工具,以及上线之后要付什么。

PEFT 开局便宜,长期不便宜。训练跑一个下午就完了;义务则会一直持续到这个适配器下线为止。

  • 当基座会做这个任务、却做得不稳定时,就该用它。长上下文下仍然守住的格式、一种领域语域、一套工具调用风格、在模型老爱变形的 schema 上可靠的结构化输出。这些都是行为问题,而行为正是适配器能挪动的东西。
  • 在提示词还没被认真试过之前,别用它。改提示词几分钟就上线且可回退;一个适配器则意味着一份数据集、一次训练、一套评估,以及一件长期存在的资产。提示、微调还是 RL 里论证的顺序依然成立——而更诚实的说法是:多数跳过提示词直奔微调的团队,手上那条提示词从来没被认真迭代过。
  • 每个适配器都要有自己的评估,而且是永久的。这是最常被漏掉的成本。十个适配器意味着十套评估、十个回归面,以及每次基座升级都要重新验证的十件事。评估负担随适配器数量线性增长——尽管服务侧的经济性极好,按租户配适配器仍然贵,贵就贵在这里。
  • 当心能力变窄。往一种行为上狠训,会让别的行为退化,而损失往往落在你训练分布之外、评估恰好没看的地方。在任务评估之外留一份泛化能力的留出检查;一个把你的指标提了四分、却在指令遵循上掉了八分的 LoRA,既常见又隐形。
  • 假定它迟早要按别人的时间表重训。适配器绑定基座 checkpoint,而 checkpoint 会被弃用。把重训当成经常性成本来预算,并把训练数据和配方一起纳入版本控制——没有它们,适配器文件一文不值。

默认配置:所有线性层、秩 8、α = 16,几千条认真核过的样本,外加一份包含了你并不打算改进的任务的留出评估。这个配置能应付绝大多数真实的微调需求,单卡一小时内训完,并且在需求其实是检索问题时快速失败。按你要教的东西来选技术——行为进适配器,事实进检索器——并按模型有多少行为需要挪动来选秩,而不是按这个项目感觉有多重要。

相关:蒸馏与量化看改变模型成本的另外两条路,后训练看适配器正在编辑的是哪一层,开放权重上的 RL 微调看有监督适配不够用时怎么办,以及面向智能体的自托管推理看是什么样的服务栈让多适配器部署真正值得拥有。