Воспроизводимые результаты при создании случайных матриц при параллельных вызовах в 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 для получения такой же последовательности каждый раз, когда вы генерируете случайные числа