Learn AI · 模型硬功底(由内而外)
第 13 课 / 经典论文 P12  ·  阶段三:规模与效率(Hu et al., 2021)

LoRA:
冻住整个大模型,只训旁边两片「瘦」矩阵
——「人人都能微调」「一底座挂无数技能插件」的根

前三课都在讲「怎么把一个大模型训出来」(统一形状、配多少算力数据)。这一课换赛道:模型已经有了,怎么用极小成本把它微调到你的场景? 全量微调一个大模型贵得离谱——要更新所有参数、每个任务存一整份几十 GB 的副本、显存爆炸。LoRA 给出一个近乎魔法的省法:把整个大模型冻住,只在旁边训练两片很「瘦」的小矩阵。 它回答你天天在用的产品形态背后的原理:为什么现在「人人都能微调」?为什么能做到「一个底座模型 + 给每个客户/任务挂一个小适配器」?
LoRA 的一句话:冻结预训练权重 W 不动,给它配一个低秩的「补丁」ΔW = B·A(两片瘦矩阵,秩 r 很小),只训练这两片。
效果:可训练参数砍掉上万倍、显存大降、每个任务的 checkpoint 从 GB 变 MB;而且推理时把补丁合并回 W零额外延迟、质量逼近全量微调。 这就是 PEFT(参数高效微调)生态、QLoRA、以及「一底座挂无数技能插件」这种产品架构的根。

一、立靶:全量微调一个大模型,到底贵在哪?

回忆 GPT-3 课你学的「改动幅度轴」:从零训 → 全量微调 → in-context learning。全量微调虽然只是「在预训练权重上小幅再拧」,但「拧」的是全部参数:

立靶:每个任务都全量微调,成本是怎么堆起来的

更新所有参数——175B 个权重每个都要算梯度、存优化器状态,显存需求是参数本身的好几倍; ② 每个任务存一整份模型——你有 100 个客户/任务,就要存 100 份几十 GB 的副本; ③ 切换/部署笨重——没法在一个底座上灵活地服务多任务。 问题来了:适配一个新任务,真的需要动全部参数吗?还是其实只需要动「一点点」?

二、抽框架:把「更新量」拆成两片瘦矩阵

关键不在 W 本身,而在微调带来的「更新量」ΔW。全量微调学的是一个和 W 同样大的 ΔW(d×k)。LoRA 说:别学整块 ΔW,把它分解成两片瘦矩阵的乘积

ΔW = B · A,其中 r ≪ d, k

A 是 r×k(矮胖→其实是「瘦高压扁」),B 是 d×r。两者相乘还原成 d×k 的更新量,但真正要训的只有 A、B 里的参数。 秩 r(rank)是唯一的核心旋钮,取 1、2、4、8 这种极小值就够用。
参数量对比(以一个 4096×4096 的权重矩阵为例):全量 = 4096×4096 ≈ 1678 万;LoRA(r=8) = 2×4096×8 ≈ 6.5 万——不到 0.4%。整个模型层层叠加,总量同比例缩小,典型砍掉约 10000 倍

三、核心洞察:为什么「低秩」就够 + 推理零延迟

两个洞察撑起整篇论文——一个解释「为什么省得掉」,一个解释「为什么省了还不亏」。

洞察说明
① 任务适配的「内在秩」很低把一个预训练好的模型适配到新任务,需要改变的方向其实很少——更新量 ΔW 活在一个低维子空间里。所以用低秩的 B·A 去近似它,几乎不丢东西。这就是 LoRA 敢把 r 取到个位数的底气。
② 推理时可合并,零额外延迟用完后把 W + B·A 算出来合并成一个新的 W,模型结构和原来一模一样——推理不多花一分钟。这是 LoRA 胜过早期 adapter(往网络里插额外层、推理变慢)的关键。

第 ① 点接得上你学过的直觉:预训练已经把通用能力压进 W,适配新任务只是在通用底子上做一个小角度的偏转——不需要重塑整个大脑,只需要一个低秩的「微调补丁」。

四、动手玩:调秩 r,看「省多少」和「亏不亏」

以一个 4096×4096 的权重矩阵为例。点不同的秩 r,看可训练参数、checkpoint 大小、质量怎么变——你会看到秩极小时省得惊人、质量却几乎不掉。

选秩 r: 

看出门道了吗:从 r=8 到全量,质量几乎没差,但参数量差了 200 多倍。这就是「内在秩很低」的实证——花极小代价,买到接近全量微调的效果。

五、对照表(一):全量微调 vs LoRA

维度全量微调LoRA
动多少参数全部(如 175B)约万分之一(只训 A、B)
显存极高(要存所有梯度+优化器状态)大降(~3 倍以上节省)
每任务 checkpoint一整份模型(GB 级)一个小补丁(MB 级)
推理延迟正常零额外延迟(合并回 W)
多任务服务每任务一份大模型,笨重一底座 + 热插拔小补丁
质量基准逼近、常持平

六、对照表(二):回扣「改动幅度轴」+ LoRA 撑起的生态

把 LoRA 放回你 GPT-3 课学的那条「动权重多少」的轴上,它正好补上中间那个「便宜的微调」档:

方式动权重吗成本 / 特点
全量微调改全部,永久贵、每任务一整份
LoRA只改低秩补丁,永久便宜、补丁 MB 级、可热插拔
in-context learning不改,临时零训练,但每次推理带例子、占 token

🔮 LoRA 之上长出一整片生态:QLoRA(把底座量化压缩 + LoRA,让你在一张消费级显卡上微调几十 B 的模型)、PEFT(参数高效微调)成为默认范式。产品形态上,它直接催生了「一个冻结底座 + 给每个客户/角色/任务挂一个小 LoRA 补丁」——这正是你做「一套模型服务多场景」时最该想到的架构。

七、映射到你的项目

你工作里的东西其实就是这篇论文的什么
你想给某个垂直场景/客户「定制」一个模型,又怕成本爆炸LoRA:冻底座、只训低秩补丁——定制成本砍上万倍,补丁 MB 级,想要多少个就存多少个
「一套模型怎么同时服务很多不同任务/客户」就是 一底座 + 热插拔 LoRA 的架构:底座只存一份,每个场景一个小补丁,按需切换
你纠结「这个需求该 few-shot 还是去微调」现在轴上多了一档:LoRA = 便宜的永久微调。高频稳定且 few-shot 压不住 → 上 LoRA,比全量微调省太多
你听到「我们在消费级 GPU 上微调了一个 13B 模型」大概率是 QLoRA——量化 + LoRA 把门槛打到一张显卡,这就是「人人都能微调」的技术底
你想做「音色定制 / 角色定制」这类低成本批量定制同一思路:一个底座 + 每个声音/角色一个小补丁,而不是为每个都全量训一份

八、检索练习(关掉上文,凭记忆答)

1. LoRA 到底训练什么?
2. 为什么「低秩」就够用?
3. LoRA 相比早期「插额外层」的 adapter,关键优势是?

九、常见问题 FAQ

把这一课接到你真实工作上的几个关键问。点开看答。

秩 r 该取多大?是不是越大越好?

不是越大越好,而是「够用就行」。r 是「补丁的容量」:太小可能装不下复杂任务的适配,太大则参数变多、向全量微调退化、还可能过拟合。论文里 r=1~8 在很多任务上就已逼近全量——因为内在秩本就低。

实操经验:从 r=8 起步,任务简单可降到 4/2,效果不够再往上调到 16/32。它是你要调的主旋钮,但调的空间通常很小——这本身就是「内在秩低」的体现。

既然能合并回 W 零延迟,那「热插拔多个补丁」又怎么实现?

两种用法,按需选:① 合并模式——把某个 LoRA 永久并进 W,得到一个专用模型,推理零延迟,但就固定成这一个任务了;② 不合并模式——保持 W 冻结、补丁单独挂着,推理时临时加上 B·A。这样同一个底座可以同时挂不同补丁、按请求切换,代价是这点旁路计算(很小)。

产品上常这么用:底座只存一份,每个客户/角色一个 MB 级补丁,请求来了挂对应的那个。要极致单任务性能就合并,要多租户灵活就不合并——两头都给你了。

LoRA(便宜微调)和 RAG / few-shot,我做产品时怎么选?

它们解决不同的事,常常组合用:

改什么适合
few-shot不改权重,临时给例子任务多变、量小、要快试
LoRA改权重(低秩补丁),永久固定风格/技能/格式,高频稳定,要省推理 token
RAG不改权重,外挂知识需要最新/私有事实,知识常变

一句话区分:要它「换个说话方式/学个技能」→ LoRA;要它「知道某些具体事实」→ RAG;要它「这次照这几个例子办」→ few-shot。RAG 是后面 P19 的正课,到时再深挖。

为什么分解的是「更新量 ΔW」,而不是直接低秩近似 W 本身?

因为 W 不是低秩的,ΔW 才是。W(预训练权重)高秩、信息致密,装着海量通用知识——直接 W≈B·A把知识压扁、大量丢失,模型废掉。而适配新任务所需的「改变量」ΔW 内在秩很低,用低秩拟合它几乎不丢东西。

比方:W 是厚百科全书(不能压),ΔW 是薄勘误便利贴(就这任务微调几处)。LoRA 只用低秩去拟合那张便利贴。附带还白赚:W 冻结 → 不灾难性遗忘;W 原样保留 → 才能合并/卸载、一底座挂多补丁。

A、B 怎么初始化?为什么一开始补丁必须等于 0?

标准做法:A = 小随机高斯,B = 全 0,于是开训那刻 ΔW = B·A = 0必须从 0 起步,是因为要从「一模一样的预训练模型」开始——补丁若一上来随机非零,等于往调好的模型注入噪声,前几步全在撤销自己的破坏。从 0 起步则第 0 步=纯预训练行为,补丁只朝有用方向慢慢长出来。

为什么不两片都设 0?会梯度死锁:∂/∂A 依赖 B、∂/∂B 依赖 A,全 0 则梯度全 0、学不动。所以一片随机(打破对称、留梯度通路)、一片归零(保证乘积为 0)。另有 α/r 缩放因子控更新幅度,次要。

LoRA 能叠加吗?一个底座挂多个补丁会打架吗?

能挂很多,看怎么用,风险递增:

用法怎么做会打架吗
切换(热插拔)每请求用「底座+一个补丁」不会,干净常规做法
合并把一个补丁永久并进 W不会,但固定成单任务
同时叠加W+ΔW₁+ΔW₂… 一起上可能打架

叠加会冲突,是因为低秩更新线性相加、而各补丁没学过共存,可能把权重往互相矛盾的方向拽。缓解:加权组合、约束正交、或路由(Mixture-of-LoRAs)。实操标准姿势是「一请求一补丁」(零冲突);同时叠多个是要小心的高级玩法(类比文生图社区混多个风格 LoRA、堆多了就糊)。服务侧有 S-LoRA 等方案:底座只放一份,成千上万补丁高效换进换出。

本课主源

读原典:Hu et al. — LoRA: Low-Rank Adaptation of Large Language Models(2021)

想看它怎么把门槛打到一张显卡:搜 QLoRA(Dettmers et al., 2023,量化 + LoRA)。

阶段三进入「效率」段:LoRA 省微调成本。下一篇 P13 FlashAttention:省的是推理/训练时 attention 的显存与速度——直接对应实时语音等低延迟场景里的长上下文与延迟问题。

我是你的老师,随时提问。 比如:「为什么是分解 ΔW 而不是直接低秩近似 W 本身?」「A、B 初始化有讲究吗(为什么一开始补丁要等于 0)?」 「LoRA 能叠加吗,一个底座挂多个补丁会打架吗?」——别带着模糊往下走。

参考:
Hu et al., LoRA: Low-Rank Adaptation of Large Language Models, 2021.