是否可以在英特尔芯片上执行半精度浮点运算?
我知道如何加载/存储/转换半精度浮点数 [1],但我不知道如何在不转换为单精度浮点数的情况下将它们相加/相乘。
[1] https://software.intel.com/en-us/articles/performance-benefits-of-half-precision-floats
是否可以在英特尔芯片上执行半精度浮点运算?
我知道如何加载/存储/转换半精度浮点数 [1],但我不知道如何在不转换为单精度浮点数的情况下将它们相加/相乘。
[1] https://software.intel.com/en-us/articles/performance-benefits-of-half-precision-floats
相关:https ://scicomp.stackexchange.com/questions/35187/is-half-precision-supported-by-modern-architecture - 有一些关于 Cooper Lake 和 Sapphire Rapids 中的 BFloat16 的信息,以及一些非英特尔信息。
Sapphire Rapids 将同时具有 BF16和FP16,其中 FP16 使用与 F16C 转换指令相同的 IEEE754binary16
格式,而不是大脑浮点数。AVX512 -FP16支持大多数数学运算,与 BF16 不同,BF16 仅将单和点积累加对转换为单精度。
这也适用于 Alder Lake,在禁用 E 内核且在 BIOS 中专门启用了 AVX-512 的系统上(目前显然尚未正式支持;只有一些主板供应商有此选项。)
(对于具有 FP16 / BF16 的 Sapphire Rapids / Alder Lake,其余答案未更新。)
是否可以在英特尔芯片上执行半精度浮点运算?
是的,显然Skylake 和更高版本中的片上 GPU 具有对 FP16 和 FP64 以及 FP32 的硬件支持。有了足够新的驱动程序,您可以通过 OpenCL 使用它。
在较早的芯片上,FP16 与 FP32 的吞吐量大致相同(可能只是即时转换几乎免费),但在 SKL / KBL 芯片上,GPGPU Mandelbrot 的吞吐量大约是 FP32 的两倍(请注意对数刻度该链接中图表的 Mpix/s 轴)。
在 Skylake iGPU 上,FP64 ( double
) 性能的提升也是巨大的。
但是在 IA 内核(英特尔架构)上没有;即使使用 AVX512,除了将它们转换为单精度之外,没有任何硬件支持。这可以节省内存带宽,并且如果您的代码在内存上出现瓶颈,肯定可以加快速度。但是对于没有内存瓶颈的代码,它不会获得峰值 FLOPS。
您当然可以实现软件浮点,甚至可能在 SIMD 寄存器中,所以从技术上讲,您提出的问题的答案仍然是“是”,但它不会比使用 F16C VCVTPH2PS
/VCVTPS2PH
指令 + 打包单vmulps
/vfmadd132ps
硬件支持更快.
在 x86 代码中使用硬件支持的 SIMD 与/从float
/的转换,__m256
以换取额外的 ALU 转换工作,以减少内存带宽和缓存占用。 但是,如果缓存阻塞(例如,对于调整良好的密集 matmul)或非常高的计算强度意味着您没有内存瓶颈,那么只需使用float
并节省 ALU 操作。
bfloat16
脑漂浮)和 AVX512 BF16已经为神经网络用例开发了一种新的 16 位 FP 格式,其指数范围与 IEEE binary32 相同。与 x86 F16C 转换指令使用的 IEEE binary16 相比,它的有效精度要低得多,但显然神经网络代码更关心大指数范围的动态范围。这使得 bfloat 硬件甚至不必费心支持次规范。
一些即将推出的 Intel x86 CPU 内核将支持这种格式的硬件。主要用例仍然是专用的神经网络加速器 ( Nervana ) 和 GPGPU 类型的设备,但至少支持硬件的转换非常有用。
https://en.wikichip.org/wiki/brain_floating-point_format有更多详细信息,特别是Cooper Lake Xeon 和 Core X CPU 预计将支持AVX512 BF16。
我还没有看到 Ice Lake(Sunny Cove 微拱门)提到它。这可能是任何一种方式,我不想猜测。
英特尔® 架构指令集扩展和未来功能编程参考修订版 -036 于 2019 年 4 月添加了有关 BF16 的详细信息,包括它计划用于“未来,库珀湖”。一旦发布,说明文档将移至主要的 vol.2 ISA 参考手册(以及https://www.felixcloutier.com/x86/index.html上的 pdf->HTML 抓取)。
https://github.com/HJLebbink/asm-dude/wiki有来自 vol.2 和 future-extensions 手册的说明,所以你已经可以在那里找到它。
只有 3 条指令:转换到/从float
,以及 BF16 乘法 + 成对累加到float
。(点积的第一个水平步骤。)所以 AVX512 BF16最终确实为 16 位浮点提供了真正的计算,但只是以这种非常有限的形式将结果转换为float
.
他们还忽略 MXCSR,始终使用默认舍入模式和 DAZ/FTZ,并且不设置任何异常标志。
VCVTNEPS2BF16 [xxy]mm1{k1}{z}, [xyz]mm2/m512/m32bcst
__m256bh _mm512_cvtneps_pbh (__m512);
其他两个不支持内存故障抑制(当对内存源操作数使用掩码时)。大概是因为屏蔽是针对每个目标元素的,并且源元素的数量不同。转换为BF16 显然可以抑制内存故障,因为与 16 位目标元素相同的掩码可以应用于 32 位源元素。
VCVTNE2PS2BF16 [xyz]mm1{k1}{z}, [xyz]mm2, [xyz]mm3/m512/m32bcst
转换(无例外) Packed Single 2(to) BF16 的 2 个寄存器。
_m512bh _mm512_cvtne2ps_pbh (__m512, __m512);
VDPBF16PS [xyz]mm1{k1}{z}, [xyz]mm2, [xyz]mm3/m512/m32bcst
BF16 对的点积累加成压缩单精度
__m512 _mm512_dpbf16_ps(__m512, __m512bh, __m512bh);
(请注意,即使是未屏蔽版本也有目标累加器的第三个输入,如 FMA)。
# the key part of the Operation section:
t ← src2.dword[ i ] (or src.dword[0] for a broadcast memory source)
srcdest.fp32[ i ] += make_fp32(src1.bfloat16[2*i+1]) * make_fp32(t.bfloat[1])
srcdest.fp32[ i ] += make_fp32(src1.bfloat16[2*i+0]) * make_fp32(t.bfloat[0])
因此,我们仍然没有获得可用于任意事物的本机 16 位 FP 数学,同时将数据保持为 16 位格式,每个向量有 32 个元素。仅将 FMA 转换为 32 位累加器。
顺便说一句,还有其他实数格式不基于符号/指数/有效数的固定宽度字段的 IEEE-754 结构。越来越受欢迎的是Posit。 https://en.wikipedia.org/wiki/Unum_(number_format),在自己的游戏中击败浮点数:Posit Arithmetic和https://posithub.org/about
他们没有将整个有效编码空间花费在 NaN 上,而是将其用于锥形/逐渐溢出,支持更大的范围。(并且删除 NaN 简化了硬件)。IEEE 浮点数仅支持逐渐下溢(带次正规),硬上溢到 +-Inf。(这通常是实际数值模拟中的错误/问题,与 NaN 没有太大区别。)
Posit 编码是一种可变宽度指数,在 1.0 附近留下更高的精度。目标是允许在更多情况下(而不是 64 或 32 位)使用 32 位或 16 位精度,同时仍然获得对科学计算/HPC 有用的结果,例如气候建模。每个 SIMD 向量的工作量加倍,内存带宽减半。
已经有一些针对 Posit FPU 硬件的论文设计,但现在还处于早期阶段,我认为只有 FPGA 实现真正被构建。一些英特尔 CPU 将配备板载 FPGA(或者这可能已经成为现实)。
截至 2019 年年中,我还没有读到任何 Posit 执行单元作为商业 CPU 设计的一部分,谷歌也没有找到任何东西。
如果您使用所有内核,我认为在许多情况下您仍然受到内存带宽的限制,半精度浮点将是一个胜利。