speed up for loop
Mostrar comentarios más antiguos
Hi everone. I have a problem with my code which was written in the following form. it take a long time and it is too time consuming.
In this code, I need to read 700 .hgt files with the size of 3600*3600 and make distincts 3*3 matrix from each of them.
I woulde be thankful if anyone could help me. Thanks in advance for your attenuation and help.
clc
clear all
close all
format long g
fid=fopen('list2.txt','r');
if fid==-1
disp('there is an error')
else
end
S = textscan(fid,'%s');
fclose(fid);
i=1;
fnames= S{i,i};
tic
NA=[];
for fiile=1:700
varargout = readhgt(fnames{fiile});
LAT=varargout.lat;LAT(end)=[];
LON=varargout.lon;LON(end)=[];
Z=varargout.z;Z(:,end)=[];
Z(end,:)=[];
% Z_vec=reshape(Z,[12967201,1]);
ROUGH=[];
for row=1:3:3597
for col=1:3:3597
A=[Z(row,col) Z(row,col+1) Z(row,col+2);Z(row+1,col) Z(row+1,col+1) Z(row+1,col+2);Z(row+2,col) Z(row+2,col+1) Z(row+2,col+2)];
Dif=(double(A)-mean(mean(A))).^2;
rough=sqrt(mean(mean(Dif)));
ROUGH=[ROUGH;mean([LAT(row) LAT(row+1) LAT(row+2)]) mean([LON(col) LON(col+1) LON(col+2)]) rough];
end
end
NA=[NA;ROUGH];
end
toc
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
actually the following part takes the most of time. in this part I am exploiting dependent 3*3 matrixs from a file with 3600*3600 elements.
for row=1:3:3597
for col=1:3:3597
A=[Z(row,col) Z(row,col+1) Z(row,col+2);Z(row+1,col) Z(row+1,col+1) Z(row+1,col+2);Z(row+2,col) Z(row+2,col+1) Z(row+2,col+2)];
Dif=(double(A)-mean(mean(A))).^2;
rough=sqrt(mean(mean(Dif)));
ROUGH=[ROUGH;mean([LAT(row) LAT(row+1) LAT(row+2)]) mean([LON(col) LON(col+1) LON(col+2)]) rough];
end
end
Respuesta aceptada
Más respuestas (1)
chicken vector
el 7 de Abr. de 2023
Try parallel computing:
% Get CPU's numebr of cores:
[~, numberOfCores] = evalc('feature(''numcores'')');
% Start parallel pool:
parpool(numberOfCores)
% Parallelise <for> loop:
parfor file = 1 : 700
% dostuff
end
Just be carefull and read the documentation about how to save restults from parfor iteratively, as you need to pre-allocate the output variable and you will have some other constraints.
3 comentarios
Mina Mino
el 7 de Abr. de 2023
chicken vector
el 7 de Abr. de 2023
Editada: chicken vector
el 7 de Abr. de 2023
The first advice that I can give you is, as Matlab suggests you, initialise your variable ROUGH before the for loop.
This is particularly important when dealing with big dataset because at each loop iteration the size of ROUGH is changed and the RAM of your computer needs to re-allocate the data inside it to have the bits representing ROUGH close to each other.
Now imagine how time expensive this could be when you do it (3597/3)^2 times, when you could save this time by "reserving" your RAM spots before the loop by substituting:
ROUGH = [];
With:
ROUGH = zeros(3597, 3);
The second advice is to use vectorisation as much as possible because it is much faster than using for loops.
Vectorisation can be seen as a sort of parallel computation rather than in sequence.
Consider as an example that I want to obtain the element-wise difference between two matrices. The following 3 methods obtain the same result, but performances are quite different:
N = 500;
x = rand(N);
y = rand(N);
% For loop without initial allocation:
tic
z = [];
for i = 1 : N
for j = 1 : N
z(i,j) = x(i,j) - y(i,j);
end
end
T1 = toc
% For loop with initial allocation:
tic
z = zeros(N);
for i = 1 : N
for j = 1 : N
z(i,j) = x(i,j) - y(i,j);
end
end
T2 = toc
% Vectorisation:
tic
z = x - y;
T3 = toc
On my computer I obtain:
T1 = 0.0147
T2 = 0.0064
T3 = 0.0005
First thing that comes to my mind is to re-organise your Z, LAT, LON variables into matrices of size [3, (3597^2)/3] so that you can already vectorise along one dimension.
Nontheless this might be a bit complex so I suggest you to begin with the initialisation of ROUGH.
In my code saves half the computational time with a 500x500 matrix which only has 2 % of the elements you have in a 3597x3597 matrix, since it scales with the square of the dimension.
TLDR:
Try this:
ROUGH = zeros(3597,3);
select = (0:2);
current_rough_row = 0;
for row = 1 : 3 : N
for col = 1 : 3 : N
current_rough_row = current_rough_row + 1;
A = Z(row + select, col + select);
Dif = (A - mean(A,'all')).^2;
rough = sqrt(mean(Dif,'all'));
ROUGH(current_rough_row,:) = [mean(LAT(row + select)) mean(LON(col + select)) rough];
end
end
And do the same with NA:
NA = zeros(3597*700, 3); % Instead of: NA = [];
NA[700*(fiile-1)+1 : 700*fiile] = ROUGH; % Instead of NA = [NA;ROUGH];
Mina Mino
el 7 de Abr. de 2023
Categorías
Más información sobre MATLAB en Centro de ayuda y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!