我使用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设置中的一些怪癖它以这种方式表演?
答案 0 :(得分:2)
像NumPy这样的FFT算法对于阵列大小来说很快,因为它们会分解成小素数的乘积,而不仅仅是2的幂。如果通过填充增加数组大小,计算工作量会增加。 FFT算法的速度也严重依赖于缓存使用。如果填充到创建低效缓存的数组大小,则效率会降低。真正快速的FFT算法,如FFTW和英特尔MKL,实际上将生成数组大小因子分解的计划,以获得最有效的计算。这包括启发式和实际测量。所以不,填充到最接近的2的幂只在入门教科书中有用,而不是在实践中有用。根据经验,如果数组大小计算为一个或多个非常大的素数,则通常会从填充中受益。
答案 1 :(得分:1)
当您想要使用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
是(start,stop,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