【问题标题】:Armadillo: Matrix multiplications taking up huge amounts of memory犰狳:矩阵乘法占用大量内存
【发布时间】:2023-03-05 16:44:01
【问题描述】:

我正在尝试使用犰狳进行线性回归,如下面的函数:

void compute_weights()
{
    printf("transpose\n");
    const mat &xt(X.t());
    printf("inverse\n");
    mat xd;
    printf("mul\n");
    xd = (xt * X);
    printf("inv\n");
    xd = xd.i();
    printf("mul2\n");
    xd = xd * xt;
    printf("mul3\n");
    W = xd * Y;
}

我已将其拆分,以便了解程序变得如此庞大时发生了什么。矩阵 X 有 64 列和超过 2300 万行。转置还不错,但是第一次乘法会导致内存占用完全爆炸。现在,据我了解,如果乘以 X.t() * X,矩阵乘积的每个元素将是 X 的列和 X.t() 的行的点积,结果应该是 64x64 矩阵。

当然,这应该需要很长时间,但是为什么内存会突然爆炸到近 30 GB 呢?

然后它似乎挂在那个内存上,然后当它到达第二个乘法时,它太多了,操作系统因为它变得如此巨大而杀死它。

有没有一种方法可以在没有太多内存使用的情况下计算产品?那段记忆能恢复吗?有没有更好的方法来表示这些计算?

【问题讨论】:

  • 您的 X 矩阵已经占用了 11 Gb。矩阵xt 占用另外 11 Gb。表达式(xt * X) 可以在内部为xt 的每一行使用一个缓存,它使用大约200 Mb。这已经超过 22 Gb,我们还没有开始计算其他对象(如矩阵 Y)或其他地方的开销(操作系统、其他正在运行的程序等)
  • 你想在内存中处理巨大的矩阵,所以它需要大量的内存。如果你把它分成几块,那将需要很多时间。在几乎没有额外内存的情况下一次性完成所有操作的唯一方法是使用魔杖。

标签: c++ matrix out-of-memory armadillo


【解决方案1】:

除非您使用大型工作站,否则您不可能一次完成整个乘法运算。就像 hbrerkere 所说,您的初始消耗量约为 22 GB。因此,您要么为此做好准备,要么另谋出路。

如果您没有这样的工作站,另一种方法是自己进行乘法运算,并将其并行化。以下是你的做法:

  1. 不要将整个矩阵加载到内存中,而是加载其中的一部分。
  2. 加载大约一百万行 X,并将其存储在某处。
  3. 加载一百万列 Y
  4. 使用std::transform 和二元运算符std::multiplies 将您加载的部分相乘(这将利用您的处理器的矢量化,并使其速度更快),并填写您计算的部分结果。
  5. 加载矩阵的下一部分,然后重复

这不会那么有效,但它会起作用。另一种选择是在将矩阵分解为更小的矩阵后考虑使用犰狳,其乘法将产生子结果。

这两种方法都比完全乘法慢得多,原因有两个:

  1. 从内存中加载和删除数据的开销
  2. 矩阵乘法已经是一个 O(N^3) 的问题...现在拆分您的乘法是 O(N^2),所以它会变成 O(N^6)...

祝你好运!

【讨论】:

    【解决方案2】:

    您可以使用 QR 分解使用更少的内存来计算权重(您可能需要查找“最小二乘 QR”);

    简单地说: 使用 houseer 变换(隐式)找到正交 Q 使得

    Q'*X = R where R is upper triangular
    

    同时变换Y

    Q'*Y = y
    

    解决

    R*y = W for W using only the top 64 rows of R and y
    

    如果你愿意覆盖 Z 和 Y,那么这不需要额外的内存;否则您将需要 X 的副本和 Y 的副本。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-01
      • 1970-01-01
      相关资源
      最近更新 更多