Воспроизводимые результаты при создании случайных матриц при параллельных вызовах в MATLAB

Я хочу создать несколько случайных матриц, но они действительно большие, чтобы вписаться в память, поэтому я хотел бы найти способ воспроизвести их на разных компьютерах, так что, когда мне нужно отправить их на другую машину, Мне просто нужно отправить код. Вот как я хочу это сделать:

num_of_iters = 10;
K = 200;
for iter = 1:num_of_iters
    parfor j = 1:K
        R = make_random_R(iter,j,.....);
        % Do something
    end
end

То, что меня беспокоит, это петра парфоров, мне нужно иметь возможность воспроизводить случайные матрицы независимо от того, какой порядок индексов в parfor. Поэтому я решил использовать поток MATLAB для этого:

  • Сохранить глобальный поток
  • Создайте новый поток, установите семя и соответствующий подпоток (который зависит от iter и j)
  • Сделайте математику
  • Вернуть глобальный поток

Вот мой код (переменные n, p, R_type управляют тем, как производятся случайные матрицы, но они не важны, а K - та же переменная, что и предыдущая, мне нужна она в строке substream_id = (iter - 1) * K + j;):

function [R] = make_random_R(iter,j,n,K,p,R_type)
% Data as code
% R_type: 'posneg' or 'normdist'
% 1 <= iter <= 100
% 1 <= j <= K
% K: Number of classifiers
% n: Number of observations

assert(strcmp(R_type,'posneg') || strcmp(R_type,'normdist'),'R_type must be posneg or normdist');
assert(iter >= 1,'Error: iter >= 1 not satisfied');
assert((1 <= j) && (j <= K),'Error: 1 <= j <= K not satisfied');
assert(K > 0,'Error: K > 0 not satisfied');

globalStream = RandStream.getGlobalStream;
globalState =  globalStream.State;

stream=RandStream('mlfg6331_64','Seed',1);
substream_id = (iter - 1) * K + j;
stream.Substream = substream_id;
RandStream.setGlobalStream(stream);

switch R_type
    case 'posneg'        
        q0=ceil(2*log(n)/0.25^2)+1;
        if (q0 < p)
            q = q0;
        else
            q = ceil(p/2);
        end
        R = randi([0 1],p,q);
        R(R == 0) = -1;
    case 'normdist'        
        q = 2*ceil(log2(p));
        R = normrnd(0,1,[p,q]);    
end
RandStream.setGlobalStream(globalStream);
globalStream.State = globalState;
end

Пробовал какой-то код, и вот он:

>> iter = 2;
>> j = 3;
>> n=100;
>> K=10;
>> p=6;
>> R_type = 'normdist';
>> for j=1:K
j
make_ran
>> parfor j=1:K
j
make_random_R(iter,j,n,K,p,R_type)
end
Starting parallel pool (parpool) using the 'local' profile ... connected to 4 workers.

ans =

     7


ans =

   -0.3660    0.8816    1.1754   -0.4987   -1.8612   -0.3683
    0.9504   -0.3067   -0.5156   -0.2383   -1.1661    0.3622
    2.0743   -0.4195    0.5021    0.3954    0.2415   -0.4552
   -0.0474   -0.1645   -0.1725   -0.4938   -0.2559    0.2188
    1.0735    0.3660    0.1043    0.4403   -0.3166    1.1241
   -1.0421   -1.4528   -0.4976   -0.7166   -1.1328   -2.0260


ans =

     2


ans =

   -1.6629    0.0213   -1.8138   -0.4375    0.3575   -0.0353
    0.6653   -1.2662   -0.3977   -0.6540   -1.2131    0.4858
    0.3421    1.1266   -0.6066   -1.2095    1.5496   -0.9341
    0.2145    0.7192   -2.2087    0.7597   -0.0110   -1.1282
   -0.3511   -0.7305   -0.1143    0.0242    0.2431   -0.8612
    0.5875    1.2665   -2.1943   -0.4879    0.0120   -1.1539


ans =

     1


ans =

   -0.5300    2.4077   -0.3478    1.8695   -1.1327   -1.0734
   -0.2540   -1.1265    0.3152    0.4265    1.2777    0.0959
    0.5005   -0.7557    0.6194    1.5873    0.0961   -1.9216
    0.7275    0.5420   -0.6237   -0.2228    0.8915    0.4644
    0.8131   -0.1492    0.9232    0.8410   -0.0637    2.1163
   -1.1995    0.2338   -1.3726    0.1604   -0.1855    1.3826


ans =

     8


ans =

   -0.5146    2.2106    2.7200   -1.2136    1.0004    1.3089
    0.7225    0.2746   -0.8798    0.2978   -0.8490    1.6744
    1.1998   -0.0363    1.9105   -0.7747   -0.8707   -0.6823
    0.6801    1.3194   -0.0685    0.5944    1.5078   -1.6821
    0.0876    1.2150   -0.0747    0.0324   -1.1552    0.0966
   -0.0624   -0.3874   -0.5356    0.6353    1.4090   -1.1014


ans =

     6


ans =

    0.5866   -1.0222   -0.2168    0.8582    1.4360    0.0699
    2.0677   -0.4740   -0.8763    1.7827    0.1930   -1.2167
   -0.3941   -0.5441    0.3719   -0.0609    0.7138   -1.0920
    0.3622   -0.0459   -0.0221    0.2030   -0.7695   -0.8963
   -0.1986   -0.2560    0.6666    0.4831   -1.2028   -0.9423
    0.1656    1.2006   -1.1131    0.7704   -0.6906   -1.3143


ans =

     5


ans =

   -0.5782   -0.3634    1.5381   -1.3173   -0.9493    0.8480
    1.5921   -0.4069    0.7795   -0.3390   -0.1071    0.4201
   -0.0184    0.2865   -0.1139   -0.1171    0.2288    0.5511
    0.1787    0.7583    0.3994    1.0457    0.3291   -0.9150
    0.3641   -0.6420   -0.2096    0.7761    0.4022   -0.7478
    0.1165    0.7142    0.7029   -1.1195    0.0905    0.6810


ans =

     4


ans =

    0.1246   -0.3173    0.8068    0.6485   -0.8572    0.2275
    0.3674   -0.0507   -0.9196    0.6161   -0.5821   -0.4291
   -1.0142   -1.1614   -2.5438    1.5915    2.0356    0.4535
   -0.2111   -0.3974    0.0376    0.3825   -1.9702    1.5318
   -0.3890    0.9210   -0.0635    0.3248    1.8666   -0.0160
    1.3908   -0.7204   -0.6772   -0.0713    0.0569    0.5929


ans =

     3


ans =

   -0.1602    0.6891    0.4725    0.0277   -2.0510   -2.2440
   -0.7497    1.8225   -0.4433    0.4090    0.9021   -1.6683
    0.0659    0.3909    0.2043    0.9065    1.4630    0.3091
   -0.3886    0.6715   -0.9742   -0.5468    0.2890    0.5625
   -0.4558    0.4770   -0.1888   -0.6504    0.3281    1.3767
    0.3983    0.5834    0.9360    0.8604   -0.9776    0.6755


ans =

    10


ans =

   -0.4843   -0.4512    0.7544    0.7585   -0.4417   -0.0208
    1.8537   -1.6935   -2.7067   -0.5077    0.9616   -1.7904
   -1.6943   -1.0988    0.1208   -0.8100    1.8778    1.1654
    1.1759   -0.7087   -1.2673   -0.1381   -0.0710    0.5343
    0.2589   -0.5128   -0.3970    0.6737    0.8097    2.7024
   -0.8933    0.2810    0.8117   -0.5428   -0.8782    1.1746


ans =

     9


ans =

    0.0254   -0.7993    1.5164    1.2921   -1.1013    1.8556
   -0.6280    0.9374   -0.1962    0.1685   -0.5079    0.4333
   -0.3962   -0.9977    0.6971   -1.0310   -1.1997   -2.1391
    0.7179    1.0177   -0.8874   -0.6732    0.7295    1.4448
   -1.1793   -1.3210    1.5292    0.2280    1.9337    1.0901
   -0.0926    0.1798   -1.1740    0.3447    2.4578    0.4170

Интересно, правильный ли код и сохраняет ли он состояние глобального потока после вызова функции? Пожалуйста, помогите мне, большое спасибо.

Ответы

Ответ 1

MATLAB генерирует случайное число из функции "KNOWN", но "complex", поэтому вы можете генерировать такую ​​же последовательность случайных чисел! номер.

для этого вы должны использовать функцию "rng"
установите rng по умолчанию, чтобы reset генерирование случайных чисел.

rng('default');
rand(1,5)
ans=
0.8147  0.9058  0.1270  0.9134  0.6324

то, если вы хотите воспроизвести эту последовательность случайных чисел, вы можете написать:

rng('default');
rand(1,5)
ans=
    0.8147  0.9058  0.1270  0.9134  0.6324

Другим способом является получение/установка семени для генерации случайных чисел:

s=rng;
rand(1,5)
ans= 0.0975  0.2785  0.5469  0.9575  0.9649

и воспроизвести один и тот же seq.

rng(s);
rand(1,5)
ans=
     0.0975  0.2785  0.5469  0.9575  0.9649

noe, что сама "rng" является богатой функцией, и вы можете изучить ее больше в документации по Matlab.

(Я надеюсь, что правильно понял вопрос)

ответить на комментарий от @m7913d

"По умолчанию клиент MATLAB® и сотрудники MATLAB используют разные генераторы случайных чисел, даже если рабочие являются частью локального кластер на той же машине с клиентом. Для клиента default - это генератор Mersenne Twister (" twister "), а для работниками по умолчанию является комбинированный многорекурсивный генератор (" CombRecursive "или" mrg32k3a "). Если необходимо создать тот же поток чисел в клиенте и рабочих, вы можете установить его на совпадают с другим".

ясно, что работники matlab используют другую функцию (для генерации случайных чисел) из самого Matlab, поэтому вы можете также установить функцию по умолчанию в функцию "rng" ,

rng(5,'twister') % for using twister method to generate random number

для получения дополнительной информации попробуйте этот документ из Matlab

чтобы показать, что вы можете воспроизвести последовательность случайных чисел в parfor:

>> parfor i=1:3
rng(3,'twister');
rand(1,5)
i
end

ans =

    0.5508    0.7081    0.2909    0.5108    0.8929


ans =

     3


ans =

    0.5508    0.7081    0.2909    0.5108    0.8929


ans =

     1


ans =

    0.5508    0.7081    0.2909    0.5108    0.8929


ans =

     2

важная часть из комментариев:

о "клиентах", как я уже сказал, прежде чем Matlab использует функцию по умолчанию для всего вашего рабочего клиента, поэтому результаты полностью воспроизводимы, просто функция по умолчанию для создания случайных чисел отличается от собственной функции по умолчанию Matlab. это не проблема, вы можете установить функцию по умолчанию в matlab и ее рабочих с помощью функции rng (последний пример в ответе)


об использовании глобального потока, не имеет смысла использовать глобальный поток, вы должны установить начальное значение с помощью функции rng для получения одинаковых воспроизводимых результатов, глобальный поток просто укажет, какую функцию вы используете для генерации случайных чисел, Matlab имеет около 6 функций для выполнения этой задачи, но если у вас есть собственная функция, вы можете установить ее в глобальном потоке, а затем снова вы должны использовать функцию rng для получения такой же последовательности каждый раз, когда вы генерируете случайные числа