[PyCUDA] TypeError: ‘numpy.int32’ does not have the buffer interface

[PyCUDA] TypeError: ‘numpy.int32’ does not have the buffer interface

PyCUDAを使い始めています。チュートリアルも完全には動いてない状況です。

○環境

  • Mac OS X Marverics
  • Python 2.7 64bit(Anaconda)
  • PyCuda 2014.01
  • CUDA6.5

さて、今日詰まったのは、

# TypeError: 'numpy.int32' does not have the buffer interface

発生箇所というと、チュートリアル中の[Advanced Topics]->[Structures]です。

class DoubleOpStruct:
    mem_size = 8 + numpy.intp(0).nbytes
    def __init__(self, array, struct_arr_ptr):
        self.data = cuda.to_device(array)
        self.shape, self.dtype = array.shape, array.dtype
        cuda.memcpy_htod(int(struct_arr_ptr), numpy.int32(array.size))
        cuda.memcpy_htod(int(struct_arr_ptr) + 8, numpy.intp(int(self.data)))
    def __str__(self):
        return str(cuda.from_device(self.data, self.shape, self.dtype))

struct_arr = cuda.mem_alloc(2 * DoubleOpStruct.mem_size)
do2_ptr = int(struct_arr) + DoubleOpStruct.mem_size

array1 = DoubleOpStruct(numpy.array([1, 2, 3], dtype=numpy.float32), struct_arr)
array2 = DoubleOpStruct(numpy.array([0, 4], dtype=numpy.float32), do2_ptr)
print("original arrays", array1, array2)

どうやらbuffer interfaceというのがPythonにはあるそうですが、上手く解決できていないのでしょうか?
簡単に調べたところ、バージョンによって、紆余曲折があるのようなないような。。。(Pythonをまだあまり知らず)

解決方法としては、numpy.getbufferでバッファインターフェイスを取得すると、動きました。

# cuda.memcpy_htod(int(struct_arr_ptr), numpy.int32(array.size))
cuda.memcpy_htod(int(struct_arr_ptr), numpy.getbuffer(numpy.int32(array.size)))

ただし、これが本当の正解であるのかわからず。。。
print関数も上手く動かないので、print命令へ変更。(仕様?)

ソースコード全てを載せておきます。自己責任で。

import pycuda.gpuarray as gpuarray
import pycuda.driver as cuda
import pycuda.autoinit
import numpy
from pycuda.compiler import SourceModule

mod = SourceModule("""
    struct DoubleOperation {
        int datalen, __padding; // so 64-bit ptrs can be aligned
        float *ptr;
    };

    __global__ void double_array(DoubleOperation *a) {
        a = &a[blockIdx.x];
        for (int idx = threadIdx.x; idx < a->datalen; idx += blockDim.x) {
            a->ptr[idx] *= 2;
        }
    }
    """)

class DoubleOpStruct:
    mem_size = 8 + numpy.intp(0).nbytes
    def __init__(self, array, struct_arr_ptr):
        self.data = cuda.to_device(array)
        self.shape, self.dtype = array.shape, array.dtype
        cuda.memcpy_htod(int(struct_arr_ptr), numpy.getbuffer(numpy.int32(array.size)))
        cuda.memcpy_htod(int(struct_arr_ptr) + 8, numpy.getbuffer(numpy.intp(int(self.data))))
    def __str__(self):
        return str(cuda.from_device(self.data, self.shape, self.dtype))

struct_arr = cuda.mem_alloc(2 * DoubleOpStruct.mem_size)
do2_ptr = int(struct_arr) + DoubleOpStruct.mem_size

array1 = DoubleOpStruct(numpy.array([1, 2, 3], dtype=numpy.float32), struct_arr)
array2 = DoubleOpStruct(numpy.array([0, 4], dtype=numpy.float32), do2_ptr)
print "original arrays", array1, array2

func = mod.get_function("double_array")
func(struct_arr, block = (32, 1, 1), grid=(2, 1))
print "doubled arrays", array1, array2

func(numpy.intp(do2_ptr), block = (32, 1, 1), grid=(1, 1))
print "doubled second only", array1, array2, "\n"

出力結果

original arrays [ 1.  2.  3.] [ 0.  4.]
doubled arrays [ 2.  4.  6.] [ 0.  8.]
doubled second only [ 2.  4.  6.] [  0.  16.]