浮点数存储在 8 位中¶
论文¶
2022 年发表了两篇论文,介绍了将浮点数存储在一个字节中,而不是将 32 位浮点数存储在 4 个字节中。浮点精度要低得多,但训练精度并没有受到太大影响。
用于深度学习的 FP8 格式 来自 NVIDIA、英特尔和 ARM,引入了两种类型,遵循 IEEE 规范。第一个是 E4M3,1 位表示符号,4 位表示指数,3 位表示尾数。第二个是 E5M2,1 位表示符号,5 位表示指数,2 位表示尾数。第一种类型主要用于权重,第二种类型用于梯度。
第二篇论文 深度神经网络的 8 位数值格式 介绍了类似的类型。IEEE 标准对 +0
(或整数 0)和 -0
(或整数 128)赋予相同的值。他们选择为这两个数字赋予不同的浮点值。本文试验了指数和尾数之间不同的分割,并表明 E4M3 和 E5M2 是最好的。
因此,在 onnx==1.15.0
中引入了四种新类型来支持有限的运算符集,以启用使用 8 位浮点数进行计算。
E4M3FN
:1 位表示符号,4 位表示指数,3 位表示尾数,只有 NaN 值,没有无穷大值(FN),E4M3FNUZ
:1 位表示符号,4 位表示指数,3 位表示尾数,只有 NaN 值,没有无穷大值(FN),没有负零(UZ)E5M2
:1 位表示符号,5 位表示指数,2 位表示尾数,E5M2FNUZ
:1 位表示符号,5 位表示指数,2 位表示尾数,只有 NaN 值,没有无穷大值(FN),没有负零(UZ)
实现通常依赖于硬件。NVIDIA、英特尔和 ARM 在其最新的图形处理器中实现了 E4M3FN
和 E5M2
。GraphCore 也一样,只是使用的是 E4M3FNUZ
和 E5M2FNUZ
。
E4M3FN 和 E5M2¶
\(S\) 表示符号。 \(10_2\) 描述一个 2 进制数。
E4M3FN |
E5M2 |
|
---|---|---|
指数偏差 |
7 |
15 |
无穷大 |
\(S.11111.00_2\) |
|
NaN |
\(S.1111.111_2\) |
\(S.11111.\{01, 10, 11\}_2\) |
零 |
\(S.0000.000_2\) |
\(S.00000.00_2\) |
最大值 |
\(S.1111.110_2\) |
\(1.75 \times 2^{15}= 57344\) |
最小值 |
\(S.0000.001_2 = 2^{-9}\) |
\(S.00000.01_2 = 2^{-16}\) |
令位表示为 \(S.b_6 b_5 b_4 b_3 b_2 b_1 b_0\)。浮点值由以下表达式定义
E4M3FN |
E5M2 |
|
---|---|---|
指数 \(\neq\) 0 |
\((-1)^S 2^{\sum_{i=3}^6 b_i 2^{i-3} - 7} \left( 1 + \sum_{i=0}^2 b_i 2^{i-3} \right)\) |
\((-1)^S 2^{\sum_{i=2}^6 b_i 2^{i-2} - 15} \left( 1 + \sum_{i=0}^1 b_i 2^{i-2} \right)\) |
指数 \(=\) 0 |
\((-1)^S 2^{-6} \sum_{i=0}^2 b_i 2^{i-3}\) |
\((-1)^S 2^{-14} \sum_{i=0}^1 b_i 2^{i-2}\) |
E4M3FNUZ 和 E5M2FNUZ¶
以前的类型支持正零和负零,正 NaN 和负 NaN。GraphCore 引入了另一种类型定义,以便更好地利用这四个值。每个类型在其名称中包含 UZ 的类型只有一个零和一个 NaN(= 负零)。另一个区别来自指数偏差。因此,一个 8 位浮点数 *FLOAT8E4M3FN*,非空,非 NaN,不能简单地转换为 *FLOAT8E4M3FNUZ*,因为存在指数偏差差异。即使尾数相同,指数也不相同。
E4M3FNUZ |
E5M2FNUZ |
|
---|---|---|
指数偏差 |
8 |
16 |
无穷大 |
||
NaN |
\(1.0000.000_2\) |
\(1.00000.00_2\) |
零 |
\(0.0000.000_2\) |
\(0.00000.00_2\) |
最大值 |
\(S.1111.111_2\) |
\(S.11111.11_2\) |
最小值 |
\(S.0000.001_2 = 2^{-10}\) |
\(S.00000.01_2 = 2^{-17}\) |
浮点值由以下表达式定义
E4M3FNUZ |
E5M2FNUZ |
|
---|---|---|
指数 \(\neq\) 0 |
\((-1)^S 2^{\sum_{i=3}^6 b_i 2^{i-3} - 8} \left( 1 + \sum_{i=0}^2 b_i 2^{i-3} \right)\) |
\((-1)^S 2^{\sum_{i=2}^6 b_i 2^{i-2} - 16} \left( 1 + \sum_{i=0}^1 b_i 2^{i-2} \right)\) |
指数 \(=\) 0 |
\((-1)^S 2^{-7} \sum_{i=0}^2 b_i 2^{i-3}\) |
\((-1)^S 2^{-15} \sum_{i=0}^1 b_i 2^{i-2}\) |
转换¶
从 8 位浮点数转换为 16 位浮点数(或 E5M10)、bfloat16(或 E8M7)、32 位浮点数(或 E8M23)更容易。转换是精确的。转换不一定保留特定值的符号,例如 -0
或 -NaN
。
转换为 8 位浮点数包括找到最接近原始 32 位浮点数的 8 位浮点数。这通常通过移位和截断来完成。
转换可能会进行饱和,所有超出范围的值都变为最高可用值。下表总结了所有情况。 [x]
表示四舍五入到目标尾数宽度的值。
x |
E4M3FN |
E4M3FNUZ |
E5M2 |
E5M2FNUZ |
---|---|---|---|---|
0 |
0 |
0 |
0 |
0 |
-0 |
-0 |
0 |
-0 |
0 |
NaN |
NaN |
NaN |
NaN |
NaN |
Inf |
FLT_MAX |
NaN |
FLT_MAX |
NaN |
-Inf |
-FLT_MAX |
NaN |
-FLT_MAX |
NaN |
[x] > FLT_MAX |
FLT_MAX |
FLT_MAX |
FLT_MAX |
FLT_MAX |
[x] < -FLT_MAX |
-FLT_MAX |
-FLT_MAX |
-FLT_MAX |
-FLT_MAX |
其他 |
RNE |
RNE |
RNE |
RNE |
转换也可以定义为不进行任何饱和。
x |
E4M3FN |
E4M3FNUZ |
E5M2 |
E5M2FNUZ |
---|---|---|---|---|
0 |
0 |
0 |
0 |
0 |
-0 |
-0 |
0 |
-0 |
0 |
NaN |
NaN |
NaN |
NaN |
NaN |
-NaN |
-NaN |
NaN |
-NaN |
NaN |
Inf |
NaN |
NaN |
Inf |
NaN |
-Inf |
-NaN |
NaN |
-Inf |
NaN |
[x] > FLT_MAX |
NaN |
NaN |
Inf |
NaN |
[x] < -FLT_MAX |
NaN |
NaN |
-Inf |
NaN |
其他 |
RNE |
RNE |
RNE |
RNE |