メインコンテンツ

parfor ループでの乱数の繰り返し

この例では、反復ごとに特定のサブストリームを代入することで、parfor ループ内の乱数発生を制御する方法を説明します。

ワーカー上の乱数ストリームの制御で説明しているように、同じジョブを処理しているクラスターの各ワーカーには独立した乱数発生器ストリームがあります。既定では、プールの各ワーカーおよび parfor ループの各反復は一意の独立した一連の乱数をもっています。その後の parfor ループの実行によって異なる数が生成されます。

parfor ループでは、反復を実行するシーケンスや、どのワーカーでどの反復を実行するかを制御することはできません。そのため、乱数発生器をリセットしても、parfor ループは異なるシーケンスで同じ値を生成できます。

parfor ループを実行するたびにそのループ内で同じ一連の乱数を再生成するには、各反復用に特定のサブストリームを割り当てることによって乱数発生を制御しなければなりません。

サブストリームをサポートしている発生器を使用して、使用するストリームを作成します。ストリームを parallel.pool.Constant として作成することで、すべてのワーカーがストリームにアクセスできるようになります。サブストリームをサポートしている発生器のリストについては、乱数発生器の選択を参照してください。

sc = parallel.pool.Constant(RandStream("Threefry"))
sc = 
 Constant with properties: 

                Value: [1x1 RandStream]

parfor ループ内で、ループ インデックスに基づいてサブストリーム インデックスを設定できます。これにより、反復を実行するワーカーや、反復が実行される順序に関係なく、各反復は個別の再現可能な一連の乱数を必ず使用するようになります。

ストリームを使用してワーカー上で乱数を生成するには、2 つの方法があります。

変更後のストリームを最初の入力引数として randrandnrandirandperm などの関数に渡すことができます。この方法では、各関数呼び出しで正しいサブストリームが確実に使用されるようになります。

r1 = zeros(1,10);
parfor idx = 1:10
    % Extract the stream from the Constant
    stream = sc.Value;
    stream.Substream = idx;
    r1(idx) = rand(stream,1);
end
disp(r1)
    0.3640    0.8645    0.0440    0.7564    0.5323    0.8075    0.2145    0.9128    0.4057    0.0581

ワーカー上のグローバル乱数ストリームを変更後のストリームに設定することもできます。この方法では、以降のすべての乱数発生呼び出しで、割り当てられたストリームを自動的に使用できるようになります。

r2 = zeros(1,10);
parfor idx = 1:10
    % Extract the stream from the Constant
    stream = sc.Value;        
    stream.Substream = idx;

    % Save previous global stream
    oldGlobalStream = RandStream.setGlobalStream(stream);
    r2(idx) = rand(1);

    % Restore the previous global stream
    RandStream.setGlobalStream(oldGlobalStream);
end
disp(r2)
    0.3640    0.8645    0.0440    0.7564    0.5323    0.8075    0.2145    0.9128    0.4057    0.0581

各オプションで生成される乱数がそれぞれの反復で同じであることを確認します。

isequal(r1,r2)
ans = logical
   1

参考

|

トピック