1. 程式人生 > >矩陣乘法的並行化演算法討論

矩陣乘法的並行化演算法討論

矩陣乘法是線性代數裡面會講到的一種非常基礎、也十分普遍的計算規則。另一方面,矩陣乘法同時也是平行計算領域常常被用來作為範例的一個話題。它的特點是首先計算量可能相當大,適合利用並行實現來提高效率。其次,它所使用的各種資料之間(矩陣中的元素)沒有相互依賴性,可以充分使用並行處理的計算資源。

序列實現

根據線性代數的基本知識,m × l 的矩陣A,乘以一個大小為 l × n 的矩陣B,將得到一個 m × n 的矩陣C=A×B,其中


下圖是用圖示來表示的這種計算規則:


為了方便討論,我們可以不是普遍性地假設有所矩陣的大小都是 n × n 的,下面就是序列實現的矩陣乘法的程式碼:

int A[n][n], B[n][n], C[n][n];
...
for(i=0;i<n;i++){
    for(j=0;j<n;j++){
        C[i][j]=0;
        for(k=0;k<n;k++)
            C[i][j]+=A[i][k]*B[k][j];
    }
}

易見,這個演算法的計算複雜度為O(n^3)。

基本並行實現的討論

正如前面所講的,矩陣相乘過程中,結果矩陣C中的每個元素都是可以獨立計算的,即彼此之間並無依賴性。所以如果採用更多的處理器,將會顯著地提高矩陣相乘的計算效率。

對於大小為n × n 的矩陣,加入我們有n個處理器,那麼結果矩陣中的每一行,都可以用一個處理器來負責計算。此時,總共的平行計算步數為 O(n^2)。你可以理解為在序列實現的程式碼中,最外層的迴圈 for(i=0;i<n;i++) 被分別由n個處理器來並行的執行,而每個處理需要完成的任務僅僅是內部的兩層迴圈。

如果採用n^2個處理器,那麼就相當於結果矩陣中的每個元素都由一個處理器來負責計算。此時,總共的平行計算步數為 O(n)。你可以理解為在序列實現的程式碼中,最外面的兩層迴圈 被分解到n^2個處理器來並行的執行,而每個處理需要完成的任務僅僅是內部的一層迴圈,即for(k=0;k<n;k++)。

更進一步,如果有n^3個處理器,那麼即使最內層的迴圈for(k=0;k<n;k++)也有n個處理器在並行的負責。但是最終的求和運算,我們需要一個類似reduction的操作,因此最終的計算複雜度就是O(log n)。

當然,你一定會想到的是,實際中,通常並不可能有像矩陣元素那麼多的處理器資源。這時我們該怎麼做。對於一個大小為n × n 的大矩陣A,我們其實可以把它切分成s^2個子矩陣Ap,q,每個子矩陣的大小為 m × m,其中 m = n / s,即0 <= p, q < s。對於兩個大矩陣A和B,現在我們有:


用圖示表示則有:


Cannon演算法

著名的Cannnon演算法使用一個由s^2

個處理器組成的二維網孔結構(mesh),而且這個mesh還是周邊帶環繞的(The processors are connected as a torus)。處理器Processor (i,j) (我們用它來表示位於位置(i,j)處的處理器)最開始時存有子矩陣Ai,jBi,j。隨著演算法的進行,這些子矩陣會向左或向上位移。如下圖所示:


這個演算法的根本出發點是在處理器陣列中,要合理分佈兩個待乘的矩陣元素。由乘積公式可知,要在處理單元 P(i,j)中計算乘積元素C(i,j),必須在該單元中準備好矩陣元素A(i,s)和B(s,j)。但是如果我們像下圖那樣分佈矩陣元素,我們在計算C(i,j)時所需的元素顯然是不足夠的,但是可以通過向上迴圈位移B的元素,並向左迴圈位移A的元素,來獲取合適的成對的矩陣元素。


Cannnon演算法的具體流程:


下面是矩陣位移的一個示例,其中s=3;


顯然,演算法的複雜度 t(n)=O(n), p(n) = n^2,w(n) = O(n^3),所以是成本最佳的。

---------------------------------------------

參考文獻與推薦閱讀材料

【1】陳國良,並行演算法的設計與分析(第3版),高等教育出版社,2009

【2】矩陣計算並行演算法(百度文庫地址:http://wenku.baidu.com/view/d64ba9b4b14e852458fb57fc.html)

(本文完)