C++ 如何加速a+=coefs*coefs.transpose()

C++ 如何加速a+=coefs*coefs.transpose(),c++,performance,matrix,eigen,eigen3,C++,Performance,Matrix,Eigen,Eigen3,我需要计算一些大约400k的小型线性最小二乘问题的解。每个问题包含10-300个方程,只有7个变量。 为了解决这些问题,我使用了特征库。直接求解需要太多的时间,我通过手工推导导数,将每个问题转化为求解7x7线性方程组 我得到了很好的加速,但我想再次提高性能 我使用vagrind来分析我的程序,我发现自我成本最高的操作是特征矩阵的运算符+=运算。此操作需要十多次调用a.ldlt.solveb 我用这个算符组成每个方程组的矩阵和B向量 //I cal these code to solve each

我需要计算一些大约400k的小型线性最小二乘问题的解。每个问题包含10-300个方程,只有7个变量。 为了解决这些问题,我使用了特征库。直接求解需要太多的时间,我通过手工推导导数,将每个问题转化为求解7x7线性方程组

我得到了很好的加速,但我想再次提高性能

我使用vagrind来分析我的程序,我发现自我成本最高的操作是特征矩阵的运算符+=运算。此操作需要十多次调用a.ldlt.solveb

我用这个算符组成每个方程组的矩阵和B向量

//I cal these code to solve each problem
const int nVars = 7;
//i really need double precision
Eigen::Matrix<double, nVars, nVars> a = Eigen::Matrix<double, nVars, nVars>::Zero();
Eigen::Matrix<double, nVars, 1> b = Eigen::Matrix<double, nVars, 1>::Zero();
Eigen::Matrix<double, nVars, 1> equationCoeffs;
//............................
//Somewhere in big cycle.
//equationCoeffs and z are updated on each iteration
a += equationCoeffs * equationCoeffs.transpose();
b += equationCoeffs * z;
其中z是一些标量

所以我的问题是:如何提高这些操作的性能


PS对不起,我的英语很差

我有一个问题Ax=b和480k浮点变量。矩阵A是稀疏的,用特征BiCGSTAB求解它需要4.8秒

我以前也和ViennaCL合作过,所以我尝试在那里解决同样的问题,只花了1.2秒。spead的增加已实现
通过GPU上的处理。

您可以尝试一次分配足够大的矩阵(例如300 x 7)来存储所有系数,然后让Eigen的优化矩阵积核为您完成以下工作,而不是手动形成正常方程的矩阵和向量分量:

Matrix<double,Dynamic,nbVars> D(300,nbVars);
VectorXd f(300);
for(...)
{
  int nb_equations = ...;
  for(i=0..nb_equations-1)
  {
    D.row(i) = equationCoeffs;
    f(i) = z;
  }
  a = D.topRows(nb_equations).transpose() * D.topRows(nb_equations);
  b = D.topRows(nb_equations).transpose() * f.head(nb_equations);
  // solve ax=b
}
您可以使用列主存储区和行主存储区对矩阵D进行测试,以确定哪一个是最好的

另一种可能的方法是将a、方程系数和b声明为8x8或8x1矩阵或向量,确保方程系数7==0。这样可以最大限度地利用SIMD。然后在调用LDLT时使用a.topLeftCorners和b.head。您甚至可以将此策略与前一个策略相结合


最后,如果您的CPU支持AVX或FMA,您可以使用devel分支并使用-mavx或-mfma进行编译,以获得显著的加速。

如果您可以使用g++5.1,您可能需要看看OpenMP . G++5.1或gcc5.1forC也有一些对OpenACC的基本支持,您也可以尝试一下。未来应该有更多的OpenACC实现

此外,如果您可以访问英特尔编译器icc,icpc,它甚至可以通过使用它来加速我的代码

如果您可以使用nvidia的nvcc,您可以使用推力库 ,他们的github上也有很多示例代码 . 然而,使用推力并不是那么直截了当,需要一些真正的思考

编辑: 推力还需要Nvidia GPU。
对于AMD卡,我相信有一个名为ArrayFire的库,它看起来非常类似于我没有尝试过的推力,但

谢谢您的回答。但我有很多非常小的密集问题,而不是一个大而稀疏的问题。我现在也不能使用GPU=谢谢你的回答!看起来很有趣。我将尝试使用大型矩阵的方法。我以前也试过使用8x8/8x1矩阵,但它并没有给我加速。谢谢你们的回答。我无法使用像icc这样的高级编译器。但也许我会尝试使用openmp。此外,我认为可以将openmp与旧版本的gcc一起使用