16 课 · 量化与 LoRA
LESSON 16 · 卷十六 装得下

模型还没训
钱包先装不下

第 14 课那个 2,677,632 个参数的小模型, 全量微调只要 0.04 GB,免费显卡随便跑。 可真实世界里的模型是 6,738,415,616 个参数 —— 同一个「每个参数 16 字节」的规矩套上去,就是 107.8 GB,七张 16 GB 的卡才装得下。 这一课给你两把刀:量化(把每个参数从 16 位压到 4 位)和 LoRA(只训练一小撮外挂参数),叠起来 = QLoRA, 让一个 7B 模型在 3.9 GB 里就能微调。

STAGE 01
先算清账
16 字节/参数是怎么来的
STAGE 02
量化
16 位 → 4 位,误差多少
STAGE 03
LoRA
只训 0.1% 的参数
STAGE 04
收官
两把刀叠起来

这一课的性质和前十四课不太一样。前面每一课都在拆「模型怎么算」,这一课拆的是「模型怎么」。 听起来像工程杂活,可它决定了一件很现实的事:你到底能不能亲手微调一个真实的模型。 而且这一课里没有一个新公式 —— 全是加减乘除。 真正难的地方在于:要先知道每个参数身上到底挂着几样东西

第 1 站

先算清账:一个参数身上挂着 16 个字节

你可能听过一句话:「7B 的模型全量微调要一百多 GB」。 一百多是多多少?为什么不是「7B × 2 字节 = 14 GB」? 因为训练时的参数,身上不止挂着它自己。 下面这张表把每一样东西点出来 —— 一行一行加起来,正好是那个 16。

核心实验换个模型,看那笔显存账怎么从 24.7 GB 涨到 107.8 GB
看哪个模型6,738,415,616 个参数(官方公布值)
每个参数身上挂着的东西字节为什么
权重(fp16)2模型本身,前向要用
梯度(fp16)2反向传播算出来的,每个参数一份
主权重(fp32)4更新时要够精确,所以留一份全精度的
Adam 一阶动量 m4梯度的滑动平均,fp32
Adam 二阶动量 v4梯度平方的滑动平均,fp32
合计16全量微调:每个参数 16 个字节
7B 档 一共 6,738,415,616 个参数,全量微调就是 6,738,415,616 × 16 = 107,814,649,856 字节 = 107.8 GB
注意这笔账的构成:模型本身(权重)只占 2 个字节, 剩下 14 个字节全是「为了让它能被训练」而多出来的 —— 梯度、全精度主权重、Adam 的两个动量。所以「省显存」最快的路子不是把模型做小,是让大部分参数根本不需要这 14 个字节。这一课的两把刀(量化、LoRA)就是冲着这件事去的。
三种做法的显存账单(同一根刻度:满格 = 全量微调 107.8 GB):
全量微调每个参数都带梯度 + 优化器状态
107.8 GB
LoRA · 基座 fp16 冻结只训 8,388,608 个外挂参数(r=8
13.6 GB
QLoRA · 基座 4 位冻结基座从 13.5 GB 压到 3.8 GB
3.9 GB
7B 档107.813.63.9 GB, 比全量微调省 7.9 倍 / 27 免费那张 T4 是 16 GB —— 全量微调 7B 要七张卡,QLoRA 一张还剩一大半
LoRA 那一步省下来的是「优化器状态」这笔账:全量要 94.3 GB,LoRA 只要 0.13 GB。 量化那一步省的是「基座本身」:13.53.8 GB。两把刀砍的是两笔不同的账,所以能叠在一起用 —— 那就是 QLoRA。
👆 图上三根条是同一条刻度,所以长短能直接比:全量那根撑满, LoRA 和 QLoRA 短得只剩一小截 —— 这不是画法问题,是真的差了 27 倍。 切到 1.5B 那档看:全量 24.7 GB,普通显卡其实已经能扛 ——所以「要不要上 QLoRA」是个按规模做的选择题,不是教条。
图 16-1 · 全量微调 / LoRA / QLoRA 三本账,同一根刻度(满格 = 全量微调)
7B 档6,738,415,616 个参数,全量微调要 107.8 GB。免费那张 T4 是 16 GB。猜一猜:要几张卡才装得下?再猜一句:光装权重、什么都不训,又要多少?
名桥 · 和 第 12 课 那本账对不上?

第 12 课算过一笔账:7B 光优化器状态(参数 + 一阶动量 + 二阶动量,三份 fp32)就要 78.2 GiB(十进制是 84.0 GB)。 这一课说「权重之外的那部分」是 94.3 GB ——两个数不一样,但都对。

差别全在口径,而且只有两处:

① 参数量取谁。第 12 课用的是「7B」这个外号,也就是 7,000,000,000;这一课用的是官方公布的准确值 6,738,415,616 —— 差了 3.7%, 「7B」本来就是四舍五入的说法。

② 每个参数算几份。第 12 课是纯 fp32 教科书口径:参数 + m + v 三份 × 4 字节 = 12 字节,即 7,000,000,000 × 12 = 84 GB。 这一课是混合精度 + AdamW 实战口径:fp16 梯度 2 + fp32 主权重 4 + 两个 fp32 动量 8 = 14 字节(权重那 2 个字节不算在内),即 6,738,415,616 × 14 = 94,337,818,624 字节 = 94.3 GB。多出来的是「梯度要单独存一份 fp16」,少掉的是「权重按 fp16 算而不是 fp32」。

两套口径加起来的量都在「一百多 GB」这一档,所以一张 16 GB 的卡横竖都塞不下。以后看到不同资料给的显存数字差一截,先问一句:它是按什么口径算的?

面试常问 · 参数量估算与显存估算
  • 训练显存 ≈ 参数量 × 16 字节(混合精度 + AdamW 那一套)。 面试里让你「估一下 7B 微调要多少显存」,答的就是这个乘法的量级。
  • 推理显存 ≈ 参数量 × 每个参数字节数:fp16 是 2、int8 是 1、NF4 是 0.5625。所以「7B 要 14 GB」说的是推理, 而「7B 要一百多 GB」说的是全量微调 —— 这两句话经常被人混在一起说。
  • 推理显存要留余量:KV cache(第 9 课那个)会随上下文长度线性涨, 还有框架自身的开销。所以「一张 16 G 卡跑 7B」是能跑,但上下文不能太长。
  • 估参数量本身:第 8 课那本账(注意力 + FFN + 嵌入 + 输出层)。 记住 FFN 是大头(在一层里大约占三分之二的参数), 这个结论在所有规模上都成立 —— 所以第 8 课那个「FFN 放大 4 倍」的超参 直接决定模型有多大。
动手实验同一个「7B」,为什么有人说是 14 GB、有人说是一百多 GB?
精度每个参数占 2 字节
模型Llama-2-7B · 7,000,000,000 个参数
推理 · 只装权重7,000,000,000 × 2 字节 = 14,000,000,000 字节 · fp16
14.0 GB
全量微调 · 要梯度 + 优化器状态7,000,000,000 × 16 字节 = 112,000,000,000 字节 · 每个参数 16 字节,纹丝不动
112.0 GB
两根条共用同一根刻度:满格 = 112.0 GB(7B 全量微调); 红色竖线 = 16 GB 显卡的位置 —— 推理那根能落在它左边,全量那根冲出去老远。
推理(只装权重):7,000,000,000 × 2 字节 = 14,000,000,000 字节 = 14.0 GB
全量微调(还要梯度 + 优化器状态):7,000,000,000 × 16 字节 = 112,000,000,000 字节 = 112.0 GB
两根条差:112.0 ÷ 14.0 = 8.0 —— 同一个 7B 档,就差在乘 2 还是乘 16
把精度从 fp32 一路切到 NF4,推理那根:28.0 → 14.0 → 7.0 → 3.9 GB(越切越短); 全量那根始终是 112.0 GB,一个字节都不动 —— 量化压的是权重,压不动梯度和优化器状态。
16 GB 显卡:推理 14.0 GB 装得下(还剩 2.0 GB); 全量 112.0 GB 要 7 张卡。
「7B 要 14.0 GB」说的是推理7,000,000,000 × 2 字节),「7B 要一百多 GB」说的是全量微调7,000,000,000 × 16 字节 = 112.0 GB)—— 这两句话经常被人混在一起说,其实是同一个模型的两笔完全不同的账, 长度差了 8 倍。
推理 · 只装权重(随精度变)
14.0 GB
7,000,000,000 × 2 字节 = 14,000,000,000 字节
占全量那根的 12.5%
全量微调 · 权重 + 梯度 + 优化器状态(不随精度变)
112.0 GB
7,000,000,000 × 16 字节 = 112,000,000,000 字节
权重只占其中 2 个字节,另外 14 个是为「能训练」多出来的
全量 ÷ 推理(差几倍)
8.0
112.0 ÷ 14.0 = 8.0
fp16 档就是 16 ÷ 2 = 8
16 GB 显卡能装下哪根
推理装得下
推理 14.0 GB(还剩 2.0 GB)
全量 112.0 GB(要 7 张卡)
👆 先点「fp32 / fp16 / int8 / NF4」:上面那根(推理)肉眼可见地变短, 下面那根(全量微调)纹丝不动 —— 因为它算的是「每个参数 16 个字节」, 跟你把权重存成几位没关系。再点「1.5B 档 / 7B 档」:两根条一起缩,但比例永远是 8 倍。红条 = 已经超出 16 GB 显卡:7B 的推理(fp16 14.0 GB) 刚好落在红线左边,全量那根(112.0 GB)直接冲出去 7 倍。
👆 先点精度(fp32 / fp16 / int8 / NF4),再点模型(1.5B 档 / 7B 档)。 盯住两根条:上面那根「推理」随精度明显变短,下面那根「全量微调」纹丝不动 —— 因为量化压的是「每个权重占几个字节」,压不动梯度和优化器状态那笔账。 红色竖线是 16 GB 显卡的位置,条一变红就说明已经装不下了。
图 16-2 · 「7B 要 14 GB」说的是推理,「7B 要一百多 GB」说的是全量微调 —— 同一根刻度下,两根条差 8 倍
第 2 站

第一把刀 · 量化:把 16 位压到 4 位

第一个念头很自然:既然那 14 个字节省不掉,那把每个字节本身变小行不行? fp16 用 16 个比特存一个权重 —— 可权重真有那么精细吗? 真实权重是训练出来的一堆小数,它们大部分挤在 0 附近, 真正需要「高精度」的地方其实很有限。 于是有了量化:不再记录精确的数,只记录「它离哪个档位最近」。 代价是误差,问题是误差有多大。

核心实验16 个档位摆上数轴,把 64 个真权重一个个按进去
A. 先算清比特账:4 位到底是多少字节?量化就是把每个参数从「16 个比特」换成「4 个比特」。但实际存的时候要多带一个缩放因子。
fp16(现在)
16 位
= 2 字节/参数
NF4:参数本身
4 位
16 档里挑一格,正好 4 个比特
64 个参数共用
1 个 fp32
32 ÷ 64 = 0.5 位/参数
平均每个参数
4.5
4.5 ÷ 8 = 0.5625 字节
16 位 → 4.5 位,账小了 3.562 ÷ 0.5625 = 3.6)。
为什么每 64 个参数要共用一个缩放因子?因为 4 个比特只有 16 个格子, 直接拿它表示真实权重(范围 -0.06 ~ +0.06)根本不够分。做法是先把这一块里最大那个数的绝对值记下来(就是这个缩放因子), 让所有数都除以它、落到 −1~+1 之间,再按码表取整。
代价藏在「共用」两个字里:同一块里的 64 个数被同一个缩放因子绑在一起, 块内某个数特别大,其余 63 个就被挤得只剩很少的格子可用。
B. 那 16 个档位长什么样?把 −1~+1 切成 16 格。切法有两种,切出来的格子宽度完全不同 —— 下图每一根竖线就是一档。
码表
-1.00-0.70-0.53-0.39-0.28-0.18-0.090.000.080.160.250.340.440.560.721.00每根竖线 = 一个可以落脚的档位 · 横轴 = −1 ~ +1(归一化之后的权重)
1-1.0002-0.6963-0.5254-0.3955-0.2846-0.1857-0.09180.00090.080100.161110.246120.338130.441140.563150.723161.000
NF4 表:最窄的一格 0.0796(就在 0 旁边), 最宽的一格 0.3038(在最边上), 宽窄差了 3.8
这就是「按正态分布的分位数切」的实际样子:中间密、两头疏。 因为真实的权重本来就是中间多、两头少 —— 档位这么排, 才把有限的 16 个格子都放在「有数的地方」。
C. 亲手按一个数进去。拖动滑块(这是归一化之后的数,范围 −1~+1),看它落到哪一档。
0.122
快速跳
0.122↓ 就存这一档 0.161
归一化之后的数
0.122
除以缩放因子 0.06014 的结果
落到第几档
10
档位值 0.1609
这一档差值多少
0.0389
这就是量化误差(单个数的)
换成原始权重
0.122 × 0.06014 = 0.00734
存进去的是 0.161 × 缩放因子 = 0.00968
拿计算器复现第 1 个真实权重:它本身是 0.00736, 这一块的缩放因子是 0.06014(块里绝对值最大的那个数)。 除一下:0.00736 ÷ 0.06014 = 0.122(就是上面滑块跳到的那一格), 离它最近的是第 100.16093020141124725; 乘回去 = 0.00968原来 0.00736、存完读回来 0.00968,差 0.00232
注意这里的「最近」是在归一化之后算的 —— 码表永远是 −1~+1 这 16 格, 缩放因子把它拉回到真实量级。所以换一块权重(换一个缩放因子), 码表不用动,这就是分块的好处。
D. 64 个真权重一起被按进去。下面这 64 个权重是按正态分布抽出来的(标准差 0.02,和真实小模型一个量级)—— 空心点是原值,实心点是「存成 4 位再读回来」的值,细线就是这次量化把它挪动了多少。
原值还原0.0601+0.0601细竖线 = 16 个档位 × 缩放因子(能落脚的地方)
这 64 个权重的平均绝对值是 0.01670, 绝对值最大的是 0.06014 —— 它就是这一块的缩放因子。
把这 64 个点从原值挪到档位线上,挪动的均方根(RMSE)是 1.96e-3, 相对误差 11.8%(误差 ÷ 平均绝对值)。
读这张图看两件事:①两头几乎没有点(权重都挤在中间), 所以 NF4 把档位在中间排密是对的;②还原点全都落在细竖线上, 一个都不偏 —— 这就是「量化」的全部含义:把连续的数换成有限格子里的一个。
三种存法的误差(同一批 64 个权重,同一根刻度:满格 = 16%):
fp16(16 位)RMSE 4.60e-6,等于「几乎没误差」
0.03%
NF4(4 位,按正态切)分位数切法 —— 胜出
11.8%
等距 16 档(4 位,平均分)同样的 4 位,切法不同就吃亏
14.6%
同样是 4 位、同样 16 个格子,NF4 的误差比等距切法小 1.24 —— 它一个比特都没多花,只是把格子摆对了地方。
而 4 位量化的误差是 fp16 的 42711.8%0.03%)—— 听起来很吓人,但模型是一整个网络在算,每个权重偏一点, 输出偏得远没有那么大。这也是为什么 4 位已经能跑得挺好。
👆 三根条是同一根刻度(0 ~ 16% 相对误差),长短直接可比。 fp16 那根细得几乎看不见 —— 那不是画错了,是它的误差真的只有 0.03%。 切上面「码表」那个开关,数轴上的竖线会从「中间密」变成「处处一样宽」, 但 16 根的数量不变 —— 位数决定了几格,切法决定了格子摆在哪,这是两件事。
图 16-3 · NF4 的 16 个档位(中间密、两头疏)与 64 个真权重的量化前后对比
一个 fp16 的数是 16 位,NF4 只用 4 位 —— 精度一下子砍掉 12 个比特猜一猜:那 64 个权重的量化误差,是 fp16 的多少倍?给个数量级就行。
面试常问 · 4 位量化 / NF4 / 分块缩放
  • 为什么是 4 位而不是 8 位或 2 位:8 位省得不够(还不如直接用 fp16 权重); 2 位误差太大、模型会明显变笨。4 位正好落在「省得多 + 还不明显掉分」的位置上。
  • NF4 的「NF」是 Normal Float:档位按标准正态分布的分位数切, 所以中间密、两头疏。而且它刻意不对称 —— 负侧 7 档、0 一档、正侧 8 档(正侧多一格)。 原因还是那句话:把有限的格子放在「有数据的地方」—— 正侧多一格,是因为按分位数切的时候,要让两端的极值也落在格子上。
  • 分块缩放(block-wise scale):每 64 个参数共用一个 fp32 缩放因子, 于是每个参数平均占 4.5 位 = 0.5625 字节。 「共用」的代价是块内会被最大的那个数带着走, 所以工程上块越小越准(但存的缩放因子也越多)。Qwen 用的是 64 或 128 的块。
  • 量化分两种时机训练后量化(PTQ,模型训好了再压,简单、但可能掉分)和 量化感知训练(QAT,训练时就把量化误差算进去,效果更好、更贵)。 QLoRA 属于前者 —— 它在 4 位的基座上微调,靠 LoRA 那部分来补回精度。
第 3 站

第二把刀 · LoRA:只训练一小撮外挂参数

量化砍的是「每个参数占几个字节」。可回过头看第 1 站那张表, 会不会发现一件事:那 14 个字节里,绝大部分根本不是权重本身—— 是梯度、是优化器状态。既然模型本身只要 2 个字节就够, 那能不能干脆让绝大多数参数连梯度都不要? LoRA 就是这么干的:把原权重冻住,在它旁边挂一对小矩阵, 只训这一对。算下来,可训练的参数量是 0.1% 这个量级

核心实验拧一拧秩:参数量怎么涨,显存为什么不动
回到第 1 站那张表:每个参数的 16 个字节里,权重只占 2 个, 剩下 14 个全是「为了训练」才挂上的。 所以真正该问的不是「怎么把参数压小」,而是 ——能不能让绝大多数参数根本不需要那 14 个字节?
LoRA 的答案:把原权重冻住(它只读、只占 2 个字节,和推理时一样), 然后在它旁边挂一对小矩阵 BA, 只有这一对小矩阵要梯度、要优化器状态。
下面这张表里,「冻结基座」那一列对任何秩都一样 —— 这就是 LoRA 最要紧的性质:省下来的钱不随秩变化。
看哪个模型d = 409632
秩 r32 层 × 4 个投影 × r × 2 × 4096
要训练的参数
8,388,608
32 × 4 × 8 × 2 × 4096 = 8,388,608
占全模型的比例
0.124%
全模型 6,738,415,616 个参数
适配器文件多大
16.8 MB
8,388,608 × 2 字节 —— 存成 fp16
训练总显存
13.6 GB
冻结基座 13.5 + 外挂 0.13 GB
拧一拧秩,看账怎么涨。秩就是那对小矩阵的「厚度」。下面的条共用一条刻度:满格 = r=6467,108,864 个参数。
秩 r算式(32 层 × 4 投影 × r × 2 × 4096可训练参数 · 占比适配器
432 × 4 × 4 × 2 × 4096 = 4,194,3044,194,304 · 0.062%8.4 MB
832 × 4 × 8 × 2 × 4096 = 8,388,6088,388,608 · 0.124%16.8 MB
1632 × 4 × 16 × 2 × 4096 = 16,777,21616,777,216 · 0.249%33.6 MB
3232 × 4 × 32 × 2 × 4096 = 33,554,43233,554,432 · 0.498%67.1 MB
6432 × 4 × 64 × 2 × 4096 = 67,108,86467,108,864 · 0.996%134.2 MB
秩从 4 涨到 6416 倍), 参数从 4,194,304 涨到 67,108,864 ——正好也是 16 倍,一比一线性
但最大的那个 67,108,864 也只占全模型的 0.996%。所以「秩该选几」基本不是显存问题(下面会看到:参数涨 16 倍、 显存只涨几个百分点),而是「给模型多少自由度去改」的问题 —— 不够就学不动,太多就退化成全量微调、又容易过拟合(第 13 课那道缝又来了)。
换个秩,训练显存动多少?(7B 档
秩 r冻结基座(只读,fp16)外挂参数要的 16 字节训练合计
413.5 GB0.07 GB13.5 GB
813.5 GB0.13 GB13.6 GB
1613.5 GB0.27 GB13.7 GB
3213.5 GB0.54 GB14.0 GB
6413.5 GB1.1 GB14.6 GB
秩涨了 16 倍,训练显存从 13.5 涨到 14.6 GB, 只涨了 7.4%
并排看这两个倍数:可训练参数 ×16,训练显存 ×1.07
原因就在最左边那一列:基座一直是 13.5 GB 不动, 它占了训练总显存的 92.6%。 外挂那点零头哪怕涨 16 倍,也只是从 0.07 涨到 1.1 GB —— 零头怎么长都还是零头
同一个模型(7B 档,r=8),三种做法(同一根刻度:满格 = 全量微调 107.8 GB):
全量微调6,738,415,616 × 16 字节
107.8 GB
LoRA(基座 fp16 冻结)只要训 8,388,608 个外挂参数
13.6 GB
QLoRA(基座 4 位冻结)第 2 站那把刀也叠上来:13.53.8 GB
3.9 GB
7B 档:全量 107.8 GB → LoRA 13.6 GB(省 7.9 倍)→ QLoRA 3.9 GB(省 27 倍)。
两把刀砍的是两笔不同的账:LoRA 砍掉「优化器状态」94.3 GB → 0.13 GB),量化砍掉「基座本身」13.53.8 GB)。 所以它们能叠 —— 叠起来就是 QLoRA。
还有个漂亮的副产品:适配器只有 16.8 MB。 一个基座配 N 个适配器(算术助手一个、写代码一个、客服一个), 换来换去就是换个几 MB 的小文件 —— 权重一个字节都不用重存
面试常问 · LoRA 训完,推理会变慢吗?

不会。LoRA 只是训练时的形状:W' = W + (α/r)·B·AW 是原来的 d×d 矩阵,B·A 是 r 很小时的两个瘦矩阵 (d×r 和 r×d)。训练完把 (α/r)·B·A 一次性算出来、 加进 W,就得到一个新的 d×d 矩阵 ——和原来一模一样大,推理路径一个字都没变

这里那 32 层 × 4 个投影,每个都是「乘出来再相加」, 加法本身不改变形状。所以:LoRA 是「训练时省显存」,不是「推理时省算力」 —— 这两件事经常被混着说,面试也爱问。

👆 三根条共用一条刻度,所以长短能直接比。切上面的秩按钮, 看「可训练参数」那张表怎么成倍翻,而下面「训练显存」那张表几乎不动 —— 这两张表放在一起看,就是 LoRA 的全部经济学:你调的是「能改多少」,不是「占多少显存」。
图 16-4 · LoRA 的秩 — 参数量 — 显存三本账(7B 档,r=8 时可训练参数 8,388,608 = 0.124%)
只训练 8,388,608 个参数 —— 占全模型的 0.124%这么点参数,能学会「按对话格式回答算术题」这种新本事吗?
面试常问 · LoRA 与 QLoRA
  • 挂在哪些层:最常见是注意力的四个投影(Q、K、V、O), 这里的账就是「层数 × 4 × r × 2d」。 讲究一点的会连 FFN 一起挂 —— 挂得越广、可训练参数越多、越接近全量微调。
  • 秩 r 与 α 的关系:前向是 W + (α/r)·B·A, 所以真正的缩放系数是 α/r。改 r 的时候一般要同步改 α, 否则等于偷偷改了学习率 —— 这是调 LoRA 时最常见的坑。
  • 训练时省、推理时不亏:训练完把 (α/r)·B·A 合并进 W, 推理路径和原来完全一样。所以 LoRA 不会让推理变慢, 也让「一个基座 + N 个几 MB 的适配器」成为可能。
  • QLoRA = 4 位基座 + LoRA:两把刀砍两笔账,所以能叠。 代价是 4 位基座的量化误差要靠 LoRA 补回来 —— 实践上补得挺好。
  • 常见变体DoRA(把方向和大小的更新拆开)、rsLoRA(改缩放为 α/√r)、GQA/MQA(那是结构层面的省,第 7 课)。 面试答出 QLoRA 和 rsLoRA 两个就够有深度了。
第 4 站 · 收官

把这一课钉在墙上

模型不是「变小」了
大部分参数不再需要那 14 个字节
本课核心 · TAKEAWAY

训练显存的大头不在权重上,在「让权重能被训练」这件事上。一个参数身上挂着五样东西:fp16 权重 2 + fp16 梯度 2 + fp32 主权重 4 + Adam 一阶动量 4 + 二阶动量 4 = 16 个字节, 而权重自己只占 2 个。所以 7B 档 全量微调要 6,738,415,616 × 16 = 107.8 GB, 而光装下它推理只要 13.5 GB。 两把刀分别砍这 14 个字节的两头:量化把每个参数从 16 位压成 0.5625 字节(基座 13.5 3.8 GB,精度代价是相对误差 11.8%, 但模型照样能用);LoRA 冻住基座,只训 32 × 4 × r × 2d 个外挂参数 (r=80.124%、适配器 16.8 MB), 让优化器状态那 94.3 GB 直接归零。 叠起来就是 QLoRA:107.813.63.9 GB, 省 27 倍 ——一张 16 GB 的免费显卡,从「装不下」变成「还剩一大半」。最后一句话:这两把刀都不改变模型的形状, LoRA 训完合并回去、量化只是换个存法 ——它们省的是账单,不是能力。

这一课你亲手做完了

  • 算清了 16 个字节:2 + 2 + 4 + 4 + 4 = 16, 权重只占 2 个;于是 7B 档 全量微调 107.8 GB、 光推理 13.5 GB,差了 8 倍。
  • 认清了 NF4 的 16 格:中间密、两头疏(最窄格与最宽格差得多), 而且刻意不对称(负 7 档 / 0 一档 / 正 8 档); 平均每参数 4.5 位 = 0.5625 字节(每 64 个共用一份 fp32 缩放)。
  • 量了一次真权重:64 个权重,相对误差 11.8%, 比等距 16 档小 1.24 倍, 是 fp16 的 427 倍 —— 但模型照样能用。
  • 拧了 LoRA 的秩:r 从 4 到 64,参数从 4,194,304 67,108,864(16 倍线性), 训练显存却只从 13.5 涨到 14.6 GB(+7.4%)—— 因为基座冻着,13.5 GB 一动不动。
  • 把两把刀叠起来:全量 107.8 → LoRA 13.6(省 7.9 倍)→ QLoRA 3.9 GB(省 27 倍), 一张 16 GB 卡搞定。
  • 合回了推理路径W' = W + (α/r)·B·A —— 还是一个 d×d 矩阵,LoRA 不拖慢推理, 所以能一个基座配 N 个几 MB 的适配器换来换去。

学习小测验

已完成 0 / 60.0%答对 0
还没提交过 —— 每题先选一个选项,再点「提交」,答完就能看到诊断。
Q1全量微调一个模型,为什么每个参数要占 16 个字节?
Q27B 档 全量微调要 107.8 GB —— 这个数是怎么算出来的?
Q3NF4 的 16 个档位为什么在 0 附近排得特别密?
Q4量化省的是哪笔账,LoRA 省的是哪笔账?
Q5LoRA 微调完,把模型拿去推理,会比原来慢吗?
Q6只有 0.124% 的参数可以训练,怎么还能学会新东西?
FINALE · 十六课走完了

从一只手指数到 7B 的账单

回到第 2 课那个问题:你没法把「三十四加十二」塞进显卡。 十六课走下来,这条线已经完整了 —— 文字变成数字(第 3 课)→ 变成向量在矩阵里流动(第 1、3、4 课)→ 靠注意力互相看(第 5、6 课)→ 拼成一个能叠的模块(第 8 课)→ 学会猜下一个字(第 8、9 课)→ 靠反向传播和优化器真的学起来(第 10、11 课)→ 知道怎么不背题(第 13 课)→ 亲手训出一个会算加减的小模型(第 14 课)→ 把它包装成会说人话的助手(第 15 课)→ 最后知道怎么用一张免费显卡把这件事放大到 6,738,415,616 个参数 (这一课)。
下一步是动手:去配套的 Kaggle notebook, 把你训练出来的那个算术模型换成一份真实的 QLoRA 微调脚本 —— 这一课算出来的 3.9 GB,就是你那张免费卡要装的东西。十六课的账,最后都要落到一次真实的训练上。

从零手册 —— 十六课完结 · 回看目录,或去 Kaggle 跑一次真模型