傅里叶变换与卷积:AI实战中的核心数学工具详解

📅 发布时间:2026/10/19 5:21:05
傅里叶变换与卷积:AI实战中的核心数学工具详解
我之前带过一个刚转来做视觉的新人他用了大半年卷积网络从来没想过去碰傅里叶变换。有天他问我这东西不是信号处理那边才学的吗我做图像分类用得着吗我想了想回了句你把卷积网络说得很熟但如果我把一个卷积核做傅里叶变换你知道会发生什么吗他愣住了。后来我把傅里叶变换和卷积这条线完整串给他听他才发现这两个数学工具在人工智能里是一条暗线——从图像滤波到音频特征从Transformer位置编码到卷积加速全都有它们的影子。这篇博文就当作一次梳理把傅里叶变换和卷积之间的关系、公式背后在算什么以及AI实操里怎么用一次性讲透。适合刚补数学基础的人也适合用了很久卷积网络却说不清底层逻辑的工程师。1. 傅里叶变换在AI里到底解决什么问题1.1 大多数人只会背定义不会用直觉傅里叶变换把信号从时域搬到频域这句话几乎每个人都能背出来但要问一句然后呢很多人就卡住了。我面试算法岗的时候经常问一个问题卷积和傅里叶变换有什么关系。候选人的典型回答是卷积是加权滑动求和傅里叶变换是求频谱它们是两门课的内容。这个回答不算错但它暴露了一个问题——学了概念但没建立联系。真正在工作里这两个概念的联系远比你想象得紧密。你手上任何一个训练好的卷积网络如果把卷积核切到频域去看你会看到它的能量集中区域、它关注的纹理尺度这些信息可以帮助你判断这个网络在干什么。傅里叶变换的核心直觉不是变量从时间变成频率而是换一个坐标系看问题。就像同样一个人站在正面和站在侧面看到的轮廓完全不同但都是同一个人。信号在时域里看起来混杂在一起搬到频域之后不同频率成分就被拆得清清楚楚。1.2 AI里真正用到傅里叶变换的具体场景我整理了一下傅里叶变换在AI项目里常见的应用场景大概是下面这些给一个表格方便对照。场景用到了什么解决什么问题音频识别前端短时傅里叶变换(STFT)、语谱图把波形变成二维图像输入给模型图像去噪FFT域低通/高通滤波高频噪声、周期性条纹去除大卷积核加速卷积定理、FFT把大卷积核的空间卷积转成频域点乘Transformer位置编码不同频率的正弦/余弦函数让模型感知序列位置模型分析权重谱、特征谱观察训练过程、判断收敛这些场景里有的直接把FFT当工具用比如音频前端和图像滤波有的是借用傅里叶的频率分解思想比如位置编码。你不需要把每一个傅里叶变换的数学推导全部手算一遍但必须理解频域视角为什么好用。1.3 一个提醒傅里叶变换不是银弹很多人学完傅里叶变换之后恨不得什么都搬到频域去做。这种冲动可以理解但要冷静一下。傅里叶变换适合的是平稳信号——统计特性不随时间变化周期性强。图像数据在一定程度上符合这个特点比如纹理、边缘都有周期性。但图像同时又有大量的局部突变——一个物体的边缘就是一个突变的奇点这在频域里意味着能量铺得很宽反而不好处理。这就是为什么后来有了短时傅里叶变换和小波变换它们试图在时间空间分辨率和频率分辨率之间做平衡。AI里更典型的做法是让卷积网络自己学特征而不是手动设计一套滤波器。这个尺度感很重要傅里叶变换是理解信号、加速计算、设计特征的工具但不是所有问题都该往里面套。2. 从时域到频域傅里叶变换的直觉与公式2.1 一个声音的类比把混合果汁拆回水果假设你按下钢琴的一个和弦三个音同时响麦克风收到的是一串叠加在一起的波形。这串波形就是你耳朵听到的混合果汁。傅里叶变换做的事情就是把这杯果汁重新拆回苹果、橙子、香蕉——它告诉你这串波形里有哪些频率每个频率的强度是多少。为什么会这样因为不同频率的正弦波是正交的。你可以把和某个频率做匹配理解为问一问这段信号里有多少这个频率的成分。这种匹配本质上是内积运算——信号和频率基函数做点乘结果越大说明这个频率成分越强。2.2 公式拆解复指数在干什么连续傅里叶变换的公式长这样X(f) ∫_{-∞}^{∞} x(t) e^{-j2πft} dt很多人看见这个积分就头皮发麻。其实你只需要拆成三步理解e^{-j2πft} 是一个单位圆上旋转的复指数频率是 f让信号 x(t) 去乘这个旋转的复指数对结果做积分也就是把所有时刻的乘积累加。累加的结果如果很大说明信号里确实有和这个频率同步的成分。这个过程本质上就是信号和各个频率的正弦波做相关性检测。实际工程里我们处理的是离散采样数据对应的公式是离散傅里叶变换DFTX(k) Σ_{n0}^{N-1} x[n] e^{-j2πkn/N}这里的 N 是采样点个数k 是频率下标。每个 X(k) 都是一个复数实部虚部合在一起给出了该频率成分的幅度和相位。我们通常画图时只看幅度部分也就是取模 |X(k)|这叫做幅度谱。2.3 DFT与FFT工程中人们说的傅里叶通常指FFT直接按DFT公式去算复杂度是 O(N^2)一万个采样点就是一亿次运算非常慢。所以才有了快速傅里叶变换FFT利用旋转因子的对称性和周期性把复杂度降到 O(N log N)。在Python里你几乎不可能自己去实现FFT直接用 numpy 就行import numpy as np fs 1000 # 采样率 1000Hz t np.linspace(0, 1, fs, endpointFalse) x np.sin(2 * np.pi * 50 * t) 0.5 * np.sin(2 * np.pi * 120 * t) X np.fft.rfft(x) # 实数信号用 rfft 就够了 freqs np.fft.rfftfreq(len(x), d1/fs) # 只看幅度谱 amp np.abs(X) # 输出前几个频率点 for i in range(5): print(f{freqs[i]:.1f}Hz, amplitude{amp[i]:.3f})这里用 rfft 是因为实数信号在频域里是共轭对称的只需要保留一半的频率点。第一次跑这个例子的人通常会惊讶50Hz和120Hz这两个峰值非常明显其他频率处几乎为零。这个峰值检测的过程就是频谱分析最朴素的应用。3. 卷积的真正含义不止加权求和3.1 翻转、平移、相乘、累加四个动作卷积的定义写出来是y(t) ∫_{-∞}^{∞} x(τ) h(t-τ) dτ离散版本是y[n] Σ_{k} x[k] h[n-k]很多教程把卷积分解成翻转、平移、相乘、累加四步。这里的 h 通常叫核函数或滤波器。我可以打个比方你站在河岸边用渔网捞鱼水流是 x渔网是 h。你每一次移动渔网的位置捞上来的鱼就是一次卷积的结果。渔网的形状h决定了你关注什么形态的鱼。3.2 图像卷积为什么卷积网络能提特征图像处理里最经典的卷积核之一是 Sobel 边缘检测核| -1 | 0 | 1 | | -2 | 0 | 2 | | -1 | 0 | 1 |这个核在图像上从左到右滑动每个位置做对应像素乘积再求和。如果当前位置恰好是一个垂直边缘左右两侧像素差异很大响应值就很高如果是一片平坦区域左右差异接近零响应值也接近零。所以卷积核本质上是一个特征模式探测器它在全图做匹配。卷积网络正是把一组可以学习的卷积核堆起来让网络自己去发现有用的特征模式。和全连接层相比卷积有两个核心优势一是局部连接一个输出只依赖一小块输入符合图像局部相关性二是共享权重同一个卷积核在整张图上滑动参数数量大大减少。这两点加在一起让CNN能用很少的参数学到很强的空间特征。3.3 深度学习里的卷积和数学卷积并不完全一样这里有一个很多书都不讲清楚的坑深度学习框架里的卷积严格来说其实是互相关不是数学卷积。数学卷积里有一个翻转步骤 h[n-k]而深度学习里的卷积操作没有翻转。原因很简单卷积核是训练出来的如果本来学到的权重模式是 w那翻转之后就是另一个模式 w网络完全可以通过调整权重来抵消这个差异。既然翻转不改变表达能力那就不翻转省一次操作。但这个区别在讲卷积定理的时候必须注意因为卷积定理在教科书里是针对真卷积推导的。你用框架里的卷积层去套卷积定理要小心定义对齐。后面我做实验验证的时候用的是标准数学卷积。4. 两个概念合体卷积定理与FFT加速4.1 卷积定理的表述与直觉卷积定理说的是F{x(t) * h(t)} X(f) · H(f)也就是说时域里的卷积搬到频域之后变成了简单的乘法。反过来时域乘法对应频域卷积。这个定理的意义怎么强调都不过分它把卷积的复杂度从每个点都滑窗求和降成了点乘一个数组。直觉上的理解是卷积在时域里是把一个信号抹开的过程经过傅里叶变换之后这个抹开过程变成对每个频率做独立的缩放。不同的频率成分被放大了或者缩小了这正是滤波的本质。4.2 完整验证频域乘法和时域卷积结果一致与其背公式不如亲手跑一遍。我写个小实验构造两个短数组分别做时域卷积和频域乘法看结果是否一致。import numpy as np a np.array([1, 2, 3, 4, 5]) b np.array([0.5, 1, 0.5]) # 方法一直接时域卷积 conv_result np.convolve(a, b) # 方法二频域相乘 n len(a) len(b) - 1 # 关键补零长度 A np.fft.fft(a, n) B np.fft.fft(b, n) fft_result np.fft.ifft(A * B).real print(直接卷积:, conv_result) print(FFT方法:, fft_result) print(一致:, np.allclose(conv_result, fft_result))输出结果中两个数组应该几乎完全一致。这里的 n 必须等于 len(a)len(b)-1这是为了做线性卷积而不是循环卷积。循环卷积是另一个大坑。如果你直接用原始长度的FFT相乘那么频域乘法对应的是循环卷积结果会混叠。可以做个实验把 n 设成 len(a)两边结果就不一样了尤其数组很长、边界效应严重的时候。这个细节在实际工程里非常容易踩雷。4.3 什么时候用FFT加速才划算用FFT做卷积并不是一直都比直接卷积快。我总结了一个复杂度对比表方法复杂度说明直接卷积核K×KO(K²·M·N)每个像素位置做K²次乘法FFT卷积O(MN·log(MN))两次FFT加一次点乘加逆变换当一个图像尺寸是1024×1024卷积核是3×3时直接卷积大约是9次乘加每个像素而FFT卷积要先对图像和核分别做FFT开销大得多这种情况下直接卷积更快。但当卷积核是31×31甚至更大时情况就反过来了——FFT的优势会非常明显。实际项目经验常规卷积网络里的3×3、5×5卷积没必要用FFT加速。但在某些大卷积核模型、或者全连接层的矩阵乘法可以被分解成卷积的场景里FFT加速是真实可用的优化手段。有一个条件是必须注意的——做卷积的输入输出尺寸和补零策略直接决定了加速收益是否成立。5. 傅里叶变换与卷积在AI实操里的三个切入点5.1 频域图像滤波的实现与坑图像去噪是傅里叶变换在AI里最常见的入门实操。噪声往往表现为高频成分所以一个简单的思路是把高频部分压掉。实现步骤如下import numpy as np # 假设 img 是已经读取的灰度图像float32类型范围0~255 img np.random.rand(64, 64).astype(np.float32) # 示例用随机图像代替 F np.fft.fft2(img) # 二维FFT F_shift np.fft.fftshift(F) # 把零频移到中心 rows, cols img.shape crow, ccol rows // 2, cols // 2 # 构造低通掩模半径D0以内的频率保留之外置零 D0 12 Y, X np.ogrid[:rows, :cols] dist np.sqrt((X - ccol)**2 (Y - crow)**2) mask dist D0 F_filtered F_shift * mask img_filtered np.fft.ifft2(np.fft.ifftshift(F_filtered)).real跑完这段代码有两点要特别留意。第一逆变换后一定要取实部。虽然理论上逆变换应该是实数但由于浮点误差结果会有极小虚部。直接用复数结果做可视化图像会显示不出来或者显示异常。第二低通滤波做过头会出现振铃效应。就是你看到的图像边缘附近多了一圈一圈的明暗波纹这是因为频域突然切断造成的吉布斯现象。要缓解这个问题可以用平滑过渡的掩模比如高斯低通而不是一个硬切边界的圆形mask。这是我最早踩过的坑之一当时把阈值设得很低结果图像全糊了边缘还出现诡异的圈圈。5.2 音频特征短时傅里叶变换为什么是前端标配处理音频时直接拿原始波形喂给模型是很低效的做法因为波形里包含的时间对齐信息太多了而且采样点之间的依赖非常长。工业界成熟的音频特征前端里短时傅里叶变换是理解整个流程的基础。STFT的思路很简单把一段长波形切成若干帧每一帧大约20到30毫秒帧之间有一定重叠然后给每一帧加窗再做一次FFT。把每一帧的频谱按时间叠起来你就得到一张语谱图横轴是时间纵轴是频率颜色深浅表示能量大小。这张图可以从视觉上被当作一个二维图像来处理这也是为什么很多音频模型能复用CNN的结构。实现STFT时有两个参数经常被反复调帧长决定了频率分辨率。帧越长频率分辨率越高但时间分辨率越低。帧移hop length决定了帧与帧之间的重叠程度。重叠越多时间连续性越好但计算量越大。窗函数的选择也会影响频谱质量。常见的汉宁窗Hann window能减少频谱泄漏。很多新手直接对整段音频做FFT得到的是一个平均频谱完全丢失了时间信息这通常没什么用。理解了STFT之后你再看音频领域的特征工程就会明白为什么每一步都是针对时间和频率分辨率平衡这个核心矛盾设计的。5.3 Transformer位置编码中的频率思想Transformer的位置编码和傅里叶变换的关系知道的人相对少一些但我觉得这是理解频率分解思想最好的一个现代例子。位置编码的一般形式是PE(pos, 2i) sin(pos / 10000^{2i/d_model}) PE(pos, 2i1) cos(pos / 10000^{2i/d_model})这里 i 是维度下标d_model 是向量维度。不同维度上的函数频率不同——前几个维度变化快高频后面的维度变化慢低频。模型通过这种多频率的组合理论上可以区分不同的绝对位置也能通过高频率部分感知相对位置差异。这本质上就是一种傅里叶展开的思路把一个复杂的位置信息用一组不同频率的正弦余弦基函数来表示。位置编码给模型提供的是一组与token本身无关的位置信号而模型内部注意力机制会学会如何利用这些不同频率的成分。顺着这个视角再看很多人讨论过的位置编码有没有用我的看法是如果没有不同频率的分量模型很难区分长距离位置之间的相对关系。频率展开提供的多尺度信息正是Transformer能处理长序列的底层原因之一。6. 怎么学以及三个容易栽跟头的误区6.1 学习顺序建议先代码后公式给刚补数学基础的人一个建议不要一上来就啃积分推导先跑通本节里面的代码观察现象再回来看公式。公式可以帮你精确理解但如果没有代码实验带来的直观感受公式就只是一堆符号。我建议的学习路径是这样的先用 numpy 对一段简单信号做FFT观察频谱峰值再做一次频域滤波实验改改截止频率看看图像有什么变化验证一遍卷积定理理解补零的作用最后再回到公式把内积、正交、基函数这些概念和自己的实验对上号。脑子和手要同时用别只看视频不动手。6.2 误区一只看幅度谱丢掉相位很多人在做频谱分析时只画幅度谱刻意忽略相位谱因为相位谱画出来一团乱麻不好看。但在图像处理和信号重建的场合相位极其重要——它决定了频率成分在时间上怎么对齐。可以做一个有趣的小实验取一张图像的幅度谱和另一张图像的相位谱组合之后做逆变换你看到的图像会拥有相位来源那个图像的轮廓特征。这说明轮廓信息大量藏在相位里。AI模型里如果用傅里叶变换做特征绝不能只保留幅度信息而丢弃相位。6.3 误区二把互相关当卷积理解一切前面讲过深度学习框架里的卷积实际上是互相关和数学定义的卷积差一个翻转。初学者如果拿深度学习里的卷积去套教科书里的卷积定理、反卷积、滤波器设计公式容易推导出一堆对不上的结果。我的建议是脑子里同时保留两个概念。做理论推导、信号处理时用数学卷积定义看深度学习框架文档时知道它实际做的是互相关。大多数情况下因为权重可以训练差异不影响结果但在涉及频域操作时最好先验证一下方向。6.4 误区三补零没用频域乘法直接套就完事频域相乘默认对应的是循环卷积不是线性卷积。数组长度不是补到 MN-1结果就不是你预期的线性卷积边界部分会糊在一起。很多人在做图像频域滤波时也碰到类似问题忘了对图像边缘做填充滤波后的边界区域出现奇怪的伪影。如果你用的是FFT卷积加速一定要先搞清楚边界处理策略是零填充、反射填充还是周期填充这会直接影响滤波结果。最后再分享一个小习惯我现在每次写频域相关代码都会顺手写一个和时域结果做对比的断言用np.allclose检查两者是不是一致。有了这一层保障后面怎么改参数都不心虚。傅里叶变换和卷积这两个工具最怕的就是以为自己懂了实际上边界和定义都没对齐。花一个下午把代码跑一遍、把坑踩一遍比看十遍教程都管用。