用户定义的本征函数使用的内存是预期的两倍

时间:2019-06-27 22:24:25

标签: c++ matrix eigen

我定义了以下功能(MWE)

(请注意,此公式是此公式的改编:How to Build a Distance Matrix without a Loop (Vectorization)?http://nonconditional.com/2014/04/on-the-trick-for-computing-the-squared-euclidian-distances-between-two-sets-of-vectors/

#include <stdlib.h>
#include <chrono>
#include <Eigen/Dense>
#include <iostream>

using MyMatrix = Eigen::MatrixXd;
using MyMatrix1D = Eigen::VectorXd;

//Calculates e^(scale * ||x-y||_2^2), where ||x-y|| is euclidean distatnce
MyMatrix get_kernel_matrix(const Eigen::Ref<const MyMatrix> x, const Eigen::Ref<const MyMatrix> y)
  {
    const double scale = 0.017;
    const MyMatrix1D XX = x.array().square().rowwise().sum().matrix();
    const MyMatrix1D YY = y.array().square().rowwise().sum().matrix();
     return (((((-2*x)*y.transpose()).colwise() + XX).rowwise() + YY.transpose()).array() * scale).exp().matrix();
  }

int main(int argc, char** argv) {
  const int num_x = 2500;
  const int num_y = 2500;

  const MyMatrix X = MyMatrix::Random(num_x, 2);
  const MyMatrix Y = MyMatrix::Random(num_y, 2);

  const auto t_b_gen = std::chrono::high_resolution_clock::now();
  const MyMatrix k_xp_x(std::move(get_kernel_matrix(X, Y)));
  const auto t_a_gen = std::chrono::high_resolution_clock::now();
  long t_gen = std::chrono::duration_cast<std::chrono::nanoseconds>(t_a_gen - t_b_gen).count();
  std::cout << "Time: " << t_gen << std::endl;
}

这可能需要2500 * 2500 * 8bytes = 50MB的内存。但是,运行/usr/bin/time -v kern_double报告:Maximum resident set size (kbytes): 103288

通过Massif运行程序表明50MB块被分配了两次,一次在functin调用中,一次是Eigen :: internal :: cal_dense_assignment。我尝试使用std::move和不使用{{1}}来强制复制省略,但是我无法减少内存占用。

我做错了什么,如何解决此问题,使其仅使用所需的内存而不是两倍的内存?

1 个答案:

答案 0 :(得分:2)

这是因为默认情况下,对矩阵乘积x*y.transpose()进行了评估,以提高效率。您仍然可以通过拆分自己的最后一个表达式来重用此临时属性,如下所示:

MyMatrix tmp = -2*x*y.transpose();
tmp = ((((tmp).colwise() + XX).rowwise() + YY.transpose()).array() * scale).exp();
return tmp;

请注意,此处既不需要.matrix()也不需要std::move