Eigen3矩阵乘法性能

时间:2015-06-24 13:57:57

标签: c++ performance matrix visual-studio-2013 eigen

注意:我也在Eigen论坛here

上发布了这个帖子

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

初始化矩阵后

android.app.PendingIntent

我评估了这两个版本

android.content.Intent

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;

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

我很惊讶列按列乘法比直接乘法快4/5倍 (如果我不使用// eigen direct multiplication for (int i = 0; i < NT; i++){ Eigen::Matrix3d T = Eigen::Matrix3d::Random(); dest.noalias() = T * points; } ,直接乘法会更慢,但这很好,因为它正在进行临时复制) 我试图将NUMCOLS从0更改为1000000,并且该关系是线性的。

我正在使用Visual Studio 2013并在发布中进行编译

下图显示了X矩阵的列数,Y表示单个操作的平均时间,蓝色表示col乘以col乘,红色表示矩阵乘法

img

有关为何会发生这种情况的任何建议吗?

1 个答案:

答案 0 :(得分:2)

简短回答

您正在计算col乘法版本中的延迟(因此缺少)评估,而不是直接版本中的惰性(但已评估)评估。

答案很长

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

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),我得到:

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);不输出任何内容(我很确定badbit已设置),但确实会导致Eigens operator<<called,这会强制对矩阵进行求值。< / p>

注意:如果我们使用outPut << dest(1,1),则dest的评估仅足以输出col乘法方法中的单个元素。

然后我们

Direct time: 0.447298
Col time: 0.681456
Eigen speedup: 1.52349

正如预期的结果。请注意,Eigen direct方法采用精确(ish)相同的时间(意味着即使没有添加ostream也进行了评估),而col方法突然花了更长的时间。