MATLAB:如何在parfor中设置随机种子以产生与序列相同的结果?

时间:2013-06-14 14:43:04

标签: matlab random parallel-processing parfor

我设置了以下最小例子:

rng(0);

randseedoffset = random('unid', 10^5) + 1;

t = cell(10,1);
for i = 1:10
    rng(randseedoffset+i);
    t{i} = random('unid', 1000);
end

disp(t);

这将生成10个随机数并将其存储在t中。它将始终可靠地生成相同的随机数,因为我在for循环中使用rng设置种子。

如果我现在将for更改为parfor,我会得到不同的结果! 虽然它们也总是可以重现的。

我想用parfor加速我的代码,并且仍然获得与...相同的完全相同的随机数

4 个答案:

答案 0 :(得分:6)

好的,我刚刚找到原因:

MATLAB支持不同的随机数生成算法。 虽然在当前版本的通常设置中,这是Mersenne Twister。 当你进入parfor循环时,这会改变他们所谓的“组合递归方法”。

可以通过在循环中明确地将类型设置为'twister'来解决问题:

parfor i = 1:10
    rng(randseedoffset+i, 'twister');
    t{i} = random('unid', 1000);
end

答案 1 :(得分:0)

我觉得有必要详细说明这一点。不要在parfor循环中重置种子,并且不要并行使用Mersenne Twister算法(您将获得较差的统计独立性结果)。

您得到不同结果的原因是因为算法因这些数字应该维护的统计属性而不同。在并行池中,MATLAB将算法设置为'combRecursive'并在每个worker上设置不同的子流,因此对于随机数,您可以使用它。此外,parfor循环不保证 -

  • 循环的顺序,
  • 哪些工人将执行每件作品,或
  • 对每个工作人员执行了多少次迭代。

因此,即使每个工作人员具有相同的状态,在parfor循环中生成随机数通常也不会返回相同的随机数。而是使用combRecursive算法的子流建立一个RandStream,在spmd块中的每个worker上设置全局流,然后在spmd块中的每个worker上生成数字:

p = gcp; % Get or open a pool

numWork = p.NumWorkers; % Get the number of workers

s = RandStream.create('mrg32k3a','NumStreams',numWork,...
    'CellOutput',true); % create numWork independent streams

n = 200; % number of values to generate on each worker
spmd
    RandStream.setGlobalStream(s{labindex});
    x = rand(1,n);
end

% I generate row vectors as the Composite matrix x will return a 
% comma-separated list using the syntax, x{:}, which can then be 
% concatenated into a single vector:
randVals2 = [x{:}]'; 

答案 2 :(得分:0)

试试这个:

p = gcp; % Get or open a pool

numWork = p.NumWorkers; % Get the number of workers

stream = RandStream('mrg32k3a','seed',mydata.seed);
RandStream.setGlobalStream(stream);

% s = RandStream.create('mrg32k3a','NumStreams',numWork,'CellOutput',true,'Seed',mydata.seed); % create numWork independent streams

n = 200; % number of values to generate on each worker
spmd
RandStream.setGlobalStream(stream);
x = rand(1,n);
end

答案 3 :(得分:0)

集群中从事同一工作的每个工作人员都有一个独立的随机数生成器流。因此,默认情况下,池中的每个 worker 以及 parfor 循环中的每次迭代都有一组唯一的、独立的随机数。 parfor 循环的后续运行生成不同的数字。

在 parfor 循环中,您无法控制迭代执行的顺序,也无法控制哪个 worker 运行哪些迭代。因此,即使您重置随机数生成器,parfor 循环也可以以不同的顺序生成相同的值。

要在每次循环运行时在 parfor 循环中重现同一组随机数,您必须通过为每次迭代分配特定子流来控制随机生成。

首先,使用支持子流的生成器创建您要使用的流。将流创建为 parallel.pool.Constant 允许所有工作人员访问该流。

sc = parallel.pool.Constant(RandStream('Threefry'))

在parfor-loop内部,可以通过循环索引设置子流索引。这确保每次迭代都使用其特定的随机数集,而不管哪个工作人员运行该迭代或运行哪个序列迭代。

r = zeros(1,16);
parfor i = 1:16
    stream = sc.Value;        % Extract the stream from the Constant
    stream.Substream = i;
    r(i) = rand(stream);
end

https://www.mathworks.com/help/parallel-computing/repeat-random-numbers-in-parfor-loops.html