将结构传递给Cupy中的原始内核

时间:2019-12-06 03:26:01

标签: python cuda chainer cupy

我有CUDA内核,这些内核采用float3,int2等结构作为参数。我似乎无法通过cupy rawkernel接口将参数正确传递给这些内核。我尝试过为float3参数传递3个浮点数的1d Cupy数组,并且在内核中未正确解释该参数。我尝试传递ctypes结构,但返回了不受支持的类型错误。是否可以将自定义结构发送到cupy中的原始内核?如果可以,怎么办?

我尝试如下使用ctype结构:

class float3(ctypes.Structure): 
    fields = [ ("X", c_float), ("Y", c_float), ("Z", c_float)] 

from cupy.cuda.function import CPointer 

class CFloat3(CPointer): 
    def __init__(self, v): super().__init__(ctypes.addressof(v)) 
        self.val = v 

val= float3(1.5, 3, 5) 
cval= CFloat3(val) 

这绕过了cupy的类型检查,但是仍然没有正确地将值传递给内核。如果您查看cupy源代码中的功能模块,似乎应该可以正常工作。它只是传递该结构的指针。我还尝试了id(v)和ctypes.POINTER(float3)(v)而不是ctypes.addressof来获取结构的地址,但这也不起作用。

我可以通过编写内核包装程序来解决此问题,该程序将接受数组作为输入,然后将数组转换为可调用常规内核的结构。不过这对我来说很丑。如果无法做到这一点,那么似乎不提供将结构传递给内核的功能似乎是一个很大的疏忽。

2 个答案:

答案 0 :(得分:2)

感谢您的提问。

一种解决float2float3类型问题的方法是在内核内部转换Cupy数组指针(但是,不建议这样做):

import cupy
add_kernel = cupy.RawKernel(r'''
    extern "C" __global__
    void my_add(const float* x1, float* y) {
        int tid = blockDim.x * blockIdx.x + threadIdx.x;
        float3* xf3 = (float3*) x1;
        y[tid] = xf3->x + xf3->y + xf3->z;
    }
    ''', 'my_add')
x1 = cupy.array([1, 2, 3], dtype='float32')
y = cupy.array([0], dtype='float32')
add_kernel((1,), (1,), (x1, y))

但是,CuPy不支持结构化数组,因此不可能将ccupy数组映射到cuda内核中的用户定义结构。

答案 1 :(得分:1)

我同意这一评论;在一般情况下,我无法找到一种方法来完成这项工作。

通过重新定义float2数据类型,可以使用一种hacky方法与double2np.complexXX配合使用。这是一个示例:

$ cat t19.py
import numpy as np
import cupy
ddim = 64
bdim = 32
d = np.complex64(1+2j)
i = cupy.ones((ddim*3), dtype=cupy.float32).reshape(ddim, 3)
o = cupy.zeros((ddim*3), dtype = cupy.float32).reshape(ddim, 3)
my_test = cupy.RawKernel(r'''
  extern "C" __global__
  void my_test(const float2 d, const  float3 * __restrict__  i, float3 * __restrict__ o, int dim) {
  int x = blockDim.x * blockIdx.x + threadIdx.x;
  if (x < dim){
    float3 temp = i[x];
    temp.x += d.x;
    temp.y += d.y;
    temp.z += d.x;
    o[x] = temp;}
  }
 ''', 'my_test')
gdim = ddim//bdim + 1
my_test((gdim,1), (bdim,1), (d, i,o,ddim))  # grid, block and arguments
r_o = cupy.asnumpy(o)
print(r_o)
$ python t19.py
[[2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]
 [2. 3. 2.]]
$

我对numpy结构化数据类型没有好运,这似乎是实现这一目标的逻辑路径。