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

C++ 为什么执行逐浮点矩阵乘法比逐整数乘法更快?,c++,numpy,matrix,eigen,avx,C++,Numpy,Matrix,Eigen,Avx,有两个整数矩阵A和B,有1000多行和10K列,我经常需要将它们转换为浮点矩阵以获得加速比(4倍或更多) 我想知道为什么会这样?我意识到在浮点矩阵乘法中有很多优化和向量化,比如AVX等。但是,还有一些指令,比如AVX2,用于整数(如果我没弄错的话)。还有,不能用SSE和AVX来表示整数吗 为什么在矩阵代数库(如Numpy或Eigen)下面没有一个启发式方法来捕捉这个并像float一样更快地执行整数矩阵乘法 关于公认的答案:尽管@sascha的答案信息丰富且相关,但@chatz的答案是导致逐点整数

有两个整数矩阵A和B,有1000多行和10K列,我经常需要将它们转换为浮点矩阵以获得加速比(4倍或更多)

我想知道为什么会这样?我意识到在浮点矩阵乘法中有很多优化和向量化,比如AVX等。但是,还有一些指令,比如AVX2,用于整数(如果我没弄错的话)。还有,不能用SSE和AVX来表示整数吗

为什么在矩阵代数库(如Numpy或Eigen)下面没有一个启发式方法来捕捉这个并像float一样更快地执行整数矩阵乘法

关于公认的答案:尽管@sascha的答案信息丰富且相关,但@chatz的答案是导致逐点整数乘法速度慢的真正原因,而不管是否存在BLAS整数矩阵运算


所有这些向量和矩阵向量操作都在内部使用。BLAS经过几十年的优化,针对不同的ARCH、CPU、指令和缓存大小,没有整数类型

正在进行(和一些)


我想我听到了英特尔的MKL(英特尔的BLAS实现)。看起来很有趣(在那个论坛中提到过),虽然它很短,可能更接近嵌入式深度学习中有用的小整数类型。

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

#包括
整数倍整数(常数本征::矩阵XXI&A,本征::矩阵XXI&B)
{
本征::矩阵xxi C=A*B;
返回C(0,0);
}
整数多浮点数(常数本征::矩阵XXF&A,本征::矩阵XXF&B)
{
本征::矩阵C=A*B;
返回C(0,0);
}
使用标志
-mavx2-S-O3
您将看到非常相似的汇编代码,用于整数和浮点版本。 然而,主要区别在于
vpmulld
的延迟是
vmulps
的2-3倍,吞吐量只有
vmulps
的1/2或1/4。(关于最近的英特尔体系结构)


参考资料:,“吞吐量”是指交互吞吐量,即,如果没有延迟发生,每个操作使用多少时钟周期(稍微简化)。

这将有助于使问题更具体,但由于更多的人需要它来进行浮点运算,因此在优化浮点运算方面做了更多的工作(在软件和硬件方面)。此问题需要一个具体的示例代码来演示性能差异(请参阅)。特别是考虑到代码被标记为[c++]和[numpy],完全不清楚您指的是什么。看起来支持IntegerSegen处理整数,当你用
g++-O3-march=somethingrecent
编译它时,它是矢量化的,你会看到像
vpmulld
@NULL这样的指令,我也没有用过它,但我看过一个关于它的讨论,他们确实给出了一些不错的性能数据。@NULL我对这项任务没有太多经验。但看起来,如果性能对您来说如此重要,那么您必须检查所有可用的软件,因为它们似乎存在差异。也许有一天OpenBLAS或MKL会添加本机支持,但那是未来。在某些用例中,我会害怕基于浮点运算的操作,但如果这对你有用(没有数字上的麻烦),那就好了。Eigen不依赖于单独的BLAS实现。默认情况下,它使用自己的实现(但是,您可以告诉它使用外部BLAS)。非常有趣!没想到
vpmulld
vmulps
在吞吐量和延迟方面会有这么大的不同。出乎意料但并不令人惊讶。浮点矩阵运算在计算机图形学中有着广泛的应用,这促使人们对其硬件优化产生了极大的兴趣。应用范围从显而易见的(视频游戏和网络应用)到面向研究的模拟引擎和数学建模。此外,如果您认为这些操作速度很快,那么在视频卡上编程这些类型的操作可以获得更高的浮点操作吞吐量(nVidia的CUDA平台就是一个很好的例子)。视频卡是专门为大规模并行浮点操作而构建的。此外,如果您使用
-march=native
,FP可以使用FMA指令-所有AVX2 CPU(除了Via中的一个)也有FMA。x86没有整数mul add指令,只有FP。matmul中的大多数失败都可以用FMA来完成,如果您能够保持执行单元的供给(每个FMA只有1个负载,否则您的负载吞吐量会出现瓶颈),吞吐量几乎会再次翻倍。
#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);
}