矩阵乘法会在CUDA上产生错误的结果

时间:2014-10-05 13:30:59

标签: c++ cuda

我用CUDA写了一小段代码来乘以2个方阵。 Hovewer,事实证明大多数细胞计算错误。根据我用过的教程,一切都应该没问题。

__global__ void gpuMM(int *C, int *A, int *B, int N)
{
    int row = blockIdx.x*blockDim.x + threadIdx.x;
    int col = blockIdx.y*blockDim.y + threadIdx.y;
    int sum = 0;
    for (int n = 0; n < N; ++n)
        sum += A[row*N+n]*B[n*N+col];

    C[row*N+col] = sum;
}

#define ROW_SIZE 5
#define MATRIX_LENGTH ROW_SIZE*ROW_SIZE
#define BLOCK_SIZE 16

void MultiplyMatrixCUDA(int * pResult, int* pFactorA, int*pFactorB)
{
    int size = MATRIX_LENGTH*sizeof(int);
    int *dA,*dB,*dC;
    cudaMalloc(&dA,size);
    cudaMalloc(&dB,size);
    cudaMalloc(&dC,size);
    int K = 100;
    dim3 threadBlock(BLOCK_SIZE,BLOCK_SIZE);
    dim3 grid(K,K);

    printf("A:\n");
    DrawMatrix(pFactorA);
    printf("\n");

    printf("B:\n");
    DrawMatrix(pFactorB);
    printf("\n");

    // Copy matrices from the host to device
    cudaMemcpy(dA,pFactorA,size,cudaMemcpyHostToDevice);
    cudaMemcpy(dB,pFactorB,size,cudaMemcpyHostToDevice);

    //Execute the matrix multiplication kernel
    gpuMM<<<grid,threadBlock>>>(dC,dA,dB,ROW_SIZE);


    // Allocate memory to store the GPU answer on the host
    int *C;
    C = new int[MATRIX_LENGTH];

    // Now copy the GPU result back to CPU
    cudaMemcpy(C,dC,size,cudaMemcpyDeviceToHost);

    cudaFree(dA);
    cudaFree(dB);
    cudaFree(dC);

    printf("\nC from CUDA:\n");
    DrawMatrix(C);
    printf("\nC:\n");
    DrawMatrix(MultiplyWithCPU(pResult,pFactorA, pFactorB));  // the code of multiplying function is irrevelant, I'm sure it works fine (double-checked)

}

结果显示矩阵乘以标准CPU方法是正确的,但CUDA错误: enter image description here enter image description here

第一行总是正确的,但所有其他部分都是完全随机的。有时他们是消极的,有时不是。有时它们接近真实值,有时它们完全不同。

我的错误是什么?我没看到失败的地方。算法看起来很好,变量似乎正确传递,但有些东西不起作用。

---编辑

所有变量(pResult和两个pFactors)都在代码的其他部分初始化(后来被删除)。

1 个答案:

答案 0 :(得分:3)

由于每个块的线程数不等于输出矩阵中的元素数(您在16x16块上映射5x5矩阵),因此某些线程正在访问/写入无效的内存位置。

解决方案包括双边界检查以解决问题。这将导致一些线程空闲。内核应如下所示:

__global__ void gpuMM(int *C, int *A, int *B, int N)
{
    int row = blockIdx.x*blockDim.x + threadIdx.x;
    int col = blockIdx.y*blockDim.y + threadIdx.y;

    if( (row < N) && (col < N))
    {
        int sum = 0;
        for (int n = 0; n < N; ++n){
            sum += A[row*N+n]*B[n*N+col];       
        }
        C[row*N+col] = sum;
    }
}

另一个解决方案 - 更有效,取决于您的设备,确实是 - 每个块启动更少的线程(在这种情况下为25)。