BOOST uBLAS矩阵乘积极其缓慢。

4

有没有办法提高boost ublas的乘积性能?

我有两个矩阵A,B,我想要进行乘法/加法/减法等运算...

在2000x2000的矩阵操作中,MATLAB和C ++的运行时间如下[s]

OPERATION | MATLAB | C++ (MSVC10)
A + B     |  0.04  |  0.04
A - B     |  0.04  |  0.04
AB        |  1.0   | 62.66
A'B'      |  1.0   | 54.35

为什么会有如此巨大的性能损失?

这些矩阵只是实数双精度。 但我还需要正定、对称和矩形乘积。

编辑: 代码很简单。

matrix<double> A( 2000 , 2000 );
// Fill Matrix A
matrix<double> B = A;

C = A + B;
D = A - B;
E = prod(A,B);
F = prod(trans(A),trans(B));

编辑2: 这些结果是10次尝试的平均值。标准偏差小于0.005。

我期望可能会有2-3倍的因素,但不是50倍!

编辑3: 所有测试都是在Release(NDEBUG / MOVE_SEMANTICS / ..)模式下进行的。

编辑4: 为产品结果预分配矩阵并没有影响运行时间。


请确保进行干净的Matlab重新运行,它往往会缓存...所有东西。完全无关,但你应该能够从Eigen中获得良好的性能和简单的语法(我对它与你的小基准测试有何关系感兴趣,提示提示 :-))。 - rubenvb
2
我预计乘法的时间比加法慢大约2000倍。 - ruslik
2
你记得为uBlas打开发布模式了吗?请参考[链接=http://www.boost.org/doc/libs/1_47_0/libs/numeric/ublas/doc/index.htm]此处[/链接]的常见问题解答,其中指出你需要使用“-DNDEBUG”或其他标志来使ublas编译为发布版本。 - Dave S
我从Eigen的社区中找到了一些不错的基准测试这里 - Kyle Heuton
请参考相关问题(以及更好的答案)此处。特别是,请尝试使用axpy_prod。 - John Doe
显示剩余2条评论
4个回答

4

请发布您的C++代码以寻求任何可能的优化建议。

但是,请注意Matlab非常专门为其设计的任务而设计,您不太可能能够使用Boost来匹配它。另一方面,Boost是免费的,而Matlab则不是。

我认为,将uBlas代码绑定到底层LAPACK实现可以获得最佳的Boost性能。


4
我相信将uBlas代码绑定到底层的LAPACK实现可以获得最佳的性能提升。 - ildjarn

3

为了消除不必要的拷贝,矩阵乘法左侧应使用noalias

使用noalias(E) = prod(A,b);代替E = prod(A,B);

文档中提到:

如果您确定左表达式和右表达式没有公共存储,则赋值没有别名。在这种情况下可以指定更有效的赋值:noalias(C) = prod(A, B); 这避免了创建需要在普通赋值中使用的临时矩阵。'noalias'赋值要求左右两边大小相同。


1

有许多高效的BLAS实现,例如ATLAS、gotoBLAS、MKL,建议使用它们。

我没有深入研究代码,但猜测ublas::prod(A, B)使用了三重循环,没有块和缓存友好。如果是这样,prod(A, B.trans())将比其他方法快得多。

如果cblas可用,可以使用cblas_dgemm进行计算。如果不行,可以简单地重新排列数据,即使用prod(A, B.trans())。


0

你不知道内存管理在这里扮演了什么角色。prod 必须分配一个32mb的矩阵,trans 也要这样做两次,然后你需要执行所有这些10次。花点时间了解一下 stackhots,看看它实际上在做什么。我猜,如果你预先分配这些矩阵,你会得到更好的结果。

加速矩阵乘法的其他方法是:

  • 预转置左侧矩阵,使其对缓存友好;和

  • 跳过零。只有 A(i,k) 和 B(k,j) 都是非零值时才有贡献。

这是否在 uBlas 中完成,任何人都可以猜测。


我非常确定boost ublas使用表达式模板来避免这种情况(或者至少应该是这样的)。 - user786653

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