优化许多小矩阵的矩阵向量乘法

计算科学 线性代数 优化
2021-11-29 09:36:01

我正在考虑加速矩阵向量产品,但我读到的所有内容都是关于如何为非常大的矩阵做这件事。我的情况是,矩阵很小,但必须完成的次数非常多。

如果有的话,有什么方法可以优化这个?从小矩阵和一个由较小向量组成的大向量中构造一个非常大的对角块矩阵并使用大矩阵向量加速技术会更快吗?或者设置全局矩阵和向量会在那里杀死任何好处?

3个回答

在尝试优化您的代码之前,有必要先询问是否有任何需要优化的地方。优化矩阵向量产品的库通过解决两个问题来做到这一点:缓存大小的限制和从内存加载数据的延迟。第一个是通过将当前缓存中的数据最大程度地用于需要使用的所有数据,然后再将其替换为其他数据,后者是通过在实际使用数据之前将数据预取到缓存中来完成的。

在您的情况下,您的数据的算术强度相对较小——您从内存中加载数据,只使用一次,然后继续下一个矩阵。这只剩下第二条优化途径:在使用之前预取数据。

但是,正如我所说,在尝试优化之前,可能值得弄清楚你已经拥有什么:计算你每秒执行多少矩阵向量乘积,计算需要从内存加载到处理器上的字节数,然后将其与您机器中碰巧拥有的处理器的带宽进行比较。你可能会发现没有什么可以让事情变得更快。

生成 C++ 代码并使用 Eigen/Armadillo 是可能的,但这取决于应用程序。

我们的解决方案是明确地写出的结果。如果没有循环,代码在现代编译器和矢量支持(64 位的 sse2、avx2 和 avx512)下非常快。N<8

请注意数据的内存对齐(最多对齐 64 个字节)并限制指针以使编译器的工作更轻松。这些矩阵大小无需使用多核支持,开销大于增益。

我们使用脚本为每个可能的组合自动生成单独的函数,并为连续调用缓存函数指针。

有一个很好的廉价库,用于手动高度优化的小型矩阵运算,称为OptiVec,它在我们的案例中运行良好。我们将它用于N8

这实际上可能无关紧要,因为您的矩阵已经包含在缓存中,但是您应该调用dgemv()sgemv()从您可以得到的最佳 BLAS 库中调用或等效项。如果您可以访问它,您应该尝试英特尔 MKL,以及 BLIS 或 ATLAS 或许多其他优化的 BLAS 库之一。