0

我在 MATLAB 中编写了一小段代码。这实际上是一个从 3D 矩阵生成线性索引的函数。这实际上是一个更大项目的一部分。问题是代码有效,但没有优化,而且速度很慢。当我在 MATLAB 上运行分析器时,该函数消耗了 90% 的计算时间。如何优化此代码?

%
A = rand(3,3);
H = 1200;
W = 1500;
S = rand(H,W,3,'uint8')
R = zeros(H,W,3,'uint8');
lIR = zeros(1,H*W*3);
lIC = zeros(1,H*W*3);
count = 0;
for rY = 1:1:H
    for rX = 1:1:W
        [oX,oY] = func1(rX,rY);
        cP = A*[oX; oY; 1];
        cP = cP / cP(3);
        cX = round(cP(1)); cY = round(cP(2));
        if cX < size(S,2) && cX > 1 && cY < size(S,1) && cY > 1
            lIR(count+1:count+3) = sub2ind([size(R) 1],[rY rY rY], [rX rX rX],1:3);
            lIC(count+1:count+3) = sub2ind([size(S) 1],[cY cY cY],[cX cX cX],1:3);
            count = count + 3;
        end
    end
end
%
function [oX,oY] = func1(rX,rY)
C1 = 1000;
C2 = 1200;
C3 = 1500;
C4 = 1700;
oX = C1 + (C3 - C1) * ((rX - 1) / (W - 1));
oY = C2 + (C4 - C2) * ((rY - 1) / (H - 1));
end

(更新)好的,我从循环中取出函数,现在这部分使用向量计算,速度更快

[rX,rY] = meshgrid(1:W,1:H);
[oX,oY] = func1(rX,rY);

现在代码如下所示:

%
A = rand(3,3);
H = 1200;
W = 1500;
S = rand(H,W,3,'uint8')
R = zeros(H,W,3,'uint8');
lIR = zeros(1,H*W*3);
lIC = zeros(1,H*W*3);
count = 0;
[rX,rY] = meshgrid(1:W,1:H);
[oX,oY] = func1(rX,rY);

for j = 1:1:H
    for i = 1:1:W

        cP = A*[oX(i); oY(j); 1];
        cP = cP / cP(3);
        c = round(cP);
        if cp(1) < size(S,2) && cp(1) > 1 && cp(2) < size(S,1) && cp(2) > 1
            lIR(count+1:count+3) = sub2ind([size(R) 1],[rY rY rY], [rX rX rX],1:3);
            lIC(count+1:count+3) = sub2ind([size(S) 1],[cY cY cY],[cX cX cX],1:3);
            count = count + 3;
        end
    end
end
%
function [oX,oY] = func1(rX,rY)
C1 = 1000;
C2 = 1200;
C3 = 1500;
C4 = 1700;
oX = C1 + (C3 - C1) * ((rX - 1) / (W - 1));
oY = C2 + (C4 - C2) * ((rY - 1) / (H - 1));
end

我还尝试制作内部函数 sub2ind 的优化版本:

function ndx = sub2ind_optimized(siz,varargin)
siz = double(siz);
numOfIndInput = nargin-1;
k = [1 siz(1) siz(1)*siz(2)];
ndx = 1;
for i = 1:numOfIndInput
    v = varargin{i};
    ndx = ndx + (v-1)*k(i);
end

这部分代码仍然很慢......

4

3 回答 3

2

只需使用sub2ind - 一个将下标转换为线性索引的内置函数。

linearInd = sub2ind(arraySize, dim1Sub, dim2Sub, dim3Sub, ...)为大小为 arraySize 的 N 维数组的每个维度返回指定下标的线性索引等效项。arraySize 输入是一个 n 元素向量,用于指定数组中的维数。dimNSub 输入是为矩阵指定一个或多个行列下标的正整数标量或向量。

例如,

A = rand(3, 4, 2);
linearInd = sub2ind(size(A), 2, 1, 2);

linearInd =
14
于 2013-04-04T05:06:18.490 回答
1

优化此代码的最佳方法是将其矢量化,但我现在似乎无法弄清楚如何做到这一点,但是,我看到一些可以优化的东西可能会给你一个小的加速,首先,线

[oX,oY] = func1(rX,rY);

可以从循环中取出并func1更新以生成两个矩阵 [oX(ry,rj)] 和 [oY(ry,rj)] 然后您只需访问这些值而不是func1再次调用,这将消除时间消耗了近 1.800.000 次调用func1,同时消耗了大约 30 MB 更多内存(我在 matlab 中创建了一个 1200x1500 随机矩阵,它大约为 14.4 MB)。

同样,这条线

cX = round(cP(1)); cY = round(cP(2));

可能只是

c=round(CP(1:2))

然后你可以一次又一次地raplace cX,再次消除近 1.800.000 次调用c(1)cYc(2)round

另外,我认为没有必要使用

cX < size(S,2) && cX > 1 && cY < size(S,1) && cY > 1

因为size(S,2)=Wsize(S,1)=H

最后,由于 matlab 的方式,列向量比行向量快一点,因此更改lIRlIC列可以为您节省一些额外的时间。

我认为这可以帮助您稍微提高代码的速度,但它不会给您带来几乎与矢量化一样好的加速。

问题是我似乎无法想出一种方法来正确矢量化这个块的行为

    if cX < size(S,2) && cX > 1 && cY < size(S,1) && cY > 1
        lIR(count+1:count+3) = sub2ind([size(R) 1],[rY rY rY], [rX rX rX],1:3);
        lIC(count+1:count+3) = sub2ind([size(S) 1],[cY cY cY],[cX cX cX],1:3);
        count = count + 3;
    end

如果我有什么新想法我明天会更新,我现在真的需要睡觉了。

干杯

于 2013-04-03T23:44:24.400 回答
0

对于一个你可以摆脱func1。您可以将其替换为

for ox = C1:(  (C3-C1)/(W-1) ):C3

oy 是类似的。

实际上我想知道在 if 条件中增加计数器是否是错误的。因为那么 lIR 和 lIC 中的位置取决于结果。它也是唯一依赖于循环之前运行的值——如果你摆脱了这种依赖,循环可以与 parfor 一起使用。

于 2013-04-04T06:28:16.787 回答