cuda 矩陣乘法函式之cublasSgemm

2021-07-27 08:43:13 字數 2823 閱讀 9657

,可以考慮使用, 例如cublassgeam()(矩陣加法), 進行一次1.0 * at + 0.0 * b的引數設定, 利用內建的轉置功能(注意這裡的1和0), 來進行將a轉換成at. 在使用cuda的cublas庫中矩陣乘法函式cublassgemm時,注意到cuda其中的二維矩陣的儲存是「按列儲存」,一天都處於蒙蔽狀態,查了很多資料,按所得結果情況,總結出如下幾條。

由博文:收到啟發:

比如,我們想求c=a*b這個矩陣運算,其中a=,,};b=,};c=,,},而對於a、b、c進行一維陣列表示有a=,b=,c=;這個在c/c++是和前面表示一樣,但是在cublassgemm中就完全不對了,那麼這個一維的a其實表示的是,};可以看到兩個矩陣其實剛好是轉置關係。那麼我們要求c=a*b,按照一維資料輸入的話結果a表示的是at,b表示的是bt,所以我們要輸入的是at和bt,這樣在公式中得到的才是a*b.假設這是得到矩陣c=a*b,但是c也是按列儲存的,我們要的是ct,而ct=bt*at,而這裡的bt其實就是原矩陣b,at其實就是原矩陣a。可見,我們通過交換ab的順序就可以得到按行儲存的c。

這裡還有一點,就是cublassgemm的引數,把自己繞的有點暈。這裡我們輸入的是b*a即(2*1)*(3*2),但是真正在函式中執行的是bt*at=ct(1*2)*(2*3=(1*3)).因此主要不要把引數搞錯了。。

#include //cuda自帶庫函式  

#include

#include

int main(void)

; float h_b[2]=;

float h_c[3];

float *d_a,*d_b,*d_c;

checkcudaerrors(cudamalloc((void**)&d_a,6*sizeof(float)));

checkcudaerrors(cudamalloc((void**)&d_b,2*sizeof(float)));

checkcudaerrors(cudamalloc((void**)&d_c,3*sizeof(float)));

checkcudaerrors(cudamemcpy(d_a,&h_a,6*sizeof(float),cudamemcpyhosttodevice));

checkcudaerrors(cudamemcpy(d_b,&h_b,2*sizeof(float),cudamemcpyhosttodevice));

checkcudaerrors(cudamemset(d_c,0,3*sizeof(float)));

cublashandle_t handle;

cublascreate(&handle);

cublassgemm(handle,cublas_op_n,cublas_op_n,1,3,2,&alpha,d_b,1,d_a,2,&beta,d_c,1);

checkcudaerrors(cudamemcpy(h_c,d_c,3*sizeof(float),cudamemcpydevicetohost));

for(int i=0;i<3;i++)

printf("\n");

return

0;

}

總結:若想獲得按行儲存的結果矩陣c=a*b(可複製到host),可以使用**:

cublassgemm(handle,cublas_op_n,cublas_op_n,m,n,k,b,ldb,a,lda,c,ldc);
說明

輸入的引數為cublas_op_n , cublas_op_n

相比原引數,a和b的位置調換(c=a*b —>ct=(bt*at) (其中ct按列儲存,實際上就是按行儲存的c!))

其中引數m為col of b ,n 為row of a , k為a和b相同的(row of b or col of a) ,引數ldb , lda , ldc 分別為col of b,a,c ;

經過驗證,結果正確。

有些矩陣為中間結果,為了避免重複使用上述方法,可以使用下面的方法,其中,gpu視訊記憶體中的為按列儲存,host記憶體中的為按行儲存。

由於cublas為了更大的適應fortan語言,二維資料的儲存採用以列優先的方式,這與c/c++中,行優先的儲存方式不同。由於本人的研究是資料的**是c**得到的,為了加速矩陣的運算效率,利用cublas來完成。本文件提出了一種有效的解決方案。

為了更好的說明,以函式cublassgemm的實現c= a*b為例。介面cublassgemm 實現的功能為c = alpha*a*b + beta*c,為了完成c= a*b 的功能,令alpha= 1.0f,beta = 0.0f
利用cublassgemm的引數 transa(transb) 和 lda(ldb)的設定來共同解決儲存方式改變的問題。

得到的結果c都是按列儲存的(拷貝出host記憶體之前轉置一下,可以考慮使用, 例如cublassgeam()(矩陣加法), 進行一次1.0 * at + 0.0 * b的引數設定, 利用內建的轉置功能(注意這裡的1和0), 來進行將a轉換成at.)。

經過驗證,結果正確。

總結

如果前邊的引數是』t』,那麼leading dimesion 就是矩陣的列數,因為此時的矩陣是按照c語言以行優先的方式來儲存的;反之如果前邊的引數是』n』,那麼leading dimesion 就是矩陣的行數,此時的矩陣保持cublas的列優先儲存方式。

CUDA之矩陣乘法 複數

做好矩陣乘法和轉置之後本來開心得不行的!準備上手做個最基本的波束形成了!突然發現希爾伯特變換完以後需要進行各種複數的運算 所以臨時補寫了乙個複數乘法 學著學著好像有點感覺了 還是蠻有意思的。當然前提是能除錯成功。用一句傅小姐的名言鼓勵一下 只要心甘情願任何事情都會變得簡單!device float ...

cuda矩陣相乘 CUDA的矩陣乘法

2 那麼下面就是不使用shared memory的並行化演算法的思路。簡單地來說,就是將上述可並行化的部分傳遞給gpu,使用cuda來計算。如下 void matrixmulondevice float m,float n,float p,intwidth int size width width ...

CUDA練習 矩陣乘法

矩陣乘法公式 ab ij k 1 paik bkj ai1b 1j a i2b2 j ai pbpj ab sum a b a b a b a b ab ij k 1p aik bkj ai1 b1j ai 2 b2 j a ip b pj 時間複雜度 c m n am k b k nc a b c...