Il semble que la convolution basée sur la FFT souffre d'une résolution limitée en virgule flottante en raison de tout évaluer autour des racines de l'unité, comme vous pouvez le voir dans l' erreur de facteur dans ce code Python:
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]
Existe-t-il des algorithmes de convolution rapide qui ne souffrent pas de ce problème?
Ou la convolution directe (temps quadratique) est-elle le seul moyen d'obtenir une solution précise?
(Que ces petits nombres soient suffisamment importants pour ne pas être coupés est hors de propos.)
fft
convolution
algorithms
fourier
fast-convolution
user541686
la source
la source
convolve()
n'appelle quefftconvolve()
maintenant, si la taille d'entrée est grande. Spécifiezmethod='direct'
si vous voulez directement.Réponses:
Avis de non-responsabilité: je sais que ce sujet est plus ancien, mais si l'on recherche une "plage dynamique élevée de convolution rapide et précise" ou similaire, c'est l'un des premiers des quelques résultats décents. Je veux partager mes idées sur ce sujet afin que cela puisse aider quelqu'un à l'avenir. Je m'excuse si je pourrais utiliser les mauvais termes dans ma réponse, mais tout ce que j'ai trouvé sur ce sujet est assez vague et conduit à la confusion même dans ce fil. J'espère que le lecteur comprendra de toute façon.
La convolution directe est généralement précise à la précision de la machine pour chaque point, c'est-à-dire que l' erreur relative est généralement approximativement ou proche de 1.e-16 pour une double précision pour chaque point du résultat. Chaque point a 16 chiffres corrects. Cependant, les erreurs d'arrondi peuvent être importantes pour des convolutions inhabituellement importantes, et à proprement parler, il faut faire attention à l'annulation et utiliser quelque chose comme la sommation de Kahan et des types de données de précision suffisamment élevée, mais dans la pratique, l'erreur est presque toujours optimale.
L'erreur d'une convolution FFT en dehors des erreurs d'arrondi est une erreur "relative globale", ce qui signifie que l'erreur en chaque point dépend de la précision de la machine et de la valeur de crête du résultat. Par exemple, si la valeur maximale du résultat est2 ⋅dix9⋅dix- 16= 2 ⋅dix- 7 dix- 9 , l'erreur relative à ce point peut être énorme. La convolution FFT est fondamentalement inutile si vous avez besoin de petites erreurs relatives dans la queue de votre résultat, par exemple vous avez une décroissance quelque peu exponentielle de vos données et avez besoin de valeurs précises dans la queue. Fait intéressant, si la convolution FFT n'est pas limitée par cette erreur, elle a des erreurs d'arrondi beaucoup plus petites que la convolution directe, car vous faites évidemment moins d'ajouts / multiplications. C'est en fait pourquoi les gens prétendent souvent que la convolution FFT est plus précise, et ils ont presque raison dans un certain sens, ils peuvent donc être assez catégoriques.
2.e9
, alors l'erreur absolue en chaque point est . Donc, si une valeur dans le résultat est supposée être très petite, disonsMalheureusement, il n'y a pas de solution universelle facile pour obtenir des convolutions rapides et précises, mais en fonction de votre problème, il peut y en avoir une ... J'en ai trouvé deux:
Si vous avez des noyaux lisses qui peuvent être bien approchés par un polynôme dans la queue, alors la méthode multipolaire rapide à boîte noire avec interpolation de Chebyshev pourrait être intéressante pour vous. Si votre noyau est "sympa", cela fonctionne parfaitement: vous obtenez à la fois une complexité de calcul linéaire (!) Et une précision de précision de la machine. Si cela correspond à votre problème, vous devez l'utiliser. Ce n'est cependant pas facile à mettre en œuvre.
Pour certains noyaux spécifiques (fonctions convexes je pense, généralement à partir des densités de probabilité), vous pouvez utiliser un "décalage exponentiel" pour obtenir une erreur optimale dans une partie de la queue du résultat. Il y a une thèse de doctorat et un github avec une implémentation de python qui l'utilisent systématiquement, et l'auteur l'appelle une convolution FFT précise . Dans la plupart des cas, cela n'est cependant pas très utile, car soit il régresse en convolution directe, soit vous pouvez utiliser la convolution FFT de toute façon. Bien que le code le fasse automatiquement, ce qui est bien sûr bien sûr.
--------------------ÉDITER:--------------------
J'ai regardé un peu l' algorithme de Karatsuba (j'ai en fait fait une petite implémentation), et il me semble qu'il a généralement un comportement d'erreur similaire à la convolution FFT, c'est-à-dire que vous obtenez une erreur par rapport à la valeur de crête du résultat. En raison de la nature de division et de conquête de l'algorithme, certaines valeurs dans la queue du résultat ont en fait une meilleure erreur, mais je ne vois pas de moyen systématique facile de dire lesquelles ou en tout cas comment utiliser cette observation. Dommage, au début, je pensais que Karatsuba pourrait être quelque chose d'utile entre la convolution directe et la FFT. Mais je ne vois pas de cas d'utilisation courants où Karatsuba devrait être préféré aux deux algorithmes de convolution communs.
Et pour ajouter au décalage exponentiel que j'ai mentionné ci-dessus: Il existe de nombreux cas où vous pouvez l'utiliser pour améliorer le résultat d'une convolution, mais encore une fois, ce n'est pas une solution universelle. J'utilise en fait cela avec la convolution FFT pour obtenir de très bons résultats (dans le cas général pour toutes les entrées: au pire, même erreur que la convolution FFT normale, au mieux erreur relative à chaque point de la précision de la machine). Mais encore une fois, cela ne fonctionne vraiment bien que pour des noyaux et des données spécifiques, mais pour moi, le noyau et les données ou quelque peu exponentiels en décomposition.
la source
Un des candidats est l' algorithme de Karatsuba , qui s'exécute en temps . Ce n'est pas basé sur la transformation. Il y a aussi du code avec une explication dans les archives de code source de Music-DSP, qui ressemble à une découverte indépendante d'un algorithme similaire.O (NJournal23) ≈O (N1.5849625)
Le test d'une implémentation Python de l'algorithme Karatsuba (installé par
sudo pip install karatsuba
) à l'aide des nombres dans votre question montre que même avec des nombres à virgule flottante 64 bits, l'erreur relative est importante pour l'une des valeurs de sortie:qui imprime:
la source
Plutôt que de supprimer l'algorithme de convolution rapide, pourquoi ne pas utiliser une FFT avec une plage dynamique plus élevée?
Une réponse à cette question montre comment utiliser la bibliothèque Eigen FFT avec boost multiprecision.
la source
Je crois que la précision de l'algorithme Cordic peut être étendue autant que vous le souhaitez, si c'est le cas, utilisez un DFT entier et une longueur de mot appropriée à votre problème.
La même chose serait vraie avec une convolution directe, utilisez des entiers très longs.
la source
La convolution temporelle quadratique pour obtenir un résultat DFT est généralement moins précise (peut générer un bruit numérique de quantification plus fin, en raison d'une superposition plus profonde des étapes arithmétiques) que l'algorithme FFT typique lors de l'utilisation des mêmes types arithmétiques et unités de fonctionnement.
Vous voudrez peut-être essayer des types de données de précision plus élevée (précision quadruple ou arithmétique bignum).
la source