这是一个相当理论化的问题,但我对它很感兴趣,如果有人对他或她愿意分享这方面的专业知识,我会很高兴。
我有一个带有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:根据GuyGreer的建议,我将提供一些示例代码来重现我的发现:
#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秒,而使用test 1
运行mean()
只需要0.03秒!
编辑3:事实证明(参见注释),sum()
不是花费这么长时间,而是将结果向量除以行数。所以新的问题是:为什么Eigen需要超过2分钟才能将一列1000个列除以一个标量?
答案 0 :(得分:7)
不知何故,每次都重新计算部分减少(总和)和除法,因为php
错误地丢失了关于部分减少的评估成本的一些关键信息...明确评估平均值修复了问题:
operator/
当然,此评估应由Eigen为您完成,由变更集42ab43a确定。此修复程序将成为下一个3.2.7和3.3版本的一部分。