在 pyCuda 内核中生成单个随机数

Sad*_*dam 2 python cuda pycuda random-seed

我见过很多生成随机数数组的方法。但我想生成一个随机数。C++ 中有没有像 rand() 这样的函数?我不需要一系列随机数。我只需要在内核内生成一个随机数。有没有内置函数可以生成随机数?我已经尝试过下面给出的代码,但它不起作用。

import numpy as np
import pycuda.autoinit
from pycuda.compiler import SourceModule
from pycuda import gpuarray

code = """
    #include <curand_kernel.h>
       __device__ float getRand()
       {
          curandState_t s;
          curand_init(clock64(), 123456, 0, &s);
          return curand_uniform(&s);
       }

        __global__ void myRand(float *values)
        {
          values[0] = getRand();
        }
"""


mod = SourceModule(code)
myRand = mod.get_function("myRand")
gdata = gpuarray.zeros(2, dtype=np.float32)
myRand(gdata, block=(1,1,1), grid=(1,1,1))
print(gdata)
Run Code Online (Sandbox Code Playgroud)

错误类似于:

/usr/local/cuda/bin/../targets/x86_64-linux/include/curand_poisson.h(548): error: this declaration may not have extern "C" linkage

/usr/local/cuda/bin/../targets/x86_64-linux/include/curand_discrete2.h(69): error: this declaration may not have extern "C" linkage

/usr/local/cuda/bin/../targets/x86_64-linux/include/curand_discrete2.h(78): error: this declaration may not have extern "C" linkage

/usr/local/cuda/bin/../targets/x86_64-linux/include/curand_discrete2.h(86): error: this declaration may not have extern "C" linkage

30 errors detected in the compilation of "kernel.cu".
Run Code Online (Sandbox Code Playgroud)

tal*_*ies 5

基本问题是,默认情况下,PyCUDA会默默地将 C 链接应用于SourceModule. 正如错误所示,cuRand需要 C++ 链接,因此getRand不能有 C 链接。

您可以通过更改这两行来解决此问题:

mod = SourceModule(code)
myRand = mod.get_function("myRand")
Run Code Online (Sandbox Code Playgroud)

mod = SourceModule(code, no_extern_c=True)
myRand = mod.get_function("_Z6myRandPf")
Run Code Online (Sandbox Code Playgroud)

这会禁用 C 链接,但确实意味着您需要为调用提供 C++ 损坏的名称get_function。您将需要查看详细的编译器输出或编译 PyCUDA 外部的代码以获得该名称(例如Godbolt)。

或者,您可以像这样修改代码:

import numpy as np
import pycuda.autoinit
from pycuda.compiler import SourceModule
from pycuda import gpuarray

code = """
       #include <curand_kernel.h>

       __device__ float getRand()
       {
          curandState_t s;
          curand_init(clock64(), 123456, 0, &s);
          return curand_uniform(&s);
       }
        
        extern "C" {
        __global__ void myRand(float *values)
        {
          values[0] = getRand();
        }
        }
"""


mod = SourceModule(code, no_extern_c=True)
myRand = mod.get_function("myRand")
gdata = gpuarray.zeros(2, dtype=np.float32)
myRand(gdata, block=(1,1,1), grid=(1,1,1))
print(gdata)
Run Code Online (Sandbox Code Playgroud)

这使得内核具有 C 链接,但不会触及使用 cuRand 的设备功能。