C++使用cuBLAS加速矩阵乘法运算的实现代码

编辑: admin 分类: c#语言 发布时间: 2021-12-12 来源:互联网

本博客主要参考cuBLAS 库 词条实现,与原文不同的是,本博客:

  1. 将cuBLAS库的乘法运算进行了封装,方便了算法调用;
  2. 将原文的结果转置实现为了不转置,这样可以直接使用计算结果;
  3. 测试并更改了乘法参数,解决了原文中更改矩阵大小时报错的问题。

总的来说,本博客的代码利用cuBLAS库实现了两个矩阵相乘,提高了矩阵乘法的计算速度。

test.cpp

#include "cuda_runtime.h"
#include "cublas_v2.h"
#include <time.h>
#include <iostream>

using namespace std;


// cuBLAS实现矩阵乘法
int **matMult_cuBLAS(int **A, int **B, int rowSizeA, int colSizeA, int colSizeB, cublasHandle_t cuHandle){
    // 结果矩阵
    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;
        }
    }

    // 在内存中为将要计算的矩阵开辟空间
    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));

    // 初始化计算矩阵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];
        }
    }

    // 在显存中为将要计算矩阵与结果矩阵开辟空间
    float *d_A, *d_B, *d_C;
    cudaMalloc (
        (void**)&d_A,    // 指向开辟的空间的指针
        rowSizeA * colSizeA * sizeof(float)    // 需要开辟空间的字节数
    );
    cudaMalloc (
        (void**)&d_B,    
        colSizeA * colSizeB * sizeof(float)    
    );
    cudaMalloc (
        (void**)&d_C,
        rowSizeA * colSizeB * sizeof(float)    
    );

    // 将矩阵数据传递进显存中已经开辟好了的空间
    cublasSetVector (
        rowSizeA * colSizeA,    // 要存入显存的元素个数
        sizeof(float),    // 每个元素大小
        h_A,    // 主机端起始地址
        1,    // 连续元素之间的存储间隔
        d_A,    // GPU 端起始地址
        1    // 连续元素之间的存储间隔
    );
    cublasSetVector (colSizeA * colSizeB, sizeof(float), h_B, 1, d_B, 1);

    // 传递进矩阵相乘函数中的参数,具体含义请参考函数手册.
    float a=1; float b=0;
    // 矩阵相乘.该函数必然将数组解析成列优先数组
    cublasSgemm (
        cuHandle,    // blas 库对象 
        CUBLAS_OP_T,    // 矩阵 A 属性参数
        CUBLAS_OP_T,    // 矩阵 B 属性参数
        rowSizeA,    // A, C 的行数 
        colSizeB,    // B, C 的列数
        colSizeA,    // A 的列数和 B 的行数
        &a,    // 运算式的 \alpha 值
        d_A,    // A 在显存中的地址
        colSizeA,    // lda
        d_B,    // B 在显存中的地址
        colSizeB,    // ldb
        &b,    // 运算式的 \beta 值
        d_C,    // C 在显存中的地址(结果矩阵)
        rowSizeA    // ldc
    );
    
    // 从 显存 中取出运算结果至 内存中去
    cublasGetVector (
        rowSizeA * colSizeB,    //  要取出元素的个数
        sizeof(float),    // 每个元素大小
        d_C,    // GPU 端起始地址
        1,    // 连续元素之间的存储间隔
        h_C,    // 主机端起始地址
        1    // 连续元素之间的存储间隔
    );

    for (int i = 0; i < rowSizeA; i++) {
        for (int j = 0; j < colSizeB; j++) {
            C[i][j] = (int)h_C[j * rowSizeA + i];
        }
    }
    
    // 清理掉使用过的内存
    free (h_A); free (h_B); free (h_C); cudaFree (d_A);
    cudaFree (d_B); cudaFree (d_C);

    return C;
}

// 构造一个随机二维数组(矩阵)
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));  //随机数种子采用系统时钟
    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) 
{   
    // 创建并初始化 CUBLAS 库对象
    // 若是CUBLAS对象在主函数中初始化,cuBLAS方法在其他函数中调用,需要将cuHandle传入该函数,并在该函数内创建status对象
    cublasHandle_t cuHandle;
    cublasStatus_t status = cublasCreate(&cuHandle);
    if (status != CUBLAS_STATUS_SUCCESS)
    {
        if (status == CUBLAS_STATUS_NOT_INITIALIZED) {
            cout << "CUBLAS 对象实例化出错" << endl;
        }
        getchar ();
        return EXIT_FAILURE;
    }

    // 矩阵大小定义
    int rowSizeA = 3; // 矩阵A的行数
    int colSizeA = 4; // 矩阵A的列数和矩阵B的行数
    int colSizeB = 2; // 矩阵B的列数

    // 构造一个3行4列的矩阵A,矩阵元素在(0,4)内随机选取
    int **A = uniformMat(rowSizeA, colSizeA, 0, 4);
    // 构造一个4行2列的矩阵B,矩阵元素在(5,9)内随机选取
    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进行矩阵乘法运算:C = A * B
    int **C = matMult_cuBLAS(A, B, rowSizeA, colSizeA, colSizeB, cuHandle);

    // 输出矩阵C,即运算结果
    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 库对象
    cublasDestroy (cuHandle);
    return 0;
}

在终端输入:

nvcc -lcublas test.cpp -o t
./t

运算结果:

矩阵 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

到此这篇关于C++使用cuBLAS加速矩阵乘法运算的文章就介绍到这了,更多相关C++ cuBLAS矩阵加速运算内容请搜索海外IDC网以前的文章或继续浏览下面的相关文章希望大家以后多多支持海外IDC网!

【本文由:日本服务器 欢迎转载】