为什么Eigens-mean()方法比sum()快得多

Why is Eigens mean() method so much faster than sum()?

本文关键字:sum 快得多 方法 为什么 Eigens-mean      更新时间:2023-10-16

这是一个相当理论化的问题,但我对此很感兴趣,如果有人愿意分享这方面的专业知识,我会很高兴。

我有一个由2000行和600列组成的浮动矩阵,并想从每行中减去列的平均值。我测试了以下两条线路,并比较了它们的运行时间:

MatrixXf centered = data.rowwise() - (data.colwise().sum() / data.cols());
MatrixXf centered = data.rowwise() - data.colwise().mean();

我想mean()不会做一些不同于将每列的总和除以行数的事情,但虽然第一行在我的计算机上执行需要12.3秒,但第二行在0.09秒后完成。

我使用的是Eigen version 3.2.6,它目前是最新版本,我的矩阵是按行主顺序存储的。

有人知道Eigen的内部结构吗?这可以解释这种巨大的性能差异?

<小时>

编辑:我应该补充一下,上面代码中的data实际上是Eigen::Map< Eigen::MatrixXf<Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> >类型,并将Eigen的功能映射到原始缓冲区。

<小时>

编辑2:根据GuyGrier的建议,我将提供一些示例代码来重现我的发现:

#include <iostream>
#include <chrono>
#include <Eigen/Core>
using namespace std;
using namespace std::chrono;
using namespace Eigen;
int main(int argc, char * argv[])
{
    MatrixXf data(10000, 1000), centered;
    data.setRandom();
    auto start = high_resolution_clock::now();
    if (argc > 1)
        centered = data.rowwise() - data.colwise().mean();
    else
        centered = data.rowwise() - (data.colwise().sum() / data.rows());
    auto stop = high_resolution_clock::now();
    cout << duration_cast<milliseconds>(stop - start).count() << " ms" << endl;
    return 0;
}

编译使用:

g++ -O3 -std=c++11 -o test test.cc

在我的机器上运行不带参数的结果程序(即使用sum())需要126秒,而使用mean()运行test 1只需要0.03秒!

<小时>

编辑3:事实证明(请参阅注释),花费这么长时间的不是sum(),而是结果向量除以行数。因此,新的问题是:为什么Eigen需要2分钟以上的时间才能将一个有1000列的向量除以一个标量?

不知何故,每次都会重新计算部分约简(和)和除法,因为operator/错误地丢失了关于部分约简评估成本的一些关键信息。。。明确评估平均值解决了问题:

centered = data.rowwise() - (data.colwise().sum() / data.cols()).eval();

当然,这个评估应该由Eigen为您完成,正如变更集42ab43a所固定的那样。此修复程序将成为下一个3.2.7和3.3版本的一部分。