我目前正在尝试在我的GPU上使用CUBLAS实现矩阵乘法。
***对于方阵和特定大小的输入,它工作得很好,但对于其他人,最后一行不会返回(并且包含0,因为它是我实现的方式)。
我假设这是cublasSgemm
的分配或语法的问题,但我找不到它在哪里。
注意:如果您不熟悉CUBLAS:它是column-majored,这就是为什么看起来操作是以另一种方式执行的原因。
任何帮助将不胜感激。
乘法源代码
- 请注意,
gpuErrchk
和cublasErrchk
在这里当然无关。
#include <cuda.h>
#include <cuda_runtime.h>
#include <cublas_v2.h>
#include <vector>
std::vector<float> CUDA_mult_MAT(const std::vector<float> &data_1 , const uint64_t data_1_rows, const uint64_t data_1_columns,
const std::vector<float> &data_2 , const uint64_t data_2_rows, const uint64_t data_2_columns){
cublasHandle_t handle;
cublasErrchk(cublasCreate(&handle));
std::vector<float> result(data_1_rows * data_2_columns); //Vector holding the result of the multiplication
/*----------------------------------------------------------------------------------------------*/
float* GPU_data_1 = NULL;
gpuErrchk(cudaMalloc((void**)&GPU_data_1 , data_1.size()*sizeof(float))); //Allocate memory on the GPU
gpuErrchk(cudaMemcpy(GPU_data_1, data_1.data(), data_1.size()*sizeof(float), cudaMemcpyHostToDevice)); //Copy data from data_1 to GPU_data_1
float* GPU_data_2 = NULL;
gpuErrchk(cudaMalloc((void**)&GPU_data_2 ,data_2.size()*sizeof(float))); //Allocate memory on the GPU
gpuErrchk(cudaMemcpy(GPU_data_2, data_2.data(), data_2.size()*sizeof(float), cudaMemcpyHostToDevice));//Copy data from data_2 to GPU_data_2
float* GPU_result = NULL;
gpuErrchk(cudaMalloc((void**)&GPU_result , result.size()*sizeof(float))); //Allocate memory on the GPU
/*----------------------------------------------------------------------------------------------*/
const float alpha = 1.f;
const float beta = 0.f;
cublasErrchk(
cublasSgemm(handle , CUBLAS_OP_N , CUBLAS_OP_N,
data_2_columns , data_2_rows ,data_1_columns,
&alpha , GPU_data_2 , data_2_columns,
GPU_data_1 , data_1_columns,
&beta , GPU_result , data_1_rows)
); //Perform multiplication
gpuErrchk(cudaMemcpy(result.data() , GPU_result , result.size() * sizeof(float) , cudaMemcpyDeviceToHost)); //Copy back to the vector 'result'
gpuErrchk(cudaFree(GPU_data_1)); //Free GPU memory
gpuErrchk(cudaFree(GPU_data_2)); //Free GPU memory
gpuErrchk(cudaFree(GPU_result)); //Free GPU memory
cublasErrchk(cublasDestroy_v2(handle));
return result;
}
测试输入
#include <iostream>
#include <vector>
int main(){
const auto r1 = CUDA_mult_MAT({1 , 2 , 3 , 4 , 5 , 6} , 2 , 3 ,
{7 , 8 , 9 , 10 , 11 , 12} , 3 , 2);
/*
Product:
7 8
1 2 3 x 9 10
4 5 6 11 12
*/
for(const auto& value: r1){std::cout << value << " " ;}
std::cout << std::endl;
const auto r2 = CUDA_mult_MAT({7 , 8 , 9 , 10 , 11 , 12} , 3 , 2 ,
{1 , 2 , 3 , 4 , 5 , 6} , 2 , 3);
/*
Product:
7 8
9 10 x 1 2 3
11 12 4 5 6
*/
for(const auto& value: r2){std::cout << value << " " ;}
std::cout << std::endl;
return 0;
}
输出
程序打印:
58 64 139 154
39 54 69 49 68 87 0 0 0
^~~~~~~
预期值:
58 64 139 154
39 54 69 49 68 87 59 82 105
^~~~~~~
1条答案
按热度按时间1zmg4dgp1#
我们可以通过不同的方式观察您的CUBLAS使用问题。
首先,研究CUBLAS Sgemm文档,我们看到3个参数
m
,n
,k
出现,按此顺序紧接在转置说明符之后:我们还观察到矩阵维数由下式给出:
A、B和C是以列为主格式存储的矩阵,维度为op(A)m × k、op(B)k × n和Cm × n,
因此,第一输入矩阵的维度为
m x k
,第二输入矩阵的维度为k x n
,并且输出矩阵的维度为m x n
让我们先关注一下输出矩阵。考虑到它的尺寸是使用
m
和n
参数指定的,它不可能是正确的(假设在非正方形的情况下)只传递**data_2
尺寸:其次,从错误检查的Angular 来看,通过使用
cuda-memcheck
运行代码,可以快速估计CUBLAS调用是否有问题。报告的第一个错误如下:当然,一个可能的解决方案是转置输入矩阵,因此它们是以列为主的顺序,CUBLAS提供了
Sgemm
选项来完成这一点(见上文)。然而,在我看来,你试图做的是C风格的行优先乘法,而不转置输入数组。有一篇文章here给出了如何做到这一点的描述。当我将启发式应用到
cublasSgemm()
调用时,我得到了这个:当我编译并运行你的代码时,我会得到这样的结果: