Ich glaube, Sie haben bereits die source code der fftconvolve
Funktion. Normalerweise verwendet es für reale Eingaben die Funktionen numpy.fft.rfftn
und .irfftn
, die N-dimensionale Transformationen berechnen. Da das Ziel mehrere 1-D-Transformationen zu tun ist, können Sie im Grunde fftconvolve
wie folgt umschreiben (vereinfacht):
from scipy.signal.signaltools import _next_regular
def fftconvolve_1d(in1, in2):
outlen = in1.shape[-1] + in2.shape[-1] - 1
n = _next_regular(outlen)
tr1 = np.fft.rfft(in1, n)
tr2 = np.fft.rfft(in2, n)
out = np.fft.irfft(tr1 * tr2, n)
return out[..., :outlen].copy()
Und um das gewünschte Ergebnis berechnen:
result = fftconvolve_1d(data, Gauss)
Das funktioniert, weil numpy.fft.rfft
und .irfft
(beachten Sie das Fehlen von n
im Namen) über eine einzelne Achse des Eingabe-Array (die letzte Achse standardmäßig) zu transformieren. Das ist ungefähr 40% schneller als der OP-Code auf meinem System.
Weitere Beschleunigung kann durch Verwendung eines anderen FFT-Back-End erreicht werden.
Zum einen scheinen die Funktionen in scipy.fftpack
etwas schneller als ihre Numpy-Äquivalente zu sein. Allerdings ist das Ausgabeformat der Scipy-Varianten ziemlich umständlich (siehe docs) und dies macht es schwierig, die Multiplikation durchzuführen.
Ein anderes mögliches Backend ist FFTW durch den PyFFTW-Wrapper. Nachteile sind, dass Transformationen eine langsame "Planungsphase" vorausgehen und dass die Eingaben 16-Byte-ausgerichtet sein müssen, um die beste Leistung zu erzielen. Dies wird in der pyFFTW tutorial ziemlich gut erklärt. Der resultierende Code könnte zum Beispiel sein:
from scipy.signal.signaltools import _next_regular
import pyfftw
pyfftw.interfaces.cache.enable() # Cache for the "planning"
pyfftw.interfaces.cache.set_keepalive_time(1.0)
def fftwconvolve_1d(in1, in2):
outlen = in1.shape[-1] + in2.shape[-1] - 1
n = _next_regular(outlen)
tr1 = pyfftw.interfaces.numpy_fft.rfft(in1, n)
tr2 = pyfftw.interfaces.numpy_fft.rfft(in2, n)
sh = np.broadcast(tr1, tr2).shape
dt = np.common_type(tr1, tr2)
pr = pyfftw.n_byte_align_empty(sh, 16, dt)
np.multiply(tr1, tr2, out=pr)
out = pyfftw.interfaces.numpy_fft.irfft(pr, n)
return out[..., :outlen].copy()
mit ausgerichteten Ein- und Cache „Planung“ Ich sah in dem OP den Code eine Beschleunigung von fast 3x über.Speicherausrichtung can be easily checked durch Blick auf die Speicheradresse im ctypes.data
Attribut eines Numpy-Array.
Was ist 'Gauß'? Irgendeine Art von 1-D-Gauss-Kernel? Wenn ja, welche Größe relativ zu 'z_depth'? –
Gaußscher Kern wird einmal vor der Schleife generiert. Daten sind 1d Vektor (z_depth) typischerweise um 1535 Elemente lang, mit 1D Gauss-Kernel der Länge typischerweise 79. Ich räumte ein paar der Overhead in fftconvolve, geht im Grunde nur direkt zu irfftn (rfftn (in1, fshape) * rfftn (in2, fshape), fshape) [fslice] .copy() – user4547612