我正在将OpenCV用于计算机视觉中的应用程序。我想在GPU上加速某些矩阵运算(矩阵相当大),并希望避免在可能的情况下直接在CUDA C中进行编码。 OpenCV 2.4.1具有许多GPU加速功能。他们在您的体验中表现如何?我最好改用另一个库(例如Thrust)吗?
编辑示例应用程序:Calculate squared Euclidean distance matrix on GPU。目前,我在Matlab中使用并行计算工具箱(PCT)进行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
UPDATE这是另一个实现相同功能的Matlab实现(由于[C0])。但是它仅在CPU上运行,因为PCT不支持https://stackoverflow.com/a/7774323/1121420。仍在寻找C ++替代方案。
bsxfun
我发现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
更快,并且已经开始使用它来代替OpenCV中的GPU内核进行图像处理。这是ArrayFire,我发现将ArrayFire(以前在另一个名为LibJacket的接口中)与OpenCV进行了比较,在我的基准测试中也是如此,ArrayFire比OpenCV中的GPU功能快2-4倍。据我了解,NVIDIA没有在OpenCV中编写GPU内核,而是将这些内核外包给了某人,这可能就是为什么它们这么慢的原因。由于我只使用1个GPU,因此可以免费使用ArrayFire。
更新,给定@Alex发布的新MATLAB代码:我在系统上运行了该代码的基准测试。我知道Parallel Computing Toolbox gpuArray比CPU慢,但是Jacket和ArrayFire却差强人意。硬件规格为:
some benchmarks
使用Parallel Computing Toolbox gpuArray(完全预热)的CPU与GPU的结果。 CPU比PCT gpuArray更快]:
Intel(R) Xeon(R) CPU X5660 @ 2.80GHz NVIDIA Tesla M2090
使用Jacket的CPU与GPU的结果(已完全预热)。 Jacket击败PCT gpuArray 3.7倍,CPU击败3X
>> 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.
这是经过修改的代码,可让您轻松运行所有代码:
>> tic; sqEuclideanDist(gdouble(rand(1581,3)),gdouble(rand(189,3))); toc; Elapsed time is 0.001876 seconds.
Jacket确实在GPU上支持BSXFUN,并且确实提高了速度:
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
请注意,这里使用的大小非常小,因此大多数尝试在这些小尺寸上运行的CUDA代码的性能可能很差。这就是为什么我喜欢使用AccelerEyes的东西的原因,因为那些家伙已经优化了GPU的功能,这与我过去尝试过的PCT gpuArray,Thrust和OpenCV不同。
这里是ArrayFire Free C ++的结果:
>> tic; sqEuclideanDist(gdouble(rand(1581,3)),gdouble(rand(189,3))); toc; Elapsed time is 0.001420 seconds.
这是我为此编写的ArrayFire代码:
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
它们是由NVidia贡献的,因此在CUDA兼容卡上确实具有良好的性能。实际性能取决于卡本身和所使用的功能。