PyopenCL中的复数数组

时间:2015-07-08 15:28:09

标签: python numpy opencl algebra pyopencl

我一直在研究PyopenCl的一个新问题,我必须处理复杂的数字。更准确地说,使用内部有复数的2D numpy数组会非常方便。 就像是: np_array [np_array [C_number,C_number,..],np_array [C_number,C_number,..],...]

然后,对于结果,我需要一个简单的1D numpy数组复数。

我也注意到pyopencl看到一个numpy复数作为float2,我使用float16作为我的数据数据数组,因为我有大约8个数字要处理。

为了解决基本操作,我构建了一个简单的程序。 我已经研究了构建首字母数组并将它们发送到内核但结果与我预期的不同。我想这与线程的ID有关,但我似乎无法弄明白。

我正在使用的代码如下。

import pyopencl as cl
import numpy as np

ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)
MF = cl.mem_flags

M = 3

zero = np.complex64(0.0)

X1_h = np.array([1 + 1j*2, 2 + 1j*3, 3 + 1j*4]).astype(np.complex64)
X2_h = np.array([1 + 1j*2, 2 + 1j*3, 3 + 1j*4]).astype(np.complex64)
X3_h = np.array([1 + 1j*2, 2 + 1j*3, 3 + 1j*4]).astype(np.complex64)
Y1_h = np.array([4 + 1j*5, 5 + 1j*6, 6 + 1j*7]).astype(np.complex64)
Y2_h = np.array([4 + 1j*5, 5 + 1j*6, 6 + 1j*7]).astype(np.complex64)
Y3_h = np.array([4 + 1j*5, 5 + 1j*6, 6 + 1j*7]).astype(np.complex64)
aux_h = np.complex64(1 + 1j*1)
RES_h = np.empty_like(X1_h)

dados_h = []
for i in range(3):
     dados_h.append(np.array([X1_h[i], X2_h[i], X3_h[i], Y1_h[i], Y2_h[i], Y3_h[i]]).astype(np.complex64))
dados_h = np.array(dados_h).astype(np.complex64)

print dados_h

aux_d = cl.Buffer(ctx, MF.READ_WRITE | MF.COPY_HOST_PTR, hostbuf=aux_h)
dados_d = cl.Buffer(ctx, MF.READ_WRITE | MF.COPY_HOST_PTR, hostbuf=dados_h)
RES_d = cl.Buffer(ctx, MF.READ_WRITE | MF.COPY_HOST_PTR, hostbuf = RES_h)

Source = """
__kernel void soma(__global float2 *aux, __global float16 *dados, __global float2 *res){
const int gid_x = get_global_id(0);
const int gid_y = get_global_id(1);
res[gid_x].x = dados[gid_y].s0;
res[gid_x].y = dados[gid_y].s1;
}
"""
prg = cl.Program(ctx, Source).build()

completeEvent = prg.soma(queue, (M,), None, aux_d, dados_d, RES_d)
completeEvent.wait()

cl.enqueue_copy(queue, RES_h, RES_d)
print "GPU"
print RES_h

我得到的输出如下:

[[ 1.+2.j  1.+2.j  1.+2.j  4.+5.j  4.+5.j  4.+5.j]
[ 2.+3.j  2.+3.j  2.+3.j  5.+6.j  5.+6.j  5.+6.j]
[ 3.+4.j  3.+4.j  3.+4.j  6.+7.j  6.+7.j  6.+7.j]]
GPU
[ 1.+2.j  1.+2.j  1.+2.j]

我的预期输出是:

[ 1.+2.j  2.+3.j  3.+4.j]

我无法理解我是如何得到这个结果的。如上所述,我认为这是与线程ID相关的东西,但我无法弄明白。如果我在红色的右边部分使用gid_x而不是gid_y [gid_x] = ......我得到以下内容

[ 1.+2.j  2.+3.j  6.+7.j]

有人能给我一些关于我做错的见解吗?

1 个答案:

答案 0 :(得分:1)

您正在启动一维内核,因此get_global_id(1)将始终返回0。这解释了为什么你的内核只是将dados数组的第一个元素复制到输出的每个元素中。

使用float16代表一行'您的输入仅在每行实际有8个复数时才有效。在您的示例中,您只有6,这就是为什么从dados[gid_x]复制时,您无法获得正确的结果。

要允许代码处理任意行大小,只需将宽度作为参数传递,然后手动计算线性索引:

__kernel void soma(__global float2 *aux,
                   __global float2 *dados,
                   __global float2 *res,
                   int rowWidth){
  const int gid_x = get_global_id(0);
  res[gid_x] = dados[gid_x*rowWidth];
}

然后在启动内核时将行宽作为额外参数传递:

# Pass your actual row-width instead of 6!
completeEvent = prg.soma(queue, (M,), None, aux_d, dados_d, RES_d, np.int32(6))