ドキュメンテーション センター

  • 評価版
  • 製品アップデート

最新のリリースでは、このページがまだ翻訳されていません。 このページの最新版は英語でご覧になれます。

GPU での乱数の生成

この例では、GPU でサポートされているいくつかの乱数発生器の間で切り換えを行う方法を示し、それぞれのパフォーマンスを調べます。

乱数は、多くのシミュレーションや推定アルゴリズムの重要な部分をなしています。通常、こうした数は関数 randrandrandirandi および randnrandn を使用して生成されます。Parallel Computing Toolbox™ にはこれらに対応する 3 つの関数が備わっており、GPU で直接、乱数を生成します。すなわち、gpuArray.randgpuArray.randgpuArray.randigpuArray.randigpuArray.randngpuArray.randn です。これらの関数では、いくつかの異なった数値生成アルゴリズムの 1 つを使用できます。GPU で使用可能な発生器は、以下にリストと説明があり、そのパフォーマンスが測定されています。

GPU 乱数発生器の検出

parallel.gpu.RandStreamparallel.gpu.RandStreamlistlist メソッドでは、使用可能な発生器の短い説明が提示されます。

parallel.gpu.RandStream.list
 
The following random number generator algorithms are available:
 
MRG32K3A:         Combined multiple recursive generator (supports parallel streams)
Philox4x32-10:    Philox 4x32 generator with 10 rounds (supports parallel streams)
Threefry4x64-20:  Threefry 4x64 generator with 20 rounds (supports parallel streams)

これらの発生器はそれぞれが並列での使用を念頭に設計されており、複数の独立した乱数ストリームを提供します。ただし、それぞれに何らかの利点と欠点があります。

  • CombRecursive (別名 MRG32k3a):同じ名前をもつ MATLAB の発生器に相当し、初期状態が同じなら同一の結果が生成されます。1999 年に導入されたこの発生器は、広くテストされ使用されてきました。

  • Threefry4x64-20:2011 年に導入された新しい発生器ですが、広くテストされ使用されている既存の ThreeFish 暗号アルゴリズムを基にしています。この発生器は、GPU のような並列性の高いシステムにおいて優れたパフォーマンスを発揮するよう設計されました。

  • Philox4x32-10:2011 年に導入された新しい発生器で、特に GPU のような並列性の高いシステムにおいて高度なパフォーマンスを発揮するよう設計されています。

これらの発生器はすべて、標準の TestU01 テスト スイートをパスします ("TestU01:A C library for empirical testing of random number generators" by Pierre L'Ecuyer and Richard Simard, ACM Transactions on Mathematical Software, Vol. 33, No. 4, August 2007 を参照)。

既定の乱数発生器の変更

関数 parallel.gpu.rngparallel.gpu.rng は発生器の状態を保存し、リセットすることができます。また、提供されている異なった発生器間の切り替えも可能です。発生器を変更する前に既存の状態を保存して、テスト終了後に復元できるようにします。

oldState = parallel.gpu.rng;

parallel.gpu.rng(0, 'Philox4x32-10');
disp(parallel.gpu.rng)
     Type: 'Philox4x32-10'
     Seed: 0
    State: [7x1 uint32]

一様分布する乱数の生成

一様分布する乱数を GPU で発生させるには、gpuArray.randgpuArray.rand または gpuArray.randigpuArray.randi のいずれかを使用します。これら 2 つの関数は、パフォーマンス上は非常に似通った動作をしますが、ここでは rand のみを測定します。gputimeitgputimeit を使用してパフォーマンスを測定することで、この関数を自動的に何度も呼び出して同期や他のタイミングの問題を的確に扱い、正確なタイミングでの結果を確保します。

generators = {'CombRecursive', 'Threefry4x64-20', 'Philox4x32-10'};
sizes = ([1, 100000:100000:2000000])';
samplesPerSec = nan(numel(sizes), numel(generators));
for g=1:numel(generators)
    % Set the generator
    parallel.gpu.rng(0, generators{g});
    % Loop over sizes, timing the generator
    for s=1:numel(sizes)
        fcn = @() gpuArray.rand(sizes(s),1);
        time = gputimeit(fcn);
        samplesPerSec(s,g) = sizes(s)/time;
    end
end

% Plot the result
plot(sizes, samplesPerSec, '.-')
legend(generators, 'Location', 'NorthWest')
grid on
xlabel('Number of elements')
ylabel('Samples generated per second')
title('Generating samples in U(0,1)')

結果は、パフォーマンスに大きな違いがあることを明確に示しています。Threefry4x64-20 は CombRecursive よりずっと速く、Philox4x32-10 は Threefry4x64-20 よりさらにずっと速いことがわかります。

正規分布した乱数の生成

多くのシミュレーションでは、正規分布からサンプルをとった摂動を利用します。これを実行するには gpuArray.randngpuArray.randn を使用します。

samplesPerSec = nan(numel(sizes), numel(generators));
for g=1:numel(generators)
    % Set the generator
    parallel.gpu.rng(0, generators{g});
    % Loop over sizes, timing the generator
    for s=1:numel(sizes)
        fcn = @() gpuArray.randn(sizes(s),1);
        time = gputimeit(fcn);
        samplesPerSec(s,g) = sizes(s)/time;
    end
end

% Plot the result
plot(sizes, samplesPerSec, '.-')
legend(generators, 'Location', 'SouthEast')
grid on
xlabel('Number of elements')
ylabel('Samples generated per second')
title('Generating samples in N(0,1)')

一様分布でのテストと同様、Threefry4x64-20 は CombRecursive より速く、Philox4x32-10 は Threefry4x64-20 より速いことがわかります。正規分布した値の生成に必要な追加作業のため、各発生器で値が生成される速度は減じ、各発生器間のパフォーマンスの相違も縮小しています。

終了する前に、発生器を元の状態に復元してください。

parallel.gpu.rng(oldState);

まとめ

この例では、3 つの GPU 乱数発生器を比較しました。それぞれに利点 (+) と注意点 (-) があります。

CombRecursive

  • (+) 比較用に CPU バージョンも使用可能

  • (+) 実際の使用で長い実績

  • (-) 最も低速

Threefry4x64-20

  • (+) 高速

  • (+) よく知られ十分テストされた Threefish アルゴリズムを使用

  • (-) 実際の使用では比較的新しい

  • (-) 比較に使用できる CPU バージョンなし

Philox4x32-10

  • (+) 最も高速

  • (-) 実際の使用では比較的新しい

  • (-) 比較に使用できる CPU バージョンなし

この情報は役に立ちましたか?