拆解三种浮点格式在 IEEE 754 下的符号位、指数位与尾数位结构:FP16 的 5 位指数与 10 位尾数、BF16 用 8 位指数换取更大表示范围、FP32 的 24 位尾数精度,并用 PyTorch 代码实测分辨率、机器精度与二进制转换过程。

FP16
FP16也叫做 float16,两种叫法是完全一样的,全称是Half-precision floating-point(半精度浮点数),在IEEE 754标准中是叫做binary16,简单来说是用16位二进制来表示的浮点数,来看一下是怎么表示的

其中:
- Sign(符号位): 1 位,0表示整数;1表示负数。
- Exponent(指数位):5位,简单地来说就是表示整数部分,范围为00001(1)到11110(30),正常来说整数范围就是 $2^1−2^{30}$,但其实为了指数位能够表示负数,引入了一个偏置值,偏置值是一个固定的数,它被加到实际的指数上,在二进制16位浮点数中,偏置值是 15。这个偏置值确保了指数位可以表示从-14到+15的范围即 $2^{−14}−2^{15}$,而不是1到30,注:当指数位都为00000和11111时,它表示的是一种特殊情况,在IEEE 754标准中叫做非规范化情况,后面可以看到这种特殊情况怎么表示的。
- Fraction(尾数位):10位,简单地来说就是表示小数部分,存储的尾数位数为10位,但其隐含了首位的1,实际的尾数精度为11位,这里的隐含位可能有点难以理解,简单通俗来说,假设尾数部分为1001000000,为默认在其前面加一个1,最后变成1.1001000000然后换成10进制就是:
计算公式:

FP16(float16)能表示的最大的正数:

同样,这个是FP16(float16)能表示的最大的负数:

这就是FP16(float16)表示的范围[-65504,65504]。
FP16(float16)特殊数值的情况:

在pytorch中是如何表示的:
1 | torch.finfo(torch.float16) |
一些解释:
resolution(分辨率):这个浮点数类型的在十进制上的分辨率,表示两个不同值之间的最小间隔。对于torch.float16,分辨率是 0.001,就是说两个不同的torch.float16数值之间的最小间隔是 0.001。min(最小值):对于torch.float16,最小值是 -65504。max(最大值):对于torch.float16,最大值是 65504。eps(机器精度):机器精度表示在给定数据类型下,比 1 大的最小浮点数,对于torch.float16,机器精度是 0.000976562,对应上表中的smallest number larger than one。smallest_normal(最小正规数):最小正规数是大于零的最小浮点数,对于torch.float16,最小正规数是 6.10352e-05,对应上表中的smallest positive normal numbertiny(最小非零数):最小非零数是大于零的最小浮点数,对于torch.float16,最小非零数也是 6.10352e-05,也是对应上表中的smallest positive normal number
这里要详细的解释一下resolution(分辨率),这个是我们以十进制来说的两个数之间的最小间隔,我们看一个例子就会明白:
1 | import torch |
float16变成2进制
1 | import struct |
把2进制变成16进制:
1 | def binary_to_float16(binary_string): |
因为在计算机中是以2进制存储计算的,所以转换后的float16值会有很多位小数,但这些后面的小数是没有精度的,换成10进制的精度是只有0.001的。注:在-1~1之间精度是0.0001。
BF16
BF16也叫做bfloat16(这是最常叫法),其实叫“BF16”不知道是否准确,全称brain floating point,也是用16位二进制来表示的,是由Google Brain开发的,所以这个brain应该是Google Brain的第二个单词。和上述FP16不一样的地方就是指数位和尾数位不一样:

- Sign(符号位): 1 位,0表示整数;1表示负数
- Exponent(指数位):8位,表示整数部分,偏置值是 127
- Fraction(尾数位):7位,表示小数部分,也是隐含了首位的1,实际的尾数精度为8位
计算公式:

这里要注意一下,并不是所有的硬件都支持bfloat16,因为它是一个比较新的数据类型,在 NVIDIA GPU 上,只有 Ampere 架构以及之后的GPU 才支持,如何判断呢?很简单:
1 | import transformers |
pytorch中是如何表示的:
1 | import torch |
bfloat16的10进制间隔精度是0.01(注:在-1~1之间精度是0.001),表示范围是[-3.40282e+38,3.40282e+38]。可以明显的看到bfloat16比float16精度降低了,但是表示的范围更大了,能够有效的防止在训练过程中的溢出。
FP32
FP32也叫做 float32,两种叫法是完全一样的,全称是Single-precision floating-point(单精度浮点数),在IEEE 754标准中是叫做binary32,简单来说是用32位二进制来表示的浮点数:

- Sign(符号位): 1 位,0表示整数;1表示负数
- Exponent(指数位):8位,表示整数部分,偏置值是 127
- Fraction(尾数位):23位,表示小数部分,也是隐含了首位的1,实际的尾数精度为24位
计算公式:

在pytorch中是如何表示的:
1 | import torch |
float32的10进制间隔精度是0.000001(注:在-1~1之间精度是0.0000001),表示范围是[-3.40282e+38,3.40282e+38]。可以看到float32精度又高,范围又大,可是32位的大小对于现在大模型时代的参数量太占空间了。

