低精度浮点格式(FP16 与 BF16)
FP16 与 BF16 都用 16 bit 存数,但 FP16 把更多位给尾数、BF16 把更多位给指数;前者相对精细,后者动态范围更接近 FP32。
| 格式 | 符号位 | 指数位 | 尾数位 | 指数 bias | 主要特征 |
|---|---|---|---|---|---|
| FP32 | 1 | 8 | 23 | 127 | 范围与精度都较高 |
| FP16 | 1 | 5 | 10 | 15 | 尾数较多,但容易上溢/下溢 |
| BF16 | 1 | 8 | 7 | 127 | 动态范围接近 FP32,但有效精度较低 |
规格化数可写为:
指数全 0 时包含零与 subnormal;指数全 1 时表示无穷或 NaN。subnormal 用更少有效位换取靠近 0 的渐进下溢区间。
范围与精度的交换
Section titled “范围与精度的交换”- FP16 的 10 位尾数使局部数值刻画比 BF16 更细,但 5 位指数限制动态范围。
- BF16 保留 FP32 的 8 位指数,较不容易因大梯度溢出;代价是只有 7 位尾数。
- 低精度节省权重、激活和带宽,不代表每个算子都应强制用同一种 dtype。
为什么训练时不能只做 dtype 转换
Section titled “为什么训练时不能只做 dtype 转换”训练包含前向、反向、梯度归约和参数更新。FP16 中很小的梯度可能下溢为 0,很大的中间值可能变成 inf。实际训练通常配合 自动混合精度(AMP):适合的算子用低精度,敏感计算保留更高精度,并在 FP16 场景用 loss scaling 放大梯度。
BF16 因范围接近 FP32,通常不依赖同样程度的动态 loss scaling;但它的尾数更短,并不保证所有任务都比 FP16 更准确。
课程中的验证方式
Section titled “课程中的验证方式”第 5 讲 notebook 通过位级拆解与 Python/NumPy 实验观察:
- 符号、指数、尾数如何还原数值;
- normal、subnormal、inf 与 NaN;
- FP16/BF16 在“大范围”和“细精度”上的不同;
- 低精度算术中的舍入、上溢和下溢。
第 7 讲把这些数值性质连接到 AMP 训练;第 8 讲进一步进入 int8 线性层量化。三者是相邻但不同的问题。
- BF16 比 FP16“位数更多”:总位数相同,只是指数/尾数分配不同。
- 低精度一定让模型更快:还取决于硬件内核、数据搬运和算子支持。
- 把模型
.half()就等于 AMP:全模型 FP16 与按算子选择精度的 AMP 不相同。 - 精度格式决定最终质量:训练配方、缩放、优化器状态和硬件实现同样关键。