2012-06-21 2 views
12

У меня есть приложение, которое требует обработки нескольких изображений параллельно, чтобы поддерживать скорость в реальном времени.Параллельные вычисления с использованием OpenCV

Насколько я понимаю, я не могу назвать функции графического процессора OpenCV многопоточным способом на одном устройстве CUDA. Я попробовал код конструкции OpenMP, такие как:

#pragma omp parallel for 
for(int i=0; i<numImages; i++){ 
    for(int j=0; j<numChannels; j++){ 
     for(int k=0; k<pyramidDepth; k++){ 
      cv::gpu::multiply(pyramid[i][j][k], weightmap[i][k], pyramid[i][j][k]); 
     } 
    } 
} 

Это, кажется, компилировать и выполнять правильно, но, к сожалению, по-видимому, выполнить numImages темы последовательно на одном устройстве CUDA.

Я должен иметь возможность выполнять несколько потоков параллельно, если у меня есть несколько устройств CUDA, правильно? Чтобы получить несколько устройств CUDA, нужны ли мне несколько видеокарт?

Кто-нибудь знает, работает ли двухчиповая карта nVidia GTX 690 как два независимых устройства CUDA с OpenCV 2.4 или новее? Я нашел подтверждение, что он может работать как таковой с OpenCL, но без подтверждения относительно OpenCV.

+0

Возможно, ответ находится в исходном коде OpenCV? –

ответ

5

Просто выполните умножение переданных изображений на cv::gpu::multiply().

OpenCV и CUDA будут обрабатывать их разделение и делить задачу наилучшим образом. Обычно каждый компьютерный блок (то есть ядро) в графическом процессоре может запускать несколько потоков (обычно> = 16 в CUDA). Это в дополнение к наличию карт, которые могут отображаться в виде нескольких графических процессоров или размещения нескольких связанных карт на одной машине.

Цель cv::gpu - избавить вас от необходимости знать что-либо о том, как работают внутренние устройства.

+0

Да, правда. Функция multiply() записывается, чтобы воспользоваться потоком CUDA внутри самой функции. Однако мне нужна более чем одна функция multiply(), работающая в параллельных потоках. Это не представляется возможным без множественного gpus. Затем вы можете выполнять функцию multiply() для каждого параллельно и для разных изображений одновременно. – mmccullo

+0

@mmccullo - yes cv :: gpu использует поточный поток cuda низкого уровня, вы можете вызывать его в нескольких пользовательских потоках, но каждый из них будет полностью использовать gpu, пока другой не закончит. Если у вас есть карта cuda2, она будет использовать потоки для этого асинхронизации, чтобы ваши потоки не блокировались. –

+0

Я использую CUDA v4.2. Я не уверен, что ваша ссылка на «cuda2» означает точно. По-видимому, он не блокирует мои потоки OpenMP, но время выполнения моего кода выше немного лучше, чем выполнение в одном потоке. Кажется, выполнение нескольких потоков происходит последовательно на одном устройстве CUDA, иначе время выполнения должно быть намного меньше, чем один поток на одном устройстве. Мой тестовый графический процессор - Quadro2000M с 2 ГБ и 192 ядрами CUDA. Изображения 1280x960 RGB. – mmccullo

0

Я ничего не знаю о функциях графического процессора OpenCV, но если они полностью автономны (т. Е. Создают контекст графического процессора, передают данные на GPU, вычисляют результаты, возвращают результаты на CPU), то неудивительно, что эти функции появляются при использовании одного графического процессора.

Если у вас несколько графических процессоров, тогда должен быть способ сообщить функции OpenCV для таргетинга на определенный графический процессор. Если у вас несколько графических процессоров и можно эффективно их настроить, я тогда не вижу причин, по которым вызовы функций GPU не будут распараллеливаться. Согласно вики OpenCV, функции GPU нацелены только на один GPU, но вы можете вручную разбить работу самостоятельно: http://opencv.willowgarage.com/wiki/OpenCV%20GPU%20FAQ#Can_I_use_two_or_more_GPUs.3F

Двойные графические процессоры, такие как GTX 690, будут отображаться как два разных устройства с собственной памятью до вашего GPU программы. Смотрите здесь: http://forums.nvidia.com/index.php?showtopic=231726

Кроме того, если вы собираетесь двойной маршрут GPU для вычислительных приложений, я рекомендовал бы против GTX 690, поскольку его производительность вычислений несколько калека по сравнению с GTX 590.

+0

Интересный комментарий о производительности 690 против 590. Эта страница [nVidia] (http://developer.nvidia.com/cuda-gpus) указывает на более высокую компьютерную способность для 690. Есть ли у вас какие-либо особенности в том, как 690 искалечен? – mmccullo

+0

«Согласно вики OpenCV, функции графического процессора нацелены только на один графический процессор, но вы можете вручную разделить работу самостоятельно», к сожалению, ссылка не активна. Что это означает, что разделить его вручную? Вы должны установить идентификатор устройства перед каждым вызовом gpu opencv? Есть ли официальный пример поддержки заявления. – alap

+0

Также это означает, что в режиме SLI/CrossFire следует использовать ручной переключатель? – alap

0

В GTX 290 ведет себя как 2 отдельных устройства CUDA, независимо от того, какую версию OpenCV вы используете. Вам не нужно несколько графических карт для получения нескольких графических процессоров, которые у вас есть на одной карте, например, в GTX 290. Но с точки зрения программирования CUDA нет большой разницы между использованием двух графических процессоров на 290 и использованием 2 графических процессора на отдельно подключенных графических картах. Многие пользователи OpenCV используют библиотеку ArrayFire CUDA, дополняющую дополнительные функции обработки изображений и простое масштабирование с несколькими GPU. Конечно, мой отказ от ответственности заключается в том, что я работаю над ArrayFire, но я действительно думаю, что это поможет вам в этом случае.

4

Ответ от Мартина работал для меня. Ключ состоит в том, чтобы использовать класс gpu :: Stream, если ваше устройство CUDA указано как вычислительная способность 2 или выше. Я переформулирую его здесь, потому что я не смог правильно разместить клип кода в мини-редакторе комментариев.

cv::gpu::Stream stream[3]; 

for(int i=0; i<numImages; i++){ 
    for(int j=0; j<numChannels; j++){ 
     for(int k=0; k<pyramidDepth; k++){ 
      cv::gpu::multiply(pyramid[i][j][k], weightmap[i][k], pyramid[i][j][k], stream[i]); 
     } 
    } 
} 

Вышеприведенный код, похоже, выполняет параллельное умножение (numImages = 3 для моего приложения). Существуют также методы Stream, которые помогают загружать/загружать изображения в память GPU и из нее, а также методы проверки состояния потока, чтобы помочь в синхронизации с другим кодом.

Итак, для параллельного выполнения кода графического процессора OpenCV, очевидно, не требуется несколько устройств CUDA (например, графических карт)!

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