跳到主内容

什么是混合精度训练?省显存又不掉精度

2026-10-06 发布 来源:我告诉你AI导航 阅读

训练大模型时,显存常常比算力更早见底。混合精度训练(Mixed Precision)是一套很具体的做法:让大部分矩阵计算跑在 16 位上,把「记账」和「更新」留在 32 位。它省下的显存通常在三成左右,代价是工程上多几处要照顾的细节...

训练大模型时,显存常常比算力更早见底。混合精度训练(Mixed Precision)是一套很具体的做法:让大部分矩阵计算跑在 16 位上,把「记账」和「更新」留在 32 位。它省下的显存通常在三成左右,代价是工程上多几处要照顾的细节。

精度是位数,位数管两件事

浮点数用一段二进制表示实数,位数分成指数位和尾数位。指数位决定能表示多大、多小的数,尾数位决定能表示多细。FP32 有 23 位尾数,十进制大约 7 位有效数字;FP16 只有 10 位尾数,大约 3 位有效数字,指数范围也窄,超过 65504 就溢出;BF16 的尾数只有 7 位,但指数位和 FP32 一样是 8 位,所以范围几乎不变,精度更粗。

训练里大量运算是矩阵乘加,对精度不敏感;参数更新却是「大数上加一个很小的数」,对精度极其敏感。混合精度的全部设计,都围绕这个差异展开。

一个训练步里,精度在哪切换

进来的是一个 batch 的输入,和一份 32 位的参数主副本。每一步开始时,参数被转成 16 位送进网络,前向计算得到 16 位的激活值和输出,损失函数通常在 32 位下计算,反向传播得到的梯度也是 16 位。接下来是关键一步:梯度被转换成 32 位,累加到 32 位的梯度缓冲区,优化器在 32 位上更新主副本,更新完再转成 16 位,供下一步使用。

出去的是更新后的 32 位参数,以及给下一步用的 16 位计算副本。整个循环里,计算走 16 位,状态存 32 位。省显存的地方在计算和激活,不在优化器状态。

为什么非要留这份 32 位副本?举个量级上的例子:学习率 1e-5,权重是 1.0,一次更新只改变十万分之一。FP16 在 1.0 附近能分辨的最小间隔约为千分之一,这个更新会被直接舍入成零,训练看起来在跑,参数其实没动。32 位主副本加 32 位累加,就是为了让这种小增量不被吞掉。

FP16 和 BF16 怎么选

FP16 的尾数多三位,数值更细,但范围窄,梯度稍大就溢出成 inf,稍小就下溢成 0。用 FP16 通常要配损失缩放:先把损失乘上一个系数,让梯度整体变大,落在可表示范围内,更新前再除回去。系数是动态调的,调不好会出现连续的溢出跳过,训练停滞。

BF16 牺牲尾数换范围,几乎不会溢出,通常不需要损失缩放,工程上更省心。代价是同样的数值精度更粗,对特别小的梯度不如 FP16 细腻。近几年的加速卡普遍原生支持 BF16,它成了常见默认项;老硬件上仍以 FP16 加缩放为主。选哪个先看硬件支持,再看任务对精度的敏感度,具体支持情况以官方文档为准。

省下来的显存到底在哪

占用项混合精度下的形态相对全 32 位的开销说明
模型参数16 位计算副本 + 32 位主副本约 1.5 倍单份,而非 2 倍两份都要存,主副本省不下
梯度16 位梯度 + 32 位累加缓冲与参数的结构类似累加缓冲不能省,否则小梯度丢失
激活值前向中间结果以 16 位保存约为原来的一半batch 越大,这项省得越多
优化器状态通常保持 32 位不省Adam 类优化器本身占数倍参数显存

这张表解释了一个常见误解:混合精度并不等于显存减半。参数主副本和优化器状态仍是 32 位,真正减半的是激活值和计算副本。总体能省多少,取决于模型结构、batch 大小和优化器类型,三成是一个常见的量级,不是承诺值。

什么情况下会掉精度

小 batch 微调容易出问题。梯度本身就小,累加次数少,16 位下舍入误差占比高,损失曲线会抖。层归一化、softmax、损失计算这类含归约的算子对精度敏感,框架一般会把它们强制跑在 32 位;如果某个实现漏掉了,表现是训练早期就出现 NaN。

损失缩放配错是另一类。系数太大,梯度溢出,优化器直接跳过这一步;系数太小,梯度下溢成 0,参数不动。两种表现都是损失不降,但原因相反,要看日志里有没有溢出计数才能分清。

还有一类是「看起来能跑,效果略差」。16 位激活在长序列、深网络上累积误差,最终指标比 32 位低一点。这种差异不会报错,只能靠对照实验发现:同一份数据、同一个随机种子,分别跑 32 位和混合精度,比较验证集指标,差得明显就退回 32 位或改用 BF16。

它和量化不是一回事

量化把训练好的权重压成 8 位、4 位整数,主要服务于推理部署,目标是让模型装得下、跑得快。混合精度服务的是训练过程,权重最终仍以 32 位保存。两者的共同点只是「用更低位数换资源」,解决的问题不同。模型量化的基本原理讲的是前者,本文讲的是后者,不要混着用。

显存估算也要分开算。先按参数量与显存的关系算出权重、梯度、优化器状态三块,再看激活值占多少,最后才轮到混合精度能省哪一块。顺序反了,估出来的数字会差很远。

自己动手时先确认三件事

硬件是否原生支持 BF16,框架版本是否提供自动混合精度开关,所用算子有没有 16 位实现。三项都满足,改动通常只是几行代码;缺一项,可能要靠手动转换和损失缩放补齐。自己下载开源权重模型做微调时,这一步尤其容易卡住。

上线前做一次对照:固定种子,跑 32 位与混合精度各一轮,记录显存峰值、每步耗时、验证指标。三个数字都拿到,才知道省下来的资源值不值那点精度差。

混合精度速查

  • 计算用 16 位,参数主副本与优化器状态留 32 位
  • FP16 范围窄,需要损失缩放;BF16 范围大,通常免缩放
  • 显存省在激活与计算副本,优化器状态不省
  • 小 batch、含归约的算子、长序列最容易掉精度
  • 上线前跑一次 32 位对照,比看文档可靠

反馈页面信息

请描述需要更正的地方,页面标题和网址会自动附上。

也可以发邮件至 [email protected]