跳至主要內容

cuBLAS 備忘錄

· 4 分鐘閱讀

這篇備忘錄記錄了 cuBLAS。

資訊

cuBLAS 是 NVIDIA 提供的一個 GPU 加速的 BLAS(基本線性代數子程序庫)實現。它提供了高性能的標準線性代數運算,如向量-向量運算、矩陣-向量運算和矩陣-矩陣運算。

cuBLAS 庫是基於 CUDA 構建的,允許開發者利用 NVIDIA GPU 的強大並行計算能力來加速線性代數的計算。

cuBLAS 的特性

  • GPU 加速:所有運算都在 GPU 上執行,提供比 CPU 快得多的性能。
  • 標準 BLAS 接口:遵循 BLAS 函數的標準命名約定(level 1, 2, 3)。
  • 多種數據類型支持:支持單精度 (float)、雙精度 (double)、半精度 (half)、複數等數據類型。
  • 易於集成:可以輕鬆地與 CUDA C/C++ 程式碼集成。

cuBLAS 的基本用法

使用 cuBLAS 通常涉及以下步驟:

  1. 初始化 cuBLAS 庫:創建一個 cuBLAS 句柄。
  2. 在 GPU 上分配內存:為輸入和輸出數據分配 GPU 內存。
  3. 將數據從主機複製到設備:將輸入數據從 CPU 內存複製到 GPU 內存。
  4. 執行 cuBLAS 運算:調用相應的 cuBLAS 函數。
  5. 將數據從設備複製回主機:將結果從 GPU 內存複製回 CPU 內存。
  6. 釋放 GPU 內存
  7. 銷毀 cuBLAS 句柄

範例:矩陣乘法 (GEMM)

矩陣乘法 (GEMM: General Matrix-Matrix Multiplication) 是 cuBLAS 最常用的功能之一。

假設我們有兩個矩陣 $A$ 和 $B$,我們想計算它們的乘積 $C = \alpha AB + \beta C$。

#include <iostream>
#include <vector>
#include <cuda_runtime.h>
#include <cublas_v2.h>

// 錯誤檢查宏
#define CUDA_CHECK(call)
do {
cudaError_t err = call;
if (err != cudaSuccess) {
fprintf(stderr, "CUDA error in %s (%s:%d): %s
", __func__, __FILE__, __LINE__, cudaGetErrorString(err));
exit(EXIT_FAILURE);
}
} while (0)

#define CUBLAS_CHECK(call)
do {
cublasStatus_t status = call;
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "cuBLAS error in %s (%s:%d): status %d
", __func__, __FILE__, __LINE__, status);
exit(EXIT_FAILURE);
}
} while (0)

int main() {
int N = 3; // 矩陣維度 (為簡化起見,假設方陣)

// 主機數據
std::vector<float> h_A(N * N);
std::vector<float> h_B(N * N);
std::vector<float> h_C(N * N);

// 初始化 A 和 B
for (int i = 0; i < N * N; ++i) {
h_A[i] = static_cast<float>(i + 1);
h_B[i] = static_cast<float>(N * N - i);
h_C[i] = 0.0f; // 初始化 C 為零
}

// 設備數據指針
float *d_A, *d_B, *d_C;

// 1. 初始化 cuBLAS 句柄
cublasHandle_t handle;
CUBLAS_CHECK(cublasCreate(&handle));

// 2. 在 GPU 上分配內存
CUDA_CHECK(cudaMalloc((void**)&d_A, N * N * sizeof(float)));
CUDA_CHECK(cudaMalloc((void**)&d_B, N * N * sizeof(float)));
CUDA_CHECK(cudaMalloc((void**)&d_C, N * N * sizeof(float)));

// 3. 將數據從主機複製到設備
CUBLAS_CHECK(cublasSetMatrix(N, N, sizeof(float), h_A.data(), N, d_A, N));
CUBLAS_CHECK(cublasSetMatrix(N, N, sizeof(float), h_B.data(), N, d_B, N));
CUBLAS_CHECK(cublasSetMatrix(N, N, sizeof(float), h_C.data(), N, d_C, N)); // 複製初始 C (這裡都是零)

// 設置標量 alpha 和 beta
const float alpha = 1.0f;
const float beta = 0.0f;

// 4. 執行 cuBLAS 運算 (C = A * B)
// 注意:cuBLAS 使用列優先存儲,所以這裡我們調用 cublasSgemm (S 代表 float, ge 表示通用矩陣, mm 表示矩陣乘法)
// 參數順序為:handle, transa, transb, m, n, k, alpha, A, lda, B, ldb, beta, C, ldc
// 對於 C = A * B,如果 A 是 M x K,B 是 K x N,則 C 是 M x N
// 在這裡,M=N, K=N, N=N
// transa, transb 分別表示是否轉置 A 和 B
// lda, ldb, ldc 分別是 A, B, C 的 leading dimension (通常是行數或列數,取決於存儲順序)
CUBLAS_CHECK(cublasSgemm(handle,
CUBLAS_OP_N, // A 不轉置
CUBLAS_OP_N, // B 不轉置
N, // m (C 的行數)
N, // n (C 的列數)
N, // k (A 的列數 / B 的行數)
&alpha, // alpha
d_A, // A 矩陣在設備上的指針
N, // A 的 leading dimension
d_B, // B 矩陣在設備上的指針
N, // B 的 leading dimension
&beta, // beta
d_C, // C 矩陣在設備上的指針
N)); // C 的 leading dimension

// 5. 將數據從設備複製回主機
CUBLAS_CHECK(cublasGetMatrix(N, N, sizeof(float), d_C, N, h_C.data(), N));

// 打印結果 (可選)
std::cout << "Result C matrix:" << std::endl;
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
std::cout << h_C[i * N + j] << " ";
}
std::cout << std::endl;
}

// 6. 釋放 GPU 內存
CUDA_CHECK(cudaFree(d_A));
CUDA_CHECK(cudaFree(d_B));
CUDA_CHECK(cudaFree(d_C));

// 7. 銷毀 cuBLAS 句柄
CUBLAS_CHECK(cublasDestroy(handle));

return 0;
}

編譯和運行

nvcc -lcublas your_program.cu -o your_program
./your_program

總結

cuBLAS 提供了一個高效且易於使用的接口,用於在 NVIDIA GPU 上執行 BLAS 運算。對於需要進行大量線性代數計算的應用程式(如深度學習、科學計算),使用 cuBLAS 可以顯著提高性能。

コメント

読み込み中...

コメントを投稿する