简体   繁体   English

提高 MATLAB 逻辑索引性能

[英]Improving MATLAB logical indexing performance

I'm working on a function that selects all points within a bounding box around a line from a large coordinate set (to speed up a RANSAC fit).我正在研究一个函数,该函数从大坐标集中选择一条线周围的边界框中的所有点(以加快 RANSAC 拟合)。 I ran the script containing the function last night, and of the total 55k seconds 30k (in 55M calls) were spent in this line ( X are 3×N cartesian coordinates, xmin , xmax etc. are vectors of same length as X and corresponding boundaries):我昨晚运行了包含该函数的脚本,总共 55k 秒中 30k(在 55M 调用中)在这一行中花费了( X是 3×N 笛卡尔坐标, xminxmax等是与X和相应的长度相同的向量)边界):

inlierIdx = ( X(1,:) >= xmin & X(1,:) <= xmax & X(2,:) >= ymin & X(2,:) <= ymax );

Could you help me on how to speed this up?你能帮我看看如何加快速度吗? Short-circuiting, which would be a good start to improve performance, doesn't seem to work with indexing.短路是提高性能的良好开端,但它似乎不适用于索引。

Or if there would be a completely different better approach, here's the rest of the function's code ( p1 , p2 are the points defining the line, a is the offset of the bounding box; the additional steps took another 12k secs for 55M calls):或者,如果有一个完全不同的更好的方法,这里是函数的其余代码( p1p2是定义线的点, a 是边界框的偏移量;对于 55M 调用,额外的步骤又花费了 12k 秒):

function [inlierX, xmin, xmax, ymin, ymax] = selectbox(X, L, a) % xmin ... ymax only for plotting purposes
% X: 3xN coords to check; L: 3x2 vector defining line; a: offset of bounding box
p1 = L(:,1);
p2 = L(:,2);

constfactor = (X(3,:)-p1(3))/(p2(3)-p1(3)); % precompute for following steps
xmin = p1(1) + (p2(1)-p1(1))*constfactor - a; % line parallel to x-component of defined line, with offset
xmax = xmin + 2*a;
ymin = p1(2) + (p2(2)-p1(2))*constfactor - a;
ymax = ymin + 2*a; 

inlierIdx = ( X(1,:) >= xmin & X(1,:) <= xmax & X(2,:) >= ymin & X(2,:) <= ymax );

if p1(3) == p2(3) % singularity if line is horizontal, discard then
    inlierIdx = [];
end

inlierX = X(:,inlierIdx); % save & return inlier coordinates

It just occurred me that I should move that singularity if-clause so the computation is skipped if true, but that's a minor performance hit.我突然想到我应该移动那个奇点 if 子句,所以如果为真则跳过计算,但这是一个轻微的性能损失。

The function is called for each RANSAC sample, to select only points in a reasonable distance from the sampled line to compute their distance for thresholding.为每个 RANSAC 样本调用该函数,以仅选择距采样线合理距离内的点来计算它们的阈值距离。

MATLAB version is R2016a. MATLAB 版本为 R2016a。

Parallel Computing Toolbox is available, I tried moving the steps into arrayfuns and calling the whole function with gpuArrays, but it was way slower. Parallel Computing Toolbox 可用,我尝试将步骤移动到 arrayfuns 并使用 gpuArrays 调用整个函数,但速度要慢得多。

The whole context is as follows:整个上下文如下:

prepare coordinates

while trialcount < expectedNumTrialsNeeded

draw random sample (generated array of randomly sampled coordinates and index into it)

check if sample is not degenerate and has allowed angle

compute number of inliers:

    this calls my selectbox function, to select a smaller set of points, which are near enough to check - takes 30k sec of 55k

    take those points and compute their distance to the line, all points within threshold are inliers - takes 12k secs of 55k

if number of inliers > best number of inliers yet, this is new best set

update expected number of trials needed to find sample of only inliers
increment trialcount

end

return best set

I work with arrays of 10k-100k points, and for each line I want to fit I run 1E+5...1E+6 trials to find the best set.我使用 10k-100k 点的数组,对于我想要拟合的每条线,我运行 1E+5...1E+6 次试验以找到最佳集合。 I have around 50 lines to fit, I work through them by deleting inliers of found lines and doing the algorithm on the remaining.我有大约 50 行要拟合,我通过删除找到的行的内点并对剩余的行执行算法来处理它们。

I doubt that that line is the real problem.我怀疑那条线是真正的问题。 You say you do 55 million calls to this function -- may we see the code that does that?你说你对这个函数进行了 5500 万次调用——我们可以看看这样做的代码吗? Because I strongly suspect that this code is where the true problem lies.因为我强烈怀疑这段代码才是真正的问题所在。

I suspect that you call this function in a loop, which would make it hard/impossible for MATLAB to accelerate the call effectively with its JIT compiler.我怀疑您在循环中调用此函数,这将使 MATLAB 难以/不可能使用其 JIT 编译器有效地加速调用。 If that is the case, then indeed, the heaviest burden shown will be this one line, but it's only so slow because your code structure forces MATLAB to keep calling the interpreter, rather than execute machine code.如果是这种情况,那么确实显示的最重负担将是这一行,但它之所以慢是因为您的代码结构迫使 MATLAB 继续调用解释器,而不是执行机器代码。 If this is indeed the case, then copy-pasting this small function in-place in the loop body will tremendously speed everything up (that is, if the remainder of the loop body can also be accelerated...)如果确实如此,那么在循环体中就地复制粘贴这个小函数将极大地加速一切(也就是说,如果循环体的其余部分也可以加速......)

Well anyway, this is what I could make of it.好吧,无论如何,这就是我能做到的。 It reduces the number of comparisons at the cost of additional indexing;它以额外的索引为代价减少了比较次数; I also doubt that this is faster...oh well, just do 1000 calls and compare.我也怀疑这是否更快……哦,好吧,只需进行 1000 次调用并进行比较。

function [inlierX, xmin, xmax, ymin, ymax] = selectbox(X, L, a)

    % X: 3xN coords to check; L: 3x2 vector defining line; a: offset of bounding box
    p1 = L(:,1);
    p2 = L(:,2);

    constfactor = (X(3,:)-p1(3)) / (p2(3)-p1(3));

    % line parallel to x-component of defined line, with offset
    xmin = p1(1) + (p2(1)-p1(1))*constfactor - a; 
    xmax = xmin + 2*a;
    ymin = p1(2) + (p2(2)-p1(2))*constfactor - a;
    ymax = ymin + 2*a;

    % singularity if line is horizontal, discard then
    if p1(3) ~= p2(3)        
        inlierIdx            = X(1,:)         >= xmin;        
        inlierIdx(inlierIdx) = X(1,inlierIdx) <= xmax(inlierIdx);
        inlierIdx(inlierIdx) = X(2,inlierIdx) >= ymin(inlierIdx);
        inlierIdx(inlierIdx) = X(2,inlierIdx) <= ymax(inlierIdx);                
    else
        inlierIdx = [];
    end

    inlierX = X(:,inlierIdx); % save & return inlier coordinates

end

What about to use columnwise indexing in your code?在你的代码中使用列索引怎么样? I mean to use X as Nx3 cartesian coordinates not as 3xN.我的意思是使用 X 作为 Nx3 笛卡尔坐标而不是 3xN。 As far, as I know columnwise indexing can be faster due to MATLAB arrays are stored in a FORTRAN manner.据我所知,由于 MATLAB 数组以 FORTRAN 方式存储,因此按列索引可以更快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM