C++使用cuBLAS加速矩陣乘法運(yùn)算的實(shí)現(xiàn)代碼
本博客主要參考cuBLAS 庫(kù) 詞條實(shí)現(xiàn),與原文不同的是,本博客:
- 將cuBLAS庫(kù)的乘法運(yùn)算進(jìn)行了封裝,方便了算法調(diào)用;
- 將原文的結(jié)果轉(zhuǎn)置實(shí)現(xiàn)為了不轉(zhuǎn)置,這樣可以直接使用計(jì)算結(jié)果;
- 測(cè)試并更改了乘法參數(shù),解決了原文中更改矩陣大小時(shí)報(bào)錯(cuò)的問(wèn)題。
總的來(lái)說(shuō),本博客的代碼利用cuBLAS庫(kù)實(shí)現(xiàn)了兩個(gè)矩陣相乘,提高了矩陣乘法的計(jì)算速度。
test.cpp
#include "cuda_runtime.h" #include "cublas_v2.h" #include <time.h> #include <iostream> using namespace std; // cuBLAS實(shí)現(xiàn)矩陣乘法 int **matMult_cuBLAS(int **A, int **B, int rowSizeA, int colSizeA, int colSizeB, cublasHandle_t cuHandle){ // 結(jié)果矩陣 int** C = new int*[rowSizeA]; for(int i = 0; i < rowSizeA; i++){ C[i] = new int[colSizeB]; } for (int i = 0; i < rowSizeA; i++){ for (int j = 0; j < colSizeB; j++){ C[i][j] = 0; } } // 在內(nèi)存中為將要計(jì)算的矩陣開(kāi)辟空間 float *h_A = (float*)malloc (rowSizeA * colSizeA * sizeof(float)); float *h_B = (float*)malloc (colSizeA * colSizeB * sizeof(float)); float *h_C = (float*)malloc (rowSizeA * colSizeB * sizeof(float)); // 初始化計(jì)算矩陣h_A和h_B for (int i = 0; i < rowSizeA; i++) { for (int j = 0; j < colSizeA; j++) { h_A[i * colSizeA + j] = (float)A[i][j]; } } for (int i = 0; i < colSizeA; i++) { for (int j = 0; j < colSizeB; j++) { h_B[i * colSizeB + j] = (float)B[i][j]; } } // 在顯存中為將要計(jì)算矩陣與結(jié)果矩陣開(kāi)辟空間 float *d_A, *d_B, *d_C; cudaMalloc ( (void**)&d_A, // 指向開(kāi)辟的空間的指針 rowSizeA * colSizeA * sizeof(float) // 需要開(kāi)辟空間的字節(jié)數(shù) ); cudaMalloc ( (void**)&d_B, colSizeA * colSizeB * sizeof(float) ); cudaMalloc ( (void**)&d_C, rowSizeA * colSizeB * sizeof(float) ); // 將矩陣數(shù)據(jù)傳遞進(jìn)顯存中已經(jīng)開(kāi)辟好了的空間 cublasSetVector ( rowSizeA * colSizeA, // 要存入顯存的元素個(gè)數(shù) sizeof(float), // 每個(gè)元素大小 h_A, // 主機(jī)端起始地址 1, // 連續(xù)元素之間的存儲(chǔ)間隔 d_A, // GPU 端起始地址 1 // 連續(xù)元素之間的存儲(chǔ)間隔 ); cublasSetVector (colSizeA * colSizeB, sizeof(float), h_B, 1, d_B, 1); // 傳遞進(jìn)矩陣相乘函數(shù)中的參數(shù),具體含義請(qǐng)參考函數(shù)手冊(cè). float a=1; float b=0; // 矩陣相乘.該函數(shù)必然將數(shù)組解析成列優(yōu)先數(shù)組 cublasSgemm ( cuHandle, // blas 庫(kù)對(duì)象 CUBLAS_OP_T, // 矩陣 A 屬性參數(shù) CUBLAS_OP_T, // 矩陣 B 屬性參數(shù) rowSizeA, // A, C 的行數(shù) colSizeB, // B, C 的列數(shù) colSizeA, // A 的列數(shù)和 B 的行數(shù) &a, // 運(yùn)算式的 \alpha 值 d_A, // A 在顯存中的地址 colSizeA, // lda d_B, // B 在顯存中的地址 colSizeB, // ldb &b, // 運(yùn)算式的 \beta 值 d_C, // C 在顯存中的地址(結(jié)果矩陣) rowSizeA // ldc ); // 從 顯存 中取出運(yùn)算結(jié)果至 內(nèi)存中去 cublasGetVector ( rowSizeA * colSizeB, // 要取出元素的個(gè)數(shù) sizeof(float), // 每個(gè)元素大小 d_C, // GPU 端起始地址 1, // 連續(xù)元素之間的存儲(chǔ)間隔 h_C, // 主機(jī)端起始地址 1 // 連續(xù)元素之間的存儲(chǔ)間隔 ); for (int i = 0; i < rowSizeA; i++) { for (int j = 0; j < colSizeB; j++) { C[i][j] = (int)h_C[j * rowSizeA + i]; } } // 清理掉使用過(guò)的內(nèi)存 free (h_A); free (h_B); free (h_C); cudaFree (d_A); cudaFree (d_B); cudaFree (d_C); return C; } // 構(gòu)造一個(gè)隨機(jī)二維數(shù)組(矩陣) int** uniformMat(int rowSize, int colSize, int minValue, int maxValue) { int** mat = new int* [rowSize]; for (int i = 0; i < rowSize; i++) mat[i] = new int[colSize]; // srand(1024); srand((unsigned)time(NULL)); //隨機(jī)數(shù)種子采用系統(tǒng)時(shí)鐘 for (int i = 0; i < rowSize; i++) { for (int j = 0; j < colSize; j++) { mat[i][j] = (int)(rand() % (maxValue - minValue + 1)) + minValue; } } return mat; } int main(void) { // 創(chuàng)建并初始化 CUBLAS 庫(kù)對(duì)象 // 若是CUBLAS對(duì)象在主函數(shù)中初始化,cuBLAS方法在其他函數(shù)中調(diào)用,需要將cuHandle傳入該函數(shù),并在該函數(shù)內(nèi)創(chuàng)建status對(duì)象 cublasHandle_t cuHandle; cublasStatus_t status = cublasCreate(&cuHandle); if (status != CUBLAS_STATUS_SUCCESS) { if (status == CUBLAS_STATUS_NOT_INITIALIZED) { cout << "CUBLAS 對(duì)象實(shí)例化出錯(cuò)" << endl; } getchar (); return EXIT_FAILURE; } // 矩陣大小定義 int rowSizeA = 3; // 矩陣A的行數(shù) int colSizeA = 4; // 矩陣A的列數(shù)和矩陣B的行數(shù) int colSizeB = 2; // 矩陣B的列數(shù) // 構(gòu)造一個(gè)3行4列的矩陣A,矩陣元素在(0,4)內(nèi)隨機(jī)選取 int **A = uniformMat(rowSizeA, colSizeA, 0, 4); // 構(gòu)造一個(gè)4行2列的矩陣B,矩陣元素在(5,9)內(nèi)隨機(jī)選取 int **B = uniformMat(colSizeA, colSizeB, 5, 9); // 輸出矩陣A和B cout << "矩陣 A :" << endl; for (int i = 0; i < rowSizeA; i++) { for (int j = 0; j < colSizeA; j++) { cout << A[i][j] << " "; } cout << endl; } cout << endl; cout << "矩陣 B :" << endl; for (int i = 0; i < colSizeA; i++) { for (int j = 0; j < colSizeB; j++) { cout << B[i][j] << " "; } cout << endl; } cout << endl; // 使用cuBLAS進(jìn)行矩陣乘法運(yùn)算:C = A * B int **C = matMult_cuBLAS(A, B, rowSizeA, colSizeA, colSizeB, cuHandle); // 輸出矩陣C,即運(yùn)算結(jié)果 cout << "矩陣 C :" << endl; for (int i = 0; i < rowSizeA; i++) { for (int j = 0; j < colSizeB; j++) { cout << C[i][j] << " "; } cout << endl; } cout << endl; // 釋放 CUBLAS 庫(kù)對(duì)象 cublasDestroy (cuHandle); return 0; }
在終端輸入:
nvcc -lcublas test.cpp -o t
./t
運(yùn)算結(jié)果:
矩陣 A :
1 3 2 0
2 1 2 1
4 3 2 4矩陣 B :
6 8
7 5
7 6
7 6矩陣 C :
41 35
40 39
87 83
到此這篇關(guān)于C++使用cuBLAS加速矩陣乘法運(yùn)算的文章就介紹到這了,更多相關(guān)C++ cuBLAS矩陣加速運(yùn)算內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VS Code 中搭建 Qt 開(kāi)發(fā)環(huán)境方案分享
這篇文章主要介紹了VS Code 中搭建 Qt 開(kāi)發(fā)環(huán)境方案分享的相關(guān)資料,需要的朋友可以參考下2022-12-12c++調(diào)用python實(shí)現(xiàn)圖片ocr識(shí)別
所謂c++調(diào)用python,實(shí)際上就是在c++中把整個(gè)python當(dāng)作一個(gè)第三方庫(kù)引入,然后使用特定的接口來(lái)調(diào)用python的函數(shù)或者直接執(zhí)行python腳本,本文介紹的是調(diào)用python實(shí)現(xiàn)圖片ocr識(shí)別,感興趣的可以了解下2023-09-09C語(yǔ)言中字符的輸入輸出以及計(jì)算字符個(gè)數(shù)的方法詳解
這篇文章主要介紹了C語(yǔ)言中字符的輸入輸出以及計(jì)算字符個(gè)數(shù)的方法,是C語(yǔ)言入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-11-11C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之棧和隊(duì)列的實(shí)現(xiàn)及應(yīng)用
棧和隊(duì)列是一種數(shù)據(jù)結(jié)構(gòu),只規(guī)定了性質(zhì),并沒(méi)有規(guī)定實(shí)現(xiàn)方式。本文將以順序結(jié)構(gòu)實(shí)現(xiàn)棧,鏈表方式實(shí)現(xiàn)隊(duì)列,感興趣的小伙伴快跟隨小編一起學(xué)習(xí)一下吧2022-08-08基于C語(yǔ)言實(shí)現(xiàn)關(guān)機(jī)小游戲的示例代碼
關(guān)機(jī)會(huì)寫(xiě)吧!猜數(shù)字會(huì)寫(xiě)吧!本文將結(jié)合這兩個(gè)功能,用C語(yǔ)言編寫(xiě)一個(gè)關(guān)機(jī)惡搞小游戲(最好的朋友轉(zhuǎn)瞬即逝),只要猜對(duì)了,1分鐘后執(zhí)行關(guān)機(jī),除非輸入“我是豬”,但是輸完后,1分鐘后還是會(huì)執(zhí)行關(guān)機(jī),該保存保存,感興趣的可以嘗試一下2022-07-07