我遇到了在parfor循环中生成混乱的准蒙特卡罗数字的问题。
问题在于,当我在parfor循环中生成多组这些数字时,每组中的数字最终都是相同的。我在下面提供了一个非常简单的例子。
D = 3;
M = 1000;
numbers = cell(1,4);
mystream = qrandstream(scramble(sobolset(D),'MatousekAffineOwen'));
myfun = @(x) qrand(mystream,x);
parfor i = 1:4
numbers{i} = myfun(M);
end
为了演示此问题,运行此代码后,数字{1},数字{2},数字{3}和数字{4}中的数字相同:
>>numbers{1}(1:3,:)
ans =
0.76 0.05 0.77
0.33 0.96 0.23
0.60 0.72 0.52
>> numbers{2}(1:3,:)
ans =
0.76 0.05 0.77
0.33 0.96 0.23
0.60 0.72 0.52
我想知道是否有人能想到解决这个问题的方法。我认为必须有一些我可以做的事情,因为当我使用普通的随机数字流时问题不会发生。
我应该提到,我不可能利用准随机数流的'Skip'或'Leap'属性。原因是我在一个更大的MATLAB程序中使用上面的代码片段,我并行运行...
答案 0 :(得分:4)
您需要单独调用以对每个并行工作进行加扰。这可以通过在parfor循环中移动qrandstream相关语句来完成,如下所示:
D = 3;
M = 1000;
numbers = cell(1,4);
parfor i = 1:4
mystream = qrandstream(scramble(sobolset(D),'MatousekAffineOwen'));
myfun = @(x) qrand(mystream,x);
numbers{i} = myfun(M);
end
为什么: 尽管MatousekAffineOwen确实具有随机加扰顺序,但MATLAB将准随机序列视为巨大的预定义数组,并且每次需要新样本时都会动态计算样本数据。加扰改变了这个顺序,但是一旦调用了加扰,qrandstream对象的行为就好像它发生了一次。之后,qrandstream是一个确定的数字流。在非并行代码中(或者如果你在没有首先启用matlabpool的情况下使用parfor),这个设置可以在单个qrandstream b / c中正常工作。每次调用qrand时,MATLAB都会在(虚拟)列表中继续工作。
但是在parfor中,所有需要的变量,函数等的副本都会传递给每个worker。结果,每个工作人员获得一个重复的,预先确定的准随机数流,从而在每个工人上产生相同的样本流。顺便说一下,这并不意味着所有数字{i}都具有相同的值。对于大于并行工作者(机器核心)数量的parfor循环范围,将在同一工作程序上进行多循环迭代,从而共享相同的非重复qrandstream。在我的两个核心机器上,您的4个迭代示例代码在numbers{1}==numbers{4}
和numbers{2}==numbers{3}