3. 卷积计算核心:im2col算法、Winograd算法、FFT在卷积中的应用对比
做卷积加速器这么多年,我见过不少团队在算法选型上栽跟头。说白了,im2col、Winograd、FFT这三兄弟,各有各的脾气。选对了,事半功倍;选错了,流片回来只能干瞪眼。
今天咱们就掰开揉碎了聊聊,这三种算法到底该怎么选、怎么用。
3.1 im2col算法:最朴实的暴力美学
im2col,名字就告诉你它想干嘛——image to column。把卷积窗口拉成列向量,然后扔给矩阵乘法去算。
你想想看,卷积本来是个四重循环:遍历输出通道、输入通道、行、列。im2col把它变成了两个步骤:
- 数据重排:把每个卷积窗口内的数据,按行优先拉成一列
- 矩阵乘法:用GEMM(通用矩阵乘法)搞定剩下的计算
我在项目中遇到过,有些团队一上来就怼im2col,觉得简单粗暴。确实,它的优点是:
- 实现简单:核心就是数据搬运 + GEMM调用
- 硬件友好:矩阵乘法有成熟的加速方案(Systolic Array、脉动阵列)
- 通用性强:任意卷积参数都能用,不用改算法
但坑也不少。我曾经在一个边缘设备项目里用im2col,结果发现内存爆炸了。为什么?
嗯,这里要注意。如果你的芯片片上SRAM有限,im2col可能直接把缓存撑爆。我建议的做法是:
- 对于小卷积核(3×3、5×5),谨慎使用im2col
- 对于大卷积核(7×7以上),im2col反而有优势,因为数据复用率高
- 实在要用,考虑分块(tiling)策略,别一次性展开整个特征图
3.2 Winograd算法:小卷积核的加速利器
Winograd算法,说白了就是用更多的加法换更少的乘法。在硬件里,乘法器比加法器贵得多,所以这个交易很划算。
核心思想是这样的:对于F(2×2, 3×3)的Winograd变换,原本需要3×3=9次乘法,变换后只需要4次乘法。节省了55%的乘法量。
我个人的习惯是,在3×3卷积占主导的网络(比如ResNet、MobileNet)里,优先考虑Winograd。为什么?
- 乘法量减少:F(2×2, 3×3)节省55%,F(4×4, 3×3)节省67%
- 适合小卷积核:3×3是Winograd的甜蜜点
- 计算精度可控:用整数Winograd可以避免浮点误差
但Winograd不是银弹。我记得有一次,团队里的小伙子兴冲冲地把所有卷积都换成Winograd,结果性能反而下降了。为什么?
因为Winograd有它的适用条件:
- 输出块大小有限:F(m×m, r×r)中,m一般取2、4、6。m越大,变换矩阵越大,额外开销越高
- 变换开销:输入和输出都需要做变换,这部分计算不能忽略
- 数值精度:浮点Winograd在高位宽下没问题,但低位宽(INT8以下)可能引入误差
在硬件实现上,Winograd需要额外的变换单元。我建议:
- 如果芯片面积充裕,可以单独设计Winograd变换引擎
- 如果面积紧张,可以用通用ALU来模拟变换,但要注意吞吐量匹配
- 对于3×3卷积,F(4×4, 3×3)是性能和面积的较好折中
3.3 FFT在卷积中的应用:大卷积核的王者
FFT做卷积,原理很简单:时域卷积等于频域相乘。把输入和卷积核都做FFT,点乘,再IFFT回来。
你想想看,对于大卷积核,直接卷积的计算量是O(N²×K²),而FFT是O(N²logN)。当K足够大时,FFT的优势就体现出来了。
我在项目中遇到过,有个语音识别的模型用了15×15的大卷积核。直接卷积根本跑不动,换成FFT后,延迟降了10倍。
FFT的适用场景很明确:
| 卷积核大小 | 推荐算法 | 原因 |
|---|---|---|
| 1×1 | 直接卷积/矩阵乘 | 没有数据复用,im2col最直接 |
| 3×3 | Winograd | 乘法量减少最明显 |
| 5×5 | Winograd或im2col | 看具体硬件资源 |
| 7×7及以上 | FFT | 计算复杂度优势明显 |
但FFT也有它的麻烦:
- 复数运算:硬件实现复数乘法比实数复杂得多
- 边界效应:需要做重叠保留法或重叠相加法,增加额外开销
- 小卷积核不划算:对于3×3,FFT的变换开销比直接计算还大
3.4 三种算法的对比与选型
说了这么多,到底该怎么选?我画了一张图,帮你理清思路:
我个人总结了一个简单的选型原则:
- 3×3卷积:优先Winograd。如果乘法器不够,用im2col+分块
- 5×5卷积:看情况。Winograd和im2col差距不大,选实现简单的
- 7×7及以上:FFT是首选。如果实时性要求高,必须用FFT
- 1×1卷积:别折腾,直接矩阵乘法
嗯,最后说一句。算法选型没有标准答案,关键是要理解你的硬件约束和应用场景。我见过太多团队,算法选得漂亮,但硬件实现时发现面积、功耗、延迟全都不达标。所以,做决定之前,先问问自己:我的芯片能承受多少乘法器?我的片上内存有多大?我的实时性要求是多少?
想清楚这些,你自然就知道该选谁了。
可可精品资料库