【发布时间】:2018-12-28 11:20:44
【问题描述】:
我想将 Eigen 矩阵与 OpenMP 归约结合使用。
下面是我如何做的一个小例子(它有效)。对象myclass 具有三个属性(一个特征矩阵,两个与其维度对应的整数)和一个成员函数do_something,它使用我定义的总和的 omp 归约,因为特征矩阵不是标准类型。
#include "Eigen/Core"
class myclass {
public:
Eigen::MatrixXd m_mat;
int m_n; // number of rows in m_mat
int m_p; // number of cols in m_mat
myclass(int n, int p); // constructor
void do_something(); // omp reduction on `m_mat`
}
myclass::myclass(int n, int p) {
m_n = n;
m_p = p;
m_mat = Eigen::MatrixXd::Zero(m_n,m_p); // init m_mat with null values
}
#pragma omp declare reduction (+: Eigen::MatrixXd: omp_out=omp_out+omp_in)\
initializer(omp_priv=MatrixXd::Zero(omp_orig.rows(), omp_orig.cols()))
void myclass::do_something() {
Eigen::MatrixXd tmp = Eigen::MatrixXd::Zero(m_n, m_p); // temporary matrix
#pragma omp parallel for reduction(+:tmp)
for(int i=0; i<m_n;i++) {
for(int l=0; l<m_n; l++) {
for(int j=0; j<m_p; j++) {
tmp(l,j) += 10;
}
}
}
m_mat = tmp;
}
问题: OpenMP 不允许(或至少不是所有实现)对类成员使用归约,而只能对变量使用归约。因此,我对一个临时矩阵进行了缩减,并且我在末尾有这个副本m_mat = tmp,我想避免这种情况(因为m_mat 可能是一个大矩阵,我在我的代码中经常使用这种缩减)。
错误修复:我尝试使用 Eigen Map 以使 tmp 对应于存储在 m_mat 中的数据。因此,我将前面代码中的 omp 归约声明和 do_something 成员函数定义替换为:
#pragma omp declare reduction (+: Eigen::Map<Eigen::MatrixXd>: omp_out=omp_out+omp_in)\
initializer(omp_priv=MatrixXd::Zero(omp_orig.rows(), omp_orig.cols()))
void myclass::do_something() {
Eigen::Map<Eigen::MatrixXd> tmp = Eigen::Map<Eigen::MatrixXd>(m_mat.data(), m_n, m_p);
#pragma omp parallel for reduction(+:tmp)
for(int i=0; i<m_n;i++) {
for(int l=0; l<m_n; l++) {
for(int j=0; j<m_p; j++) {
tmp(l,j) += 10;
}
}
}
}
但是,它不再起作用,并且在编译时出现以下错误:
错误:从'const ConstantReturnType {aka const 特征::CwiseNullaryOp, Eigen::Matrix >}' 到非标量类型 ‘Eigen::Map, 0, Eigen::Stride >’ 请求 初始化器(omp_priv=Eigen::MatrixXd::Zero(omp_orig.rows(), omp_orig.cols()))
我知道从 Eigen::MatrixXd 到 Eigen::Map<Eigen::MatrixXd> 的隐式转换在 omp 减少中不起作用,但我不知道如何使它起作用。
提前致谢
编辑 1:我忘了提到我在 Ubuntu 机器上使用 gcc v5.4(尝试了 16.04 和 18.04)
编辑 2: 我修改了我的示例,因为第一个没有减少。这个例子并不完全是我在我的代码中所做的,它只是一个最小的“愚蠢”例子。
【问题讨论】:
-
我不太熟悉 Eigen 的实现细节,但我认为它们支持移动语义,在这种情况下,这似乎是最简单的解决方案? (事实上,你确定这不会发生吗?)
-
你的意思是当我做
m_mat = tmp时,它会将与m_mat相关的指针更改为指向tmp,而不是从tmp硬拷贝到m_mat? -
您的示例没有实现缩减。每个线程将处理自己的一组
tmp行,无需并发访问。 -
是的,没错,我正在改变它。我并没有在我的代码中完全这样做,我未能将其简化为最小示例。谢谢