我已使用boost::numeric::ublas::matrix
实现了一次矩阵乘法(参见my full, working boost code)
Result result = read ();
boost::numeric::ublas::matrix<int> C;
C = boost::numeric::ublas::prod(result.A, result.B);
另一个使用标准算法(参见full standard code):
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 x 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
ikj算法 28.19秒,Boost 60.99秒。所以Boost仍然相当慢。
为什么提升比我的实施慢得多?
答案 0 :(得分:47)
如TJD所指出的那样,可以通过调试后者的功能来部分解释uBLAS版本的较慢性能。
以下是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 FAQ的以下部分来解释剩余的性能差异“为什么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_prod
和block_prod
都比实施速度快一些。仅测量没有I / O的计算时间,删除不必要的复制并仔细选择block_prod
(我使用64)的块大小可以使差异更加深远。
另请参阅uBLAS FAQ和Effective uBlas and general code optimization。
答案 1 :(得分:13)
我相信,你的编译器没有足够的优化。 uBLAS代码大量使用模板和模板需要大量使用优化。我在发布模式下通过MS VC 7.1编译器为1000x1000矩阵运行代码,它给了我
对于uBLAS 10.064
7.851
s for vector
差异仍然存在,但绝不是压倒性的。 uBLAS的核心概念是惰性评估,因此prod(A, B)
仅在需要时评估结果,例如prod(A, B)(10,100)
将立即执行,因为实际上只会计算一个元素。因此,实际上没有用于整个矩阵乘法的专用算法可以被优化(见下文)。但你可以稍微帮助图书馆,宣布
matrix<int, column_major> B;
会减少4.426
的运行时间,而单手操作可以击败你的功能。这个声明使得在乘法矩阵时可以更加顺序地访问内存,从而优化缓存的使用。
P.S。读完uBLAS文档到最后;),您应该已经发现实际上有一个专用函数可以立即乘以整个矩阵。 2个功能 - axpy_prod
和opb_prod
。所以
opb_prod(A, B, C, true);
即使是未经优化的row_major B矩阵也会在8.091
秒内执行,并且与您的矢量算法相同
P.P.S。还有更多的优化:
C = block_prod<matrix<int>, 1024>(A, B);
在4.4
中执行,无论B是column_还是row_ major。
考虑描述:“函数block_prod是为大密度矩阵设计的。”为特定任务选择特定工具!
答案 2 :(得分:2)
我创建了一个小网站Matrix-Matrix Product Experiments with uBLAS。它是关于将矩阵矩阵产品的新实现集成到uBLAS中。如果您已经拥有boost库,则它只包含额外的4个文件。所以它几乎是独立的。
如果其他人可以在不同的机器上运行简单的基准测试,我会感兴趣。