跳到主要内容
TileLang 系统教程

tilelang-tutorial.huandu.me

第 27 章 低精度、量化与数值正确性

/code/27-low-precision-quantization/

01-number-formats/README.md2573 字节
# 示例 01:低精度格式的范围与精度是怎么算出来的

## 目的

正文第 2 节的三张表(有效位与 `u`、表示范围、E8M0 值域)都由这个脚本产出。
做法是**枚举位模式**而不是抄参数:

* fp16 用 numpy 的 `finfo`;bf16 按 `1+8+7`、bias 127 直接算边界;
* fp8 e4m3(OCP FN)枚举全部 256 个位模式,命中 `0x7f`/`0xff` 时跳过 NaN;
* fp8 e5m2 同样枚举,指数全 1 视为 inf / NaN;
* fp4 e2m1 枚举 16 个位模式;
* E8M0 枚举 255 个指数编码。

## 运行前提

Python 3.9+ 与 numpy。**不需要 GPU / NPU**。

## 运行命令

```bash
python3 number_formats.py
python3 number_formats.py --show-fp4
```

## 期望输出

作者在写作机上的实际输出(2026-10-01,macOS / Apple Silicon,Python 3.11.7 +
numpy 1.24.1,`--show-fp4`):

```text
== 一、表示精度:有效位与单位舍入误差 u = 2^-p ==
u 是这个格式「能分辨多小差别」的上界,也是第 12 章容差模型的唯一输入。
格式          符号/指数/尾数          有效位 p     u = 2^-p      atol 起点(10 的幂)
fp32          1/8/23              24          5.960e-08       1e-07
fp16          1/5/10              11          4.883e-04       1e-03
bf16          1/8/7               8           3.906e-03       1e-02
fp8 e4m3      1/4/3               4           6.250e-02       1e-01
fp8 e5m2      1/5/2               3           1.250e-01       1e+00
fp4 e2m1      1/2/1               2           2.500e-01       1e+00

== 二、表示范围:三个边界 ==
「最小规格化数」是相对精度开始退化的地方(再往下是次正规数,间距不再随值缩小)。
格式          max 有限值         min 规格化数        min 次正规数        动态范围(10 的幂)
fp16          6.55e+04          6.104e-05         5.96e-08          12.0
bf16          3.39e+38          1.175e-38         9.184e-41         78.6
fp8 e4m3      448               0.01562           0.001953          5.4
fp8 e5m2      5.734e+04         6.104e-05         1.526e-05         9.6
fp4 e2m1      6                 1                 0.5               1.1

== 三、MX 的 E8M0 scale ==
可表示值个数:255(8 位指数,编码 255 留给 NaN;没有 0,也没有负数)
最小:2^-127 = 5.877472e-39
最大:2^127  = 1.701412e+38
相邻值之比恒为 2:缩放本身不引入尾数误差,只搬运指数。
注意:E8M0 不能表示 0,所以「整块全零」要选一个约定的最小指数兜底。

== 四、fp4 e2m1 的全部取值(做量化时可以直接当码本用)=
非负值:0, 0.5, 1, 1.5, 2, 3, 4, 6
间距在 [1,2) 上是 0.5 → u = 0.25:靠近 1 的数只有 3 位有效信息。
```

## 这张表怎么用

* `u = 2^-p` 是第 12 章容差模型的唯一输入;fp8 的 `u` 是 6.25e-2,
  比 bf16 大一个数量级,这直接决定了 fp8 的对拍必须换一套判据。
* fp8 e4m3 的 `448` 是权重/激活量化的关键常数:锁定版本的 MXFP8 量化就是
  `ceil_to_ue8m0(amax / 448)`(见 `examples/blockscaled_gemm_sm100/`),
  保证除以 scale 之后一定落在 e4m3 的值域内。
* e5m2 的动态范围(9.6 个数量级)比 e4m3(5.4 个)宽得多,代价是有效位只有 3 位。
  这就是「梯度用 e5m2、前向用 e4m3」这条经验的来源。
* E8M0 不能表示 0 与负数:它是**缩放因子**,不是数据格式。

## 注意事项

* bf16 的边界是**按布局推出的解析值**,不是枚举位模式的结果;numpy 没有原生 bf16,
  所以这里没有做「枚举 + 往返」的自检。正文引用这些数字时按解析值处理。
* e4m3 的舍入规则(round-to-nearest-even)没有在这里实现,只有码本本身;
  量化时的舍入在 `02` 里用「最近码本值」近似,平局处理与硬件不一定逐位一致。

## 作者实际做到的验证级别

**CPU 逻辑验证**:在 macOS (Apple Silicon)、Python 3.11.7 + numpy 1.24.1 上实际运行过,
退出码 0。未在任何加速器上运行过任何 kernel。

← 浏览本章全部代码