繁体   English   中英

为什么在NumPy中填充FFT会使运行速度慢得多?

[英]Why does padding an FFT in NumPy make it run much slower?

我使用NumPy的fft函数编写了一个脚本,在该脚本中,我将输入数组填充到最接近的2的幂以获取更快的FFT。

在对代码进行性能分析后,我发现FFT调用花费了最长的时间,因此我在参数中弄乱了,发现如果我填充输入数组,则FFT的运行速度快了好几倍。

这是一个最小的示例来说明我在说什么(我在IPython中运行了该示例,并使用%timeit魔术对执行时间进行计时)。

x     = np.arange(-4.*np.pi, 4.*np.pi, 1000)
dat1  = np.sin(x)

计时结果:

%timeit np.fft.fft(dat1)
100000 loops, best of 3: 12.3 µs per loop

%timeit np.fft.fft(dat1, n=1024)
10000 loops, best of 3: 61.5 µs per loop

将阵列填充为2的幂会导致非常急剧的减速。

即使我创建了具有素数元素的数组(因此理论上最慢的FFT)

x2    = np.arange(-4.*np.pi, 4.*np.pi, 1009)
dat2  = np.sin(x2)

运行所需的时间仍然没有发生太大变化!

%timeit np.fft.fft(dat2)
100000 loops, best of 3: 12.2 µs per loop

我本以为填充数组将是一次性操作,然后计算FFT应该更快。 我有什么想念的吗?

编辑:我应该使用np.linspace而不是np.arange 以下是使用linspace的计时结果

In [2]: import numpy as np

In [3]: x = np.linspace(-4*np.pi, 4*np.pi, 1000)

In [4]: x2 = np.linspace(-4*np.pi, 4*np.pi, 1024)

In [5]: dat1 = np.sin(x)

In [6]: dat2 = np.sin(x2)

In [7]: %timeit np.fft.fft(dat1)
10000 loops, best of 3: 55.1 µs per loop

In [8]: %timeit np.fft.fft(dat2)
10000 loops, best of 3: 49.4 µs per loop

In [9]: %timeit np.fft.fft(dat1, n=1024)
10000 loops, best of 3: 64.9 µs per loop

填充仍然会导致速度降低。 这可能是本地问题吗? 即,由于我的NumPy设置中有些怪异,它的行为是这样的吗?

像NumPy一样的FFT算法对于数组大小快速分解,该大小分解为小质数的乘积,而不仅仅是2的幂。 如果通过填充增加数组大小,则计算量会增加。 FFT算法的速度也严格取决于高速缓存的使用。 如果填充到会导致效率较低的缓存的阵列大小,则会降低效率。 真正快速的FFT算法(例如FFTW和Intel MKL)将为阵列大小分解生成计划,以实现最高效的计算。 这包括启发式和实际测量。 因此,不可以,将其填充到最接近的2的幂仅对入门级教科书有用,而对实际操作没有必要。 根据经验,如果数组大小分解为一个或多个非常大的素数,通常可以从填充中受益。

当您想使用np.arange时,您正在使用np.linspace

In [2]: x     = np.arange(-4.*np.pi, 4.*np.pi, 1000)

In [3]: x
Out[3]: array([-12.56637061])

np.arange采用参数(开始,停止,步进),而np.linspace是(开始,停止,number_of_pts)。 使用我怀疑您认为正在使用的数据进行计算时,您会得到预期的行为:

In [4]: x = np.linspace(-4.*np.pi, 4.*np.pi, 1000)

In [5]: dat1 = np.sin(x)

In [6]: %timeit np.fft.fft(dat1)
1 loops, best of 3: 28.1 µs per loop

In [7]: %timeit np.fft.fft(dat1, n=1024)
10000 loops, best of 3: 26.7 µs per loop

In [8]: x = np.linspace(-4.*np.pi, 4.*np.pi, 1009)

In [9]: dat2 = np.sin(x)

In [10]: %timeit np.fft.fft(dat2)
10000 loops, best of 3: 53 µs per loop

In [11]: %timeit np.fft.fft(dat2, n=1024)
10000 loops, best of 3: 26.8 µs per loop

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM