5

我设置了以下最小示例:

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. 它总是会可靠地产生相同的随机数,因为我rng在 for 循环中设置了种子。

如果我现在换成forparfor我会得到不同的结果!尽管它们也将始终是可重现的。

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

4

4 回答 4

6

好的,我刚刚找到原因:

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

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

parfor i = 1:10
    rng(randseedoffset+i, 'twister');
    t{i} = random('unid', 1000);
end
于 2013-06-14T14:55:34.673 回答
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
于 2016-01-25T14:29:17.810 回答
0

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

您得到不同结果的原因是由于这些数字应保持的统计属性,算法是不同的。在并行池中,MATLAB 将算法设置为“combRecursive”,并在每个工作人员上设置不同的子流,所以对于随机数,你很高兴。此外,parfor循环不保证——

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

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

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{:}]'; 
于 2015-08-26T19:01:05.083 回答
0

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

在 parfor 循环中,您无法控制迭代执行的顺序,也无法控制哪个工作人员运行哪些迭代。因此,即使您重置随机数生成器,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

于 2021-01-11T04:34:41.763 回答