【问题标题】:Monte Carlo with rates, system simulation with CUDA C++带有速率的蒙特卡洛,使用 CUDA C++ 进行系统仿真
【发布时间】:2018-02-21 00:44:00
【问题描述】:

所以我试图模拟一个名为 Tasep 的一维物理模型。

我用 C++ 编写了一个代码来模拟这个系统,但我肯定需要提高性能。

模型非常简单(下面的 c++ 代码) - 10 的数组。 1 代表一个粒子,0 是无粒子,意思是空的。如果该元素为空,则粒子以1 的速率向右移动一个元素。最后一个位置的粒子将以beta 的速率消失(比如 0.3 )。最后,如果第一个位置是空的,则会在那里出现一个粒子,频率为alpha

一个线程很容易,我只是随机选择一个元素,并以1 / alpha / beta 的概率行事,如上所述。但这可能需要很长时间。

所以我尝试使用 GPU 对多个线程做类似的事情,这引发了很多问题:

  1. 在这样的事情上使用 GPU 和 CUDA 是个好主意吗?

  2. 我应该有多少线程?我可以为每个网站创建一个主题 (10E+6),应该吗?

  3. 如何在不同线程之间同步对内存的访问?到目前为止,我使用了原子操作。

  4. 生成随机数据的正确方法是什么?如果我使用一百万个线程,每个线程都有一个随机生成器可以吗?

  5. 如何处理费率?

我对 CUDA 很陌生。我设法从 CUDA 示例和一些教程中运行代码。虽然我有上面的一些代码(虽然仍然给出奇怪的结果),但我没有把它放在这里,因为我认为问题更笼统。

所以这里是它的 c++ 单线程版本:

int Tasep()
{
    const int L = 750000;

    // rates
    int alpha = 330;
    int beta  = 300;
    int ProbabilityNormalizer = 1000;

    bool system[L];
    int pos = 0;
    InitArray(system); // init to 0's and 1's

    /* Loop */
    for (int j = 0; j < 10*L*L; j++)
    {
        unsigned long randomNumber = xorshf96();
        pos = (randomNumber % (L)); // Pick Random location in the the array

        if (pos == 0 && system[0] == 0) // First site and empty
            system[0] = (alpha > (xorshf96() % ProbabilityNormalizer)); // Insert a particle with chance alpha

        else if (pos == L - 1) // last site
            system[L - 1] = system[L - 1] && (beta < (xorshf96() % ProbabilityNormalizer)); // Remove a particle if exists with chance beta

        else if (system[pos] && !system[pos + 1]) // If current location have a particle and the next one is empty - Jump right
        {
            system[pos] = false;
            system[pos + 1] = true;
        }
        if ((j % 1000) == 0) // Just do some Loggingg
            Log(system, j);
    }

    getchar();
    return 0;
}

我会非常感谢愿意提供帮助和建议的人。

【问题讨论】:

    标签: cuda gpgpu gpu


    【解决方案1】:

    我认为您的目标是执行蒙特卡洛模拟。 但我未能完全理解您的主要目标(即获得频率或平均功率损失等)

    问题 01

    既然您询问了随机数据,我相信您可以有多个随机种子(可能每个线程一个),我建议您使用任何伪随机生成器在 GPU 中生成种子(您甚至可以使用相同的作为 CPU),将种子存储在 GPU 全局内存中,并使用动态并行性启动尽可能多的线程。 所以,是的,CUDA 是一种合适的方法,但请记住在学习所需的时间与从当前代码中获取结果所需的时间之间取得平衡。 如果您将来会使用这些知识,学习 CUDA 可能值得,或者如果您可以在许多 GPU 上升级您的代码并且在 CPU 上花费太多时间,您将需要经常解决这个等式,这也是值得的。看起来你很接近,但如果它是一个简单的一次性结果,我建议你让 CPU 解决它,因为根据我的经验,你学习 CUDA 所花费的时间可能比 CPU 解决它所花费的时间更多(恕我直言)。

    问题 02

    线程数是新手很常见的问题。答案很大程度上取决于您的项目,但是将您的代码作为洞察力,我会尽可能多地使用每个线程和不同的种子。 我的建议是使用寄存器就是你所谓的“站点”(注意这是很强的限制),然后运行多个循环来评估你的粒子,就像汽车轮胎坏路的想法一样(SMEM 中的数据),所以您的 L 每个循环限制为 255 个(避免溢出以您的项目为代价,更少的寄存器意味着每个块有更多的扭曲)。为了产生扰动,我会在共享内存中加载向量,一个用于 alpha(short),一个用于 beta(short)(我确实假设不同的分布),一个“存在或不存在粒子”在下一个站点(char),和另外两个作为伪生成器源与 threadID、blockID 和一些当前时间信息(帮助您选择初始 alpha、beta 以及是否存在)组合在一起,这样您就可以为块中的每个线程重用这个速率,并且因为数据不会改变(只有读取位置改变)您只需在读取后同步一次,您也可以“随机选择扰动位置并重复使用数据。初始值可以从全局内存中加载并在特定之后“刷新”隐藏加载延迟的循环数。简而言之,您将在共享中重复使用相同的数据多次,但是由于伪随机值,为每个线程选择的值在每次交互时都会发生变化。考虑到您在谈论大数字,你可以加载不同的数据我n 每一个block,伪随机算法应该够用了。此外,您甚至可以将先前运行的存储在 gpu 中的结果用作随机源,翻转一个变量并进行一些位操作,因此您可以将每个位用作粒子。

    问题 03

    对于您的特定项目,我强烈建议您避免线程合作,并使它们完全独立。但是,您可以在同一个 warp 中使用 shuffle,而且成本不高。

    问题 04

    很难生成真正随机的数据,但您应该担心您的周期持续多久(因为任何生成器都有一个随机周期并且它们会重复)。我建议您使用一个可以与您的内核并行工作的生成器,并使用它来为您的内核提供服务(您可以使用动态并行)。在你的情况下,因为你想要一些随机的,你不应该太担心一致性。我在上一个问题中给出了一个使用伪随机数据的例子,这可能会有所帮助。请记住,没有真正的随机生成器,但有一些替代品,例如互联网比特。

    问题 05

    已经在问题 03 中解释过,但请记住,您不需要完整的值序列,只需要足够的部分以多种形式使用,给内核处理足够的时间,然后您可以刷新你排序,如果你保证不以相同的顺序喂块,那将很难陷入模式。

    希望我能得到帮助,我与 CUDA 合作了一年多,开始时和你一样,但每周我都会改进我的代码,现在已经差不多好了。现在我看到它如何完美地适应我的统计挑战:对随机事物进行聚类。

    祝你好运!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-19
      • 2018-10-03
      • 1970-01-01
      • 2019-08-04
      • 2018-02-10
      • 2014-03-26
      • 2021-01-06
      相关资源
      最近更新 更多