为什么是提升矩阵乘法比我慢?(Why is boosts matrix multiplication

2019-06-25 14:46发布

我已经实现了一个矩阵乘法boost::numeric::ublas::matrix (见我的全力,努力提升代码 )

Result result = read ();

boost::numeric::ublas::matrix<int> C;
C = boost::numeric::ublas::prod(result.A, result.B);

和另一个标准算法(参见完整的标准代码 ):

vector< vector<int> > ijkalgorithm(vector< vector<int> > A, 
                                    vector< vector<int> > B) {
    int n = A.size();

    // initialise C with 0s
    vector<int> tmp(n, 0);
    vector< vector<int> > C(n, tmp);

    for (int i = 0; i < n; i++) {
        for (int k = 0; k < n; k++) {
            for (int j = 0; j < n; j++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
    return C;
}

这是我的测试速度:

time boostImplementation.out > boostResult.txt
diff boostResult.txt correctResult.txt

time simpleImplementation.out > simpleResult.txt
diff simpleResult.txt correctResult.txt

这两个程序读取一个硬编码的文本文件包含两个2000×2000矩阵。 这两个程序被编译与这些标志:

g++ -std=c++98 -Wall -O3 -g $(PROBLEM).cpp -o $(PROBLEM).out -pedantic

我得到了15秒我的实现和超过4分钟升压实现!

编辑:有它编译后

g++ -std=c++98 -Wall -pedantic -O3 -D NDEBUG -DBOOST_UBLAS_NDEBUG library-boost.cpp -o library-boost.out

28.19秒为ikj算法和60.99秒的提升。 所以升压仍然是相当慢。

为什么这么助推比我的执行慢得多?

Answer 1:

的的uBLAS版本的性能下降可以通过正如指出的TJD调试后者的特征部分原因。

这里是由uBLAS库版本调试上所花的时间:

real    0m19.966s
user    0m19.809s
sys     0m0.112s

下面是与调试关闭(采取的uBLAS版本时-DNDEBUG -DBOOST_UBLAS_NDEBUG添加编译器标志):

real    0m7.061s
user    0m6.936s
sys     0m0.096s

因此,与调试关,uBLAS库的版本快了近3倍。

其余的性能差异可以通过引用以下部分中介绍的uBLAS常见问题解答 “为什么比uBLAS库(atlas-)BLAS这么慢得多”:

uBLAS库的一个重要的设计目标是要尽可能通用。

这种通用性几乎总是带有一个成本。 尤其是prod功能模板可以处理不同类型的矩阵,例如稀疏或三角形的。 幸运的uBLAS提供替代品稠密矩阵乘法优化,特别地, axpy_prod和block_prod 。 以下是比较不同方法的结果:

ijkalgorithm   prod   axpy_prod  block_prod
   1.335       7.061    1.330       1.278

正如你可以同时看到axpy_prodblock_prod比你实现稍快。 测量刚计算时间没有I / O,去除不必要的复制和的块大小的仔细选择block_prod (I用64)可以使不同更深刻。

另见的uBLAS常见问题和有效的uBLAS和一般的代码优化 。



Answer 2:

我相信,你的编译器不优化不够。 uBLAS库代码大量使用的模板和模板需要大量使用优化。 我跑了通过MS VC 7.1编译器代码在发布模式为1000×1000矩阵,它给了我

10.064 S代表的uBLAS

7.851 S代表矢量

所不同的是仍然存在,但绝不是压倒性的。 uBLAS库的核心概念是惰性计算,所以prod(A, B)的计算结果仅在需要时的结果,例如prod(A, B)(10,100)将在任何时间执行,因为只有一个元件实际上将被计算。 这样实际上有一个为全矩阵乘法它可以优化 (见下文) 没有专门的算法 。 但是你可以帮助图书馆一点,声明

matrix<int, column_major> B;

将减少运行时间,以4.426 S的用一只手绑击败你的函数。 矩阵相乘时,优化缓存使用这个声明使得访问存储更多的顺序。

PS读过的uBLAS文档,以结束),你应该已经发现,竟然有一个专用的功能一下子成倍整个矩阵。 2个功能- axpy_prodopb_prod 。 所以

opb_prod(A, B, C, true);

即使在未优化row_major乙矩阵执行8.091秒,是在同水准与你的载体算法

PPS甚至还有更多的优化:

C = block_prod<matrix<int>, 1024>(A, B);

执行4.4 S,不管B是否是column_或row_重大。 请看介绍:“该功能block_prod是专为大型密集矩阵”。 选择针对特定任务特定的工具!



Answer 3:

我创建了一个小网站用的uBLAS矩阵-矩阵产品实验 。 这是关于整合的新实现对矩阵矩阵产品投入的uBLAS。 如果你已经有了Boost库只包含额外的4个文件。 所以它是非常自足。

我会感兴趣,如果其他人可以运行在不同的机器上简单的基准。



文章来源: Why is boosts matrix multiplication slower than mine?