浮点格式

从IEEE 754到AI时代的低精度浮点格式与大模型量化

Posted by CloudingYu on March 30, 2026

一、浮点数的基本概念

1.1 科学计数法回顾

浮点数的本质就是科学计数法(Scientific Notation):

  • 十进制:$6.02 \times 10^{23}$
  • 二进制:$1.xxxx \times 2^{E}$

两点关键:

  1. 科学计数法约定小数点前必须有且仅有一位非零数字(规范形式)
  2. 对二进制来说,小数点前的数字只能是1(不可能是0,否则移小数点即可)

以前觉得浮点数没什么好讲的——IEEE 754标准往那一放就行了。但近两年因为大模型的出现,浮点数突然变成了非常有趣的课题。

1.2 浮点数的基本结构

以32位(单精度)为例:

\[(-1)^S \times (1 + M) \times 2^{E - bias}\]
字段 位数(FP32) 说明
符号位 S 1 bit 0正1负
阶码 E 8 bits 移码(biased)表示,bias = 127
尾数 M 23 bits 纯小数部分,隐含最高位的1

1.3 隐藏位(Hidden Bit)——计算机人的”小trick”

既然规格化后小数点前的一定位一定是1,那就不用存了,硬生生多出一位精度。这是计算机人的小trick——数学人不在乎,反正纸上要多长有多长。

对于尾数23位的FP32,实际精度是24位(23 + 隐藏的1)。同理,双精度的52位尾数实际精度是53位。

1.4 浮点数的分布特性

浮点数不是均匀分布的:

  • 在小数附近(阶码小):尾数的23位变化可以描述得非常精细,密度高
  • 在大数附近(阶码大):同样23位尾数的变化步长被阶码放大,变得稀疏

从1万到10万是$2^{23}$个描述,从1亿到10亿也是$2^{23}$个描述。数的稀疏程度完全不同——大的时候稀疏,小的时候密集。

1.5 移码(Biased Exponent)

8位阶码用移码表示,bias=127:

  • 将0~255的整数空间平分,00000000→-127,01111111→0,11111111→+128
  • 偏移量127 = $2^{7}-1$

这样设计的好处:比较两个浮点数大小时,可以先按无符号整数比较阶码部分,硬件实现简单。


二、IEEE 754标准

2.1 标准化的历史

1950年代计算机就出现了,但直到1985年才完成浮点数标准的制定,由William Kahan主导完成,并因此获得图灵奖。这么常用的东西居然等了三十多年,令人难以置信。在IEEE 754之前,各家厂商各自定义浮点数格式,互不兼容。

2.2 规格化数(Normalized Numbers)

当阶码 $E$ 满足 $1 \leq E \leq 254$ 时:

\[\text{value} = (-1)^S \times (1.M) \times 2^{E - 127}\]

阶码全0和全1被留作特殊用途。

2.3 特殊值编码

IEEE 754的特殊值体系:

阶码 E 尾数 M 表示的值 说明
0 0 $\pm 0$ 正零和负零(浮点数有符号零)
0 $\neq 0$ 非规格化数(Subnormal) 表示非常接近零的值,解决”下溢缺口”
1~254 任意 规格化数 正常的浮点数
255 0 $\pm\infty$ 正无穷/负无穷
255 $\neq 0$ NaN(Not a Number) 非法运算结果(如0/0、$\infty - \infty$)

2.4 无穷大(Infinity)

整数除零是异常,程序会崩;但浮点数除零不报异常,而是返回无穷大。这是设计上的有意选择——浮点运算希望能”优雅地”继续下去。

2.5 NaN(Not a Number)

NaN 是调试浮点程序的关键工具:

  • 任何涉及 NaN 的运算结果都是 NaN
  • 不同类型的 NaN(Signaling NaN vs Quiet NaN)提供了更细粒度的控制

没有NaN就没法debug浮点数。出错了就不知道在哪出错了。

2.6 非规格化数(Subnormal / Denormalized)

当阶码为0、尾数非零时,采用不同的解释方式:

\[\text{value} = (-1)^S \times (0.M) \times 2^{-126}\]

隐藏位变为0(不再隐含为1),这使得可以表示比最小规格化数($2^{-126}$)更接近零的值。

2.7 关于正负零的讨论

补码设计时特意避免了正零和负零的问题,但IEEE 754保留了正负零的存在。对计算机来说无非是多一个if-else判断。


三、浮点数运算的精度问题

3.1 浮点数不能直接判等

千万不要在代码里写 if (a == b) 来判断两个浮点数相等。必须用差值小于一个很小的阈值来判断两个浮点数是否”足够接近”。

\[|a - b| < \delta\]

这是浮点数天生的精度限制导致的问题。

3.2 大数吃小数

当一个极大的数和一个很小的数相加时,小的数可能被”吃掉”——大数在该量级下的分辨率不足以表示小数的贡献。例如,在FP32中 $3.4 \times 10^{38} + 1$ 的结果还是 $3.4 \times 10^{38}$。


四、从FP32到低精度:AI时代的浮点数革命

4.1 FP32的问题

FP32的表示范围和精度够用,但AI时代的计算量太大——FP32太大了、太慢了。

4.2 FP16(传统半精度)

如果32位用5位阶码+10位尾数,可以按比例缩到16位。但传统FP16(5位阶码+10位尾数)与FP32之间没有简单的转换关系。

4.3 BF16(Brain Float 16)——AI时代的明星

BF16 是Google为TPU设计的格式:1位符号 + 8位阶码 + 7位尾数。

BF16成功的核心原因:BF16与FP32共享相同的8位阶码(相同的指数范围),从FP32转BF16只需要截断尾数——硬件上一个assign语句就完成,不消耗任何时间。

格式 总位数 阶码 尾数 与FP32转换
FP32 32 8 23
BF16 16 8 7 直接截断尾数
FP16 16 5 10 需要完整转换

从高精度降到低精度,就像砍一棵树——不能把头砍掉。阶码(指数)是”头”,尾数是”尾”——保留指数范围比保留尾数精度更重要。把蛇头砍掉,这蛇就没法活了。

5.4 TF32(TensorFloat-32)

NVIDIA提出的TF32:名义上32位,实际有效位只有19位(1符号+8阶码+10尾数)。

5.5 FP8(2022年)

FP8在2022年正式提出,只有8位。有两种主要变体:

变体 阶码 尾数 特点 适用场景
E4M3 4 3 精度更高 前向传播
E5M2 5 2 动态范围更大 梯度计算

混合精度训练不要求所有层用同一种格式——精度敏感的层用高精度,不敏感的层用低精度。

5.6 FP4

FP4只有4位,一共只能表示16个数。不同的人可以定义不同的FP4变体,1位符号+若干位阶码+若干位尾数的分配方式有很多种。


五、大模型量化:从浮点到整数

5.1 量化的动机

大模型参数量太大(几百B到上千B),普通显卡部署不下。推理时浮点数计算太麻烦——反正推理对精度要求没那么高,凑合用整数就行了。

5.2 整数量化谱系

精度 可表示值个数 说明
FP32 $\sim 4\times 10^9$ 原始训练精度
INT8 256 HuggingFace/ModeScope上常见
INT4 16 大幅减小模型大小
INT2 4 极端压缩
INT1 2 1-bit量化

六、BitNet:1-bit Transformer

6.1 从INT8/INT4直奔1-bit

一般的选手每次都破一点点纪录,拿一点点奖金。BitNet那帮人直接开一大刀——从INT16/INT8什么的一步跳到1-bit。

6.2 BitNet(2023年10月)

微软研究院、中科院、清华联合发表的BitNet论文提出:将Transformer的权重全部量化为 +1 或 -1。

\[W_{\text{quantized}} = \text{sign}(W) = \begin{cases} +1, & W > 0 \\ -1, & W < 0 \end{cases}\]

核心收益:乘法变成加法和取反!

  • ×(+1) → 不变号,就是加法
  • ×(-1) → 取反
  • 不需要浮点乘法器,能耗大幅下降

6.3 1-bit的局限性

0.01和-0.001本来差别很小,但一个变成+1一个变成-1,差别巨大。靠近零的权重被过度放大。

6.4 BitNet 1.58(2024年2月)

将权重量化为三个值:-1、0、+1

为什么叫”1.58 bit”?

\[\log_2(3) \approx 1.58\]

这名字起得真好。正常思维三值需要2位,但人家说是1.58 bit。你说是1.58?他说是,你也没办法。论文标题叫 The Era of 1-bit LLMs——让人一下就记住了。

6.5 BitNet 1.58的性能

实验结果表明(相对于FP16基线):

  • 内存占用:从2.0G降到0.8G(2.6倍提升)
  • 延迟:1.23倍到2.4倍的加速(取决于模型规模)
  • 精度(loss):略高于FP16基线(5.24 vs 4.7),但随着模型增大差距缩小到0.09——有竞争力(competitive)

不要太相信论文的漂亮数字——”就像出门见人,把衣服穿漂亮了、脸洗了,但可能牙没刷、衬衣破了洞。论文里面一定有坑,只是坑在哪。”


七、论文写作方法论

7.1 摘要的八股文结构

摘要写作的固定结构:

  1. 第一句:背景 + 当前存在的问题
  2. 第二句:我们做了什么工作(”In this work we introduce…“)
  3. 第三句:实验结果表明什么(”Experimental results show…“)

不要一上来就来散文——”在这样的日子里”——不知道你要说什么。八股文很重要。

7.2 英文论文的语言艺术

  • “competitive performance”:不说”超过”,说有竞争力的表现
  • “match full precision”:敢说匹配全精度了
  • 介绍工作要敢于说出亮点,但措辞要严谨

7.3 取名的重要性

1.58这个数字比”2”有趣得多。如果叫”2-bit”,别人觉得早就有了;叫”1.58-bit”一下子让人记住。写论文就是在讲故事,起个好名字太重要了。


八、浮点格式全谱系总结

各种浮点格式按精度从高到低梳理:

格式 总位数 符号 阶码 尾数 典型用途
FP80 80 1 15 64 x86扩展精度(已少用)
FP64 64 1 11 52 科学计算双精度
FP32 32 1 8 23 经典单精度
TF32 19 1 8 10 NVIDIA GPU训练
BF16 16 1 8 7 AI训练/推理首选
FP16 16 1 5 10 传统半精度
FP8 E4M3 8 1 4 3 前向传播
FP8 E5M2 8 1 5 2 梯度计算
FP4 4 极端量化
BitNet 1.58 1.58 {-1, 0, +1} 三值
BitNet 1 {-1, +1} 二值

九、核心总结

9.1 三条主线

  1. IEEE 754标准:从科学计数法到计算机内部二进制表示,理解规格化数、非规格化数、特殊值(零、无穷、NaN)的编码方式
  2. 从FP32到低精度:AI驱动了浮点格式的创新——BF16的巧妙设计(保留阶码)、FP8的双变体、FP4的极端压缩
  3. 1-bit革命的启示:BitNet和BitNet 1.58展示了极端量化的可能性,乘法变加法的硬件收益巨大;同时也展示了论文写作、命名、传播的科学方法论

9.2 核心观点

  • IEEE 754看似简单,但直到1985年才标准化——简单的标准有时最需要洞察力
  • BF16成功的本质:共享FP32的指数范围,转换零开销
  • 量化一定有精度损失——关键是如何让损失可控、让收益超过损失
  • 1-bit不是终点——从INT8到BitNet 1.58,每一步都是工程权衡
  • 论文命名和写作很重要——”1.58”比”2”有趣一万倍

1985年IEEE 754那个时代大家没抓住机会——现在浮点数这个时代又走到了脚底下。机会又来了。