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 つの方法があります。
変更後のストリームを最初の入力引数として rand、randn、randi、randperm などの関数に渡すことができます。この方法では、各関数呼び出しで正しいサブストリームが確実に使用されるようになります。
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