浮点数用「符号 + 指数 + 尾数」三段式在有限位宽内表示实数:指数定范围,尾数定精度。FP16/BF16/TF32 的全部差异都源于位宽分配的取舍,而梯度下溢、GradScaler、混合精度选型这些训练侧问题,根因都在这张位分配表里。
IEEE 754 三段式结构
值公式:
- 符号位 S:1 bit
- 指数位 E:以 bias 偏移编码正负指数,FP32/FP16/BF16 的 bias 分别为 127/15/127
- 尾数位 M:只存小数部分——首位是隐含前导 1(正规数恒可写成 ,这个 1 不必存),FP16 的 10 bit 尾数因此有 11 bit 有效位
指数以 2 为底是硬件决定的选择:乘 等价于小数点移位,走线切换即可、近乎零成本;若底为 10, 含因子 5,缩放必须走完整乘法器,延迟、面积、功耗全面上涨。IEEE 754-2008 确实定义了 decimal32/64/128 供金融场景——0.1 这类十进制小数在二进制浮点下无法精确表示,会计不容累积舍入误差——但无 GPU 原生加速,科学计算与深度学习全不用它。
三种格式的边界
| 格式 | S/E/M | bias | 最小正规数 | 最大正规数 | 最小次正规数 |
|---|---|---|---|---|---|
| FP32 | 1/8/23 | 127 | |||
| FP16 | 1/5/10 | 15 | 65504 | ||
| BF16 | 1/8/7 | 127 |
BF16 是对 FP32 的直接截尾(指数位与 bias 原封不动,尾数 23→7),因此范围与 FP32 完全一致、只牺牲精度;FP16 则是全新分配,5 bit 指数换来 10 bit 尾数,范围骤减。
正规数、次正规数与溢出
- 正规数(normal):指数非全 0 非全 1,带隐含 1,是格式的主力区间
- 次正规数(subnormal/denormal):指数全 0 时隐含位变 0,能表示更接近 0 的数,但有效位随数值缩小而减少,GPU 上还常走慢速路径或被 flush-to-zero 直接归零
- 下溢(underflow):小于最小次正规数 → 0
- 上溢(overflow):超过最大正规数 →
inf
训练梯度的典型量级是 。FP16 正规区间下限 ,梯度一转 FP16 就落入次正规区甚至归零:
torch.tensor([1e-7]).half() # 1.19e-07,舍到次正规格点,有效位寥寥
torch.tensor([5e-8]).half() # 5.96e-08,被钳到最小次正规,再小即归零这就是 FP16 训练必须配 GradScaler(放大 loss 把梯度推回正规区间)、而 BF16 免疫下溢(正规区间下限 )的全部原因。训练侧的工程取舍——autocast 分流、scaler 链路、TF32——见 torch.cuda 与混合精度;BF16 的产业背景见 bfloat16。