簡體   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