如何在Python使用快速傅立叶变换(FFT)执行更快的卷积?
卷积是信号处理中最重要的数学运算之一。这个简单的数学运算出现在许多科学和工业应用中,从它在十亿层大型 CNN 中的使用到简单的图像去噪。卷积本质上既可以是模拟的,也可以是离散的,但是由于现代计算机的数字性质,离散卷积是我们随处可见的!
两个一维向量的离散卷积和 , 被定义为
由于需要两个向量相乘,离散卷积使用乘法的时间复杂度(假设向量的长度为 ) 是 .这就是快速傅立叶变换 (FFT) 的用武之地。使用 FFT,我们可以将这种复杂性从到 !
使用 FFT 进行卷积背后的直觉
最基本的信号处理结果之一表明,时域中的卷积等效于频域中的乘法。为了执行卷积,我们可以将两个信号都转换为它们的频域表示,然后将逆傅立叶变换为 Hadamard 乘积(或点积)以获得卷积答案。工作流程可以总结为以下方式
安装:
出于本文的目的,我们将使用Python库numpy 和 scipy 中的一些内置函数。您可以使用 pip 包管理器来安装它们。
pip install scipy numpy
Python的FFT卷积
为了使用 FFT 计算卷积,我们将使用Python中 scipy.signal 库中的 fftconvolve()函数。
Syntax: scipy.signal.fftconvolve(a, b, mode=’full’)
Parameters:
- a: 1st input vector
- b: 2nd input vector
- mode: Helps specify the size and type of convolution output
- ‘full’: The function will return the full convolution output
- ‘same’: The function will return an output with dimensions same as the vector ‘a’ but centered at the centrer of the output from the ‘full’ mode
- ‘valid’: The function will return those values only which didn’t rely on zero-padding to be computed
下面是实现:
Python
from scipy import signal
a = [1, 2, 3]
b = [4, 5, 6]
y = signal.fftconvolve(a, b, mode = 'full')
print('The convoluted sequence is ', y)
Python
import numpy as np
from scipy import signal
a = np.random.randn(10**5)
b = np.random.randn(10**5)
print('Time required for normal discrete convolution:')
%timeit np.convolve(a, b)
print('Time required for FFT convolution:')
%timeit signal.fftconvolve(a, b)
输出
The convoluted sequence is [ 4. 13. 28. 27. 18.]
FFT卷积与普通离散卷积的性能对比
- 为了计算两个向量的正常线性卷积,我们将使用np.convolve函数。
- Jupyter notebooks 的%timeit魔法函数用于计算给定向量的 2 个函数中的每一个所需的总时间。
下面是实现:
Python
import numpy as np
from scipy import signal
a = np.random.randn(10**5)
b = np.random.randn(10**5)
print('Time required for normal discrete convolution:')
%timeit np.convolve(a, b)
print('Time required for FFT convolution:')
%timeit signal.fftconvolve(a, b)
输出:
Time required for normal discrete convolution:
1.1 s ± 245 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Time required for FFT convolution:
17.3 ms ± 8.19 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
可以看到FFT卷积产生的输出比普通离散卷积产生的输出快1000倍!