parfor循环中的matlab随机数生成
matlab random number generation in parfor loop
我想为循环和 parfor 循环生成相同的正态随机数。根据 MATLAB 文档,我尝试了三种不同的方法:
方法一:使用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。
我推断您担心的是 for
和 parfor
循环的伪随机生成数字不匹配。然而,这是预期的行为。您使用了 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
使用此代码,samps
和 pf_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 特别是很好的并行生成器。
我想为循环和 parfor 循环生成相同的正态随机数。根据 MATLAB 文档,我尝试了三种不同的方法:
方法一:使用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。
我推断您担心的是 for
和 parfor
循环的伪随机生成数字不匹配。然而,这是预期的行为。您使用了 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
使用此代码,samps
和 pf_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 特别是很好的并行生成器。