Schneller und genauer Faltungsalgorithmus (wie FFT) für hohen Dynamikbereich?


8

Es scheint, dass die FFT-basierte Faltung unter einer begrenzten Gleitkommaauflösung leidet, da alles um die Wurzeln der Einheit herum ausgewertet wird, wie Sie im -Faktorfehler in diesem Python-Code sehen können:1014

from scipy.signal import convolve, fftconvolve
a = [1.0, 1E-15]
b = [1.0, 1E-15]
convolve(a, b)     # [  1.00000000e+00,   2.00000000e-15,   1.00000000e-30]
fftconvolve(a, b)  # [  1.00000000e+00,   2.11022302e-15,   1.10223025e-16]

Gibt es schnelle Faltungsalgorithmen, die nicht unter diesem Problem leiden?
Oder ist eine direkte (quadratische) Faltung der einzige Weg, um eine genaue Lösung zu erhalten?

(Ob solch kleine Zahlen signifikant genug sind, um nicht abzuhacken, ist neben meinem Standpunkt.)


Beachten Sie, dass convolve()nur fftconvolve()jetzt aufgerufen wird , wenn die Eingabegröße groß ist. Geben method='direct'Sie an, ob Sie direkt möchten.
Endolith

@endolith: Guter Punkt! Das habe ich erst kürzlich gelernt, aber hier vergessen.
user541686

Antworten:


5

Haftungsausschluss: Ich weiß, dass dieses Thema älter ist, aber wenn man nach einem "schnellen, genauen Faltungs-Hochdynamikbereich" oder ähnlichem sucht, ist dies eines der ersten von nur wenigen anständigen Ergebnissen. Ich möchte meine Erkenntnisse zu diesem Thema teilen, damit es in Zukunft jemandem helfen kann. Ich entschuldige mich, wenn ich in meiner Antwort möglicherweise die falschen Begriffe verwende, aber alles, was ich zu diesem Thema gefunden habe, ist ziemlich vage und führt selbst in diesem Thread zu Verwirrung. Ich hoffe der Leser wird es trotzdem verstehen.

Die direkte Faltung ist meistens auf die Maschinengenauigkeit für jeden Punkt genau, dh der relative Fehler liegt normalerweise ungefähr oder nahe bei 1.e-16 für die doppelte Genauigkeit für jeden Punkt des Ergebnisses. Jeder Punkt hat 16 korrekte Ziffern. Rundungsfehler können für untypisch große Windungen von Bedeutung sein, und genau genommen sollte man beim Löschen vorsichtig sein und so etwas wie Kahan-Summierung und ausreichend genaue Datentypen verwenden, aber in der Praxis ist der Fehler fast immer optimal.

2.e921091016=2107109kann der relative Fehler in diesem Punkt sehr groß sein. Die FFT-Faltung ist grundsätzlich nutzlos, wenn Sie kleine relative Fehler im Ende Ihres Ergebnisses benötigen, z. B. wenn Ihre Daten etwas exponentiell abfallen und genaue Werte im Ende benötigen. Interessanterweise weist die FFT-Faltung, wenn sie nicht durch diesen Fehler begrenzt ist, im Vergleich zur direkten Faltung viel kleinere Rundungsfehler auf, da Sie offensichtlich weniger Additionen / Multiplikationen durchführen. Dies ist tatsächlich der Grund, warum Menschen oft behaupten, dass die FFT-Faltung genauer ist, und sie haben in gewissem Sinne fast recht, so dass sie ziemlich unnachgiebig sein können.

Leider gibt es keine einfache universelle Lösung , um schnelle und genaue Windungen zu erhalten, aber abhängig von Ihrem Problem kann es eine geben ... Ich habe zwei gefunden:

Wenn Sie glatte Kernel haben, die durch ein Polynom im Schwanz gut angenähert werden können, ist die Black-Box-Fast-Multipole-Methode mit Chebyshev-Interpolation möglicherweise für Sie interessant. Wenn Ihr Kernel "nett" ist, funktioniert dies tatsächlich perfekt: Sie erhalten sowohl lineare (!) Rechenkomplexität als auch Maschinengenauigkeit. Wenn dies zu Ihrem Problem passt, sollten Sie es verwenden. Es ist jedoch nicht einfach zu implementieren.

Für einige spezifische Kernel (konvexe Funktionen, glaube ich, normalerweise aus Wahrscheinlichkeitsdichten) können Sie eine "exponentielle Verschiebung" verwenden, um einen optimalen Fehler in einem Teil des Endes des Ergebnisses zu erhalten. Es gibt eine Doktorarbeit und einen Github mit einer Python-Implementierung , die diese systematisch verwendet, und der Autor nennt sie eine genaue FFT-Faltung . In den meisten Fällen ist dies jedoch nicht besonders nützlich, da es entweder zur direkten Faltung zurückkehrt oder Sie die FFT-Faltung trotzdem verwenden können. Obwohl der Code es automatisch macht, ist das natürlich schön.

--------------------BEARBEITEN:--------------------

Ich habe mir den Karatsuba- Algorithmus ein wenig angesehen (ich habe tatsächlich eine kleine Implementierung vorgenommen), und für mich sieht es so aus, als ob er normalerweise ein ähnliches Fehlerverhalten wie die FFT-Faltung aufweist, dh Sie erhalten einen Fehler relativ zum Spitzenwert des Ergebnisses. Aufgrund der Teilung und Eroberung des Algorithmus weisen einige Werte am Ende des Ergebnisses tatsächlich bessere Fehler auf, aber ich sehe keine einfache systematische Methode, um festzustellen, welche oder auf jeden Fall, wie diese Beobachtung verwendet werden soll. Schade, zuerst dachte ich, Karatsuba könnte etwas Nützliches zwischen direkter und FFT-Faltung sein. Ich sehe jedoch keine häufigen Anwendungsfälle, in denen Karatsuba den beiden üblichen Faltungsalgorithmen vorgezogen werden sollte.

Und um die oben erwähnte exponentielle Verschiebung zu ergänzen : Es gibt viele Fälle, in denen Sie damit das Ergebnis einer Faltung verbessern können, aber es ist wiederum keine universelle Lösung. Ich verwende dies tatsächlich zusammen mit der FFT-Faltung, um ziemlich gute Ergebnisse zu erzielen (im allgemeinen Fall für alle Eingaben: im schlimmsten Fall der gleiche Fehler wie bei der normalen FFT-Faltung, bestenfalls relativer Fehler in jedem Punkt zur Maschinengenauigkeit). Aber auch dies funktioniert nur für bestimmte Kernel und Daten wirklich gut, aber für mich sowohl Kernel als auch Daten oder etwas exponentiell im Zerfall.


+1 Willkommen und vielen Dank für die Veröffentlichung! :)
user541686

1
z=1z

2
Die Originalveröffentlichung von Kahan scheint aus dem Jahr 1964 zu stammen.
oli

Es ist die heutige Überraschung. Eigentlich hatte @DanBoschen eine Weile nach einem DSP-Puzzle gefragt, unter Berücksichtigung des Dynamikbereichs von Gleitkommazahlen, bei dem es sich eigentlich um das gleiche Konzept handelte, sehr kleine Zahlen zu sehr großen Zahlen
hinzuzufügen

3

O(Nlog23)O(N1.5849625)

Das Testen einer Python-Implementierung des Karatsuba-Algorithmus (installiert von sudo pip install karatsuba) unter Verwendung der Zahlen in Ihrer Frage zeigt, dass selbst bei 64-Bit-Gleitkommazahlen der relative Fehler für einen der Ausgabewerte groß ist:

import numpy as np
from karatsuba import *
k = make_plan(range(2), range(2))
l = [np.float64(1), np.float64(1E-15)]
np.set_printoptions(formatter={'float': lambda x: format(x, '.17E')})
print "Karatsuba:"
print(k(l, l)[0:3])
print "Direct:"
print(np.convolve(l, l)[0:3])

welche druckt:

Karatsuba:
[1.0, 1.9984014443252818e-15, 1.0000000000000001e-30]
Direct:
[1.00000000000000000E+00 2.00000000000000016E-15 1.00000000000000008E-30]

2
Es gibt ein extra] am Ende des Links zum Karatsuba-Algorithmus

+1, weil es brillant ist und mir nie in den Sinn gekommen ist, dass Karatsuba ein Faltungsalgorithmus ist, aber es wäre schön, wenn Sie erklären könnten, warum es dieses Problem lösen sollte. Ich kann es für den 2x2-Fall leicht sehen, aber in der allgemeinen rekursiven Einstellung sehe ich nicht, warum es dieses Problem beheben sollte. Es scheint mir plausibel, dass es im Allgemeinen nicht einmal reparierbar ist, aber ich weiß es nicht.
user541686

1
O(n2)1014

1
IEEE-Doppel haben im allgemeinen Fall nur eine Genauigkeit von 15 bis 16 Dezimalstellen. 1e-14 ist also ein vernünftiger Größenfehler für eine Folge einiger arithmetischer Operationen (es sei denn, Sie wählen einige magische Werte aus).
hotpaw2

1
Wenn Sie jemals einen Gleitkomma-Addierer entworfen haben, wissen Sie, dass der Exponent während der Normalisierung durch das Mantissenergebnis bestimmt wird. Sie haben Zahlen ausgewählt, die eine unwahrscheinlich schmale Mantisse erzeugen.
hotpaw2

3

Warum nicht eine FFT mit einem höheren Dynamikbereich verwenden, anstatt den Algorithmus für schnelle Faltung zu verschrotten?

Eine Antwort auf diese Frage zeigt, wie die Eigen-FFT-Bibliothek mit Boost-Multipräzision verwendet wird.


2

Ich glaube, dass die Genauigkeit des Cordic-Algorithmus so weit erweitert werden kann, wie Sie möchten, wenn Sie eine ganzzahlige DFT und eine Wortlänge verwenden, die Ihrem Problem entspricht.

Das gleiche gilt für die direkte Faltung, verwenden Sie sehr lange ganze Zahlen.


1

Die quadratische Zeitfaltung zum Erhalten eines DFT-Ergebnisses ist normalerweise weniger genau (kann aufgrund einer tieferen Schichtung von arithmetischen Schritten ein endlicheres numerisches Quantisierungsrauschen verursachen) als der typische FFT-Algorithmus, wenn dieselben arithmetischen Typen und Operationseinheiten verwendet werden.

Möglicherweise möchten Sie Datentypen mit höherer Genauigkeit (Quad-Genauigkeit oder Bignum-Arithmetik) ausprobieren.


Er, dies wird unter Verwendung der gleichen arithmetischen Typen und Betriebseinheiten, nicht wahr? Klar ist es genauer. Ich denke, die Art von Lärm, von der Sie sprechen, ist nicht die gleiche wie die Art, von der ich spreche. Die Wurzeln der Einheit haben eine Größe von 1, was bedeutet, dass sie einfach keine sehr kleinen Werte darstellen können. Dies scheint nicht vollständig mit der Frage zu tun zu haben, wie sich Rauschen im System ausbreitet.
user541686

In Ihrem Beispiel scheint dies nur genauer zu sein, da Sie eine Länge und Werte ausgewählt haben, bei denen die Rundung zu Ihren Gunsten funktioniert hat. Versuchen Sie einen Bereich von viel längeren Windungen mit viel mehr Koeffizienten ungleich Null mit einer Verteilung, die eine große Größenordnung enthält.
hotpaw2

Das Problem, das ich zu lösen versuche, hat jedoch nichts mit Rundung zu tun. Das ist ein anderes Problem, das ich nicht zu lösen versuche. Die ursprünglichen Beispiele, die ich hatte, waren genau wie das, was Sie gerade gesagt haben, und sie funktionierten gut mit direkter Faltung, wurden aber von FFT zerstört.
user541686

Rundungen (oder andere Quantisierungsmethoden) sind an allen Arithmetiken mit endlicher Genauigkeit beteiligt. Einige Rechenergebnisse ändern sich, wenn sie gerundet sind, andere nicht oder weniger.
hotpaw2

Ich habe nie etwas anderes behauptet. Was ich Ihnen gerade gesagt habe, ist das Problem, das ich zu lösen versuche, hat nichts mit Rundung zu tun. Es ist ein anderes Problem. Ich möchte Rundungen nicht vermeiden, aber ich möchte dieses Problem vermeiden.
user541686
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.