我需要计算小型线性最小二乘问题的许多(大约 400k)解决方案。每个问题包含 10-300 个方程,只有 7 个变量。 为了解决这些问题,我使用 eigen 库。直接求解需要太多时间,我通过手工推导导数将每个问题转化为求解 7x7 线性方程组。
我得到了很好的加速,但我想再次提高性能。
我使用 vagrind 来分析我的程序,我发现 self 成本最高的操作是特征矩阵的运算符 += 。这个操作需要调用十多次a.ldlt().solve(b);
我使用这个运算符来组成每个方程组的A矩阵和B vector
//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抱歉我的英语不好
最佳答案
您可以尝试一次分配一个足够大的矩阵(例如 300 x 7)来存储所有系数,然后让 Eigen 的优化矩阵,而不是手动形成正规方程的矩阵和 vector 分量,一次一个方程-matrix 产品内核可以为您完成这项工作:
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
, equationCoeffs
,和b
作为 8x8 或 8x1 矩阵或 vector ,确保 equationCoeffs(7)==0
。这样您就可以最大限度地利用 SIMD。然后使用a.topLeftCorners<7,7>()
, b.head<7>()
调用 LDLT 时。您甚至可以将此策略与前一个策略结合起来。
最后,如果您的 CPU 支持 AVX 或 FMA,您可以使用 devel 分支并使用 -mavx
进行编译。或-mfma
获得显着的加速。
关于c++ - Eigen:如何加速 += coeffs * coeffs.transpose(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31472359/