如题,这篇文章将尝试从卷积拆分的角度看一看各种经典CNN backbone网络module是如何演进的,为了视角的统一,仅分析单条路径上的卷积形式。
方便起见,对常规卷积操作,做如下定义,
所以,输入为(M \times I \times I)的tensor,卷积核为(N \times M \times K \times K)的tensor,feature map为(N \times F \times F)的tensor,所以常规卷积的计算量为
[FLOPS = K \times K \times M \times N \times F \times F ]
特别地,如果仅考虑SAME padding且(stride = 1)的情况,则(F = I),则计算量等价为
[FLOPS = K \times K \times M \times N \times I \times I ]
可以看成是((K \times K \times M) \times (N \times I \times I)),前一个括号为卷积中一次内积运算的计算量,后一个括号为需要多少次内积运算。
参数量为
[#Params = N \times M \times K \times K ]
总览SqueezeNet、MobileNet V1 V2、ShuffleNet等各种轻量化网络,可以看成对卷积核(M \times K \times K) 进行了各种拆分或分组(同时引入激活函数),这些拆分和分组通常会减少参数量和计算量,这就为进一步增加卷积核数量(N)让出了空间,同时这种结构上的变化也是一种正则,通过上述变化来获得性能和计算量之间的平衡。
这些变化,从整体上看,相当于对原始(FLOPS = K \times K \times M \times N \times I \times I)做了各种变换。
下面就从这个视角进行一下疏理,简洁起见,只列出其中发生改变的因子项,
[M \rightarrow \frac{M}{G} ]
[(K \times K) \rightarrow (k \times k + \dots + k \times k) ]
[(K \times K) \rightarrow (K \times 1 + 1 \times K) ]
[(K \times K \times M \times N) \rightarrow (M \times \frac{N}{t} + \frac{N}{t} \times (1-p)N + K \times K \times \frac{N}{t} \times pN) \ K = 3 ]
[(K \times K \times M \times N) \rightarrow (M \times \frac{N}{t} + K \times K \times \frac{N}{t} \times \frac{N}{t} + \frac{N}{t} \times N) \ t = 4 ]
[(K \times K \times M \times N) \rightarrow (M \times \frac{N}{t} + K \times K \times \frac{N}{tG} \times \frac{N}{t} + \frac{N}{t} \times N) \t = 2, \ G = 32 ]
[(K \times K \times N) \rightarrow (K \times K + N) ]
[(K \times K \times M) \rightarrow (M + K \times K) ]
但实际在实现时还是depthwise + pointwise + ReLU。。。
[(K \times K \times M \times N) \rightarrow (\frac{M}{G} \times \frac{N}{t} + channel \ shuffle +K \times K \times \frac{N}{t} + \frac{N}{tG} \times N) ]
[(K \times K \times M \times N) \rightarrow (M \times tM + K \times K \times tM + tM \times N) \t = 6 ]
最后小结一下,早期的CNN由一个个常规卷积层堆叠而成,而后,开始模块化,由一个个 module构成,module的演化,可以看成是不停地在常规卷积的计算量(FLOPS = K \times K \times M \times N \times I \times I)上做文章。
不同拆分和分组的方式排列组合就构成了各种各样的module。