Algorithmen zur parallelen Berechnung der FFT


12

Ich versuche, die Berechnung einer FFT für Terabyte große Signaldateien zu parallelisieren. Im Moment dauert eine solche FFT mit einer Open-Source-Bibliothek viele Stunden, selbst wenn sie mit der schnellsten GPU, die ich habe, durch CUDA läuft. Das Framework, das ich an diesen Prozess anpassen möchte, ist Hadoop. Grundsätzlich verteilt Hadoop ein Problem auf folgende Weise auf eine beliebige Anzahl von Serverknoten:

• Sie teilen Ihre Eingabedatei in Paare (Schlüssel, Wert) auf.
• Diese Paare werden in einen "Map" -Algorithmus eingespeist, der Ihre (Schlüssel-, Wert-) Paare in einige andere (Schlüssel-, Wert-) Paare umwandelt, je nachdem, was Sie in die Map einfügen.
• Das Framework sammelt dann alle (Schlüssel-, Wert-) Ausgaben der Maps und sortiert sie nach Schlüssel. Außerdem werden die Werte mit demselben Schlüssel zu einem einzigen Paar zusammengefasst, sodass Sie am Ende (Schlüssel, Liste (Wert1, Wert2, ..)) Paare
• Diese Paare werden dann in einen "Reduzieren" -Algorithmus eingespeist, der wiederum mehr (Schlüssel, Wert) Paare als Ihr Endergebnis ausgibt (in eine Datei geschrieben).

Es gibt viele Anwendungen für dieses Modell in praktischen Dingen wie der Verarbeitung von Serverprotokollen, aber es fällt mir schwer, das Framework zum Zerlegen einer FFT in "Map" - und "Reduction" -Aufgaben anzuwenden, zumal ich mit DSP nicht wirklich vertraut bin.

Ich werde Sie mit dem Programmier-Hokuspokus nicht belästigen, da dies eine DSP-Frage und Antwort ist. Ich bin jedoch verwirrt darüber, welche Algorithmen für die parallele Berechnung von FFTs existieren. Map- und Reduce-Aufgaben können (technisch) nicht miteinander kommunizieren, daher muss die FFT in unabhängige Probleme aufgeteilt werden, aus denen die Ergebnisse am Ende irgendwie wieder zusammengeführt werden können.

Ich habe eine einfache Implementierung von Cooley-Tukey Radix 2 DIT programmiert, die an kleinen Beispielen funktioniert, aber die Verwendung für die rekursive Berechnung von DFTs mit ungeraden / geraden Indizes für eine Milliarde Bytes wird nicht funktionieren. Ich habe ein paar Wochen damit verbracht, viele Artikel zu lesen, darunter einen über einen MapReduce-FFT-Algorithmus (geschrieben von Tsz-Wo Sze als Teil seines Beitrags zur SSA-Multiplikation, ich kann nicht mehr als zwei Hyperlinks verknüpfen) und die "Vier-Schritt-FFT". ( hier und hier), die einander und dem, was ich zu erreichen versuche, ähnlich zu sein scheinen. Ich bin jedoch hoffnungslos schlecht in Mathematik und wende eine dieser Methoden von Hand auf eine einfache Menge von Dingen wie {1,2, 3, 4, 5, 6, 7, 8} an (wobei alle imaginären Komponenten 0 sind) mir wild falsche ergebnisse. Kann mir jemand einen effizienten parallelen FFT-Algorithmus im Klartext erklären (einen, den ich verknüpft habe oder einen anderen), damit ich ihn programmieren kann?

Edit: Jim Clay und jeder andere, der durch meine Erklärung verwirrt sein könnte, ich versuche, eine einzelne FFT der Terabyte-Datei zu machen. Ich möchte es jedoch auf mehreren Servern gleichzeitig ausführen können, um den Vorgang zu beschleunigen.


1
Was genau versuchst du zu erreichen? Möchten Sie eine einzelne FFT der Terabyte-Signaldatei oder mehrere kleinere FFTs jeder Datei ausführen?
Jim Clay

Antworten:


13

Ich denke, Ihr Hauptproblem ist nicht, wie der Algorithmus parallel geschaltet werden soll (was tatsächlich möglich ist), sondern die numerische Genauigkeit. FFTs einer so großen Größe sind zahlenmäßig recht knifflig. Die FFT-Koeffizienten haben die Form und wenn N sehr groß ist, wird die Koeffizientenberechnung verrauscht. Nehmen wir an, Sie habenN=240und verwenden eine 64-Bit-Arithmetik mit doppelter Genauigkeit. Die ersten 1000 Koeffizienten haben einen Realteil, der genau eins ist (obwohl dies nicht der Fall sein sollte), sodass Sie eine genauere Mathematik benötigen, die sehr ineffizient und umständlich zu verwenden ist.ej2πkNN=240

Sie werden auch viele Rundungs- und Kürzungsfehler ansammeln, da die Anzahl der Operationen, die in eine einzelne Ausgabenummer fließen, ebenfalls sehr groß ist. Aufgrund der Natur der FFT "jeder Ausgang hängt von jedem Eingang ab" ist die Fehlerausbreitung weit verbreitet.

Mir ist kein einfacher Weg bekannt, das zu umgehen. Ihre Anfrage ist ungewöhnlich. Die meisten Anwendungen, die eine Spektralanalyse großer Datenmengen durchführen, führen eine laufende Analyse durch, bei der dieses Problem nicht auftritt. Wenn Sie Ihre Anwendung und die damit verbundenen Einschränkungen besser beschreiben können, können wir Sie möglicherweise auf eine geeignetere Lösung hinweisen.


Ziemlich sicher. Ich werde mehr darüber nachdenken müssen. Vielleicht greife ich am Ende auf eine "Laufanalyse" zurück, wie Sie sagen.
Philipp

Ich weiß, dass ich wirklich spät dran bin, aber haben Sie zufällig eine Quelle dafür, wie es gemacht werden kann, da Sie erwähnt haben, dass es gemacht werden kann?
Claudio Brasser

4

Anstatt zu versuchen, die FFT neu zu schreiben, können Sie versuchen, eine vorhandene FFT-Implementierung (wie z. B. die FFTW ) zu verwenden und sie wiederholt über die Überlappungs-Addition oder die Überlappungs-Addition entlang der Länge Ihres Signals (egal wie groß sie ist) anzuwenden. Methoden speichern . Dies ist möglich, indem die FFT als Faltung ausgedrückt wird .

Diese kürzeren FFTs müssen nicht miteinander kommunizieren, und das gesamte Schema entspricht den Schritten zur Kartenreduzierung.

Im Allgemeinen möchten Sie Ihr Signal X in kleinere Segmente aufteilen lassen, die sich ebenfalls überlappen können (z. B. X [0:10], X [5:15], X [10:20] ... .). Führen Sie die FFT für diese kleinen Segmente durch und kombinieren Sie sie am Ende neu, um das endgültige Segment zu erstellen. Dies passt sehr gut zu den Kartenreduzierungsoperatoren.

Während "map" können Sie Paare (Schlüssel, Wert) erzeugen, wobei "key" eine fortlaufende ID jedes Segments ist (0,1,2,3,4,5, ....) und "value" der Wert ist INDEX (oder Dateiposition) des ersten Wertes eines Segments in der Datei Ihres Signals. Wenn Ihre Datei beispielsweise mit INT32s gefüllt ist, hat der Index des zweiten Segments (oben) die 5-fache Größe von (INT32). (Oder wenn es in einem anderen Format ist, haben Sie vielleicht eine Bibliothek dafür)

Jetzt erhält jeder Worker einen (Schlüssel, Wert), öffnet eine Datei, sucht nach dem richtigen Punkt, liest M Samples daraus (wobei M 10 oben ist), führt die FFT durch und speichert sie in einer Datei mit einem Namen, zum Beispiel " RES_ [INKEY] .dat "und gibt ein (Schlüssel-, Wert-) Paar zurück. In diesem Fall wäre "Schlüssel" der INDEX (der "Wert" des eingehenden (Schlüssel, Wert) Tupels) und "Wert" der Name der Datei, die die FFT-Ergebnisse enthält. (Wir werden darauf zurückkommen)

In "Reduzieren" können Sie jetzt entweder Überlappung hinzufügen oder Überlappung speichern, indem Sie einen (Schlüssel, Wert) aus dem Schritt "Map" akzeptieren, diese Datei öffnen, die FFT-Ergebnisse laden, entweder oa oder os ausführen und sie dann speichern den richtigen INDEX in Ihrer Ausgabedatei. (Siehe Pseudocode in diesem (oder jenem ) Schritt "map" behandelt das "yt = ..." parallel und der Schritt "reduction" behandelt den Teil "y (i, k) = ...".)

Möglicherweise müssen Sie einige Dateien jonglieren, um den Datenverkehr im Netzwerk oder die Auslastung eines Servers zu verringern, auf dem sich möglicherweise Ihre eigentliche Datendatei befindet.


1
Ich bin mir nicht sicher, ob Überlappung addieren und Überlappung speichern gilt, um die kleineren Blöcke zu kombinieren, um die größere FFT zu erhalten = AB kann in A DFTs der Größe B, Zweifaktoranwendung, dann B DFTs der Größe A) zerlegt werden. Es könnte funktionieren, wenn wir eine Ausgabe mit niedrigerer Auflösung wünschen ...
pichenettes

Hallo picenettes, danke dafür, was ich im Kopf hatte, war dies ( engineeringproductivitytools.com/stuff/T0001/PT11.HTM ), das ich in die Antwort aufnehmen werde.
A_A

2

2N

2N/2N/22N/2

Genauer gesagt, es ist nicht erforderlich, MR während der gesamten Rekursion zu verwenden. Dies ist in der Tat recht ineffizient. Ihr Problem kann in eine Million Megabyte große innere und äußere FFTs unterteilt werden, und diese Megabyte-FFTs können perfekt mit FFTW oder dergleichen berechnet werden. MR wird nur für die Überwachung des Daten-Shufflings und der Rekombination verantwortlich sein, nicht für die eigentliche FFT-Berechnung ...

Meine allererste Idee wäre die folgende, aber ich vermute, dass dies in einem einzigen MR mit einer intelligenteren Datendarstellung möglich ist.

sR=2N/2

Erste MR: innere FFT

Map: Führen Sie eine zeitliche Dezimierung durch und gruppieren Sie die Abtastwerte in Blöcken für die innere FFT

(k,v)k0..2N1vs[k]

(k%R,(k/R,v))

Reduzieren: innere FFT berechnen

(k,vs)kvs(i,v)

inRin[i]=v

RinoutR

i0..R1(k,(i,out[i]))

Zweiter MR: äußere FFT

Karte: Gruppieren Sie die Muster für das äußere Feld und wenden Sie zwei Faktoren an

(k,(i,v))k(i,v)

(i,(k,v×exp2πjik2N))

Reduzieren: äußere FFT durchführen

(k,vs)kvs(i,v)

inRin[i]=v

RinoutR

i0..R1(i×R+k,out[i]))

Proof-of-Concept-Python-Code hier.

Wie Sie sehen, mischen die Mapper nur die Reihenfolge der Daten, also unter den folgenden Annahmen:

  • Die zeitliche Dezimierung (Mapper 1) kann in einem vorherigen Schritt erfolgen (z. B. durch das Programm, das die Daten in das richtige Eingabeformat konvertiert).
  • Ihr MR-Framework unterstützt Reduzierer, die auf einen anderen Schlüssel als den Eingabeschlüssel schreiben. (In der Implementierung von Google können Reduzierer Daten nur auf den gleichen Schlüssel ausgeben, den sie erhalten haben. Ich denke, dies liegt daran, dass SSTable als Ausgabeformat verwendet wird.)

All dies kann in einem einzigen MR durchgeführt werden, der inneren FFT im Mapper und der äußeren FFT im Reducer. Proof of Concept hier .


Ihre Implementierung scheint vielversprechend zu sein, und ich werde sie gerade durcharbeiten, aber im inneren FFT-Reduzierer schreiben Sie "FFT mit Größe 2 ^ R einführen, um einen Vektor aus Größe 2 ^ R zu erhalten". Wenn R 2 ^ (N / 2) ist, wäre diese FFT dann nicht 2 ^ (2 ^ N / 2) und damit falsch? Meinten Sie FFT von Größe R?
Philipp

R2Rexp2πjik2N

0

Wenn Ihr Signal mehrdimensional ist, kann die Parallelisierung der FFT relativ einfach durchgeführt werden. Halten Sie eine Dimension in einem MPI-Prozess zusammenhängend, führen Sie die FFT durch und transponieren Sie (altoall), um an der nächsten Dimension zu arbeiten. FFTW macht das.

Wenn die Daten 1D sind, ist das Problem viel schwieriger. Beispielsweise hat FFTW keine 1D-FFT mit MPI geschrieben. Wenn man einen Radix-2-Algorithmus für die Frequenzdezimation verwendet, können die ersten Stufen als naive DFT ausgeführt werden, sodass 2 oder 4 Knoten ohne Genauigkeitsverlust verwendet werden können (dies liegt daran, dass die Einheitswurzeln für die Die ersten Stufen sind entweder -1 oder i, mit denen man gut arbeiten kann.

Übrigens, was haben Sie mit den Daten vor, nachdem Sie sie transformiert haben? Es könnte sein, dass man etwas tut, wenn man weiß, was mit dem Ausgang passiert (z. B. eine Faltung, ein Tiefpassfilter usw.).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.