【问题标题】:Random Number Generator in CUDACUDA 中的随机数生成器
【发布时间】:2010-10-24 16:32:58
【问题描述】:

我整天都在为此苦苦挣扎,我试图在我的 CUDA 代码中为线程获取一个随机数生成器。我浏览了所有论坛,是的,这个话题出现了很多,但我花了几个小时试图解开各种代码,但无济于事。如果有人知道一个简单的方法,可能是一个 device 内核,可以调用它来返回 0 到 1 之间的随机浮点数,或者我可以转换的整数,我将不胜感激。

再次,我希望在内核中使用随机数,就像 rand() 一样。

提前致谢

【问题讨论】:

标签: random cuda prng


【解决方案1】:

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

【讨论】:

  • 我认为他正在寻找一个他可以调用的库,而不是自己实现它。仍然是为他指出解决方案的好答案。
  • 线性同余的实现非常简单。您可以通过在每个线程中使用具有自己状态的单独 PRNG 来使用 CUDA 来做到这一点。
  • 这让我有点困惑。每个线程都会说是从其线程 ID 播种的,但他们不会很快开始重叠吗?
  • 那些随机算法从 x_n 计算 x_n+1,尝试将它们用于并行随机数创建将导致具有非常独特模式的“随机”数。这是因为 x_n+1 是 x_n 的函数。
  • alifeofzen:种子中的线性依赖已经够糟糕了,确实(参见portal.acm.org/citation.cfm?doid=1276927.1276928),也许你应该找到一些其他的播种方式。 Danny:最简单的(对于该主题,因为并行和分布式系统的随机数很难正确)可能是一系列滞后的 Fibonacci 生成器。我只是找不到概述这一点的论文了。
【解决方案2】:

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

我在 NVidia 论坛 here 上找到了它(很容易,使用 Google,我假设您尝试过 :-)。

【讨论】:

  • 是的,我也发现了.. 但努力让它做我想做的事.. 我想我只是度过了愚蠢的一天.. 我会再检查一遍,谢谢
  • 根据 NVidia 论坛中的 cmets(包括作者的),实现效果不佳。
【解决方案3】:

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

【讨论】:

  • 有人知道这个算法的 CUDA 版本吗?
  • “好”是什么意思?根据您的要求,一个简单的 MD5 哈希(请参阅 cuDPP)可能就足够了。在某些情况下,多个 Mersenne Twister 可能是最好的,因为它们的周期非常长并且流之间的独立性很好。 NAG 有 l'Ecuyer 的 MRG32k3a,如果您需要跨多个线程/块的单个流,它的效果非常好。
  • 一个好的开始将是一个重复的伪随机数生成器,在单元格之间具有低依赖性 - 适用于创建一组随机数数组,用多个线程填充每个数组的内容,但创建一个接一个的数组。
【解决方案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,正如该问题的最新答案所提到的,它是可用的,并提供了许多生成器和发行版。这绝对是最容易开始的地方。

【讨论】:

    【解决方案5】:

    对于任何感兴趣的人,您现在可以通过cuRAND 进行。

    【讨论】:

      【解决方案6】:

      最好的方法是编写你自己的设备函数,这是一个

      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 倍,而且效果很好;)

      【讨论】:

      • 编者评论:它是一个简洁的小RNG,但对于需要良好随机数的计算来说,它远不可用。它的周期为 2^16,不能跨越整个 32 位数字空间,而且由于步骤简单,周期小,所以相当容易可逆。
      【解决方案7】:

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

      cuRAND 库是您的最佳选择。我很欣赏人们想要重新发明轮子(它让人欣赏并更正确地使用 3rd 方库),但高性能高质量数字生成器数量众多且经过良好测试。我可以推荐的最佳信息是这里不同生成器上 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 调用作为种子的相同经纱。请参阅此处的论文:http://developer.download.nvidia.com/compute/cuda/2_2/sdk/website/projects/MersenneTwister/doc/MersenneTwister.pdf。我实际上正在使用这个库来实现一些东西,如果我让它正常工作,我会发布我的代码。 Nvidia 在其文档站点上有一些当前 CUDA 工具包的示例。

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


      【讨论】:

        【解决方案8】:

        你可以试试Mersenne Twister for GPUs

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

        【讨论】:

        【解决方案9】:

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

        【讨论】:

          猜你喜欢
          • 2013-02-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-12
          • 1970-01-01
          • 2023-01-03
          相关资源
          最近更新 更多