【问题标题】:Strange behaviour of simple pycuda kernel简单pycuda内核的奇怪行为
【发布时间】:2018-04-25 20:55:35
【问题描述】:

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

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

(一个 4x3 矩阵)。

基本上和做numpy.tile(array, (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
 ...]

我真的不知道是什么导致了这个问题,但也许这只是我缺少的一些简单的东西......

任何帮助将不胜感激,在此先感谢!

【问题讨论】:

  • 我用你的代码测试过的每个例子似乎都能正常工作(例如 d=88,n=567)通过np.allclose(np.tile(vec_cpu, (n, 1)),out_cpu)。您能否编辑一个您已确认不适用于您的问题的确切案例?
  • 我确切地知道了如何重现这个错误:首先我用 d=88, n=32 运行脚本,它工作正常;然后我将 d 更改为 128,同样的 n,它仍然可以正常工作;然后我把 d 改回 88,同样的 n,我得到了第一列的错误!

标签: python numpy cuda pycuda


【解决方案1】:

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

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 &lt; x &lt; d0 &lt; y &lt; n。通过允许 x=d 您有未定义的行为,允许输出数组的下一行中的第一个条目被未知值覆盖。这就解释了为什么有时结果是正确的,而有时不是。

【讨论】:

    猜你喜欢
    • 2021-12-10
    • 2014-01-24
    • 1970-01-01
    • 2014-08-08
    • 2019-04-01
    • 1970-01-01
    • 2021-03-16
    • 1970-01-01
    相关资源
    最近更新 更多