2012-04-13 5 views
10

Ich experimentiere seit Tagen mit CUDA Kernel um eine schnelle 2D Faltung zwischen einem 500x500 Bild (aber ich könnte auch die Abmessungen variieren) und einem sehr kleinen 2D Kernel (a Laplace-2d-Kernel, so ist es ein 3x3-Kernel .. zu klein, um einen großen Vorteil mit all den Cuda-Threads zu nehmen).CUDA kleiner Kernel 2d Faltung - wie geht das?

Ich habe eine CPU-Classic-Implementierung (zwei For-Schleifen, so einfach wie Sie denken) erstellt und dann begann ich CUDA-Kernel zu erstellen.

Nach einigen enttäuschenden Versuchen, eine schnellere Faltung auszuführen ich mit diesem Code endete: http://www.evl.uic.edu/sjames/cs525/final.html (den Shared-Memory-Abschnitt), läßt es im Grunde ein 16x16 Fäden Lesen alle Faltungsdatenblock er in dem gemeinsamen genutzten Speicher benötigt und führt dann die Faltung durch.

Nichts, die CPU ist immer noch viel schneller. Ich habe den FFT-Ansatz nicht versucht, weil das CUDA-SDK angibt, dass es mit großen Kernel-Größen effizient ist.

Unabhängig davon, ob Sie alles habe ich gelesen, geschrieben, meine Frage ist:

wie kann ich eine schnelle 2D Faltung zwischen einem relativ großen Bild und einem sehr kleinen Kern (3x3) mit CUDA durchführen?

+4

Was meinen Sie mit "die CPU ist immer noch viel schneller"? Zählen Sie das vollständige Programm, einschließlich des Kopierens von Arbeitsspeicher auf und von der GPU oder nur die Zeit, die der Kernel zum Starten und Beenden benötigt? –

+0

Ich brauche kein Timing für jetzt, ich kann sehen, dass das Programm mit der CPU viel schneller beendet :( – paulAl

Antwort

7

Sie haben Recht, dass 3x3-Kernel nicht für FFT-basierte Ansatz geeignet ist. Der beste Weg, um damit umzugehen, wäre, den Kernel in konstanten Speicher zu pushen (oder wenn Sie eine Fermi + -Karte verwenden, sollte dies nicht zu viel Bedeutung haben).

Da Sie die Kernelgröße kennen, ist es am schnellsten, wenn Sie Teile des Eingangsbildes/Signals in den gemeinsamen Speicher einlesen und eine entrollte Multiplikations- und Additionsoperation ausführen.

-

Wenn Sie bereit sind, Bibliotheken zu verwenden, um diesen Vorgang ArrayFire und OpenCV auszuführen haben Convolution Routinen hoch optimiert, dass Sie eine Menge Entwicklungszeit sparen.

Ich bin nicht vertraut mit OpenCV, aber in ArrayFire können Sie etwas wie folgt tun.

array kernel = array(3, 3, h_kernel, afHost); // Transfer the kernel to gpu 
array image = array(w, h, h_image , afHost); // Transfer the image to gpu 
array result = convolve2(image, kernel);  // Performs 2D convolution 

EDIT

Der zusätzliche Nutzen von ArrayFire mit seinem dosierten Betrieb ermöglicht Faltung parallel auszuführen. Sie können lesen, wie convolvutions unterstützen Batch-Operationen über here

Wenn Sie zum Beispiel 10 Bilder hatten, dass Sie den gleichen Kernel falten möchten, können Sie somehting wie folgt tun könnte:

array kernel = array(3, 3, h_kernel, afHost);  // Transfer the kernel to gpu 
array images = array(w, h, 10, h_images, afHost); // Transfer the images to gpu 
array res = convolve2(images, kernel); // Perform all operations simultaneously 

-

Vollständige Offenlegung: Ich arbeite bei AccelerEyes und aktiv an ArrayFire arbeiten.

+0

Die Links sind tot.Um die Beleidigung der Verletzung hinzuzufügen, wurde das Archiv der Wayback Machine explizit gelöscht: http://www.accelereyes.com/robots.txt – Hjulle

+0

@Hjulle Wir haben uns von accelereyes in arrayfire umbenannt. Die Links wurden für mich auf unsere aktuelle Dokumentation umgeleitet. Es tut mir leid, wenn Sie Probleme hatten. Ich habe den Code und die Links aktualisiert, um die neueste Version von arrayfire wiederzugeben. –

+0

Es tut mir leid, wenn ich genervt geklungen habe, danke. Der OpenCV-Link ist jedoch immer noch defekt. – Hjulle