Matlab的功能性能 - 太多的循环(Matlab Function Performance -

2019-10-18 13:31发布


我在中行的很多txt文件的几个信息写入。 结果就像一个文件:

result.txt:
RED;12;7;0;2;1;4;7;0.0140
RED;12;7;0;2;2;9;7;0.1484
RED;12;7;0;2;3;7;4;0.1787
RED;12;7;0;2;4;2;6;0.7891
RED;12;7;0;2;5;9;6;0.1160
RED;12;7;0;2;6;9;1;0.9893
...

这是通过下面的代码建立(有一些减小的尺寸):

/* the variables 'str1', 'num1', 'day', 'vect1', 'vect2' and 'MD' are inputs of this function
/* str1 is a string 1x1
/* num1 is a integer 1x1 
/* day is a vector 10x1
/* vect1 is a vector 7x1
/* vect2 is a vector 180x1
/* MD is a 4D matrix (7x180x10x15)*/

fid = fopen(path_result, 'Wt');    
for i1 = 1:15   
    for i2 = 1:10    
        for i3 = 1:7           
           for i4= 1:180
            /* print all the values */
                fprintf(fid,'%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%.4f \n',...
                str1,';',num1,';',i1,';',0,';',2,';',...
                day(i2,1),';',vect1(i3),';',...
                vect2(i4),';',MD(i3,i4,i2,i1));
            end
        end
    end
end

我看到一些量化这里 (计算器后),但我不认为这是可能在这里申请。 有任何想法吗?
提前致谢

Answer 1:

它可以适用于任何情况下,第一优化是生成一个格式字符串,姑且称之为fmt

fmt       = sprintf('%s;%d;%%d;%d;%d;%%d;%%d;%%d;%%.4f \\n',str1,num1,0,2)
fmt =
RED;4;%d;0;2;%d;%d;%d;%.4f \n

在这之后的循环中的代码变成:

x = sprintf(fmt, i1, day(i2,1), vect1(i3), vect2(i4), MD(i3,i4,i2,i1));

现在,一个完全量化的解决方案,权衡上RAM,但幅度达到加速的顺序,在我的设置〜10.8倍,从9.61至0.89秒。

tic
[a,b,c,d] = ndgrid(vect2,vect1,day,1:15);
out       = sprintf(fmt, [d(:), c(:), b(:), a(:), reshape(permute(MD,[2,1,3,4]),[],1)]'); 
toc


Answer 2:

一个可以做,以优化你的代码的事情是寻找代码的“重复”位。 在你的情况,你格式的所有最内层循环的结果字符串的 - 虽然大部分的字符串不会改变。 你也“格式化”分隔字符串';' 几次 - 你可以直接在你的格式化字符串(你可以穿插在格式字符串文本格式化命令)。 我结合在几个不同的方式这些想法,并且定时它们:

str1 = 'hello';
num1 = 123;
day = (1:10)';
vect1 = (1:7)';
vect2 = (1:180)';
MD = rand(7,180,10,15);
path_result = './mixedOutput1.txt';
fid = fopen(path_result, 'Wt');    
tic
for i1 = 1:15   
    for i2 = 1:10    
        for i3 = 1:7           
           for i4= 1:180
%             /* print all the values */
                fprintf(fid,'%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%.4f \n',...
                str1,';',num1,';',i1,';',0,';',2,';',...
                day(i2,1),';',vect1(i3),';',...
                vect2(i4),';',MD(i3,i4,i2,i1));
            end
        end
    end
end
fprintf(1, 'time for original loop: %.2f sec\n',toc)
fclose(fid);
%%
path_result = './mixedOutput2.txt';
fid = fopen(path_result, 'Wt');    
tic
for i1 = 1:15   
    for i2 = 1:10    
        for i3 = 1:7           
           for i4= 1:180
%             /* print all the values */
                fprintf(fid,'%s;%d;%d;0;2;%d;%d;%d;%.4f \n',...
                str1, num1, i1, day(i2,1), vect1(i3), vect2(i4),MD(i3,i4,i2,i1));
            end
        end
    end
end
fprintf(1, 'time for faster loop: %.2f sec\n',toc)
fclose(fid);
%%
path_result = './mixedOutput3.txt';
fid = fopen(path_result, 'Wt');    
tic
y = cell(1,15*10*7*180);
cc = 0;
for i1 = 1:15   
    for i2 = 1:10    
        for i3 = 1:7           
           for i4= 1:180
%             /* print all the values */
                cc = cc + 1;
                y{1,cc} = sprintf('%s;%d;%d;0;2;%d;%d;%d;%.4f \n',...
                str1, num1, i1, day(i2,1), vect1(i3), vect2(i4), MD(i3,i4,i2,i1));
            end
        end
    end
end
fprintf(1, 'time for loop with sprintf intermediate step: %.2f sec\n', toc)
fprintf(fid, '%s', y{:});
fprintf(1, 'time including file write: %.2f sec\n', toc);
fclose(fid);

%% optimize loop more:

path_result = './mixedOutput4.txt';
fid = fopen(path_result, 'Wt');    
tic
y = cell(1,15*10*7*180);
cc = 0;
for i1 = 1:15   
    for i2 = 1:10    
        for i3 = 1:7           
            x = sprintf('%s;%d;%d;0;2;%d;%d;', ...
                str1, num1, i1, day(i2,1), vect1(i3));
            for i4= 1:180
                fprintf(fid, '%s%d;%.4f \n', ...
                     x, vect2(i4), MD(i3,i4,i2,i1));
            end
        end
    end
end
fprintf(1, 'time for fastest loop: %.2f sec\n', toc);
fclose(fid);

在我的机器,这导致以下基准:

Original loop: 15.9 sec
Faster format:  9.2 sec
With sprintf:   8.2 sec
preformat:      6.2 sec

该“预格式化”不是尽可能有效地完成 - 它只是在那里说明。 中间弦x的计算量常常要少,然后再使用。

最后-我没有创建代码的“量化”的版本-这意味着整个sprintf发生在一个单一的线。 这需要创建一个大的单元阵列( Kahuna ,下同)用正确的元素-事实证明,实际上略高于上述最后一个代码(与“预格式化”)效率较低,但在这里它是以防万一:

%% truly vectorized:
tic
Kahuna = cell(7, 15*10*7*180);
N = 15 * 10 * 7 * 180;
N1 = ones(1, N);
% final order needs to be [180 7 10 15] - inner loop first
Kahuna(1,:) = cellstr(repmat(str1, [N 1]))';
Kahuna(2,:) = mat2cell(repmat(num1, [N 1]), N1, 1);
Kahuna(3,:) = mat2cell(reshape(repmat(reshape(1:15,    1, 1, 1, 15), [180 7 10  1]), [], 1), N1, 1);
Kahuna(4,:) = mat2cell(reshape(repmat(reshape(day,     1, 1, 10, 1), [180 7  1 15]), [], 1), N1, 1);
Kahuna(5,:) = mat2cell(reshape(repmat(reshape(vect1,   1, 7, 1,  1), [180 1 10 15]), [], 1), N1, 1);
Kahuna(6,:) = mat2cell(reshape(repmat(reshape(vect2, 180, 1, 1,  1), [  1 7 10 15]), [], 1), N1, 1);
Kahuna(7,:) = mat2cell(reshape(permute(MD, [2 1 3 4]), [], 1), N1, 1);

x = sprintf('%s;%d;%d;0;2;%d;%d;%d;%.4f \n', Kahuna{:});
toc


Answer 3:

实际上,它似乎只是第一创造的一切,以后写它(的方式我试了一下)没有给出一个的速度增加。 我最初的想法是将数据与保存save(file,data,'-ascii')但给了意想不到的效果。

如果你只会有数字数据,你也许可以使用dlmwrite但我想这是不是现在的选项。

这里是我的尝试相比,你的原代码,包括一些假设投入的时机:

str1 = 'RED';
num1 = 4;
day = rand(10);
vect1 = 1:7;
vect2 = 1:180;
MD = rand(7,180,10,15);
y=[];

tic
for i1 = 1:15   
    for i2 = 1:10    
        for i3 = 1:7           
           for i4= 1:180

                x=sprintf('%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%.4f \n',...
                str1,';',num1,';',i1,';',0,';',2,';',...
                day(i2,1),';',vect1(i3),';',...
                vect2(i4),';',MD(i3,i4,i2,i1));
                y{end+1} = x;
            end
        end
    end
end

fid = fopen('test.txt','w');
for i=1:length(y)
         fprintf(fid,y{i});
end
fclose(fid)
t1=toc;

tic
fid = fopen('test.txt', 'Wt');    
for i1 = 1:15   
    for i2 = 1:10    
        for i3 = 1:7           
           for i4= 1:180
                fprintf(fid,'%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%.4f \n',...
                str1,';',num1,';',i1,';',0,';',2,';',...
                day(i2,1),';',vect1(i3),';',...
                vect2(i4),';',MD(i3,i4,i2,i1));
            end
        end
    end
end
t2=toc;

myTime = t1 % 56 secs
originalTime = t2 % 12 secs


文章来源: Matlab Function Performance - Too many loops