首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Eigen3矩阵乘法性能

Eigen3矩阵乘法性能
EN

Stack Overflow用户
提问于 2015-06-24 13:57:57
回答 1查看 1.8K关注 0票数 3

注意:我也把这个贴在了这里论坛上

我想用3x3矩阵对3xN矩阵进行预乘,即转换3D点,如p_dest =T* p_source

初始化矩阵之后:

代码语言:javascript
复制
Eigen::Matrix<double, 3, Eigen::Dynamic> points = Eigen::Matrix<double, 3, Eigen::Dynamic>::Random(3, NUMCOLS);
Eigen::Matrix<double, 3, Eigen::Dynamic> dest = Eigen::Matrix<double, 3, Eigen::Dynamic>(3, NUMCOLS);
int NT = 100;

我已经评估了这两个版本

代码语言:javascript
复制
// eigen direct multiplication
for (int i = 0; i < NT; i++){
  Eigen::Matrix3d T = Eigen::Matrix3d::Random();
  dest.noalias() = T * points;
}

代码语言:javascript
复制
// col multiplication
for (int i = 0; i < NT; i++){
  Eigen::Matrix3d T = Eigen::Matrix3d::Random();
  for (int c = 0; c < points.cols(); c++){
    dest.col(c) = T * points.col(c);
  }
}

NT重复仅仅是为了计算平均时间。

我感到惊讶的是,列逐列乘法比直接乘法快约4/5倍(如果不使用.noalias(),直接乘法甚至更慢,但这很好,因为它是临时复制),我尝试将NUMCOLS从0更改为1000000,并且关系是线性的。

我正在使用Visual 2013并在发行版中编译

下一幅图在X上显示矩阵的列数,在Y中显示一次运算的平均时间,以蓝色表示的是由c乘法,以红色表示的是矩阵乘法。

有什么好的建议吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-06-29 13:49:28

简短回答

在col乘法版本中,您正在对懒惰(因此缺少)计算进行计时,而在直接版本中则对懒惰(但已评估)的计算进行计时。

长答案

让我们来看一个完整的MCVE,而不是代码片段。首先,“你是”版本:

代码语言:javascript
复制
void ColMult(Matrix3Xd& dest, Matrix3Xd& points)
{
    Eigen::Matrix3d T = Eigen::Matrix3d::Random();
    for (int c = 0; c < points.cols(); c++){
        dest.col(c) = T * points.col(c);
    }
}

void EigenDirect(Matrix3Xd& dest, Matrix3Xd& points)
{
    Eigen::Matrix3d T = Eigen::Matrix3d::Random();
    dest.noalias() = T * points;
}

int main(int argc, char *argv[])
{
    srand(time(NULL));

    int NUMCOLS = 100000 + rand();

    Matrix3Xd points = Matrix3Xd::Random(3, NUMCOLS);
    Matrix3Xd dest   = Matrix3Xd(3, NUMCOLS);
    Matrix3Xd dest2  = Matrix3Xd(3, NUMCOLS);
    int NT = 200;
    // eigen direct multiplication
    auto beg1 = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < NT; i++)
    {
        EigenDirect(dest, points);
    }
    auto end1 = std::chrono::high_resolution_clock::now();

    std::chrono::duration<double> elapsed_seconds = end1-beg1;

    // col multiplication
    auto beg2 = std::chrono::high_resolution_clock::now();
    for(int i = 0; i < NT; i++)
    {
        ColMult(dest2, points);
    }

    auto end2 = std::chrono::high_resolution_clock::now();

    std::chrono::duration<double> elapsed_seconds2 = end2-beg2;
    std::cout << "Direct time: " << elapsed_seconds.count() << "\n";
    std::cout << "Col time: " << elapsed_seconds2.count() << "\n";

    std::cout << "Eigen speedup: " << elapsed_seconds2.count() / elapsed_seconds.count() << "\n\n";
    return 0;
}

使用此代码(并打开SSE ),我得到:

代码语言:javascript
复制
Direct time: 0.449301
Col time: 0.10107
Eigen speedup: 0.224949

和你抱怨的4到5次减速一样。为什么?!在我们找到答案之前,让我们修改一下代码,以便将dest矩阵发送到ostream。将std::ostream outPut(0);添加到main()的开头,然后结束,计时器添加outPut << dest << "\n\n";outPut << dest2 << "\n\n";std::ostream outPut(0);没有输出任何东西(我很确定坏位已经设置),但是它确实导致了本征operator<<被称为,这就强制对矩阵进行求值。

注:,如果我们使用outPut << dest(1,1),那么dest的计算量将仅够输出col乘法中的单个元素。

然后我们得到

代码语言:javascript
复制
Direct time: 0.447298
Col time: 0.681456
Eigen speedup: 1.52349

结果如预期的那样。请注意,特征直接法采用了精确的(Ish)时间(这意味着评估是在没有添加ostream的情况下进行的),而col方法突然花费的时间要长得多。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31028636

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档