0

我对 C++ 编码很陌生,目前正在尝试使用 CUDA 进行一些 GPU 计算。

基本上我有一个矩阵A (N by N),以及几个向量bx0。b 和 x0 也有 N 个元素。

这是我要实现的一段代码:

for (unsigned i=1;i<=N;i++){
    T sum = 0;
    for (unsigned j=1;j<=N;j++){
        sum += A[j][i]*x0[j];
    }
    v[i] = b[i] - sum;
}

其中T是一个模板变量(据我所知,可以分配一个双精度)。

是否有可能并行化整个事情,如果可以,我将如何做到这一点?我还可以使用一些关于如何将此类问题的线程分解为块以及如何将 2D 从主机移动到设备并返回的指针......

如果需要任何其他信息,请告诉我。

编辑 1:在研究了 CUBLAS 并没有走多远之后,我决定展平我的矩阵并自己编写代码。我的第一个发现是我的 cuda 内核不喜欢使用双类型变量/数组[有人可以确认吗?]。

将所有内容转换为浮点数后,我编写的 cuda 内核看起来像这样:

__global__ void cudaMatTimesVect(float *p, float  *x0, float *v, float *sum, float *toSum, float *b, int N){

int idx = blockIdx.x * blockDim.x + threadIdx.x; // thread index

if (idx < N*N){
    toSum[idx] = p[idx] * x0[blockIdx.x];
}

__syncthreads();
if( idx-(blockIdx.x * blockDim.x) == 0){
    for(int i=0; i<blockDim.x; i++){
        sum[blockIdx.x] += toSum[idx+i];
    }

v[blockIdx.x] = b[blockIdx.x] - sum[blockIdx.x];
}

我不确定syncthreads()命令是否会在尝试执行 sum 循环之前等待所有线程相乘。

以下是有关仅在 GPU 上初始化的 sum 和 toSum 数组的 CPU 代码片段:

float *d_sum;
float *d_toSum;
cudaError_t  cudaStatus;
...
// allocate toSum memory
cudaStatus = cudaMalloc(&d_toSum, N*N*sizeof(float));
if (cudaStatus != cudaSuccess){
    std::cout << "couldnt allocate device memory for d_toSum!" << std::endl;
    cudaFree(d_toSum);
}
// allocate sum mem on device
cudaStatus = cudaMalloc(&d_sum, N*sizeof(float));
if (cudaStatus != cudaSuccess){
    std::cout << "couldnt allocate device memory for d_sum" << std::endl;
    cudaFree(d_sum);
}

... 
...
// call the kernel
cudaMatTimesVect<<<N,N>>>(d_p, d_x0, d_v, d_sum, d_toSum, d_b, N);
...


cudaFree(d_toSum);
cudaFree(d_sum);

这是进行求和最有效的方法吗?

编辑 2:我现在更改了代码以使用不同的块索引来运行行计算。上面的内核编译运行了,但是v中的数组元素似乎越来越小而不是重新启动...

如果我想使用<vector>定义我的主机数组,我仍然有兴趣了解为什么我不能使用双精度数以及我的代码需要如何更改。

谢谢,

阿门

4

1 回答 1

1

您可以在cublas中解决此问题:

使用cublasSetVectorcublasSetMatrix将数据复制到 GPU

Get 使用相应的函数将结果复制回来。

矩阵向量乘法由gemv处理。向量-向量减法由axpy处理。

cuda示例中提供了一个工作的 cublas 示例。

基于附加评论:没有理由将数据分割成一维块来解决这个问题。我推荐cublas。但如果您想查看其他代码示例,请查看向量加法示例矩阵乘法示例

对于主机上的双下标矩阵,您应该将其展平,以便您可以使用单个 ( *) 指针和索引来引用数据。无论您是使用 cublas 还是编写自己的代码,这都是正确的。

编辑:回复问题中的更新。您发布的乘法代码在我看来不像矩阵向量乘法,除非您将向量的长度复制了 N 次,以使其与矩阵的长度 (NxN) 匹配。那么它似乎是正确的。

求和代码看起来不正确,此外,由于它不依赖idx于任何方式,所有线程都在做完全相同的事情。所以那里没有并行的好处,我们通常不会那样编写 GPU 代码。

您的向量减法代码似乎大致正确,除了您似乎在矩阵的整个长度(NxN)上进行向量减法,而矩阵向量乘法的结果应该只产生一个长度为 N 的向量。

如果此代码可以生成与相同数据集的串行代码匹配的结果,我会感到惊讶。您是否检查过它是否为非平凡数据集产生了正确的结果?(不要使用每个数字都相同的数据集。)

于 2013-08-20T16:41:36.567 回答