Disclaimer: so che questo argomento è più vecchio, ma se si è alla ricerca di "convoluzione veloce elevata gamma dinamica elevata" o simile, questo è uno dei primi di pochi risultati decenti. Voglio condividere le mie intuizioni che ho avuto su questo argomento in modo che possa aiutare qualcuno in futuro. Mi scuso se potrei usare i termini sbagliati nella mia risposta, ma tutto ciò che ho trovato su questo argomento è piuttosto vago e può creare confusione anche in questo thread. Spero che il lettore capirà comunque.
La convoluzione diretta è per lo più accurata alla precisione della macchina per ciascun punto, ovvero l' errore relativo è generalmente approssimativamente o vicino a 1.e-16 per una doppia precisione per ciascun punto del risultato. Ogni punto ha 16 cifre corrette. Gli errori di arrotondamento possono essere significativi per convoluzioni di grandi dimensioni atipiche e, a rigor di termini, si dovrebbe fare attenzione con la cancellazione e utilizzare qualcosa come la somma di Kahan e tipi di dati di precisione sufficientemente elevati, ma in pratica l'errore è quasi sempre ottimale.
L'errore di una convoluzione FFT oltre agli errori di arrotondamento è un errore "relativo globale", il che significa che l'errore in ciascun punto dipende dalla precisione della macchina e dal valore di picco del risultato. Ad esempio, se il valore di picco del risultato è 2.e9
, allora l'errore assoluto è in ciascun punto2⋅109⋅10−16=2⋅10−7. Quindi, se un valore nel risultato dovrebbe essere molto piccolo, diciamo10−9, l'errore relativo in quel punto può essere enorme. La convoluzione FFT è sostanzialmente inutile se hai bisogno di piccoli errori relativi nella coda del tuo risultato, ad esempio hai un decadimento in qualche modo esponenziale dei tuoi dati e hai bisogno di valori precisi nella coda. È interessante notare che se la convoluzione FFT non è limitata da quell'errore, ha errori di arrotondamento molto più piccoli rispetto alla convoluzione diretta, poiché ovviamente si fanno meno aggiunte / moltiplicazioni. Questo è il motivo per cui le persone spesso dichiarano che la convoluzione della FFT è più accurata e hanno quasi ragione in un certo senso, quindi possono essere piuttosto irremovibili.
Sfortunatamente non esiste una soluzione universale facile per ottenere convoluzioni veloci e precise, ma a seconda del problema potrebbe essercene uno ... Ne ho trovati due:
Se hai kernel lisci che possono essere approssimati bene da un polinomio nella coda, allora il metodo multipolare veloce in scatola nera con interpolazione di Chebyshev potrebbe essere interessante per te. Se il tuo kernel è "carino", in realtà funziona perfettamente: ottieni complessità computazionale lineare (!) E precisione di precisione della macchina. Se questo si adatta al tuo problema, dovresti usarlo. Tuttavia, non è facile da implementare.
Per alcuni kernel specifici (penso che funzioni convesse, di solito a densità di probabilità) è possibile utilizzare uno "spostamento esponenziale" per ottenere un errore ottimale in alcune parti della coda del risultato. C'è una tesi di dottorato e un github con un'implementazione di Python che lo utilizza sistematicamente, e l'autore lo definisce convoluzione FFT accurata . Nella maggior parte dei casi, ciò non è molto utile, poiché o regredisce alla convoluzione diretta o è possibile utilizzare la convoluzione FFT comunque. Anche se il codice lo fa automaticamente, il che è carino ovviamente.
--------------------MODIFICARE:--------------------
Ho guardato un po 'l' algoritmo Karatsuba (in realtà ho fatto una piccola implementazione), e a me sembra che abbia un comportamento di errore simile alla convoluzione FFT, cioè si ottiene un errore rispetto al valore di picco del risultato. A causa della divisione e della conquista della natura dell'algoritmo, alcuni valori nella coda del risultato hanno effettivamente un errore migliore, ma non vedo un modo semplice e sistematico per dire quali o comunque usare questa osservazione. Peccato, all'inizio pensavo che Karatsuba potesse essere qualcosa di utile tra la convoluzione diretta e la FFT. Ma non vedo casi d'uso comuni in cui Karatsuba dovrebbe essere preferito rispetto ai due comuni algoritmi di convoluzione.
E per aggiungere al cambiamento esponenziale che ho menzionato sopra: ci sono molti casi in cui puoi usarlo per migliorare il risultato di una convoluzione, ma ancora una volta non è una soluzione universale. In realtà lo uso insieme alla convoluzione FFT per ottenere risultati abbastanza buoni (nel caso generale di tutti gli input: nel peggiore stesso errore della normale convoluzione FFT, nella migliore delle ipotesi errore relativo in ogni punto della precisione della macchina). Ma ancora una volta, funziona davvero bene solo per kernel e dati specifici, ma per me sia kernel che dati o in qualche modo esponenziale in decadimento.
convolve()
chiama solofftconvolve()
ora, se le dimensioni di input sono grandi. Specificaremethod='direct'
se si desidera diretto.