省内存省的到底是哪一块账

建议用时:25 分钟(含练习)

学习目标

能够把训练显存拆成权重、梯度与优化器状态、激活三笔账,并说清 LoRA、QLoRA 与量化各自动的是哪一笔。

本节产出

一份单卡可跑与否的显存预算表

核心知识:训练显存是三笔账,不是一笔

"这张卡跑不动微调"是一句混话。它可能指三件完全不同的事:模型本身就装不下;装得下,但梯度和优化器状态一分配就爆;前两项都装得下,一个 batch 的激活算出来超了。三件事各有各的解法,把解法用错格子,钱花完问题还在。

这一节要你带走的不是某个数字,是一张能把"跑不动"落到具体一格的表。表按四格记:权重、梯度与优化器状态、激活、峰值余量。第四格不是第五笔开销,它是前三格算完之后必须留下的缓冲——分配器碎片、某个 step 上的临时尖峰、日志里那次"刚好差一点"的重试。四格里的数全是估算口径,本课不安排真机测量,也不许把估算写成论文结论。

第一格:权重

权重就是模型本身那些数字占的地方,由两个量相乘决定:参数量,和每个参数存几个字节。同一套权重,用 16 位浮点存是一个体积,用 4 位存是另一个体积,比例差得很远(这是换算,不是某篇论文的测量结果)。这一格的特点是它跟你要不要训练没关系:只推理也得装着它,全量微调也是装着它,能变的只是精度。

第二格:梯度与优化器状态

这一格是唯一会被"可训练参数量"直接压下来的一格。要更新一个参数,就得给它算梯度;用 Adam 这一类优化器,每个可训练参数还要额外配上和它同形状的缓冲(动量、方差,有些实现另存一份高精度主副本)。所以这一格的规模大致等于可训练参数量乘上一个不小的倍数。全量微调时,可训练参数就是全部参数,这一格往往是权重的数倍(推断);把参数冻住、只让一小撮新参数参与更新,这一格立刻塌下来。

这就是 LoRA 省的地方,也是它只省到这里的原因。

第三格:激活

激活是前向时每一层算出来的中间结果,反向时要拿它们算梯度,所以必须留着。它由 batch 大小、序列长度、层宽共同决定,和参数量不是一条线。同一张卡、同一个模型,把序列从短拉到很长,前两格几乎不动,这一格成倍地涨。很多人第一次撞墙就撞在这格上,却回头怀疑"是不是模型太大",于是去换更小的模型,问题一点没解决。

LoRA 动的是第二格

LoRA 的做法摘要里写得很清楚:冻住预训练权重,往 Transformer 的每层注入可训练的低秩矩阵。原始权重一个都不更新,更新只发生在那几个小矩阵上。

于是三件事同时成立。要算梯度的参数从全部变成一小撮,第二格塌下去;权重还是原来那份、原来那个精度,第一格一点没动;推理时可以把低秩矩阵合并回去,作者据此在摘要里说它不像 adapter 那样增加推理延迟。作者还报告,相比用 Adam 全量微调 GPT-3 175B,可训练参数量降到万分之一、显存降到三分之一。

这三句是摘要原话,属论文主张。它们量的是那篇论文里的对照实验,不是你手上这张卡。最常见的误读正好卡在把"参数降到万分之一"读成"显存降到万分之一"——显存里最大的一块,往往恰恰是它不动的那一块。

QLoRA 接着去动第一格

QLoRA 保住 LoRA"冻权重"这一手,把目标换成第一格:把冻结的预训练模型量化到 4 位,再让梯度穿过它。权重变小了,可训练参数还是 LoRA 那一小撮,第二格照旧塌着。摘要列出三件配套工具:

  • 4-bit NormalFloat(NF4):摘要的说法是对服从正态分布的权重信息论最优的一种 4 位格式;
  • 双重量化:连量化时算出的那些缩放常数也再量化一次,把平均占用再压一层;
  • 分页优化器:对付显存尖峰,优化器状态按页存放,撞峰值时不至于整次训练被一次分配挤爆。

这里有一个必须留档的细节:英文摘要里"分页优化器"那个词拼作 paged optimziers,是原文自身的拼写错误。本课正文一律按"分页优化器"讲;要引用英文原词时,要么照抄那串拼错的写法,要么注明原文拼错,不许悄悄替它改好再当成原文。

作者据此在摘要里说,能在一张 48GB 的卡上微调 65B 参数模型,并保持 16 位微调的任务表现。这一句同样是摘要口径,它说的是 65B 与 48GB 那一组配置,不能搬来给我们那张 24GB 的卡作证。

GPTQ 与 AWQ 记在另一本账上

GPTQ 与 AWQ 都属于面向部署的权重量化:模型已经训好了,要把上线的成本压下来。AWQ 摘要的说法是 activation-aware 的权重量化与加速,也就是按激活里体现出的重要性来决定哪些通道更该保住精度。它们回答的问题是"推理时占多少、跑多快",不是"训练时塞不塞得进"。

为什么这两件事不能互替?一句话:训练要在同一套权重上算梯度并写回更新,量化误差会被反向传播一路放大;部署只要前向,算完就走,没人往权重里回写。用训练时那套办法去省推理,代价是精度与速度不一定划算;用部署量化去救训练 OOM,等于拿收银台的账本去填仓库的空——两本账,一本都糊不上另一本。

什么时候这套拆法不够用

四格拆法给的是"先看哪一格"的顺序,不是保证。三种场合它不够:多卡并行要再加通信缓冲与分片副本那一层,本课不展开也不安排真实多卡运行;序列很长、batch 很大时第三格会盖过前两格,这时 LoRA 与 QLoRA 都救不了,该动的是长度、切分或重计算;真要改模型的表示本身(换分词、加新模块),低秩这条假设够不够用,本课未取证,不给结论。

训练显存拆成权重、梯度与优化器状态、激活三笔账,LoRA 与 QLoRA 分别动其中不同的两笔

这张图承担的论证只有一句:LoRA 与 QLoRA 不是"省得更多"和"省得更少"的关系,而是伸进了不同的格子。图上那两条箭头若被读成一条从 LoRA 指向 QLoRA 的升级阶梯,本节最想纠正的混淆就白讲了。

案例:星湾那次 OOM 爆在哪一格(以下为教学用虚构读数)

星湾社区服务中心要一个按本地口径回答政策问题的助手,模型代号 example-chat-mini,参数量按 70 亿算。周衡手上只有一张 24GB 的卡,推理接口是他自己搭的 https://api.example.invalid/v1。2026-09 他第一次做微调,任务在起步阶段就报错退出;李陌给的主意是"上 4 位量化,量化能省内存",理由是他上个月刚用 AWQ 把上线成本压下来一半。下面的表是课堂推演,每一个数都是估算,不对应任何真实测量。

格子全量微调(估算)LoRA(估算)QLoRA(估算)换算依据
权重约 14GB约 14GB,不动约 3.5GB参数量乘以每参数字节数
梯度与优化器状态数十 GB,可训练参数等于全参数约 0.1GB 量级,只算那一小撮同 LoRA,仍然是一小撮按可训练参数计
激活随 batch 与序列长度成倍变化同左同左与参数量不同线
峰值余量已被第二格吃光,无余量只剩个位数 GB 给激活与尖峰权重让出十来个 GB分配器碎片与临时尖峰

推演三步。第一步看全量那栏:第二格单独就超过整张卡,所以周衡那次报错不可能是权重装不下,是更新一套参数的开销先撞墙。第二步看 LoRA 那栏:第二格塌成零点几 GB,可第一格 14GB 原样占着,剩下的空间要同时供激活和峰值,于是短序列、单条样本累加勉强排得下,序列一拉长就爆第三格。第三步看李陌那句话:他的方向对,格子找错了——他上次省的是部署那一本账,那次量化过的模型根本不承担梯度回写。

真正要改的是第一格的存储精度,而且要在"冻结但参与反向"的那份权重上改,这就是 QLoRA 那一栏。张老师最后拍板的记录里写了两条:一是先按 QLoRA 排预算,二是把最不确定的那一格明确标成"激活,未实测",等第一次真跑完再回填。这张表到这儿只是一份假设清单,不是跑通证明;本课也不把它当跑通证明。

动手练习

  1. 填一张四格预算表。输入:7B 模型、24GB 单卡、用 LoRA 微调、权重按 16 位存、batch 取 1、序列长度取 1024、LoRA 挂满每层且可训练参数按总参数的千分之一估。任务:四格各填一个数并写出换算依据,标出你最不确定的是哪一格。预期输出:一张四行表,加一句"这张卡能不能跑"的结论。验收条件:所有数字写明是估算;至少一格写"未查";不许把论文摘要里的比例当成自己的实测。
  2. 给四份配置归账。输入:甲,16 位全量微调 7B;乙,LoRA 微调 7B;丙,4 位量化基座上加 LoRA 微调;丁,训练完成后用 AWQ 把模型量化到 4 位供线上推理。任务:各归到"省训练显存"或"省部署显存",并指出其中被归错的那一份错在哪一步。预期输出:四行归类加三五行说明。验收条件:说明里必须出现"哪一格"这个词,不许用"更省资源"这种含混说法过关。
  3. 交预算表。任务:把前两题合成一份交付:四格表、一句能不能跑的结论、一个"如果爆了就最先拧动的旋钮"(说清它拧的是哪一格)。预期输出:半页纸。验收条件:结论与旋钮必须指向同一格;写了"跑通"就必须附上读数来源,没跑就写"未跑"。

参考答案与推演

完成检查

  • 不用"参数量"这个词,也能说出全量微调为什么比 LoRA 更容易 OOM:被算梯度的是哪一批参数、要额外存什么。
  • 能分清两笔不同的省:省可训练参数(动第二格)与省权重本身(动第一格),并各举一个例子。
  • 能说出训练时量化与部署时量化为什么不能互替,并说出本课那条判据:这份权重接下来会不会被梯度写回。
  • 交出的四格表里,权重、梯度与优化器状态、激活三格各有换算依据,至少一格标着未查,且没有一处估算被写成论文数字。

参考与来源

附件

省内存省的到底是哪一块账

3 道题 · 及格分 60 分

开始测验