CUDA中的随机数发生器

时间:2009-05-08 02:10:08

标签: random cuda prng

我整天都在苦苦挣扎,我正在尝试为我的CUDA代码中的线程获取一个随机数生成器。我查看了所有论坛,是的,这个主题有点讨论,但我花了好几个小时试图解开各种代码无济于事。如果有人知道一个简单的方法,可能会被调用的设备内核返回0到1之间的随机浮点数,或者我可以转换的整数,我将非常感激。

同样,我希望在内核中使用随机数,例如rand()。

提前致谢

9 个答案:

答案 0 :(得分:11)

对于任何有兴趣的人,您现在可以通过cuRAND

来完成

答案 1 :(得分:5)

我不确定我理解为什么你需要什么特别的东西。任何传统的PRNG都应该或多或少地直接移植。 linear congruential应该可以正常工作。你有一些你想要建立的特殊属性吗?

答案 2 :(得分:4)

根据您的应用程序,您应该警惕使用LCG而不考虑流(每个线程一个流)是否会重叠。你可以用LCG实现蛙跳,但是你需要有足够长的时间LCG以确保序列不会重复。

越级的例子可能是:

template <typename ValueType>
__device__ void leapfrog(unsigned long &a, unsigned long &c, int leap)
{
    unsigned long an = a;
    for (int i = 1 ; i < leap ; i++)
        an *= a;
    c = c * ((an - 1) / (a - 1));
    a = an;
}

template <typename ValueType>
__device__ ValueType quickrand(unsigned long &seed, const unsigned long a, const unsigned long c)
{
    seed = seed * a;
    return seed;
}

template <typename ValueType>
__global__ void mykernel(
    unsigned long *d_seeds)
{
    // RNG parameters
    unsigned long a = 1664525L;
    unsigned long c = 1013904223L;
    unsigned long ainit = a;
    unsigned long cinit = c;
    unsigned long seed;

    // Generate local seed
    seed = d_seeds[bid];
    leapfrog<ValueType>(ainit, cinit, tid);
    quickrand<ValueType>(seed, ainit, cinit);
    leapfrog<ValueType>(a, c, blockDim.x);

    ...
}

但是在大​​多数情况下,那个发电机的周期可能不够。

说实话,我会考虑使用第三方库,例如NAG。 SDK中也有一些批处理生成器,但在这种情况下,这可能不是您正在寻找的。

修改

由于这只是刚刚投票,我认为值得更新,提及cuRAND,正如最近对这个问题的答案所提到的那样,并且提供了许多生成器和发行版。这绝对是最容易开始的地方。

答案 3 :(得分:4)

我认为对这个问题的任何讨论都需要回答Zenna的原始请求,那就是线程级实现。特别是设备功能,可以在内核或线程中调用。对不起,如果我过度使用“粗体”短语,但我真的认为到目前为止的答案还没有完全解决这里所寻求的问题。

cuRAND库是您最好的选择。我很欣赏人们想要重新发明轮子(它让人欣赏并更恰当地使用第三方库)但是高性能的高质量数字生成器非常丰富且经过良好测试。我可以推荐的最佳信息是关于不同生成器上GSL库的文档:http://www.gnu.org/software/gsl/manual/html_node/Random-number-generator-algorithms.html

对于任何严肃的代码,最好使用数学家/计算机科学家一直在寻找系统性弱点的主要算法之一。 “mersenne twister”是具有大约10 ^ 6000(MT19997算法意味着“Mersenne Twister 2 ^ 19997”)的周期(重复循环)的东西,其特别适合于Nvidia在线程内的线程级别使用。使用线程ID调用作为种子的相同warp。请参阅此处的论文:http://developer.download.nvidia.com/compute/cuda/2_2/sdk/website/projects/MersenneTwister/doc/MersenneTwister.pdf。我实际上正在努力使用这个库实现somehting,如果我让它正常工作,我将发布我的代码。 Nvidia在他们的文档站点上有一些关于当前CUDA工具包的例子。

注意:仅仅为了记录,我不为Nvidia工作,但我承认他们的文档和CUDA的抽象设计是我迄今为止留下深刻印象的东西。


答案 4 :(得分:3)

最好的方法是编写自己的设备功能,这是一个

void RNG()
{   
    unsigned int m_w = 150;
    unsigned int m_z = 40;

    for(int i=0; i < 100; i++)
    {
        m_z = 36969 * (m_z & 65535) + (m_z >> 16);
        m_w = 18000 * (m_w & 65535) + (m_w >> 16);

        cout <<(m_z << 16) + m_w << endl;  /* 32-bit result */
    }
}

它会给你100个随机数,结果为32位。

如果你想要一些1到1000之间的随机数,你也可以在消费点或生成点取result%1000

((m_z << 16) + m_w)%1000

更改m_w和m_z起始值(在示例中为150和40)可让您每次都获得不同的结果。您可以使用threadIdx.x作为其中之一,每次都应该为您提供不同的伪随机序列。

我想补充说它的工作速度比rand()函数快2倍,效果很好;)

答案 5 :(得分:2)

有一个MDGPU包(GPL),其中包含CUDA here的GNU rand48()函数的实现。

我发现它(非常容易,使用谷歌,我认为你试过:-)在NVidia论坛here上。

答案 6 :(得分:2)

我没有为CUDA找到一个好的并行数生成器,但我确实找到了一个基于学术研究的并行随机数生成器:http://sprng.cs.fsu.edu/

答案 7 :(得分:0)

你可以尝试Mersenne Twister for GPUs

它基于面向SIMD的Fast Mersenne Twister(SFMT),它是一种非常快速和可靠的随机数发生器。它通过Marsaglias DIEHARD测试随机数生成器。

答案 8 :(得分:0)

如果您在Numba for Python中使用cuda.jit,则此Random number generator很有用。