簡體   English   中英

MATLAB提高和運算符的性能

[英]MATLAB improving performance of sum operator

我有一些代碼,目的是在掩碼數組為true時求和一個數組。 我需要保持水平尺寸不變(即不能僅僅做sum(A(mask)),因為那樣會返回標量)。 遮罩是矩陣中足夠接近特定位置的元素-我正在根據斜邊進行計算。 有什么方法可以使其更快,它是較大代碼的一部分,但這是最慢的部分。

碼:

A = rand(1024,8004);        % data set
xidx = 5019; yidx = 325;    % center of circle for mask
mask_radius = 100;          % radius of circle for mask

[XX,YY] = meshgrid(1:size(A,2),1:size(A,1));            % XX and YY matrices
mask = ((XX-xidx).^2 + (YY-yidx).^2) < (mask_radius)^2; % mask is based on hypotenuse

% attempt 1
tic
tmp = A;                    % duplicate data
tmp(~mask) = 0;             % turn it into zeros
data_sum = sum(tmp);        % add
toc

% attempt 2
tic; sum(A.*mask); toc;

這使用了for循環,根據Matlab的說法,這是一個很大的禁忌,但速度要快40%。

tic
[~,b] = find(mask);
v = min(b):max(b);

for ii = 1:length(v)
    s(ii) = sum(A(mask(:,v(ii)), v(ii)));
end
toc

clf
plot(data_sum(data_sum~=0),'LineWidth',2); hold on
plot(s,'o'); 

輸出:

Elapsed time is 0.032778 seconds.
Elapsed time is 0.012450 seconds.
Elapsed time is 0.006974 seconds.

代碼圖形輸出

通過不對已知矩陣不在圓內的輸入矩陣區域進行評估,可以節省大量時間(即,如果其中一個mask_radius選定點的距離大於mask_radius ,並且不對這些區域求和,則可以節省大量時間。

您可以通過將矩陣裁剪為一半大小的mask_radius的正方形來非常簡單地完成此mask_radius 這將是代碼:

[height,width] = size(A);
left = max(xidx - mask_radius, 1);
right = min(xidx + mask_radius, width);
top = max(yidx - mask_radius, 1);
bottom = min(yidx + mask_radius, height);
A = A(top:bottom, left:right);
[XX,YY] = meshgrid(1:size(A,2),1:size(A,1));            
mask = ((XX-(xidx-left+1)).^2 + (YY-(yidx-top+1)).^2) < (mask_radius)^2;
A(~mask) = 0;
out = sum(A);
out = [zeros(1,left-1),out]; % pad result to the left
out(width) = 0;              % pad result to the right

我們可以不使用meshgrid ,而是依靠隱式單例擴展來進一步加快速度:

XX = 1:size(A,2); YY = (1:size(A,1)).';
mask = ((XX-(xidx-left+1)).^2 + (YY-(yidx-top+1)).^2) < mask_radius^2;

我在下面的時間中包括了創建遮罩所需的時間。 如果僅計時,則仍然可以節省大量時間,但是我認為創建掩碼是您的任務之一。

注意我正在使用timeit來計時代碼。 執行時間低於1秒的任何內容都應該使用timeit進行計時,因為它比tic / toc更精確。

A = rand(1024,8004);        % data set
xidx = 5019; yidx = 325;    % center of circle for mask
mask_radius = 100;          % radius of circle for mask

res1 = method1(A,xidx,yidx,mask_radius);
res2 = method2(A,xidx,yidx,mask_radius);
res3 = method3(A,xidx,yidx,mask_radius);
res4 = method4(A,xidx,yidx,mask_radius);
assert(isequal(res1,res2))
assert(isequal(res1,res3))
assert(isequal(res1,res4))

timeit(@()method1(A,xidx,yidx,mask_radius))
timeit(@()method2(A,xidx,yidx,mask_radius))
timeit(@()method3(A,xidx,yidx,mask_radius))
timeit(@()method4(A,xidx,yidx,mask_radius))

% OP's method
function out = method1(A,xidx,yidx,mask_radius)
[XX,YY] = meshgrid(1:size(A,2),1:size(A,1));            % XX and YY matrices
mask = ((XX-xidx).^2 + (YY-yidx).^2) < (mask_radius)^2; % mask is based on hypotenuse
A(~mask) = 0;    % turn it into zeros
out = sum(A);    % add
end

% liorr's method, with preallocation and correct output
function out = method2(A,xidx,yidx,mask_radius)
[XX,YY] = meshgrid(1:size(A,2),1:size(A,1));
mask = ((XX-xidx).^2 + (YY-yidx).^2) < (mask_radius)^2;
[~,b] = find(mask);
v = min(b):max(b);
out = zeros(1,size(A,2)); % PREALLOCATE!!!
for ii = 1:length(v)
    out(v(ii)) = sum(A(mask(:,v(ii)), v(ii))); % FIXED BUG!!!
end
end

% My method
function out = method3(A,xidx,yidx,mask_radius)
[height,width] = size(A);
left = max(xidx - mask_radius, 1);
right = min(xidx + mask_radius, width);
top = max(yidx - mask_radius, 1);
bottom = min(yidx + mask_radius, height);
A = A(top:bottom, left:right);
[XX,YY] = meshgrid(1:size(A,2),1:size(A,1));            
mask = ((XX-(xidx-left+1)).^2 + (YY-(yidx-top+1)).^2) < mask_radius^2;
A(~mask) = 0;
out = sum(A);
out = [zeros(1,left-1),out]; % pad to the left
out(width) = 0;              % pad to the right
end

% My method without MESHGRID
function out = method4(A,xidx,yidx,mask_radius)
[height,width] = size(A);
left = max(xidx - mask_radius, 1);
right = min(xidx + mask_radius, width);
top = max(yidx - mask_radius, 1);
bottom = min(yidx + mask_radius, height);
A = A(top:bottom, left:right);
XX = 1:size(A,2); YY = (1:size(A,1)).';
mask = ((XX-(xidx-left+1)).^2 + (YY-(yidx-top+1)).^2) < mask_radius^2;
A(~mask) = 0;
out = sum(A);
out = [zeros(1,left-1),out]; % pad to the left
out(width) = 0;              % pad to the right
end

我的系統上的輸出(在MacOS上為MATLAB R2017a):

ans =
    0.0733

ans =
    0.0276

ans =
   5.8832e-04

ans =
   2.4890e-04

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM