FP16与bfloat16位模式可视化工具
可视化半精度浮点数(FP16、IEEE 754 binary16)和bfloat16的位模式。支持十进制与位模式互相转换,符号位、指数部、尾数部分色显示。适合学习机器学习中的量化与推理加速。
FP16与bfloat16的结构比较
两者合计都是16位,但指数部与尾数部的位数分配不同,导致可表示的数值范围和精度完全不同。
| 项目 | FP16 (IEEE 754 半精度) | bfloat16 |
|---|---|---|
| 总位数 | 16 | 16 |
| 指数部位数 | 5 | 8 |
| 尾数部位数 | 10 | 7 |
| 可表示的数值范围 | 约±6.1×10⁻⁵ 至 ±65504(范围较窄但尾数位多、精度较高) | 约±1.2×10⁻³⁸ 至 ±3.4×10³⁸(与float32相同的宽范围,但精度较低) |
| 主要用途 | 图像处理、图形学、推理时的省内存化(半精度训练) | 深度学习训练(TPU、最新GPU)。从float32转换时无需担心指数溢出 |
bfloat16的指数部位数(8位)和偏移量(127)与float32(单精度)完全相同,因此只需截断float32的尾数部即可转换,这是实现上的一个优势。
使用提示
- 即使是同一个值0.1,FP16和bfloat16的舍入误差表现也完全不同。切换格式比较尾数部的位模式吧。
- bfloat16的指数部位数和偏移量与float32相同,因此即使是超过65504的大数值也不易溢出。相反FP16一旦超过65504就会立即变为无穷大。
- 将"70000"转换为FP16会溢出变为无穷大,而bfloat16则能正常表示(精度有所下降)。
- 在PyTorch、TensorFlow等机器学习框架中进行模型量化时,bfloat16容易从float32转换,而FP16由于范围较窄有时需要预先缩放。
- 从位模式逆向转换为十进制时,需输入带`0x`前缀的4位十六进制值,或16位二进制值(`0b`前缀可省略)。
常见问题
两者合计都是16位,但FP16(IEEE 754半精度)是指数部5位、尾数部10位,而bfloat16是指数部8位、尾数部7位。FP16尾数位多精度更高但范围较窄,bfloat16能表示与float32相同的宽范围但精度较低。
深度学习训练中,梯度和参数可能变得非常大或非常小,因此更倾向于使用能保持float32那样宽的表示范围(不易溢出/下溢)同时将内存和计算量减半的bfloat16。FP16范围较窄容易溢出,训练时有时需要额外的损失缩放(loss scaling)。
约65504。若将超过此值的数转换为FP16,会因溢出而变为无穷大(Infinity)。而bfloat16与float32指数部位数相同,可表示约3.4×10³⁸的数值。
指数部全为0而尾数部不为0的位模式。常规(正规化)浮点数尾数有隐含的前导1,而非正规数省略了这一点,从而能表示比通常最小值更接近零的值(但牺牲了有效精度)。
bfloat16的指数部位数(8位)和偏移量(127)与float32完全一致,因此只需保留float32位模式尾数部的高7位(并四舍五入)即可转换,无需重新计算指数或检查范围,实现十分简单。
闲话 ― 为何机器学习需要"降低精度"的数值表示
2018年前后,Google为其TPU(Tensor Processing Unit)设计了一种新的16位浮点格式bfloat16。此前已存在的FP16(IEEE 754半精度)已在图像处理和图形学领域实用化,但由于指数部仅5位,可表示的数值范围较窄,难以应对深度学习训练中梯度时而极小、时而极大的现象(梯度消失、梯度爆炸)。
bfloat16的设计思路很明确:牺牲尾数部的精度,换取与float32(单精度)完全相同的8位指数部宽度,从而能安全处理训练过程中频繁出现的极大极小值。"Brain Floating Point"这个名字来源于Google的机器学习研究部门"Google Brain"。
在传统计算机科学中,降低浮点数精度一直被视为"漏洞的温床"而被避免。但深度学习模型有一种特殊性质:即使存在一定的数值误差,对最终预测精度的影响也微乎其微。利用这种"稍有不精确但整体仍能工作"的特性,将内存占用和计算成本减半的16位表示得以广泛普及,这可以说是有别于传统计算机科学常识的、机器学习领域独有的优化。