1. 告别O(n²)的煎熬:自注意力机制的计算瓶颈与FFTNet的破局
朋友们,如果你玩过Transformer模型,不管是搞自然语言处理(NLP)还是计算机视觉(CV),肯定对“自注意力”(Self-Attention)又爱又恨。爱的是它那强大的全局建模能力,能让模型“看到”序列中任意两个元素之间的关系,这是CNN和RNN难以比拟的。恨的是什么?是它那令人头疼的计算复杂度——O(n²)。
我来给你算笔账。假设你有一个序列,长度是n(比如一句话有100个词,或者一张图片被切成100个patch)。自注意力要计算每个词(或patch)与其他所有词(或patch)的关联度,这个计算量会随着n的平方增长。当n=100时,计算量还算可控;但当n变成1000,甚至像高分辨率图像那样达到数万(比如224x224的图像,patch序列长度就是50176),这个计算量就会爆炸,对显存和算力都是噩梦。这就是为什么处理长序列任务(长文本、高分辨率图像、长视频)时,原始的Transformer模型会那么吃力,大家不得不绞尽脑汁去想各种近似方法,比如局部窗口注意力、稀疏注意力等等,多少都会牺牲一些全局建模的能力。
那么,有没有一种方法,既能保持这种全局的、密集的交互能力,又能把计算复杂度降下来呢?这就是今天要聊的FFTNet要解决的问题。它来自一篇2025年3月的最新论文,核心思想非常巧妙:我们不直接在原始的“时域”(或者说序列空间)里计算两两之间的关联,而是把整个序列通过快速傅里叶变换(FFT)转换到“频域”去处理。
为什么这么做?因为FFT这个操作本身的时间复杂度是O(n log n),比O(n²)低太多了。在频域里,信号的全局信息被压缩到了各个频率分量上。我们可以设计一个可学习的“滤波器”,在频域里对这些分量进行调制(放大某些频率、抑制另一些频率),这本质上就实现了一种全局的、高效的“信息混合”。处理完后,再用逆FFT变换回时域,就得到了经过全局交互后的新序列。整个过程的核心计算就是FFT/iFFT,复杂度稳稳地控制在O(n log n)。
我第一次看到这个思路时,感觉就像发现了一条“作弊通道”。我们绕开了在时域里笨拙地计算NxN的注意力矩阵,转而利用信号处理领域成熟了数十年的工具,优雅地达成了类似的目标。这不仅仅是速度的提升,更是一种计算范式的革新。下面,我们就来拆解一下FFTNet到底是怎么玩的。
2. 信号处理的“降维打击”:快速傅里叶变换(FFT)如何赋能AI
要理解FFTNet,我们得先搞懂FFT到底是什么,以及它为什么能帮上忙。别怕,我们不用深究复杂的数学公式,用几个生活化的类比就能明白。
想象一下,你正在听一首交响乐。在时间轴上,你听到的是各种乐器声音混合在一起的、随时间变化的复杂波形。这就是“时域”表示。但一个训练有素的音乐家或调音师,能听出这里面包含了哪些频率的声音:低沉的大提琴基音、明亮的小提琴泛音等等。他们大脑里仿佛做了一个傅里叶变换,把时域信号分解成了频域上的不同分量。
快速傅里叶变换(FFT)就是干这个事的算法。它能把一个时域序列(比如一段音频采样、一个时间序列、或者我们模型里的一个token序列)高效地转换成频域表示。这个转换是“无损”的,这要归功于帕塞瓦尔定理:信号在时域的总能量,等于其在频域各分量能量之和(差一个常数因子)。这意味着,我们在频域里捣鼓,只要操作得当,就不会丢失原始信号的本质信息。
在深度学习的语境下,我们可以把每个token的嵌入向量(embedding)看作一个多维信号。FFT沿着序列长度维度进行,将整个序列从“token空间”转换到了“频率空间”。在这个空间里:
- 低频分量:通常对应序列中变化缓慢、全局性的趋势信息。比如在一段文本中,可能对应着整个段落的主题基调。
- 高频分量:通常对应序列中快速变化、局部细节的信息。比如文本中某个突兀的转折词,或者图像中两个patch之间的边缘。
FFTNet的核心模块,就是在这个频域空间里工作的。它引入了一个可学习的线性层(nn.Linear)作为“滤波器”。这个滤波器会对每个频率分量的实部和虚部(因为FFT结果是复数)分别进行加权组合。你可以把它想象成一个智能的“调音台”,自动学习应该增强哪些频率的信息(可能是对任务重要的全局模式),减弱哪些频率的信息(可能是噪声或不重要的细节)。
更有趣的是,论文还引入了针对复数域的激活函数,比如ModReLU。传统的ReLU没法直接用在复数上,ModReLU的聪明之处在于,它保持复数的相位不变,只对幅度(可以理解为该频率信号的强度)进行ReLU操作。这就在频域中引入了必要的非线性,让模型能够学习更复杂的频率调制模式。
整个过程就像是对整个序列做了一次全局的、可学习的“信息滤波”,而不是像自注意力那样进行两两配对计算。这就是复杂度从O(n²)降到O(n log n)的魔法所在。
3. 手把手代码实战:解剖FFTNet核心模块
光说不练假把


577

被折叠的 条评论
为什么被折叠?



