简单pycuda内核的奇怪行为

时间:2017-11-13 08:26:54

标签: python numpy cuda pycuda

我对cuda和pycuda很新。 我需要一个内核,通过简单的"重复"来创建一个矩阵(维数为n x d)的数组(1 x d)。相同的数组n次: 例如,假设我们有n = 4和d = 3,那么如果数组是[1 2 3] 我的内核的结果应该是:

[1 2 3
 1 2 3
 1 2 3
 1 2 3]

(矩阵4x3)。

基本上,它与做numpy.tile(数组,(n,1))

相同

我已经编写了以下代码:

kernel_code_template = """
__global__ void TileKernel(float *in, float *out)
{
    // Each thread computes one element of out
    int y = blockIdx.y * blockDim.y + threadIdx.y;
    int x = blockIdx.x * blockDim.x + threadIdx.x;

    if (y > %(n)s || x > %(d)s) return;

    out[y * %(d)s + x] = in[x];
}
"""

d = 64
n = 512

blockSizex = 16
blockSizey = 16
gridSizex = (d + blockSizex - 1) / blockSizex 
gridSizey = (n + blockSizey - 1) / blockSizey 

# get the kernel code from the template 
kernel_code = kernel_code_template % {
    'd': d,
    'n': n
    }
mod = SourceModule(kernel_code)
TileKernel = mod.get_function("TileKernel")

vec_cpu = np.arange(d).astype(np.float32) # just as an example
vec_gpu = gpuarray.to_gpu(vec_cpu)
out_gpu = gpuarray.empty((n, d), np.float32)

TileKernel.prepare("PP")
TileKernel.prepared_call((gridSizex, gridSizey), (blockSizex, blockSizey, 1), vec_gpu.gpudata,  out_gpu.gpudata)

out_cpu = out_gpu.get()

现在,如果我使用d等于2> = 16的幂运行此代码,我得到正确的结果(就像numpy.tile(vec_cpu,(n,1))); 但如果我将d等于其他任何东西(让我们说例如88)我得到输出矩阵的每个元素都有 正确的值,除了第一列:一些条目是正确的,但其他条目有另一个值,显然是随机的,对于每个错误的元素都是相同的,但每次运行都不同, 并且每次运行时,具有错误值的第一列的条目也不同。 例如:

[0  1  2
 0  1  2
 6  1  2
 0  1  2
 6  1  2
 ...]

我真的无法弄清楚是什么导致了这个问题,但也许它只是一些我想念的简单......

任何帮助将不胜感激,提前谢谢!

1 个答案:

答案 0 :(得分:0)

内核代码中的边界检查不正确。此

if (y > n ||  x > d) return;
out[y * d + x] = in[x];

应该是:

if (y >= n ||  x >= d) return;
out[y * d + x] = in[x];

或更好:

if ((y < n) && (x < d))
    out[y * d + x] = in[x];

数组中的所有数组有效索引都位于0 < x < d0 < y < n。通过允许x=d您具有未定义的行为,允许输出数组的下一行中的第一个条目被未知值覆盖。这解释了为什么有时结果是正确的,有时则不是。