如何在OpenCL中获得"随机"数字

32 opencl

我想在OpenCL中获得一个随机数.它不必是真正的随机或甚至是随机的.只需简单快捷的东西.

我看到在OpenCL中有大量真正的随机并行花式裤子随机算法,就像成千上万行.我不需要那样的东西.一个简单的'random()'就可以了,即使很容易看到它的模式.

我看到有一个Noise功能?有什么简单的方法来获取随机数?

icl*_*126 16

我在最近几天解决了这个"没有随机"的问题,我提出了三种不同的方法:

  1. Xorshift - 我基于这个创建了生成器.您所要做的就是uint2为整个内核提供一个数字(种子),每个工作项都将计算自己的兰特数

    // 'randoms' is uint2 passed to kernel
    uint seed = randoms.x + globalID;
    uint t = seed ^ (seed << 11);  
    uint result = randoms.y ^ (randoms.y >> 19) ^ (t ^ (t >> 8));
    
    Run Code Online (Sandbox Code Playgroud)
  2. Java随机 - 我使用.next(int bits)方法中的代码生成随机数.这次你必须提供一个ulong数字作为种子.

    // 'randoms' is ulong passed to kernel
    ulong seed = randoms + globalID;
    seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
    uint result = seed >> 16;
    
    Run Code Online (Sandbox Code Playgroud)
  3. 只需在CPU上生成所有内容并将其传递给一个大缓冲区中的内核.

我在我的进化算法中测试了所有三种方法(生成器),计算了图中的最小支配集.

我喜欢第一个生成的数字,但看起来我的进化算法没有.

第二个生成器生成具有一些可见模式的数字,但我的进化算法无论如何都喜欢它,并且整个事情比第一个生成器运行得快一点.

但第三种方法表明,从主机(cpu)提供所有数字绝对没问题.首先,我生成(在我的情况下)1536 int32数字并在每次内核调用中将它们传递给GPU将太昂贵(计算并转移到GPU).但事实证明,它和我以前的尝试一样快.CPU负载低于5%.

顺便说一句,我也试过MWC64X随机但是在我安装了新的GPU驱动程序后,该功能mul_hi开始导致构建失败(甚至整个AMD内核分析程序崩溃).


van*_*ale 11

以下是java.util.Random该类根据doc使用的算法:

(seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)
Run Code Online (Sandbox Code Playgroud)

请参阅文档了解其各种实现.将工人的身份传递给种子并循环几次应产生良好的随机性

或者另一个方法是进行一些随机操作,这些操作相当容易溢出:

 long rand= yid*xid*as_float(xid-yid*xid);
 rand*=rand<<32^rand<<16|rand;
 rand*=rand+as_double(rand);
Run Code Online (Sandbox Code Playgroud)

xid=get_global_id(0);yid= get_global_id(1);


Tar*_*ara 10

我目前正在实现一个实时路径跟踪器.您可能已经知道路径跟踪需要许多随机数.
在GPU上生成随机数之前,我只是在CPU上生成它们(使用rand(),这很糟糕)并将它们传递给GPU.
这很快就成了瓶颈.
现在,我使用Park-Miller伪随机数生成器(PRNG)在GPU上生成随机数.
它实现起来非常简单并取得了很好的效果.
我收集了数千个样本(范围为0.0到1.0)并将它们平均在一起.
结果值非常接近0.5(这是您所期望的).在不同的运行之间,0.5的差异大约为0.002.因此它具有非常均匀的分布.

这是一篇描述算法的论文:
http://www.cems.uwe.ac.uk/~irjohnso/coursenotes/ufeen8-15-m/p1192-parkmiller.pdf
这里有一篇关于为CUDA优化的上述算法的论文(其中可以很容易地移植到OpenCL):http://www0.cs.ucl.ac.uk/staff/ucacbbl/ftp/papers/langdon_2009_CIGPU.pdf

这是我如何使用它的一个例子:

int rand(int* seed) // 1 <= *seed < m
{
    int const a = 16807; //ie 7**5
    int const m = 2147483647; //ie 2**31-1

    *seed = (long(*seed * a))%m;
    return(*seed);
}

kernel random_number_kernel(global int* seed_memory)
{
    int global_id = get_global_id(1) * get_global_size(0) + get_global_id(0); // Get the global id in 1D.

    // Since the Park-Miller PRNG generates a SEQUENCE of random numbers
    // we have to keep track of the previous random number, because the next
    // random number will be generated using the previous one.
    int seed = seed_memory[global_id];

    int random_number = rand(&seed); // Generate the next random number in the sequence.

    seed_memory[global_id] = *seed; // Save the seed for the next time this kernel gets enqueued.
}
Run Code Online (Sandbox Code Playgroud)

代码就是一个例子.我没有测试过.
在第一次执行内核之前,数组"seed_memory"只用rand()填充一次.之后,所有随机数生成都发生在GPU上.我认为也可以简单地使用内核id而不是使用rand()初始化数组.


Meg*_*raj -2

您无法在内核中生成随机数,最好的选择是在主机(CPU)中生成随机数,然后通过缓冲区将其传输到 GPU 并在内核中使用它。

  • 您可以使用任何随机化算法生成随机数,但种子需要包含线程的 global_id,因此每个数字都是真正随机的 (9认同)