Python 在pyopencl中添加复杂的三维阵列

Python 在pyopencl中添加复杂的三维阵列,python,complex-numbers,pyopencl,Python,Complex Numbers,Pyopencl,我试图在python库pyopencl的帮助下添加2个三维复杂数组。在gpu上获得的结果与使用cpu获得的参考结果不同。为什么GPU代码不提供正确的复数加法?我期望相应的变量res和ref彼此相等。我使用的代码是: import pyopencl as cl import numpy as np from numpy.fft import fftn, ifftn from numpy.random import random, normal import os os.environ['PYO

我试图在python库pyopencl的帮助下添加2个三维复杂数组。在gpu上获得的结果与使用cpu获得的参考结果不同。为什么GPU代码不提供正确的复数加法?我期望相应的变量res和ref彼此相等。我使用的代码是:

import pyopencl as cl
import numpy as np
from numpy.fft import fftn, ifftn
from numpy.random import random, normal
import os


os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1'

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

Lx = 100
Ly = 100
Lz = 1
L = Lx * Ly * Lz


const = np.zeros(4).astype(np.float32)
const[0] = Lx
const[1] = Ly
const[2] = Lz
const[3] = L

const_buf = cl.Buffer(ctx, cl.mem_flags.READ_ONLY | cl.mem_flags.COPY_HOST_PTR,    hostbuf=const)


arr1 = np.random.rand(Lz, Ly, Lx).astype(np.float32)
arr2 = np.random.rand(Lz, Ly, Lx).astype(np.float32)

F1 = fftn(arr1)
F2 = fftn(arr2)

out = np.zeros((Lz,Ly,Lx)).astype(np.complex64)
out_buf = cl.Buffer(ctx, cl.mem_flags.WRITE_ONLY, out.nbytes)

do_it_code = """
#include <pyopencl-complex.h>
__kernel void doit(__global const float *constants,
__global const cfloat_t *IN1,__global const cfloat_t *IN2,
__global cfloat_t *out)

{   int z = get_global_id(0);
    int y = get_global_id(1);
    int x = get_global_id(2);
    const int len = constants[3];
  const int lx = constants[0];
const int ly = constants[1];
const int lz = constants[2];
const int pl = lx * ly;
int i = x + y * lx + z * pl;

if (x <= lx-1 && y <= ly-1 && z <= lz-1) {
out[i] = cfloat_add(IN1[i],IN2[i]);

};
};
"""
bld_do_it = cl.Program(ctx, do_it_code).build()

def do_it(a,b):
    a_buf = cl.Buffer(ctx, cl.mem_flags.READ_ONLY | cl.mem_flags.COPY_HOST_PTR,     hostbuf=a.astype(np.complex64))
    b_buf = cl.Buffer(ctx, cl.mem_flags.READ_ONLY | cl.mem_flags.COPY_HOST_PTR, hostbuf=b.astype(np.complex64))
    launch = bld_do_it.doit(queue, a.shape, None, const_buf, a_buf, b_buf, out_buf)
    launch.wait()
    cl.enqueue_copy(queue, out, out_buf)

    return out

ref=F1+F2
print(ref)
print("_________")
res=do_it(F1,F2)
print(res)
将pyopencl导入为cl
将numpy作为np导入
从numpy.fft导入fftn,ifftn
从numpy.random导入随机、正常
导入操作系统
os.environ['PYOPENCL_编译器_输出']='1'
ctx=cl.创建一些上下文()
queue=cl.CommandQueue(ctx)
Lx=100
Ly=100
Lz=1
L=Lx*Ly*Lz
常量=np.zeros(4).aType(np.float32)
常数[0]=Lx
常数[1]=Ly
常数[2]=Lz
常数[3]=L
const_buf=cl.Buffer(ctx,cl.mem_flags.READ_ONLY | cl.mem_flags.COPY_HOST_PTR,hostbuf=const)
arr1=np.random.rand(Lz,Ly,Lx).astype(np.float32)
arr2=np.random.rand(Lz,Ly,Lx).astype(np.float32)
F1=fftn(arr1)
F2=fftn(arr2)
out=np.zeros((Lz,Ly,Lx)).astype(np.complex64)
out\u buf=cl.Buffer(仅ctx、cl.mem\u flags.WRITE\u、out.nbytes)
do_it_code=”“”
#包括
__内核void doit(uu全局常量float*常量,
__全局常数cfloat*IN1,全局常数cfloat*IN2,
__全局cfloat_t*out)
{int z=get_global_id(0);
int y=获取全局id(1);
int x=获取全局id(2);
常数int len=常数[3];
常数int lx=常数[0];
常数int ly=常数[1];
常数int lz=常数[2];
常数int pl=lx*ly;
int i=x+y*lx+z*pl;

如果(x要找出错误,通常最好使用更小的数据集。让我们设置
Lx=Ly=2
并检查得到的结果:

[[[ 3.40425836+0.j -2.09837677+0.j]
  [-0.27708016+0.j  0.60454108+0.j]]]
_________
[[[ 3.4042583 +0.j -0.27708015+0.j]
  [-2.0983768 +0.j  0.60454106+0.j]]]
这些数字几乎完全相同,只是并不都在预期的位置。简单的转置可以解决这一问题:

res=np.转置(res,(0,2,1))

然后结果与参考结果匹配:

[[[ 3.4042583 +0.j -2.0983768 +0.j]
  [-0.27708015+0.j  0.60454106+0.j]]]
结果之间仍然存在一些差异(逗号后面的几个数字),但这可以通过CPU和GPU之间使用不同的FPU单元来解释(在我的例子中)。例如,可以阅读更多关于这方面的内容


这应该不需要转置-Lx,Ly,Lz的位置一定是错误的-我会让OP来解决这个问题。

结果的差异似乎是逗号后的几个数字,这表明可能是由于CPU和加速器上的FPU单元不同。请看更多信息否,差异远远超过逗号后的几个数字。是的,哟你是对的,不止这些——看我的答案。谢谢你,这很有意义!