14

私は一日中これに苦労してきました.CUDAコードでスレッド用の乱数ジェネレーターを取得しようとしています. 私はすべてのフォーラムを調べましたが、このトピックはかなり出てきますが、あらゆる種類のコードを解明しようとして何時間も費やしましたが、役に立ちませんでした. 誰かが簡単な方法を知っていれば、おそらくデバイスカーネルを呼び出して、0 から 1 の間のランダムな浮動小数点数、または変換できる整数を返すことができます。

ここでも、たとえば rand() のように、カーネルで乱数を使用したいと考えています。

前もって感謝します

4

9 に答える 9

12

興味のある方は、cuRANDを介して実行できるようになりました。

于 2012-04-11T14:51:32.517 に答える
5

特別なものが必要な理由がよくわかりません。従来の PRNG は、多かれ少なかれ直接移植する必要があります。線形合同法はうまく機能するはずです。確立しようとしている特別なプロパティはありますか?

于 2009-05-08T02:18:29.970 に答える
4

アプリケーションによっては、ストリーム (スレッドごとに 1 つのストリーム) がオーバーラップするかどうかを考慮せずに 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が利用可能であり、多くのジェネレーターとディストリビューションを提供していることに言及することは更新する価値があると思います。それは間違いなく最も簡単に開始できる場所です。

于 2009-11-20T15:33:15.100 に答える
4

これを行う最善の方法は、独自のデバイス関数を作成することです。

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 */
    }
}

32ビットの結果で100個の乱数が得られます。

1 から 1000 までの乱数が必要な場合はresult%1000、消費時または生成時に を取得することもできます。

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

m_w と m_z の開始値 (例では 150 と 40) を変更すると、毎回異なる結果を得ることができます。それらの1つとして使用できますthreadIdx.x。これにより、毎回異なる疑似乱数シリーズが得られます。

rand() 関数よりも 2 倍速く動作し、うまく動作することを追加したかった ;)

于 2012-09-01T18:11:33.900 に答える
4

この質問に関する議論は、Zenna の元の要求に答える必要があると思います。それは、スレッド レベルの 実装のためのものです。具体的には、カーネルまたはスレッド内から呼び出すことができるデバイス関数です。「太字」の言い回しをやりすぎて申し訳ありませんが、これまでの回答は、ここで求められていることを十分に扱っていないと思います.

cuRAND ライブラリが最善の策です。人々が車輪の再発明を望んでいることに感謝します(サードパーティのライブラリを高く評価し、より適切に使用するようになります)が、高性能で高品質の数値ジェネレーターが豊富にあり、十分にテストされています. 私がお勧めできる最良の情報は、さまざまなジェネレーターに関する GSL ライブラリーのドキュメントです: http://www.gnu.org/software/gsl/manual/html_node/Random-number-generator-algorithms.html

深刻なコードの場合、数学者/コンピューター科学者が体系的な弱点を何度も探して地面に持っている主要なアルゴリズムの1つを使用するのが最善です. 「メルセンヌ ツイスター」は、10^6000 (MT19997 アルゴリズムは「メルセンヌ ツイスター 2^19997」を意味する) のオーダーの周期 (繰り返しループ) を持つものであり、Nvidia がスレッド内のスレッド レベルで使用するために特に適合されています。スレッド ID 呼び出しをシードとして使用する同じワープ。こちらの論文を参照してください: http://developer.download.nvidia.com/compute/cuda/2_2/sdk/website/projects/MersenneTwister/doc/MersenneTwister.pdf . 私は実際にこのライブラリを使用して何かを実装するために取り組んでおり、適切に動作するようになったらコードを投稿します。Nvidia のドキュメント サイトには、現在の CUDA ツールキットの例がいくつかあります。

注: 記録のために、私は Nvidia で働いていませんが、CUDA のドキュメンテーションと抽象化設計は、私がこれまでのところ感銘を受けたものであることを認めます。


于 2013-07-15T19:56:34.157 に答える
2

ここには、CUDA 用の GNU rand48() 関数の実装を含む MDGPU パッケージ (GPL) があります。

私はそれを見つけました(Googleを使用して、あなたが試したと思います:-)ここのNVidiaフォーラムで。

于 2009-05-08T02:25:38.737 に答える
2

CUDA 用の適切な並列数ジェネレーターは見つかりませんでしたが、ここで学術研究に基づいた並列乱数ジェネレーターを見つけました: http://sprng.cs.fsu.edu/

于 2009-06-15T20:06:01.477 に答える
0

Python 用の Numba で cuda.jit を使用している場合は、この乱数ジェネレーターが役立ちます。

于 2020-02-07T15:10:48.983 に答える