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