我正在尝试在Cuda中实现Metropolis-Hastings算法。对于这个算法,我需要能够生成许多具有不同范围的均匀随机数。因此,我想有一个名为runif(min,max)的函数,它返回此范围内的均匀分布数。必须在实际实现算法的另一个函数内多次调用此函数。
基于this帖子,我试图将显示在那里的代码放到一个函数中(见下文)。如果我理解正确,相同的状态会导致相同的数字序列。所以,如果状态没有改变,我总是得到相同的输出。一种替代方法是在runif函数内生成一个新状态,这样每次调用该函数时,都会调用另一个状态。正如我所听到的那样,这是不可取的,因为函数变慢了。
那么,这样一个函数的最佳实现是什么?我应该在函数内部生成新状态,还是在每次调用函数时生成一个新状态?或者还有另一种方法吗?
__device__ float runif(float a, float b, curandState state)
{
float myrandf = curand_uniform_double(&state);
myrandf *= (b - a + 0.999999);
myrandf += a;
return myrandf;
}
答案 0 :(得分:1)
curand_uniform*
函数族接受指向curandState
对象的指针,以某种方式使用它并对其进行修改,因此当下一次curand_uniform*
函数将使用相同的状态对象调用时,您可以拥有期望的随机性。
重要的是:
为了获得有意义的结果,您需要将curandState
更改回来。
现在您按值传递curandState
,因此在内核返回后状态更改将丢失。甚至没有提到复制时不必要的浪费时间。
在内核中创建和初始化一个新的本地状态不仅会破坏性能(并且不会使用任何CUDA),但会给你错误的分发。
在您链接的示例代码中,curandState
由指针传递,以确保保存修改(此指针指向的位置)。
通常,您希望在程序中分配和初始化一次随机状态数组(在启动任何需要RNG的内核之前)。然后,为了生成一些数字,您可以从内核访问此数组,索引基于线程ID。需要多个(多个)状态来避免数据争用(每个并发运行curand_uniform*
函数至少有一个状态。)
这样可以避免副本和状态初始化的性能成本,并获得完美的分发。
有关模式信息和示例代码,请参阅cuRand documentation。