2

我在 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

为了演示该问题,运行此代码后,numbers{1}、numbers{2}、numbers{3} 和 numbers{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

我想知道是否有人可以想到解决此问题的方法。我想一定有我可以做的事情,因为当我使用正常的随机数字流时不会出现问题。

我应该提到,我不可能利用准随机数流的“跳过”或“跳跃”属性。原因是我在并行运行的更大的 MATLAB 程序中使用了上面的代码片段......

4

1 回答 1

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 MATLAB 每次调用 qrand 时都会通过(虚拟)列表工作。

但是在 parfor 中,所有需要的变量、函数等的副本都会传递给每个 worker。结果,每个工作人员都会获得一个重复的、预先确定的准随机数流,从而在每个工作人员身上产生相同的样本流。顺便说一句,这并不意味着所有数字{i} 都将具有相同的值。对于大于并行工作程序(机器核心)数量的 parfor 循环范围,多个循环迭代将发生在同一个工作程序上,因此共享相同的非重复 qrandstream。在我的两台核心机器上,您的 4 次迭代示例代码通过numbers{1}==numbers{4}numbers{2}==numbers{3}

于 2012-04-06T14:15:22.593 回答