2012-06-29 2 views
8

Я использую OpenCV для приложения в компьютерном зрении. Я хотел бы ускорить некоторые операции с матрицами (матрицы довольно большие) на графическом процессоре и, если это возможно, избегать кодирования непосредственно в CUDA C. В OpenCV 2.4.1 есть несколько ускоренных функций GPU. Насколько хорошо они работают на вашем опыте? Лучше ли мне использовать другую библиотеку (например, Thrust)?Насколько хороша библиотека OpenCV GPU для операций с матрицей?

EDIT Образец приложения: Calculate squared Euclidean distance matrix on GPU. В настоящее время моя ускоренная (и векторизованная) реализация графического процессора в Matlab с использованием Parallel Computing Toolbox (PCT) примерно в 5-10 раз быстрее, чем моя реализация на C++ с OpenCV.

реализация 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, которая выполняет те же (благодаря https://stackoverflow.com/a/7774323/1121420). Но он работает только на CPU, потому что bsxfun не поддерживается PCT. Тем не менее, поиск альтернативы на 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 
+0

Какие функции, в частности, вы планируете использовать? –

+0

Базовая матрица. gpu :: reduce, gpu :: multiply (на умножение матрицы элементов). Кроме того, матричное умножение, нахождение матричных собственных значений и собственных векторов, матрица транспонирована. – Alexey

+1

@Alex - все простые матричные операторы используют библиотеку NVidia (thrust?) Напрямую, поэтому очень хорошо оптимизированы –

ответ

3

Я нахожу ArrayFire намного быстрее и начал использовать его вместо ядер графического процессора в OpenCV для обработки изображений. Вот some benchmarks Я нашел сравнение ArrayFire (используемого в другом интерфейсе под названием LibJacket) для OpenCV, и это было верно и в моем бенчмаркинге, что ArrayFire на 2-4 раза быстрее, чем функции GPU в OpenCV. Из того, что я слышал, NVIDIA не записывала ядра GPU в OpenCV, но навязывала их кому-то, и, возможно, поэтому они настолько медленны. Поскольку я использую только 1 графический процессор, я могу использовать ArrayFire бесплатно.

Обновление, учитывая новый код MATLAB, отправленный @Alex: Я запустил эталон этого кода в своей системе. Я получаю, что Parallel Computing Toolbox gpuArray медленнее, чем процессор, но Jacket и ArrayFire. HW спецификации:

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

Результаты CPU против GPU с использованием параллельных вычислительных Toolbox gpuArray (полностью подогреваемый). процессор быстрее, чем РСТ 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. 

Результаты CPU против GPU с использованием Jacket (полностью подогреваемый). Куртка бьет PCT gpuArray на 3.7X и бьет CPU по 3X

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

куртка делает поддержку BSXFUN на GPU, и это делает улучшить скорость несколько :

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

Обратите внимание, что размеры, используемые здесь довольно малы, поэтому большинство CU код, который пытается работать на этих небольших размерах, вероятно, плохо работает. Вот почему я люблю использовать материалы AccelerEyes, потому что эти ребята оптимизировали черту из графического процессора, в отличие от PCT gpuArray, Thrust, OpenCV, каждый из которых я пытался в прошлом.

Вот в ArrayFire Free 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 

Вот код 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; 
} 
+1

отличная работа. Спасибо за предоставление альтернатив. Определенно узнал что-то сегодня: не знал о поддержке Jacket для bsxfun, и мне нравится простой код ArrayFire. Единственное, что есть - хотя есть бесплатная версия библиотеки ArrayFire C++, бесплатная версия предлагает довольно ограниченную функциональность (например, она не поддерживает операции линейной алгебры). Я ищу библиотеку с открытым исходным кодом, можете ли вы предложить ее? – Alexey

+0

Добро пожаловать. Удивительно, сколько людей отказалось от этой должности. Возможно, сотрудники MathWorks. –

+0

К сожалению, нет библиотеки с открытым исходным кодом, которая дает очень хорошую производительность. Вот почему я использую ArrayFire, потому что, по крайней мере, это бесплатно для того, что мне нужно. Практически каждая функция в ArrayFire является бесплатной, за исключением тех, которые поступают из CULA, что лучше, чем MAGMA для линейной алгебры. Но у ArrayFire есть свободные функции линейной алгебры с одной точностью, которые я использую довольно часто. Будет ли это работать на вас? BTW, код, который вы опубликовали, не использует эти функции линейной алгебры. –

1

Они были внесены компанией NVidia, поэтому имеют хорошую производительность на совместимых с CUDA картах. Реальная производительность зависит от самой карты и функции, которую вы используете.

По моему опыту только cvRotate и cvResize имели лучшую производительность, чем обычный процессор Intel. (Примечание: меня интересовали только функции, связанные с изображением)

Смежные вопросы