2012-06-29 12 views
8

Ich benutze OpenCV für eine Anwendung in Computer Vision. Ich möchte einige Matrixoperationen (Matrizen sind ziemlich groß) auf GPU beschleunigen und möchte Kodierung, wenn möglich, direkt in CUDA C vermeiden. OpenCV 2.4.1 hat eine Reihe von GPU-beschleunigten Funktionen. Wie gut sind sie in Ihrer Erfahrung? Ist es besser, stattdessen eine andere Bibliothek (z. B. Thrust) zu verwenden?Wie gut ist OpenCV GPU-Bibliothek für Matrixoperationen?

BEARBEITEN Beispielanwendung: Calculate squared Euclidean distance matrix on GPU. Derzeit ist meine GPU beschleunigte (und vektorisierte) Implementierung in Matlab mit der Parallel Computing Toolbox (PCT) etwa 5-10 mal schneller als meine C++ Implementierung mit OpenCV.

Matlab Implementierung:

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 

UPDATE Hier ist eine andere Matlab-Implementierung, die die gleichen (dank https://stackoverflow.com/a/7774323/1121420) erreicht. Aber es läuft nur auf der CPU, weil bsxfun nicht von PCT unterstützt wird. Immer noch auf der Suche nach C++ Alternative.

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 
+0

Welche Funktionen insbesondere erwägen Sie verwenden? –

+0

Grundlegende Matrix Zeug. gpu :: reduzieren, gpu :: multiplizieren (pro Element Matrix Multiplikation). Auch Matrixmultiplikation, Finden von Matrixeigenwerten und Eigenvektoren, Matrixtransponierung. – Alexey

+1

@Alex - alle einfachen Matrix Ops verwenden die NVidia (Schub?) Bibliothek direkt, so sind sehr gut optimiert –

Antwort

3

Ich finde ArrayFire viel schneller und habe begonnen, es anstelle der GPU-Kernel in OpenCV für die Bildverarbeitung zu verwenden. Hier sind some benchmarks Ich fand ArrayFire vergleichen (früher in einer anderen Schnittstelle namens LibJacket) zu OpenCV und es war auch in meinem Benchmark wahr, dass ArrayFire 2-4X schneller ist als die GPU-Funktionen in OpenCV. Von dem, was ich höre, hat NVIDIA die GPU-Kernel in OpenCV nicht geschrieben, sondern sie an jemanden vergeben, was vielleicht der Grund dafür ist, dass sie so langsam sind. Da ich nur 1 GPU verwende, kann ich ArrayFire kostenlos nutzen.

Update, angesichts der neuen MATLAB-Code von @Alex: Ich lief den Benchmark dieses Codes auf meinem System. Ich bekomme, dass die Parallel Computing Toolbox gpuArray langsamer als die CPU ist, aber Jacket und ArrayFire Kick Butt. HW-Spezifikationen sind:

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

Ergebnisse CPU vs GPU Parallel Computing Toolbox gpuArray (vollständig aufgewärmt) verwendet wird. CPU ist schneller als PCT gpuArray:

>> 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. 

Ergebnisse CPU vs GPU mit Jacke (vollständig aufgewärmt). Jacke schlägt PCT gpuArray von 3.7X und schlägt die CPU von 3X

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

Hier ist der modifizierte Code, dass wir Sie alle laufen, die leicht:

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 

Jacke hat Unterstützung BSXFUN auf der GPU, und es macht die Geschwindigkeiten etwas verbessern :

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

Beachten Sie, dass die Größen hier sind ziemlich klein verwendet, so dass die meisten CUDA-Code, der auf diesen kleinen Größen zu laufen versucht wahrscheinlich schlecht abschneiden. Deshalb benutze ich gerne AccelerEyes 'Zeug, weil diese Jungs das Beste aus der GPU gemacht haben, im Gegensatz zu PCT gpuArray, Thrust, OpenCV, die ich in der Vergangenheit probiert habe.

Hier die Ergebnisse ++ ArrayFire Freie C:

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 

Hier wird der ArrayFire Code, den ich für diese schrieb:

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; 
} 
+1

toller Job. Danke für die Bereitstellung der Alternativen. Definitiv etwas gelernt heute: wusste nicht über Jackets Unterstützung für bsxfun und ich mag den einfachen Code von ArrayFire. Die einzige Sache ist - obwohl es eine kostenlose Version von ArrayFire C++ - Bibliothek gibt, bietet die kostenlose Version ziemlich eingeschränkte Funktionalität (zum Beispiel unterstützt sie keine linearen Algebra-Operationen). Ich bin auf der Suche nach einer Open-Source-Bibliothek. Können Sie mir etwas vorschlagen? – Alexey

+0

Gern geschehen. Überraschend, wie viele Leute diesen Beitrag abgelehnt haben. Wahrscheinlich MathWorks Mitarbeiter. –

+0

Es gibt leider keine Open-Source-Bibliothek, die sehr gute Ergebnisse liefert. Deshalb verwende ich ArrayFire, weil es zumindest für das, was ich brauche, kostenlos ist. So gut wie jede Funktion in ArrayFire ist kostenlos, außer für diejenigen, die von CULA kommen, was für lineare Algebra-Sachen besser ist als MAGMA. Aber ArrayFire hat freie Lineare Algebra-Funktionen mit einfacher Genauigkeit, die ich recht häufig verwende. Würde das für dich funktionieren? Übrigens verwendet der von Ihnen gepostete Code diese linearen Algebra-Funktionen nicht. –

1

Sie wurden von NVidia beigetragen, also hat eine gute Leistung auf CUDA-kompatiblen Karten. Die tatsächliche Leistung hängt von der Karte selbst und der Funktion ab, die Sie verwenden.

In meiner Erfahrung hatten nur cvRotate und cvResize eine bessere Leistung als eine normale Intel-CPU. (Hinweis: Ich war nur an bildbezogenen Funktionen interessiert)