矩陣乘法的平行計算
阿新 • • 發佈:2019-02-15
設兩個矩陣A和B,大小分別為M * N 和 N * P, 如果C = A * B, 則C的大小為M * P。
矩陣演算法的演算法表示,虛擬碼如下:
- for (i = 0; i < M; ++i){
- for (j = 0; j < P; ++j){
- C[i][j] = 0;
- for (k = 0; k < N; ++k){
- C[i][j] += A[i][k] * B[k][j];
- }
- }
- }
從上面的演算法中可以看出該演算法的時間複雜度為O(M*N*P),當M,N,P都非常大時該計算將非常耗時。那麼如何將上面的序列演算法轉換成並行演算法呢?
從上面的三層迴圈中可以看出最外層的迴圈是獨立的,即對C[i][*]的計算不依賴於任何C[ii][*]的計算,因此我們可以非常容易將最外層的迴圈轉換成並行。
- #prama omp parallel for num_threads(CORE_NUM)
- for (i = 0; i < M; ++i){
- for (j = 0; j < P; ++j){
- C[i][j] = 0;
- for (k = 0; k < N; ++k){
- C[i][j] += A[i][k] * B[k][j];
-
}
- }
- }
但是這裡有一個侷限,如果假設cpu的核數CORE_NUM > M,同樣無法充分利用所有的計算資源。
進一步分析, 由於C矩陣的大小為M * P,那麼我們能不能將C的計算下平均分配到CORE_NUM個核心上呢,即每個核分配ceil(M*P/CORE_NUM)個計算任何,即將上面的第一和第二層並行化。
首先將C轉換成一維的陣列T[M*P] , 則C[i][j] = T[i * M + j], 反過來T[z] = C[z/M] [ z %P]。
故進一步的並行演算法為:
- #prama omp parallel for num_threads(NUM)
-
for
- i = z / P;
- j = z % P;
- C[i][j] = 0;
- for (k = 0; k < N; ++k){
- C[i][j] += A[i][k] * B[k][j];
- }
- }
效能優化。
看最裡面一層的計算
- for (k = 0; k < N; ++k){
- C[i][j] += A[i][k] * B[k][j];
- for (k = 0; k < N; ++k){
- C[i][j] += A[i][k] * B[j][k];
另外一點需要注意的就是C[i][j] += A[i][k] * B[j][k];計算時的偽共享問題。