繁体   English   中英

乘以大方阵的转置要比仅乘大方阵的速度慢…如何解决?

[英]Multiplying a large square matrix by it's transpose being slower than large square matrix just multiplying… How to fix?

显然,转置矩阵然后乘以它比仅将两个矩阵相乘要快。 但是,我的代码现在没有这样做,我也不知道为什么...(正常的乘法只是三重嵌套循环,它给了我大约1.12秒的时间来乘以1000x1000矩阵,而这段代码给了我8时间(慢而不是快)倍...我迷失了,任何帮助将不胜感激!:D

A = malloc (size*size * sizeof (double));
B = malloc (size*size * sizeof (double));
C = malloc (size*size * sizeof (double));



/* initialise array elements */
for (row = 0; row < size; row++){
    for (col = 0; col < size; col++){
      A[size * row + col] = rand();
      B[size * row + col] = rand();
    }
  }

t1 = getTime();

/ *要测量的代码在这里* /

T = malloc (size*size * sizeof(double));

for(i = 0; i < size; ++i) {
  for(j = 0; j <= i ; ++j) {
    T[size * i + j] = B[size * j + i];
  }
}

for (j = 0; j < size; ++j) {
  for (k = 0; k < size; ++k) {
    for (m = 0; m < size; ++m) {
      C[size * j + k] = A[size * j + k] * T[size * m + k];
        }
  }
}


t2 = getTime();

我看到几个问题。

  1. 您只是在设置C[size * j + k]的值,而不是对其进行递增。 即使这是计算错误,也不应影响性能。 另外,您需要在最内层循环开始之前将C[size * j + k]初始化为0.0 否则,您将增加一个未初始化的值。 这是一个严重的问题,可能导致溢出。

  2. 乘法项是错误的。

    请记住,您的乘法项需要表示:

      C[j, k] += A[j, m] * B[m, k], which is C[j, k] += A[j, m] * T[k, m] 

    代替

      C[size * j + k] = A[size * j + k] * T[size * m + k]; 

    你需要

      C[size * j + k] += A[size * j + m] * T[size * k + m]; // ^ ^ ^^^^^^^^^^^^^^^^ // | | Need to get T[k, m], not T[m, k] // | ^^^^^^^^^^^^^^^^ // | Need to get A[j, m], not A[j, k] // ^^^^ Increment, not set. 

我认为,除了错误之外,影响性能的主要原因是您使用T[size * m + k] 当您这样做时,会有很多内存跳跃( m是循环中变化最快的变量)才能获取数据。 当您使用正确的术语T[size * k + m] ,将更少,您应该会看到性能上的提高。

总之,使用:

for (j = 0; j < size; ++j) {
   for (k = 0; k < size; ++k) {
      C[size * j + k] = 0.0;
      for (m = 0; m < size; ++m) {
         C[size * j + k] += A[size * j + m] * T[size * k + m];
      }
   }
}

您可以使用以下方法获得更多性能:

double* a = NULL;
double* c = NULL;
double* t = NULL;

for (j = 0; j < size; ++j) {
   a = A + (size*j);
   c = C + (size*j);
   for (k = 0; k < size; ++k) {
      t = T + size*k;
      c[k] = 0.0;
      for (m = 0; m < size; ++m) {
         c[k] += a[m] * t[m];
      }
   }
}

PS我还没有测试代码。 只是给你一些想法。

在此测试中,转置的运行速度可能比乘法运算的速度慢,因为转置是将数据从内存加载到高速缓存的位置,而矩阵乘法的运行空间不足,至少对于许多现代处理器而言,对于1000x1000而言(24 MB适合在许多Intel Xeon处理器上缓存)。

无论如何,转置和乘法都非常低效。 您的转置会影响TLB,因此您应该使用32左右的阻塞因子(例如,请参见https://github.com/ParRes/Kernels/blob/master/SERIAL/Transpose/transpose.c )。

此外,在x86上,最好连续写入(由于高速缓存行锁定和阻塞存储的工作方式-如果仔细使用非临时存储,则可能会发生变化),而在PowerPC的某些变体上,尤其是Blue Gene变体,您希望连续读取(由于顺序执行,无阻塞存储和直写式缓存)。 参见https://github.com/jeffhammond/HPCInfo/blob/master/tuning/transpose/transpose.c作为示例代码。

最后,我不在乎您说什么(“尽管我特别需要这样做”),您需要对矩阵乘法使用BLAS。 故事结局。 如果您的主管或其他同事告诉您,否则,他们是无能的,除非经过全面的培训,否则不允许他们谈论代码。 如果您不想自己告诉他们,请参考他们的信息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM