阶段 5 · 大模型怎么炼成

LoRA:只训 0.1% 的参数
效果却几乎一样

上一章 《思维链与测试时计算》 算的是「多想一会儿」的训练账;这一章问:只改千分之一的参数够吗? 全量微调一个 70B 模型,光是训练状态(权重+梯度+Adam 动量方差)就要 840 GB 显存。 LoRA 的做法是:把原模型全部冻住,只在旁边插两个很小的矩阵,只训这两个。

1

全量微调的显存账单

训练和推理的显存需求完全不是一个量级。推理时一个 7B 模型用 bf16(16 位浮点,每个参数占 2 字节)只要 14GB; 训练时同样一个模型要多少?
项目每个参数占多少说明
权重(bf16)2 字节模型本身
梯度(bf16)2 字节反向传播算出来的
Adam 动量 m4 字节fp32 存,否则精度不够
Adam 方差 v4 字节同上
合计12 字节还没算激活值(前向计算中途要留下的中间结果),也不含 FP32 参数主副本
70B 模型全量微调 ≈ 70 × 109 × 12 字节 ≈ 840 GB
加上激活值和通信缓冲,实际要上千 GB —— 要一整个机柜的 A100
口径注:12 字节 = 权重 2 + 梯度 2 + Adam 的 m、v 各 4,不含 FP32(32 位浮点)主副本。 混合精度训练通常还要多存一份 4 字节的 FP32 主副本(防舍入误差), 加上就是 16 字节/参数,70B 约 1.1 TB——《分布式训练与集群》那章用的正是这个口径。

互动 · 训练比推理,多吃的是哪几个字节

推理(只存权重)
—
训练(权重+梯度+优化器)
—
训练 ÷ 推理
—

🎯 类比

你想给一本 1000 章的教科书加几条批注。
全量微调 = 把整本书重写一遍,还要保留所有草稿(梯度 + 优化器状态)。
LoRA = 在书页边上贴便签。原书一个字不动,只写那几条便签。

💡 为什么"贴便签"居然够用

因为微调不需要重新学会一门语言。基座模型已经会了。微调只是让它 "更倾向于某种回答方式"或"适应某个领域"——这是一个小改动,不是一次重写。
而"小改动"在数学上有个精确的说法:低秩。第 3 节会看到这个假设怎么被演示。

2

低秩假设:改动只需要几个方向

假设一个权重矩阵 W 是 4096 × 4096——d = 4096 就是矩阵的行宽,也就是一层的宽度。 全量微调会改动它的每个元素;LoRA 赌的是:真正需要的改动,可以用少数几个「方向」组合出来。 这里的「方向」就是后面窄门里过门的人;能同时过去的人数 r 叫秩,ΔW 最多由 r 个独立方向拼出来。

W' = W + ΔW ,其中 ΔW = B · A
A 的形状 r × d  B 的形状 d × r  r ≪ d
W 冻住不训;只有 A 和 B 是可训练的。A 随机初始化、B 全 0,所以一开始 ΔW = 0,模型和原来一模一样(LoRA 原文的做法)。

互动 · 秩 r 决定参数量

互动 · 三维看低秩:改动都挤在一张纸上

公式里还有一个 α/r:实际更新用的是 ΔW = (α / r) · B·A。 为什么要补这一下?因为调大 r 时 B·A 的数值也会跟着变大(加了更多项); 没有它,改了 r 之后学习率还得跟着重调。 配上 α/r,改 r 就只影响容量,不影响更新的幅度。 所以常见做法是 α 取 r 的 1~2 倍(或直接固定成 16),只调 r;起步用 r = 8~16 就够了,效果不够再加。

M

数学 · 一条只有 r 宽的窄门

「改动只需要几个方向」在数学上是一个形状问题: 原来的改动是一张 d×d 的大表(d2 个自由度),LoRA 换成两块窄条—— A 是 r×d、B 是 d×r,中间只留一个 r 宽的通道。 x 是这一层收到的输入(这里取 8 个数演示;真实模型里 d = 4096)。 把鼠标移到下面公式卡的符号上,对应的滑杆会亮。

动画 · 数据穿过窄门:d → r → d

🎯 用「窄门」理解低秩

想象一排 d 个人要过一道门。全量微调把门开成整面城墙那么宽—— 每个人都能单独决定自己怎么改,所以要 d2 个旋钮。
LoRA 把门收成只让 r 个人过去:剩下的人怎么变,只能靠这 r 个人组合出来。 旋钮从 d2 掉到 2dr,代价是「组合不出来的改动,永远做不到」—— 这就是第 7 节那条限制的来源。

上面那一行是活的:拖本节那两根滑杆,它会跟着变。

🎬 自己验一遍

把「窄门宽度 r」从 1 一路拖到 8:
· r = 1 时中间只有一个数能过门——所有改动只能沿同一个方向;
· r = 8(和输入一样宽)时门等于没关,这时候 2dr = 2×8×8 = 128,比 d² = 64 还大,LoRA 反而不省了。
所以真正的参数账要去第 2 节看:那里 d = 4096、r = 8,这一层的可训参数省了 256 倍。

3

多少秩才够?一个真算的谱分析

LoRA 的秩 r 是它唯一的重要超参。下面这个互动真做一次 SVD(奇异值分解): 把一张表拆成若干层,每一层的重要性就是一个奇异值;这些奇异值排成的那列数叫谱。 矩阵是我们构造的,一共只有 10 个方向(秩 = 10),所以 r = 10 时误差正好为 0。

互动 · 秩 r 与近似误差(真算的 SVD)

左图:奇异值谱明显是「陡降」的。前几个奇异值占了绝大部分"能量", 后面的迅速衰减到接近 0。这就是低秩假设成立时的样子—— 如果谱是平的,说明每个方向都同样重要,那就不存在"低秩"这回事,LoRA 根本不该有效。

右图:误差曲线在某个点之后基本变平。那个拐点就是"够用的秩"。 再往上加秩,参数量在涨,但误差几乎不降——纯浪费。

⚠️ 注意这是"理论最优"误差

这里算的误差是给定秩下最好的可能近似(数学上能保证截断 SVD 就是最优的)。 实际 LoRA 训练从随机初始化开始做梯度下降,达不到这个上界。
所以真实的 LoRA 需要比拐点稍大一点的秩:实践里 r = 8~64 是常见区间,而理论上的拐点常在 r = 2~4。 起步可以先试 r = 8~16。

4

QLoRA:再砍一刀

LoRA 把可训练参数压到了千分之一上下,但基座模型本身还是要占显存——65B 模型 bf16 就占 130GB。 QLoRA 的答案是:把冻住的基座也量化掉。

互动 · 三种方案的显存对比

技巧做什么省下什么
NF4 量化 把权重量化成 4 位的"正态分布友好"格式 基座显存直接砍到 1/4。NF4 是专门为神经网络权重设计的, 比普通 int4 精度更高
双重量化 连量化用的"缩放系数"本身也量化一遍 每 64 个参数存一个 fp32 缩放系数,累积起来不小。再量化一次能省约 0.4 bit/参数
分页优化器 显存不够时把优化器状态临时换到内存 避免长序列训练时的显存尖峰直接 OOM(显存不够,程序当场崩)

互动 · NF4 和「普通的 4bit」到底差在哪

均匀档位的误差
—
NF4 档位的误差
—
NF4 好多少
—

2023 年,QLoRA 让 65B 模型的微调第一次能在单张 48GB 的工作站显卡上跑完。 在这之前,微调 65B 需要一整个机柜;这一下把"自己微调一个大模型"从只有大公司能做的事,变成了单张专业卡就能做的事。 消费级 24GB 卡(配 QLoRA)能微调的通常是 7B~13B。 今天大部分消费级显卡上的微调,走的就是 QLoRA 这条路。

5

加在哪?目标模块的选择

LoRA 可以插在 Transformer 的任何线性层上。

插在哪参数量效果
只有 q, v
LoRA 原论文(Hu et al. 2021)的选择
最小 在原论文的设定下够用,是流传最广的默认值。但这是在 GPT-3 时代的模型上得出的结论
q, k, v, o2 倍 略好。注意力部分全覆盖
所有线性层
含 FFN
4~6 倍 明显更好。FFN 占了 2/3 的参数,也大致占了 2/3 的"知识"(粗略说法)—— 想改知识必须动它
embedding + lm_head
把词表映射成向量、再把向量映射回词表的两张表
视词表而定 学新词汇、新语言时必须加,否则新 token 学不到东西

互动 · 插在哪几个模块,差多少参数(LLaMA-7B 的真账)

可训练参数
—
占 7B 模型的
—

⚠️ 一个常见的反向误区

很多人听说"r 越大越好",就一直往上加 r。但 r 不是越大越好:
秩给多了,模型会开始拟合数据里的噪声和格式癖好,泛化反而变差。 一种经验说法是,LoRA 的瓶颈常常不在容量,而在数据质量(见第 7 节 ④)。
先确保数据是对的,再考虑要不要加秩。 数据量看任务:LIMA 用 1,000 条,Alpaca 用 5.2 万条。

6

省参数的不止 LoRA 一家

方法在哪加参数特点
Adapter
2019
在每层后面插一个小 MLP 最早的方案。但增加了推理深度,推理时会变慢
Prefix / Prompt Tuning 在输入前面拼一段可训练的"虚拟 token" 不改模型结构。但占用上下文长度,效果不如 LoRA 稳定
LoRA
2021
旁挂在权重矩阵上,ΔW = BA 推理时可以合并回原权重,零额外延迟——这是它胜出的关键
QLoRA
2023
LoRA + 4bit 量化的基座 消费级显卡也能微调大模型。历史意义最大的一次
LoRA+ 给 B 用比 A 更大的学习率 收敛更快。实现极简,性价比高
DoRA
2024
把权重拆成「幅度」和「方向」分开调(每个数的长度和朝向) 低秩时明显优于 LoRA,接近全量微调。代价是训练慢一些
PiSSA 用 SVD 的主成分初始化 A 和 B,而不是随机 收敛更快,效果更好。思想就是拿这一章第 3 节的谱分析结果当初始化
AdaLoRA 不同层分配不同的秩,重要层给大秩 自动化了"该给多少秩"这个问题,但实现复杂
VeRA / LoHa 共享一对随机矩阵、只学缩放向量 / 用 Hadamard 积(两个矩阵对应位置的数直接相乘) 参数更少,适合极端的显存限制
全量微调 — 上限最高,原因是没有容量约束——不是它"学到了更多"。 数据够多、算力够时它仍然是最好选择

互动 · 这一家成员,各要多少参数(同一个 7B 模型上的真账)

7

LoRA 学不会什么

下面是另一个例子:一个行为型的改动,主要成分只有 3 个方向。 它和第 3 节那张谱不是同一个矩阵——但两张图回答同一个问题:一个改动里有多少能被 r 个方向装下。

限制具体表现
① 只能"激活已有的",学不会全新的 这是最重要的一条。LoRA 是在原权重的边上加扰动, 它能改变模型"倾向于做什么",但很难塞进基座完全不具备的知识或技能。
换句话说:调行为,LoRA 够;学新知识,得靠继续预训练。
② 多 LoRA 会互相干扰 虽然可以给不同任务训不同的 LoRA 再动态切换,但 同时加载多个、或者远距离任务之间,会互相打架。 这也是为什么"统一的通用 LoRA"很难训出来
③ 合并之后无法反悔 把 ΔW 合并回 W 之后推理零延迟,但你就失去了这个 LoRA 的独立身份,不能再做切换或撤销。 不合并、让多个 LoRA 动态切换也行:每个插了 LoRA 的模块多算两次小矩阵乘,额外开销很小
④ 对数据的质量更敏感 因为容量小,它没法"稀释"坏数据的影响。 同样一批脏数据,全量微调可能还能扛住,LoRA 会更快地被带偏

互动 · 同一张改动,LoRA 够得着哪一部分

示意图 · 能改到的区域,一眼看完

预训练好的 W(起点) 虚线大圆 = 全量微调能去的地方(d² 个方向) 窄带 = LoRA 能去的地方(只有 2dr 个旋钮) ● 改行为:够得着 ● 塞新知识:够不着 带子有多窄,就看 r 占 d 的多少

前面那两张误差图说的都是这件事:窄带内的地方随便去,窄带外的地方一步也迈不出去。

⚠️ 选型时先问一个问题

「我要改的是知识,还是行为?」
· 行为(输出格式、说话风格、遵循指令的方式、领域术语的用法)→ LoRA 足够
· 知识(这个学科的专业事实、一门新语言、一个陌生的代码库)→ LoRA 基本无效,要么 RAG,要么继续预训练
「领域术语的用法」拿不准时:用法偏行为,术语背后的新事实偏知识;还是拿不准就先上 RAG。
这一条判断错了,后面调什么参数都是白费。

8

小结

它对应哪条线 ④ 学习即压缩——LoRA 的全部赌注就是「微调带来的那点改动,信息量小到能被压进少数几个方向」
一句话 这一章的做法,本质上是在承认「微调只需要很少的信息」,并把这个信息量硬性焊成秩 r 这道窄门—— 原模型一动不动,只在旁边挂一条低秩的偏置 ΔW = BA。
它牺牲了什么 牺牲了容量——也就是「能装进多少新东西」。低秩把整模型的可训练参数压到了千分之一上下, 代价明明白白写在第 7 节的第 ① 条:它只能激活基座里已有的行为,塞不进全新的知识(回扣暗线 B)。 省掉的是真实的表达能力——不是甩掉了多余参数;而这个损失只在你恰好需要它时才露出来。
🎬 检验一下:你现在能指着哪个互动说这句话

回到第 3 节那张「秩 r 与近似误差(真算的 SVD)」。把 r 从 1 一格一格拖到 11, 盯着右图那条误差曲线:前几格陡降,过了某个拐点就几乎躺平、不再往下走。

那个躺平的瞬间你看到的就是「学习即压缩」:误差不再降,说明你要的那点改动里信息量就这么大, 秩再往上加,加进去的只是参数和噪声。

再往下挖一层:低秩为什么会成立?

直觉上实际发生的事
微调 = 教模型新东西,所以得动很多参数 微调更像是让一个已经会说话的东西换一种说法。 基座早就把「世界」压进权重里了,微调只是在已有表征上选边站—— 选边是一项低信息量的动作
秩 r 小 = 模型被削笨了 秩 r 小 = 可训练的自由度少。它不是「不会」,只是能改的地方太少, 所以坏数据一来就直接把它带偏(见第 7 节 ④)
参数越多,能力越强 本章就是反例:参数量降到千分之一,效果常常看不出差别。 「能力」和「参数量」不是同一件事——能力的大部分存在你根本没动的那些参数里

它在暗线里站在哪

暗线这一章的回答
信息流动 输入输出的形状一个都没变,变的只有前向沿途经过的那些权重矩阵: d×d 的 W 被换成 W + BA,其中 A 是 r × d、B 是 d × r。 信息穿过 ΔW 时被迫挤过一道只有 r 宽的窄门——这就是「低秩」在形状上的全部含义
什么被牺牲了 牺牲容量,换来显存和延迟两块。而且这笔交换是不对称的: 省下的显存是形状必然带来的,损失的能力却只在任务恰好需要它时才出现, 所以它在「改行为」的任务上看起来像白赚的。这笔交易的账单就是第 7 节那张表
参数账本 全量微调 70B:12 字节/参数 ≈ 840 GB (不含 FP32 主副本;含主副本 16 字节/参数 ≈ 1.1 TB)。
LoRA 的账:一个 4096×4096 的权重有 16,777,216 个参数; r=8 时 ΔW = BA 只有 2 × 4096 × 8 = 65,536 个,是这一层的 0.39%(整模型的可训占比见第 5 节)。
QLoRA 的账:65B 基座 bf16 要 130 GB, NF4 之后约 33 GB(双重量化再省约 0.4 bit/参数)—— 这就是「单张 48GB 卡能微调 65B」这个数字的来源
它假设了什么 假设「不同下游任务之间的差异是低维的」——这是一句关于世界的断言,不是数学定理。 第 3 节那张奇异值谱画的就是它成立时的样子:谱陡降,假设成立;谱要是平的,LoRA 根本不该有效。 LoRA 赌的是「人交给模型的那些微调任务,彼此只差几个方向」——低秩近似好不好用,是这句话的推论
违背了哪个直觉 「模型越大越难微调」是错的。模型越大,ΔW 相对基座的占比越小,LoRA 越划算—— 它把「能不能微调」从算力问题换成了装不装得下的问题。
第二个反直觉:参数量不等于能力。降到千分之一而效果不变, 说明能力大部分躺在你根本没动的那些参数里
🎯 前后钩子

它接住了上一章的什么:《思维链与测试时计算》留下的账是 「训一个会想的模型,贵在训练显存」;LoRA 问:这笔账能不能只付千分之一?

它给后面哪一章留了什么:如果连微调都能压到千分之一, 那「让模型记住一批事实」是不是可以完全不碰权重?这就是更后面的 《RAG 检索增强》的出发点。

一句话带走 LoRA

LoRA 赌的是"微调带来的改动是低秩的"——用 ΔW = BA 两个小矩阵代替整个矩阵的更新, 整模型的可训参数降到千分之一,而且推理时可以合并回原权重,零额外延迟。
α/r 缩放是让人能安心调 r 的关键;r 调到某个值之后误差就不再降, 再加秩纯属浪费。QLoRA(4bit 基座 + LoRA)把大模型微调拉进了消费级显卡。
最后记住那条分界线:LoRA 改「行为」绰绰有余,改「知识」基本没用—— 先想清楚你要改的是哪一个。

9

拓展阅读

上面讲的都是「够用」的版本。想往下挖,这里有三个入口—— 它们不是必修内容,是给想再往前走一步的读者准备的。

📄 这一章的说法从哪来

💻 工业界怎么写

∑ 更严格的形式