このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。
GPU での乱数の生成
この例では、GPU でサポートされているいくつかの乱数発生器の間で切り替えを行う方法を示します。
乱数は、多くのシミュレーションや推定アルゴリズムの重要な部分をなしています。通常、このような数は関数rand
、randi
およびrandn
を使用して生成されます。Parallel Computing Toolbox™ には、これらに対応し、GPU で乱数を直接生成する 3 つの関数が備わっています。すなわち、rand
、randi
、randn
です。これらの関数では、いくつかの異なった数値生成アルゴリズムの 1 つを使用できます。
d = gpuDevice; fprintf("This example is run on a " + d.Name + " GPU.")
This example is run on a GeForce GTX 1080 GPU.
GPU 乱数発生器の検出
関数parallel.gpu.RandStream.list
では、使用可能な発生器の短い説明が提示されます。
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
): 1999 年に導入されたこの発生器は、広くテストされ使用されてきました。Philox (別名 Philox4x32_10): 2011 年に導入された新しい発生器で、特に GPU のような並列性の高いシステムにおいて高度なパフォーマンスを発揮するよう設計されています。
Threefry (別名 Threefry4x64_20): 2011 年に導入された新しい発生器で、広くテストされ使用されている既存の ThreeFish 暗号アルゴリズムを基にしています。この発生器は、GPU のような並列性の高いシステムにおいて優れたパフォーマンスを発揮するよう設計されました。これが GPU 計算の既定の発生器です。
GPU で使用できる 3 つの発生器は、MATLAB® での CPU 上の用途にも使用できます。MATLAB® の発生器は同じ名前をもち、初期状態が同じであれば同一の結果を生成します。これは、GPU と CPU で同じ一連の乱数を生成させる場合に便利です。詳細については、GPU 上の乱数ストリームを参照してください。
これらの発生器はすべて、標準の TestU01 テスト スイートをパスします [1]。
既定の乱数発生器の変更
関数gpurng
は、GPU の発生器の状態を保存し、リセットすることができます。gpurng
を使用して、提供されている異なった発生器間の切り替えも可能です。発生器を変更する前に既存の状態を保存して、テスト終了後に復元できるようにします。
oldState = gpurng;
gpurng(0, "Philox4x32-10");
disp(gpurng)
Type: 'philox' Seed: 0 State: [7×1 uint32]
一様分布する乱数の生成
一様分布する乱数を GPU で生成するには、rand
またはrandi
のいずれかを使用します。パフォーマンスに関して、これら 2 つの関数は非常に似通った動作をしますが、ここでは rand
のみを測定します。gputimeit
を使用してパフォーマンスを測定することで、この関数を自動的に何度も呼び出して同期または他の時間測定の問題を的確に扱い、正確な時間測定結果を確保します。
異なる発生器のパフォーマンスを比較するために、各発生器について rand
を使用して、GPU 上で大量の乱数を生成します。次のコードで、rand
は 個の乱数を生成し、各発生器について 100 回呼び出されています。各実行時間は、gputimeit
を使用して測定されています。大量の乱数サンプルを生成するには、数分かかる場合があります。結果は、GPU で使用できる 3 つの乱数発生器のパフォーマンスの比較を示しています。
generators = ["Philox","Threefry","CombRecursive"]; gputimesU = nan(100,3); for g=1:numel(generators) % Set the generator gpurng(0, generators{g}); % Perform calculation 100 times, timing the generator for rep=1:100 gputimesU(rep,g) = gputimeit(@() rand(10000,1000,"gpuArray")); end end
% Plot the results figure hold on histogram(gputimesU(:,1),"BinWidth",1e-4); histogram(gputimesU(:,2),"BinWidth",1e-4); histogram(gputimesU(:,3),"BinWidth",1e-4) legend(generators) xlabel("Time to generate 10^7 random numbers (sec)") ylabel("Frequency") title("Generating samples in U(0,1) using " + d.Name) hold off
より新しい発生器である Threefry と Philox のパフォーマンスは同程度です。いずれも CombRecursive より高速です。
正規分布した乱数の生成
多くのシミュレーションでは、正規分布からサンプルをとった摂動を利用します。一様分布のテストと同様に、randn
を使用して、正規分布乱数を生成する場合の 3 つの発生器のパフォーマンスを比較します。大量の乱数サンプルを生成するには、数分かかる場合があります。
generators = ["Philox","Threefry","CombRecursive"]; gputimesN = nan(100,3); for g=1:numel(generators) % Set the generator gpurng(0, generators{g}); % Perform calculation 100 times, timing the generator for rep=1:100 gputimesN(rep,g) = gputimeit(@() randn(10000,1000,"gpuArray")); end end
% Plot the results figure hold on histogram(gputimesN(:,1),"BinWidth",1e-4); histogram(gputimesN(:,2),"BinWidth",1e-4) histogram(gputimesN(:,3),"BinWidth",1e-4) legend(generators) xlabel("Time to generate 10^7 random numbers (sec)") ylabel("Frequency") title("Generating samples in N(0,1) using " + d.Name) hold off
ここでもまた、結果は Threefry と Philox の各発生器のパフォーマンスが同程度で、いずれも CombRecursive より著しく高速であることを示しています。正規分布した値の生成に追加処理が必要なため、各発生器で値の生成速度が低下します。
完了する前に、発生器を元の状態に復元します。
gpurng(oldState);
まとめ
この例では、3 つの GPU 乱数発生器を比較しました。厳密な結果は、GPU とコンピューティング プラットフォームに応じて異なります。それぞれの発生器に利点 (+
) と注意点 (-
) があります。
Threefry
(
+
) 高速(
+
) 有名で十分にテストされた Threefish アルゴリズムに基づく(
-
) 実際の使用では比較的新しい
Philox
(
+
) 高速(
-
) 実際の使用では比較的新しい
CombRecursive
(
+
) 実際の使用で長い実績(
-
) 最も低速
参考文献
[1] L'Ecuyer, P., and R. Simard."TestU01: A C library for empirical testing of random number generators."ACM Transactions on Mathematical Software. Vol. 33, No. 4, 2007, article 22.
参考
gpurng
| parallel.gpu.RandStream