为什么执行浮点数矩阵乘法比整数矩阵乘法更快?

27
拥有两个int矩阵A和B,超过1000行和1万列,我经常需要将它们转换为浮点矩阵以获得加速(4倍或更多)。 我想知道这是为什么?我意识到有很多优化和矢量化,例如AVX等与浮点矩阵乘法相关的内容。但是,如果我没有弄错的话,还有像AVX2这样的整数指令。那么,不能使用SSE和AVX进行整数计算吗? 为什么像Numpy或Eigen这样的矩阵代数库中没有启发式方法来捕获此类情况并像浮点数一样快地执行整数矩阵乘法呢?

5
如果问题更加具体会更有帮助,但是由于更多人需要它适用于浮点数,在软硬件方面都进行了优化。 - Marc Glisse
这个问题需要一个具体的示例代码来展示性能差异(请参见[mcve])。特别是考虑到代码被标记为[c++]和[numpy],完全不清楚你所指的是什么。 - Zulan
2个回答

15
如果您编译这两个简单的函数,它们本质上只是计算一个乘积(使用Eigen库)。

如果你编译这两个简单函数,它们主要就是计算一个乘积(使用Eigen库)

#include <Eigen/Core>

int mult_int(const Eigen::MatrixXi& A, Eigen::MatrixXi& B)
{
    Eigen::MatrixXi C= A*B;
    return C(0,0);
}

int mult_float(const Eigen::MatrixXf& A, Eigen::MatrixXf& B)
{
    Eigen::MatrixXf C= A*B;
    return C(0,0);
}

使用标志-mavx2 -S -O3,您将看到整数版本和浮点版本的非常相似的汇编代码。

然而,主要区别在于vpmulld的延迟时间是vmulps的2-3倍,并且吞吐量只有vmulps的1/2或1/4。(在最新的Intel架构上)

参考:Intel Intrinsics Guide,“吞吐量”指的是倒数吞吐量,即如果没有延迟发生,每个操作使用多少个时钟周期(有些简化)。


非常有趣!从来没有想过 vpmulldvmulps 在吞吐量和延迟方面会有这么大的差异。 - NULL
3
出乎意料却毫不奇怪。浮点矩阵运算在计算机图形学中被广泛使用,因此在硬件优化方面引起了极大兴趣。应用范围从显而易见的(视频游戏和网络应用程序)到以研究为导向的仿真引擎和数学建模。此外,如果您认为这些速度很快,您可以在视频卡上编程执行此类操作来获得更多的浮点运算吞吐量(一个很好的示例是nVidia的CUDA平台)。视频卡是专门为大规模并行浮点运算而构建的。 - user1258361
1
此外,如果您使用-march=native,FP可以使用FMA指令。除了Via的一个CPU之外,所有AVX2 CPU也都有FMA。x86没有整数乘加指令,只有FP。在matmul中的大部分FLOP可以通过FMAs完成,如果您可以保持执行单元的供给(每个FMA只有1个负载),则吞吐量几乎增加了一倍,否则会限制负载吞吐量。 - Peter Cordes

15

所有的向量-向量和矩阵-向量运算都在内部使用BLAS。BLAS已经经过数十年的优化,针对不同的架构、CPU、指令和缓存大小进行了优化,但它没有整型!

这里有一些OpenBLAS的分支正在处理此问题(还有一些在Google-groups上讨论链接)。

我想我听说英特尔的MKL(英特尔的BLAS实现)也可能正在处理整型这个演讲看起来很有意思(在那个论坛中提到),虽然它很短,可能更多地是接近于嵌入式深度学习中有用的小整型)。


3
看起来 Blaze 支持整数。 - NathanOliver
1
Eigen可以处理整数数据类型,在使用g++ -O3 -march=somethingrecent进行编译时,它会被向量化,你可以看到类似于vpmulld的指令。 - Marc Glisse
2
@NULL 我也没有使用过它,但我看过一次关于它的演讲,他们展示了一些不错的性能数据。 - NathanOliver
1
@NULL 我在这项任务上没有太多经验。但是看起来,如果性能对您非常重要,您必须检查所有可用的软件,因为似乎存在差异。也许有一天OpenBLAS或MKL会添加本地支持,但那是未来的事情。在某些用例中,我会担心基于浮点数的操作,但如果它适用于您(没有数值问题),那就很好。 - sascha
2
Eigen不依赖于单独的BLAS实现。默认情况下,它使用自己的实现(但是您可以告诉它使用外部BLAS)。 - chtz
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接