繁体   English   中英

PyopenCL中的复数数组

[英]Array of complex numbers in PyopenCL

我一直在研究PyopenCl的一个新问题,其中我必须处理复数。 更准确地说,使用内部带有复数的2D numpy数组真的很方便。 类似的东西:np_array [np_array [C_number,C_number,..],np_array [C_number,C_number,..],...]

然后对于结果,我将需要一个简单的一维复数的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有关,但我不知道。 如果我在red [gid_x] =的右侧使用gid_x而不是gid_y ... ...

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

请问有人可以告诉我我做错了什么吗?

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

仅当实际上每行有8个复数时,才使用float16表示输入的一个“行”。 在您的示例中,您只有6个,这就是为什么从dados[gid_x]复制时没有得到正确结果的dados[gid_x]

为了使您的代码能够处理任意的行大小,只需将width作为参数传递,然后手动计算线性索引:

__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))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM