Encuentro ArrayFire mucho más rápido y comencé a usarlo en lugar de los núcleos GPU en OpenCV para el procesamiento de imágenes. Aquí están some benchmarks Encontré comparando ArrayFire (solía estar en una interfaz diferente llamada LibJacket) para OpenCV y también ha sido cierto en mi evaluación comparativa que ArrayFire es 2-4 veces más rápido que las funciones de la GPU en OpenCV. Por lo que he escuchado, NVIDIA no escribió los núcleos de la GPU en OpenCV, sino que los contrató a alguien, y es por eso que son muy lentos. Como solo uso 1 GPU, puedo usar ArrayFire gratis.
Actualización, dado el nuevo código de MATLAB publicado por @Alex: Corrí el punto de referencia de este código en mi sistema. Entiendo que el gpuArray de Parallel Computing Toolbox es más lento que el CPU, pero Jacket y ArrayFire patean el trasero. especificaciones HW son:
Intel(R) Xeon(R) CPU X5660 @ 2.80GHz
NVIDIA Tesla M2090
Resultados de CPU vs GPU usando Parallel Computing Toolbox gpuArray (completamente calentado). CPU es más rápido que 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.
Resultados de CPU vs GPU utilizando Jacket (completamente calentado). Jacket beats PCT gpuArray por 3.7X y golpea a la CPU por 3X
>> tic; sqEuclideanDist(gdouble(rand(1581,3)),gdouble(rand(189,3))); toc;
Elapsed time is 0.001876 seconds.
Aquí está el código modificado que vamos a ejecutar los que fácilmente:
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
chaqueta hace de soporte BSXFUN en la GPU, y lo hace mejorar las velocidades de algo :
>> tic; sqEuclideanDist(gdouble(rand(1581,3)),gdouble(rand(189,3))); toc;
Elapsed time is 0.001420 seconds.
Tenga en cuenta que los tamaños utilizados aquí son bastante pequeñas, por lo que la mayoría del código CUDA que intenta ejecutar en estos tamaños pequeños es probable que un mal desempeño. Es por eso que me gusta usar las cosas de AccelerEyes, porque esos tipos han optimizado la GPU, a diferencia de PCT gpuArray, Thrust, OpenCV, cada uno de los cuales he probado en el pasado.
Aquí es el resultado ArrayFire libre de 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
Aquí está el código ArrayFire que escribí para esto:
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;
}
¿Qué funciones, en particular estás considerando utilizar? –
Cosas básicas de matriz. gpu :: reduce, gpu :: multiplicar (por multiplicación de matrices de elementos). Además, la multiplicación de matrices, la búsqueda de autovalores y vectores propios de la matriz, la transposición de la matriz. – Alexey
@Alex: todas las operaciones simples de matriz utilizan directamente la biblioteca NVidia (¿de empuje?), Así que están muy bien optimizadas –