parfor循环中的matlab随机数生成

matlab random number generation in parfor loop

我想为循环和 parfor 循环生成相同的正态随机数。根据 MA​​TLAB 文档,我尝试了三种不同的方法:

方法一:使用rng(seed, 'twister')

N = 1;

for ind = 1:10
    rng(ind, 'twister')
    samps(ind) = normrnd(0,1,N,1);
end

plot(samps); hold on

parfor ind = 1:10
    rng(ind, 'twister')
    samps(ind) = normrnd(0,1,N,1);
end

scatter(1:length(samps), samps)
legend({'using for loop', 'using parfor loop'})

方法二:使用RandStream方法

N = 1;
 
sc = parallel.pool.Constant(RandStream('Threefry'));
for ind = 1:10
    stream = sc.Value;
    stream.Substream = ind;
    samps(ind) = normrnd(0,1,N,1);
end

plot(samps); hold on

sc = parallel.pool.Constant(RandStream('Threefry'));
parfor ind = 1:10
       stream = sc.Value;
       stream.Substream = ind;
       samps(ind) = normrnd(0,1,N,1);
end

scatter(1:length(samps), samps)
legend({'using for loop', 'using parfor loop'})

方法三:使用另一种RandStream方法

N = 1;
 
stream = RandStream('mrg32k3a');
for ind = 1:10
    stream.Substream = ind;
    samps(ind) = normrnd(0,1,N,1);
end

plot(samps); hold on

stream = RandStream('mrg32k3a');
parfor ind = 1:10
       set(stream,'Substream',ind);
       samps(ind) = normrnd(0,1,N,1);
end

scatter(1:length(samps), samps)
legend({'using for loop', 'using parfor loop'})

我的问题是为什么后两种方法不起作用。如果我正确理解 MATLAB 文档,它们应该可以工作。另外,使用 rng(seed, 'twister') 方法和不同的种子来产生统计上独立的样本有什么问题吗?

编辑: 这是我使用的 MATLAB 文档的 link

我推断您担心的是 forparfor 循环的伪随机生成数字不匹配。然而,这是预期的行为。您使用了 MRG32K3A 伪随机算法,该算法“不保证使用相同参数的固定种子和对 mrg32k3a.RandomState 方法的固定系列调用将始终产生相同的结果。” Source.

看来一切正常。

当您执行 normrnd(0,1,N,1) 时,您不是使用 stream 生成随机数,而是使用默认 RNG。相反,请使用 randn(stream,N,1),请参见 the documentation

据我所知,normrnd 和统计和机器学习工具箱中的其他生成器始终使用默认 RNG,不能使用自定义 RandStream 对象。

正如@Cris 指出的那样,normrnd 使用当前的全局流。以下是如何使您的第三个案例在客户端和工作人员之间匹配 - 您需要明确设置全局流。 (请注意,我也在使用它后立即还原全局流)。

N = 1;

stream = RandStream('mrg32k3a');
for ind = 1:10
    stream.Substream = ind;
    prev = RandStream.setGlobalStream(stream);
    samps(ind) = normrnd(0,1,N,1);
    RandStream.setGlobalStream(prev);
end

stream = RandStream('mrg32k3a');
parfor ind = 1:10
    set(stream,'Substream',ind);
    prev = RandStream.setGlobalStream(stream);
    pf_samps(ind) = normrnd(0,1,N,1);
    RandStream.setGlobalStream(prev);
end

使用此代码,sampspf_samps 是相同的。

此外,您不应该并行使用“twister”,因为通过以这种方式设置种子获得的随机样本的质量不如使用“并行”生成器(如 mrg32k3a)。 (我不是专家,但我的理解是 twister“种子”值不能像 streams/substreams 那样 select 统计独立的样本序列)

在最新版本的 MATLAB 中,可以使用更快的支持多个流的生成器。请参阅文档 https://www.mathworks.com/help/matlab/math/creating-and-controlling-a-random-number-stream.html#brvku_2 。 Philox 和 Threefry 特别是很好的并行生成器。