Using rng('shuffle') function in parallel computing - matlab

I have a parfor loop for parallel computing in Matlab. I want have different random numbers in every calling of these parforloops on 8 workers. If i don't use rng('shuffle') function i have same random number for randperm(10). In this case my code run rng('shuffle') function before randperm at the same time in all workers. Have i different random numbers in this condition? when I see randperm outputs in parfor loop, Some of these outputs are same !
I need save rng before rng('shuffle') and use something likes rng(saved_rng) after ending parallel loop?
We have this in Matlab help :
Note Because rng('shuffle') seeds the random number generator based
on the current time, you should not use this command to set the random
number stream on different workers if you want to assure independent
streams. This is especially true when the command is sent to multiple
workers simultaneously, such as inside a parfor, spmd, or a
communicating job. For independent streams on the workers, use the
default behavior; or if that is not sufficient for your needs,
consider using a unique substream on each worker.
So what should i do? Have I different random numbers if i delete rng? I have two versions of these codes. One of them is calculation with parfor and other using for loop, Can i remove shuffle from for loop? I have different random numbers in this condition?
Thanks.
Ps.
I can have these structures:
parfor I=1:X
xx = randperm(10)
end
parfor I=1:X
rng('shuffle');
xx = randperm(10)
end
rng('shuffle');
parfor I=1:X
xx = randperm(10)
end
I want have different random numbers from randperm function. How can I do that? for for structure i need shuffle function (without it the random numbers are the same) but when i add it to parfor some random outputs of randperm are the same !

To do this properly, you need to choose an RNG algorithm that supports parallel substreams (in other words, you can split up the random stream into substreams, and each of the substreams still has the right statistical properties that you want from a random stream).
The default RNG algorithm (Mersenne Twister, or mt19937ar) does not support parallel substreams, but MATLAB supports two algorithms that do (the multiplicative lagged Fibonacci generator mlfg6331_64 and the combined multiple recursive generator mrg32k3a).
For example:
s = RandStream.create('mrg32k3a','NumStreams',4,'Seed','shuffle','CellOutput',true)
s is now a cell array of random number substreams. All have the same seed, and you can record s{1}.Seed for reproducibility if you want.
Now, you can call rand(s{1}) (or randn(s{1})) to generate random numbers from stream 1, and so on. Reset a stream to its initial configuration with reset(s{1}), and you should find that each stream is separately reproducible.
Each worker can then generate random numbers in a way that is still statistically sound, and reproducible even in parallel:
parfor i = 1:4
rand(s{i})
end
For more information, look in the documentation for Statistics Toolbox under Speed up Statistical Computations. There are a few articles in there that take you through all the complicated details. If you don't have Statistics Toolbox, the documentation is online on MathWorks website.

Related

Using multiple GPUs in Matlab

I am using Matlab and I want to utilize my 2 GPUs
I have a big matrix that does not fit into 1 GPU but half of the matrix fits into 1 GPU. So I want to chop the matrix into half and let each one of my 2 GPUs work on half of the matrix. What I did is the following
try
parpool('local',gpuDeviceCount)
end
spmd
gpuDevice
end
dp = 0.00001;
R = zeros(1,2);
parfor k=1:1:2
if k==1
M = gpuArray([dp:2*dp:10])
else
M = gpuArray([2*dp:2*dp:10])
end
R(k) = arrayfun(#(x) myfun,M);
end
My question is: how can I know that I indeed create 2 M vector (they are different) on each of my GPU? Is there a single built-in function to show this? Why we need the spmd gpuDevice end? Currently, I can feel that in terms of speed, the parfor seems to be 2 times faster than a regular for. But how can I confirm that indeed each GPU stores a different M? I don't know if it actually copied gpuArray([dp:2*dp:10]) twice and gpuArray([2*dp:2*dp:10]) twice?
And after this block of code is finished, I find that my vector M does not appear in the workspace. But other variables defined outside the parfor code are still in the workspace. If I just use for instead of parfor (but with a smaller size M so that it can fit into 1 GPU), after the for loop, the vector M is in the workspace and its type is gpuArray. Why if I use parfor, then after the parfor loop, those variables defined within the parfor loop are gone?
To answer some of your questions.
M is not present after the end of the for loop, because it is a local variable, they are present only on the worker. To make sure your code works as intended, I would suggest to close the parallel computing pool (leaving the parfor in your code) and then use the debugger to set a breakpoint and check M. This way you can check if your code does everything right and then enable the parallel pool. In case you need M for later computations, you have to make it sliced variable of it. Considering the constraints (see same link above), you can either use a 2d matrix or cell array which you initialize outside the parfor.
About the use of gpuDevice, according to the documentation it is not required but "To identify which GPU each worker is using, call gpuDevice inside an spmd block. The spmd block runs gpuDevice on every worker." Looks like you con't have to include it. source

Iterative running of K mean clustering algorithm inside clusters

I am using the k mean clustering function of MATLAB. I need to make K=2 every time till all the clusters match a defined condition.
If my data was
all_data=5*[3*rand(1000,1)+5,3*rand(1000,1)+5];
and I run
[IDX C]=kmeans(all_data,2);
I need to check the size of all_data(IDX==1) and all_data(IDX==2) every iteration and continue clustering with k=2 till the size of resulting cluster reach a specific value.
How can this be implemented in an iterative loop in MATLAB?

Generating similar but different vectors

I want to generate 100 vectors each of size 1x7. I have the following code currently, but when I plot it, it seems to be too linearly spaced. Is there a way to achieve a similar result only rougher?
P = randi([7 12],100,7)'/10.* repmat(randn(1,7),100,1)';
You may use different distribution for the randomizing part. randi is using uniformly distribution. You can use rng function to control random number generation. There are different generators like :
'twister' Mersenne Twister
'combRecursive' Combined Multiple Recursive
'multFibonacci' Multiplicative Lagged Fibonacci
as an example:
rng('shuffle')
rng(1);
A = rand(2,2);
rng(2);
B = rand(2,2);
it produces different numbers each time.
check this link for more info.

How to select randomly and fairly data in matlab

How can I select randomly and fairly some data from a dataset in matlab?
When we use the randperm function to select data, they are random and fair?
As you already suggested, selecting k uniformly random chosen rows out of n can be done with randperm, assuming you don't want duplication.
Example:
dataSet = rand(1000,4);
idx = randperm(size(dataSet,1),10)
dataSet(idx,:)
If you have the Statistics Toolbox, you can use randsample:
sample = randsample(data,k);
takes k values sampled uniformly at random, without replacement, from the values in the vector data. See above link for other options.
Equivalent code with randperm:
ind = randperm(numel(data));
sample = data(ind(1:k));
Yes, either of these approaches gives random samples, and yes, they are fair. I assume that by "fair" you mean "uniform": each entry of data is picked with the same probability.
anything that uses uniform distribution is "fair". because the output is supposed to be distributed randomly in an specific range. for example, rand function in matlab.

Random Number Generator Matlab with Multiple CPUs

I would like to write a matlab script which runs in parallel using multiple CPUS. The script should then print out a sequence of normally distributed random numbers. At the moment my script looks like this:
matlabpool close force local
clusterObj = parcluster;
matlabpool(clusterObj);
parfor K = 1:10
disp(randn)
end
It prints out a sequence of random numbers as expected. However, when I run the code again it, once again, prints out that exact same sequence of numbers. I do not want this. Each time I run my script it should print out an independently random sequence of numbers. Similarly, each time I start matlab, my script should, when I run it for the first time, print out a different sequence of 10 randomly generated numbers. How do I do this?
The solutions given so far are really not correct and may even be bad ideas. One should avoid setting the seed of the generator repeatedly. More importantly, two streams created separately with different seeds are not necessarily independent. This is addressed on this page that describes the creation of multiple streams:
For generator types that do not explicitly support independent streams, different seeds provide a method to create multiple streams. However, using a generator specifically designed for multiple independent streams is a better option, as the statistical properties across streams are better understood.
Thus, to guarantee the best statistical properties it is best to use a generator that supports substreams. Unfortunately, only the multiplicative lagged Fibonacci generator ('mlfg6331_64') and combined multiple recursive generator ('mrg32k3a') currently support this property. Compared to the default Mersenne Twister generator ('mt19937ar') these have significantly smaller periods. Here is how you would go about creating and using a random number stream with substreams:
seed = 1;
n = 10;
[stream{1:n}] = RandStream.create('mrg32k3a','NumStreams',n,'Seed',seed);
parfor k = 1:n
r = randn(stream{k},[1 3]);
disp(r);
end
Several things. You may get much better performance simply generating all of your random numbers in one call outside of your loop. This will also allow you to use the default Mersenne Twister algorithm, which may be important if, for example, you plan on doing large-scale Monte Carlo simulations. If you're going to be working with random numbers (and parallelization) I recommend that you spend some time reading the documentation for the RandStream class and going through the examples here.
Reset the random number generator used by rand, randi, and randn to its default startup settings, so that rand produces the same random numbers as if you restarted MATLABĀ®:
rng('default')
rand(1,5)
ans =
0.8147 0.9058 0.1270 0.9134 0.6324
Save the settings for the random number generator used by rand, randi, and randn, generate 5 values from rand, restore the settings, and repeat those values:
s = rng;
u1 = rand(1,5)
u1 =
0.0975 0.2785 0.5469 0.9575 0.9649
rng(s);
u2 = rand(1,5)
u2 =
0.0975 0.2785 0.5469 0.9575 0.9649
Reinitialize the random number generator used by rand, randi, and randn with a seed based on the current time. rand returns different values each time you do this. Note that it is usually not necessary to do this more than once per MATLAB session as it may affect the statistical properties of the random numbers MATLAB produces:
rng('shuffle');
rand(1,5);
I would try different generators:
rng('shuffle', generator)
rng('shuffle', generator) additionally specify the type of the random number generator used by rand, randi, and randn. The generator input is one of:
'twister' Mersenne Twister
'combRecursive' Combined Multiple Recursive
'multFibonacci' Multiplicative Lagged Fibonacci
'v5uniform' Legacy MATLABĀ® 5.0 uniform generator
'v5normal' Legacy MATLAB 5.0 normal generator
'v4' Legacy MATLAB 4.0 generator
You can set the random seed to a different value for each iteration:
matlabpool close force local
clusterObj = parcluster;
matlabpool(clusterObj);
rng('shuffle');
seeds = round(10000*abs(randn(10,1)));
parfor K = 1:10
rng(seeds(K))
disp(randn)
end
Some of the random number generators store a value that is essentially an index into the sequence of psuedo-random numbers for a particular seed value.
When running in parallel the different CPUs could be overlaying each others setting of that index value.
You could pre-allocate a vector of random numbers using one CPU and then exec the parallel for loop that pulls numbers from that vector.