【问题标题】:Cuda matrix multiplication gives wrong answerCuda矩阵乘法给出错误答案
【发布时间】:2013-05-19 00:40:03
【问题描述】:

更新!

我当前的代码不检查越界内存访问。当我运行 cuda memcheck 时,它说即使对于只有 2 x 2 的矩阵,内存访问也很糟糕!我正在访问我不应该以某种方式访问​​的内存,这就是问题所在!

要检查内存访问是否越界,请运行 cuda-memcheck ./(在此处插入可执行文件)

下面显示的是我的矩阵乘法代码:

dim3 block(32,32);
dim3 grid( (n+31)/32, (n+31)/32 );
matrixMul<<<grid,block>>>(d_C, d_A, d_B, n, k);

kA 和 kB 是其中包含值的矩阵(为了更容易,它们都是 2)。

m, n, k 对于我的方阵来说都是同一个数

kC 是存储答案的矩阵。

#ifndef _MATRIXMUL_KERNEL_H_
#define _MATRIXMUL_KERNEL_H_

#include <stdio.h>

__global__ void matrixMul(float *kC, float *kA, float *kB, int n, int k)
{

    int tx = blockIdx.x * 32 + threadIdx.x;
    int ty = blockIdx.y * 32 + threadIdx.y;
    float value = 0;

    for (int i=0;i<n;i++)
    {
        float elementA=kA[ty*n+i];
        float elementB=kB[i*k+tx];
        value += elementA*elementB;
    }

    kC[ty*n+tx] = value;
}

#endif // #ifndef _MATRIXMUL_KERNEL_H_

【问题讨论】:

  • 我只是内存不足还是什么?
  • 变量value的定义在哪里?您是否在 for 循环之前将其初始化为零?这段代码看起来无法编译。
  • @Robert Crovella 我的错,我在移动代码时写错了变量名。它应该是“浮动值”而不是“浮动存储”。不过,我的程序中有“浮动值”。如果它一直工作到 10x10,你认为这可能是我的记忆吗?在 10x10 之后,矩阵的某些行或有时其他的值会翻倍......
  • 这个内核没有像if ((ty &lt; n) &amp;&amp; (tx &lt; k)){这样的线程检查。所以你也应该展示你的内核调用,可能还有主机代码的数据复制部分。
  • @Robert Crovella 我更新了代码以显示所有内容。

标签: c++ cuda matrix-multiplication


【解决方案1】:

根据您定义线程网格的方式,您应该像这样在内核代码中添加线程检查:

#ifndef _MATRIXMUL_KERNEL_H_
#define _MATRIXMUL_KERNEL_H_

#include <stdio.h>

__global__ void matrixMul(float *kC, float *kA, float *kB, int n, int k)
{

    int tx = blockIdx.x * 32 + threadIdx.x;
    int ty = blockIdx.y * 32 + threadIdx.y;

    if ((ty < n) && (tx < n)) { // add this line
      float value = 0;

      for (int i=0;i<n;i++)
      {
        float elementA=kA[ty*n+i];
        float elementB=kB[i*k+tx];
        value += elementA*elementB;
      }

      kC[ty*n+tx] = value;
    }  //  add this line
}

#endif // #ifndef _MATRIXMUL_KERNEL_H_

否则有效数组数组之外的线程会破坏您的结果。事情适用于 32x32 的倍数,因为没有无效线程。在这种情况下,您将启动所需数量的线程。但在其他情况下,您正在启动额外的线程。如果允许这些额外的线程计算无效的矩阵位置,则会破坏结果。

【讨论】:

  • 哇,解决了所有问题。我很感激。所以基本上发生的事情是线程是根据我的内核调用初始化并运行的,即使它们超出了 if 语句的范围?
  • 是的,您使用内核调用定义网格的大小。当内核使用该网格启动时,所有这些线程都将启动,并在某个时候开始执行线程代码(内核代码)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-11
  • 1970-01-01
  • 1970-01-01
  • 2020-11-03
  • 2014-11-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多