CUDA C矩阵乘法

4

针对链接问题,进行了更新。

我目前正在尝试在CUDA中重新实现基本的矩阵乘法,虽然我的代码适用于方阵和行列数为8的倍数的长方形矩阵,但似乎无法处理长宽不是8的倍数的矩阵。

以下是我的核心乘法函数:

 __global__ void matrixMultiply(float * A, float * B, float * C,
               int numARows, int numAColumns,
               int numBRows, int numBColumns,
               int numCRows, int numCColumns) {
    int Row = blockIdx.y * blockDim.y + threadIdx.y;
    int Col = blockIdx.x * blockDim.x + threadIdx.x;
    if (numAColumns != numBRows) return ;
    if ((Row < numARows) && (Col < numBColumns)){
        float Cvalue = 0;
        for (int k = 0 ; k < numAColumns ; ++k )
            Cvalue += A[Row*numAColumns + k] * B[k * numBColumns + Col];
        C[Row*numCColumns + Col] = Cvalue;
    }

}

以下是内存分配(为了易读性,我省略了错误检查):
cudaMalloc((void**) &deviceA, ARows*sizeof(float)*AColumns);
cudaMalloc((void**) &deviceB, BRows*sizeof(float)*BColumns);
cudaMalloc((void**) &deviceC, CRows*sizeof(float)*CColumns);
cudaMemcpy(deviceA, hostA, ARows*sizeof(float)*AColumns, cudaMemcpyHostToDevice);
cudaMemcpy(deviceB, hostB, BRows*sizeof(float)*BColumns, cudaMemcpyHostToDevice);
cudaMemcpy(deviceC, hostC, CRows*sizeof(float)*CColumns, cudaMemcpyHostToDevice);

以下是调用的内容:
dim3 dimGrid((int)ceil(numCRows / 8.0) , (int)ceil(numCColumns / 8.0), 1);
dim3 dimBlock(8 , 8, 1);
multiplyMatrices<<<dimGrid,dimBlock>>>(deviceA, deviceB, deviceC, numARows, AColumns, BRows, BColumns, CRows, CColumns);

最后是将内存移回:

cudaMemcpy(hostC, deviceC, CRows*sizeof(float)*CColumns, cudaMemcpyDeviceToHost);

我已经反复追踪了我的算法,我认为它没有任何问题,因此我个人认为可能是我使用的块/网格大小方案有问题。如果有任何比我更懂CUDA/C(我是Ruby/JavaScript程序员)的人可以看一下,并帮助我解决具体问题,我会非常感激。


这个问题可能会引起兴趣:https://dev59.com/pmzXa4cB1Zd3GeqPQSFD。 - Robert Crovella
1
为什么我们需要所有的行和列变量?numARows,ARows,CRows不都必须是相同的数字吗?BColumns和CColums也是如此。无论如何,由于可被8整除的维度可以正常工作,我猜当维度不能被8整除(在边界上强制额外块)时,一些线程没有正确关闭。因此,我会关注这一行:if ((Row < numARows) && (Col < numBColumns)){如果将其更改为:if ((Row < numCRows) && (Col < numCColumns)){会发生什么?或者,我想看到每个行和列变量的数值。 - Robert Crovella
所有这些输入参数都是由教师提供的模板代码的一部分。 - Barry Brown
2
你没有将矩阵B复制到设备上吗?还是问题中有错别字? - pQB
很好的发现,不幸的是那只是一个打字错误。正在修订问题。 - Abraham P
1个回答

3
问题出在你创建的网格大小上: dim3 dimGrid((int)ceil(numCRows / 8.0) , (int)ceil(numCColumns / 8.0), 1); 由于行是矩阵的Y维度,列是X维度,所以你实际上正在创建转置网格。
为了创建正确的网格,请按以下步骤操作: dim3 dimGrid((int)ceil(numCColumns / 8.0) , (int)ceil(numCRows / 8.0), 1); 更好的方法是采用以下方法:
dim3 dimGrid;

dimGrid.x = (numCColumns + dimBlock.x - 1)/dimBlock.x;

dimGrid.y = (numCRows + dimBlock.y - 1)/dimBlock.y;

我有一个问题,您是故意在初始化网格之后再设置x和y值吗?此外,这种方法比使用ceiling/cast更有效率吗?还是有其他原因采用这种方式? - Abraham P
不需要。这只是为了提高代码的可读性。再次回答:不需要,它只是节省了一个函数调用。 - sgarizvi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接