7

コンピュータービジョンのアプリケーションにOpenCVを使用しています。GPUでいくつかの行列演算(行列はかなり大きい)を高速化し、可能であればCUDACで直接コーディングすることを避けたいと思います。OpenCV 2.4.1には、GPUアクセラレーション機能が多数あります。彼らはあなたの経験でどれくらいうまく機能しますか?代わりに別のライブラリ(Thrustなど)を使用したほうがいいですか?

サンプルアプリケーションの編集: GPUで2乗ユークリッド距離行列を計算します。現在、Parallel Computing Toolbox(PCT)を使用したMatlabでのGPUアクセラレーション(およびベクトル化)実装は、OpenCVを使用したC ++実装よりも約5〜10倍高速です。

Matlabの実装:

function K = sqEuclideanDist(P_cpu,Q_cpu)
% Vectorized method to compute pairwise squared Euclidean distance on GPU
% Returns K(i,j) = (P(i,:) - Q(j,:))'*(P(i,:) - Q(j,:))

P_gpu = gpuArray(P_cpu);
Q_gpu = gpuArray(Q_cpu);

[nP, d] = size(P_gpu);
[nQ, d] = size(Q_gpu);

pmag = sum(P_gpu .* P_gpu, 2);
qmag = sum(Q_gpu .* Q_gpu, 2);

% note that K is on GPU
K = ones(nP,1)*qmag' + pmag*ones(1,nQ) - 2*P_gpu*Q_gpu';

end

更新これは、同じことを実現する別のMatlab実装です( https://stackoverflow.com/a/7774323/1121420に感謝します)。ただしbsxfun、PCTでサポートされていないため、CPUでのみ実行されます。ただし、C++の代替手段をまだ探しています。

function K = sqEuclideanDist(P_cpu,Q_cpu)
% Returns K(i,j) = (P(i,:) - Q(j,:))'*(P(i,:) - Q(j,:))
% Runs on CPU only.

K = bsxfun(@plus,sum(p.^2,2),sum(q.^2,2)') - 2*(p*q');

end
4

2 に答える 2

5

ArrayFireのがはるかに高速で、OpenCVのGPUカーネルの代わりに画像処理に使用し始めました。ArrayFire (以前はLibJacketと呼ばれる別のインターフェイスにあった)をOpenCVと比較して見つけたベンチマークをいくつか示します。私のベンチマークでも、ArrayFireはOpenCVのGPU機能よりも2〜4倍高速です。私が聞いたところによると、NVIDIAはOpenCVでGPUカーネルを作成しませんでしたが、それらを誰かに委託しました。これが、GPUカーネルが非常に遅い理由である可能性があります。GPUを1つしか使用していないので、ArrayFireを無料で使用できます。

@Alexによって投稿された新しいMATLABコードを前提として、更新し ます。システムでこのコードのベンチマークを実行しました。Parallel Computing ToolboxのgpuArrayはCPUよりも遅いと思いますが、JacketとArrayFireはお尻を蹴ります。HWの仕様は次のとおりです。

Intel(R) Xeon(R) CPU X5660  @ 2.80GHz
NVIDIA Tesla M2090

Parallel Computing Toolbox gpuArrayを使用したCPUとGPUの結果(完全にウォームアップ)。 CPUはPCTgpuArrayよりも高速です

>> tic; sqEuclideanDist(gpuArray(rand(1581,3)),gpuArray(rand(189,3))); toc;
Elapsed time is 0.006859 seconds.
>> tic; sqEuclideanDist(rand(1581,3),rand(189,3)); toc;
Elapsed time is 0.005712 seconds.

ジャケットを使用したCPUとGPUの結果(完全にウォームアップ)。 ジャケットはPCTgpuArrayを3.7倍上回り、CPUを3倍上回ります

>> tic; sqEuclideanDist(gdouble(rand(1581,3)),gdouble(rand(189,3))); toc;
Elapsed time is 0.001876 seconds.

これが、すべてを簡単に実行できるようにする変更されたコードです。

function K = sqEuclideanDist(P,Q)
% Vectorized method to compute pairwise squared Euclidean distance on GPU
% Returns K(i,j) = (P(i,:) - Q(j,:))'*(P(i,:) - Q(j,:))

[nP, d] = size(P);
[nQ, d] = size(Q);

pmag = sum(P .* P, 2);
qmag = sum(Q .* Q, 2);

K = ones(nP,1)*qmag' + pmag*ones(1,nQ) - 2*P*Q';

end

ジャケットはGPUでBSXFUNをサポートし、速度をいくらか改善します。

>> tic; sqEuclideanDist(gdouble(rand(1581,3)),gdouble(rand(189,3))); toc;
Elapsed time is 0.001420 seconds.

ここで使用されているサイズはかなり小さいため、これらの小さいサイズで実行しようとするほとんどのCUDAコードはパフォーマンスが低下する可能性があります。だから私はAccelerEyesのものを使うのが好きです。なぜなら、私が過去に試したPCT gpuArray、Thrust、OpenCVとは異なり、それらの人たちはGPUから一体を最適化したからです。

ArrayFire FreeC++の結果は次のとおりです。

Time:  0.0003577 seconds
Speedups:  19.2X faster than PCT gpuArray, 16X faster than the CPU, 5.2X faster
than Jacket in MATLAB original version, 4X faster than Jacket in MATLAB using
BSXFUN

これが私がこれのために書いたArrayFireコードです:

static array SqEuclideanDist(array P, array Q)
{
    // 0 based indexing
    array pmag = sum(P * P, 1);
    array qmag = sum(Q * Q, 1);

    int np = P.dims(0);
    int nq = Q.dims(0);

    array K = tile(qmag.T(), np, 1) + tile(pmag, 1, nq) - 2 * matmul(P, Q.T());
    return K;
}

int main(int argc, char **argv)
{
    double *P_cpu = new double[1581 * 3];
    double *Q_cpu = new double[189 * 3];

    array P = array(1581, 3, P_cpu);
    array Q = array(189 , 3, Q_cpu);
    af::sync();

    int iter = 1000;

    timer::tic();
    for (int i = 0; i < iter; i++) {
        array K = SqEuclideanDist(P, Q);
        af::eval(K);
    }

    af::sync();
    printf("Time taken: %2.4lfms\n", (1000 * timer::toc()) / iter);

    delete[] P_cpu;
    delete[] Q_cpu;
}
于 2012-06-29T13:57:07.207 に答える
1

これらはNVidiaによって提供されているため、CUDA互換カードで優れたパフォーマンスを発揮します。実際のパフォーマンスは、カード自体と使用している機能によって異なります。

私の経験では、cvRotateとcvResizeのみが通常のIntelCPUよりも優れたパフォーマンスを示しました。(注:私は画像関連の機能にのみ興味がありました)

于 2012-06-29T12:51:34.467 に答える