Eigen优化过程
背景
最近在写一个保边滤波的算法。为了加快运算速率,采用C++语言,使用Eigen库进行大矩阵运算。
效率问题
作为基于全局图像的算法,需要创建一个全局的矩阵(n*m在数千万到数亿的级别),但是,有效数据大约只有数十万级别,也就是说这是一个不折不扣的稀疏矩阵。因此,我们所有的矩阵运算都是基于Eigen::SparseMatrix
对于矩阵的构建,常用的有以下几种方法。
-
直接给稀疏矩阵(SparseMatrix赋值)
Eigen::SparseMatrix<double> sparse(rows,cols);
sparse.insert(row, col, num);
sparse.coeffRef(row,col,num);
经过测试,在没有数据的情况下,insert()和coeffRef(),不论从效率上,还是从效果上,基本没有什么大的差别。
在实际运行过程中,这种写法是效率最差的一种。20W+的数据跑了1分钟没出结果,果断停了。我们是要做到毫秒级的!!!
-
使用三元组初始化稀疏矩阵
typename Eigen::Triplet<double> TD;
vector<TD> tripletList;
tripletList.reserve(N);
for(int i=0;i<N;i++;){
tripletList.push_bach(TD(row,col,num));
}
Eigen::SparseMatrix<double> sparse(rows,cols);
sparse.setFromTriplet(tripletList.begin(),tripletList.end());
if(!m_sparseB.isCompressed())
m_sparseB.makeCompressed();
代码简洁明了,不多做解释。
在实际运行过程中,这种官方推荐,且被大量使用的写法,效率上依旧是不能满意(20W+的数据,跑7S)。接下来,我们深入探究一下这个原因。
探究及优化
-
vector::push_back()是个性能非常的差。
void fVector() {
vector<int> vec;
for (size_t i = 0; i < 2000000; i++) {
vec.push_back(i);
}
}
void fvecSize() {
vector<int> vec(2000000);
for (size_t i = 0; i < 2000000; i++) {
vec[i] = i;
}
}
void farray() {
int* vec = new int[2000000];
for (size_t i = 0; i < 2000000; i++) {
vec[i] = i;
}
delete[] vec;
}
-
在实际测试中,200W的数据,跑出了0.4s,的成绩。
-
提前分配内存,使用 = 操作,时间消耗只有0.04s。性能差了10倍!!!
-
直接使用数组,则只需要0.009s
综上:我要干掉push操作
-
setFromTriplet是需要编译器优化的
干掉push之后,效率问题依旧没有得到明显的改变。经过分析,setFromTriplet跑了6S+,我再一次陷入沉思。因为,同样的逻辑,大兄弟跑出了1.3s的骄人成绩。他还是做了大量矩阵计算的前提下,而我,只是得到了两个矩阵,还没有进行计算。
经过我虚心请教,得到两个可以极大提升效率的优化操作:
-
开启VS的优化设置
根据自己需要,选择时间优先,或者空间优先。
选择之后,需要关闭编译时的检查,否则会D8016报错。
把运行时检查选为默认值即可。
-
用release跑
在我跑的代码中,release版本比debug 效率提升大概4倍左右。
VS D8016
D8016 “/Ox”和“/RTC1”命令行选项不兼容
关于该错误,详细了解可看官方文档
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)