2

2772x128 マトリックスと 4000x128 マトリックスの間の製品を作ろうとしています。両方とも、次のコードを使用した SIFT 記述子の行列です。

Mat a = Mat(nframes, descrSize, CV_8U, DATAdescr);
Mat b = Mat(vocabulary_size, descrSize, CV_8U, vocabulary);
Mat ab =a * b.t();

問題は、製品を計算するときにエラーがスローされることです

err_msg = 0x00cdd5e0 "..\..\..\src\opencv\modules\core\src\matmul.cpp:711: error: (-215) type == B.type() && (type == CV_32FC1 || type == CV_64FC1 || type == CV_32FC2 || type == CV_64FC2)"

これに対する解決策は、データ型を CV_32FC1 に変換することでした

Mat a = Mat(nframes, descrSize, CV_8U, DATAdescr);
Mat b = Mat(vocabulary_size, descrSize, CV_8U, vocabulary);
a.convertTo(a, CV_32FC1);
b.convertTo(b, CV_32FC1);
Mat ab = a * b.t();

うまく機能しますが、時間がかかりすぎて、約 1.2 秒かかります。同じ製品を整数を使用して試して、これを高速化できるかどうかを確認したいと思います。私は何か間違ったことをしていますか?CV_8U マトリックス間のマトリックス積を実行できない理由がわかりません。

編集:答えは、他のライブラリを使用するか、他の方法で解決することに関連しています。私の問題を解決するためのアドバイスを含む新しいスレッドを開くことを考えていましたが、最初の質問に答えてくれる人はいますか? CV_8U または CV32S 行列を乗算できませんか? 本当に?

4

4 に答える 4

2

他のメッセージで、次のコードは0.9秒かかるとおっしゃいました。

MatrixXd A = MatrixXd::Random(1000, 1000);
MatrixXd B = MatrixXd::Random(1000, 500);
MatrixXd X;

私は自分のマシンで少しベンチマークを試しました。Linux上で実行されているIntelCorei7です。私の完全なベンチマークコードは次のとおりです。

#include <Eigen/Dense>
using namespace Eigen;

int
main(int argc, char *argv[])
{
  MatrixXd A = MatrixXd::Random(2772, 128);
  MatrixXd B = MatrixXd::Random(4000, 128);
  MatrixXd X = A*B.transpose();
}

Linuxのtimeコマンドを使用するだけなので、実行時間には実行可能ファイルの起動と停止が含まれます。

1 /最適化なしでコンパイル(gccコンパイラ):

g++ -I/usr/include/eigen3 matcal.cpp -O0 -o matcal
time ./matcal
real    0m13.177s  -> this is the time you should be looking at
user    0m13.133s
sys     0m0.022s

13秒、それは非常に遅いです。ちなみに、行列の乗算がないと、0.048秒かかります。0.9秒の例よりも大きな行列が必要です。なぜ ??

Eigenでコンパイラの最適化を使用することは非常に重要です。2 /いくつかの最適化を使用してコンパイル:

g++ -I/usr/include/eigen3 matcal.cpp -O2 -o matcal
time ./matcal
real    0m0.324s
user        0m0.298s
sys     0m0.024s

今0.324秒、それは良いです!

3 /すべての最適化フラグを切り替える(少なくとも私が知っていることはすべて、私はこの分野の専門家ではありません)

g++ -I/usr/include/eigen3 matcal.cpp -O3 -march=corei7 -mtune=corei7 -o matcal 
time ./matcal
real    0m0.317s
user    0m0.291s
sys     0m0.024s

0.317、近いですが、数ミリ秒が得られました(一貫していくつかのテストで)。したがって、私の意見では、Eigenの使用に問題があります。コンパイラの最適化を切り替えないか、コンパイラが単独で切り替えないかのどちらかです。

私はEigenの専門家ではありませんが、数回しか使用していませんが、ドキュメントは非常に優れていると思います。おそらく、それを最大限に活用するために読む必要があります。

MatLabとのパフォーマンスの比較に関して、前回Eigenについて読んだとき、MatLabはおそらくマルチスレッドライブラリを使用していましたが、マルチスレッドではありませんでした。行列の乗算では、行列をいくつかのチャンクに分割し、TBBを使用して各チャンクの乗算を並列化できます。

于 2012-09-29T21:36:47.310 に答える
1

remi の提案で、Eige を使用して同じ行列乗算を実装しました。ここにあります:

const int descrSize = 128;
MatrixXi a(nframes, descrSize);
MatrixXi b(vocabulary_size, descrSize);
MatrixXi ab(nframes, vocabulary_size);

unsigned char* dataPtr = DATAdescr;
for (int i=0; i<nframes; ++i)
{
    for (int j=0; j<descrSize; ++j)
    {
        a(i,j)=(int)*dataPtr++;
    }
}
unsigned char* vocPtr = vocabulary;
for (int i=0; i<vocabulary_size; ++i)
{
    for (int j=0; j<descrSize; ++j)
    {
        b(i,j)=(int)*vocPtr ++;
    }
}


ab = a*b.transpose();
a.cwiseProduct(a);
b.cwiseProduct(b);
MatrixXi aa = a.rowwise().sum();
MatrixXi bb = b.rowwise().sum();

MatrixXi d = (aa.replicate(1,vocabulary_size) + bb.transpose().replicate(nframes,1) - 2*ab).cwiseAbs2();

重要な行は、次の行です。

ab = a*b.transpose();

ボキャブラリーと DATAdescr は unsigned char の配列です。DATAdescr は 2782x128、語彙は 4000x128 です。実装時に Map を使用できることがわかりましたが、最初は使用できませんでした。割り当ての初期ループは 0.001 コストなので、これはボトルネックにはなりません。全体のプロセスは約 1.23 秒です。

matlab での同じ実装 (0.05 秒) は次のとおりです。

aa=sum(a.*a,2); bb=sum(b.*b,2); ab=a*b'; 
d = sqrt(abs(repmat(aa,[1 size(bb,1)]) + repmat(bb',[size(aa,1) 1]) - 2*ab));

助けてくれてありがとう、レミ。

于 2012-09-21T09:03:09.653 に答える
0

バックエンドとしてEIGENを使用してOpenCVをコンパイルしてみてください。CMakeListにはこれに対するオプションがあります。行列の乗算を高速化するためだけにOpenCVを使用するというコマンドを読みました。そのため、EIGENを直接試してみることもできます。

最後の解決策は、OpenCVのGPUモジュールを使用することです。

于 2012-09-18T20:56:54.697 に答える
0

行列を掛ける場合、要素の値を掛けて合計します。範囲が 0 ~ 255 しかない場合、積が 255 を超える可能性が非常に高くなります。したがって、CV_8U 行列の積はあまり役に立ちません。

結果がバイトに収まることがわかっている場合は、要素をループして自分で乗算を行うことができます。

編集: float バージョンが非常に遅いことに少し驚いています。一般に、マルチコアと最適化された SSE2 命令を使用すると、opencv のパフォーマンスはかなり優れています。ソースからビルドしましたか?TBB (つまり、マルチスレッド) と SSE2 CPU はありますか?

于 2012-09-18T15:07:18.423 に答える