我正在使用pyCUDA进行CUDA编程。我需要在内核函数中使用随机数。 CURAND库在其中不起作用(pyCUDA)。因为,在GPU中有很多工作要做,在CPU内部生成随机数然后将它们转移到GPU将无法工作,而是解决了使用GPU的动机。
补充问题:
答案 0 :(得分:4)
尽管你在问题中断言,但PyCUDA对CUrand提供了相当全面的支持。 GPUArray模块具有直接接口,使用主机端API填充设备内存(注意在这种情况下随机生成器在GPU上运行)。
在PyCUDA内核代码中使用CUrand的设备端API也是完全可能的。在这个用例中,最棘手的部分是为线程生成器状态分配内存。有三种选择 - 静态代码,动态使用主机内存端分配,动态使用设备端内存分配。以下(非常轻微测试的)示例说明了后者,在您的问题中看到了它:
import numpy as np
import pycuda.autoinit
from pycuda.compiler import SourceModule
from pycuda import gpuarray
code = """
#include <curand_kernel.h>
const int nstates = %(NGENERATORS)s;
__device__ curandState_t* states[nstates];
__global__ void initkernel(int seed)
{
int tidx = threadIdx.x + blockIdx.x * blockDim.x;
if (tidx < nstates) {
curandState_t* s = new curandState_t;
if (s != 0) {
curand_init(seed, tidx, 0, s);
}
states[tidx] = s;
}
}
__global__ void randfillkernel(float *values, int N)
{
int tidx = threadIdx.x + blockIdx.x * blockDim.x;
if (tidx < nstates) {
curandState_t s = *states[tidx];
for(int i=tidx; i < N; i += blockDim.x * gridDim.x) {
values[i] = curand_uniform(&s);
}
*states[tidx] = s;
}
}
"""
N = 1024
mod = SourceModule(code % { "NGENERATORS" : N }, no_extern_c=True, arch="sm_52")
init_func = mod.get_function("_Z10initkerneli")
fill_func = mod.get_function("_Z14randfillkernelPfi")
seed = np.int32(123456789)
nvalues = 10 * N
init_func(seed, block=(N,1,1), grid=(1,1,1))
gdata = gpuarray.zeros(nvalues, dtype=np.float32)
fill_func(gdata, np.int32(nvalues), block=(N,1,1), grid=(1,1,1))
这里有一个初始化内核需要运行一次,为发生器状态分配内存并用种子初始化它们,然后是使用这些状态的内核。如果要运行大量线程,则需要注意malloc堆大小限制,但可以通过PyCUDA驱动程序API接口对其进行操作。
答案 1 :(得分:-1)
我接受的答案有一个问题。
我们在那里有一个令人讨厌的名称(这些_Z10initkerneli
和_Z14randfillkernelPfi
)。
为避免这种情况,我们可以手动将代码包装在extern "C" {...}
子句中。
code = """
#include <curand_kernel.h>
const int nstates = %(NGENERATORS)s;
__device__ curandState_t* states[nstates];
extern "C" {
__global__ void initkernel(int seed)
{ .... }
__global__ void randfillkernel(float *values, int N)
{ .... }
}
"""
然后,该代码仍使用no_extern_c=True
进行编译:
mod = SourceModule(code % { "NGENERATORS" : N }, no_extern_c=True)
这应该与
一起使用init_func = mod.get_function("initkernel")
fill_func = mod.get_function("randfillkernel")
希望有帮助。