2016-05-03 16 views
2

大きな座標セット(RANSACフィットを高速化するため)から、線の周りの境界ボックス内のすべてのポイントを選択する関数を作成しています。私は最後の夜に関数を含むスクリプトを実行し、合計55k秒の30k(55Mコールで)がこの行に費やされた(Xは3×Nデカルト座標です。xmin,などはXと同じ長さのベクトルで、境界線):MATLABの論理インデックスパフォーマンスを改善する

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

これをスピードアップする方法を教えてください。パフォーマンスを向上させるための良いスタートとなる短絡は、索引付けでは機能しないようです。 p2は、線を定義する点であり、aは境界ボックスのオフセットであり、追加のステップではさらに12k秒がかかっています。 55Mコールは):

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 

それだけでは、真の場合、計算がスキップされている場合、WHERE句ので、私はその特異点を移動しなければならないことを私に起こったが、それはマイナーなパフォーマンスヒットです。

この関数は、各RANSACサンプルに対して呼び出され、サンプリングされた線から適度な距離にある点のみを選択して、しきい値設定の距離を計算します。

MATLABバージョンはR2016aです。

Parallel Computing Toolboxが利用可能で、私はarrayfunsにステップを移動し、gpuArraysを使って関数全体を呼び出そうとしましたが、遅くなりました。検索する

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 

私は10K-100Kポイントの配列を扱う、そして各ラインのために、私は+ 5 1Eを実行収まるようにしたい... 1E + 6件の試験を次のように

全体の文脈があります最高のセット。私は約50行を収めるために、見つかった行のinliersを削除し、残ったものに対してアルゴリズムを実行することによってそれらを処理します。

+0

さらにコードを投稿できますか?プロファイラは時には誤解を招くことがあります。特に、ループがJITされていないと... ...また、どのバージョンのMATLABを使用していますか? –

+0

@Rody done、おめでとうございます。 –

+0

...その他のコード?同様に、これは関数かスクリプトですか?関数を呼び出すのは何ですか? 'inlierX'だけが重要か' inlierIdx'ですか?ただあなたが持っているすべてのMWEを投稿してください! :) –

答えて

1

私はその行が実際の問題であるとは思わない。あなたは、この関数の呼び出しを5500万回呼び出したとします。これを行うコードが表示されるのでしょうか?私は強く疑うからこのコードは真の問題がある場所です。

この関数をループで呼び出すと、MATLABがそのJITコンパイラで呼び出しを効果的に加速することが困難/不可能になることが考えられます。このような場合、実際に表示される重い負担はこの1行になりますが、コード構造によってMATLABがマシンコードを実行するのではなくインタプリタを呼び出し続けるため、速度が遅くなります。これが本当に当てはまる場合、この小さな関数をループ本体にコピー貼り付けすると、ループ本体の残りの部分も高速化することができます(つまり、ループ本体の残りの部分も高速化できれば...)

とにかく、これは私がそれを作ることができるものです。これは、追加の索引作成を犠牲にして比較の数を減らします。私もこれがより高速であることを疑う...まあ、ちょうど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 
+0

あなたのコードは、私のオリジナルでは210対60とかなり遅かったです。配列全体の最初のブール演算は5秒かかっていましたが、他の演算は〜45回かかっていましたので、インデックス作成が問題になっています。 –

+0

は完全なスクリプト –

+0

@ LukasKを記述する擬似コードを追加しました。関数本体をループ本体にコピー貼り付けしてみましたか? –

1

コードで列インデックスを使用するのはどうですか?私は3xNではなくNx3デカルト座標としてXを使うことを意味します。私が知る限りでは、MATLAB配列はFORTRAN方式で格納されているため、列方向の索引付けは高速になります。

+0

私は列方向の索引付けについて考えましたが、直感的に私は3xNは列方向の索引付け個々の列のアドレス指定に使用します。したがって、丸で囲んだ別の方法は、1つの列内でインデックスを作成することを意味しますか? –

+0

真実ですが、このようなことのスピードアップは通常は驚異的ではありません.1.5程度の考え方です。 –

+0

@RobyOldenhuis合意。リニアインデックスについてはどうですか?この場合に使用する別の方法は、C++のdllまたはmexfunctionです。 –

関連する問題