隨着CNN在手機終端部署的越來越多,很多研究人員在研究如何降低神經網絡的計算量。同時,大家都觀察到一個現象,feature map 中的冗余是 CNN 的重要特點。
下圖是 ResNet50 中的 feature map,可以看到很多的 feature map 是很相似的,比如圖中標出的紅、綠、藍三組,這也說明 feature map 中存在較多的冗余。下面分析下相關的三個工作:
GhostNet,CVPR 2020
華為在 CVPR 2020 發表的 GhostNet (論文:https://arxiv.org/pdf/1911.11907.pdf)沒有去除冗余特征,而是采用一種比傳統卷積更輕量化的方法來生成冗余特征。通過“少量傳統卷積計算”+“輕量的冗余特征生成器”的方式,既能減少網絡的整體計算量,又能保證網絡的精度。
作者提出了用於代替傳統卷積層的Ghost module。Ghost module 如下圖所示,包括兩次卷積:
第一次卷積: 假設output中的通道數為 init_channels * ratio,那么第一次卷積生成 init_channels 個 feature map
第二次卷積: 每個 feature map 通過映射生成 ratio-1 個新的 feature map,這樣會生成 init_channels * (ratio-1)個 feature map 。最后,把第一次卷積和第二次卷積得到的 feature map 拼接在一起,得到 output。
代碼如下所示:
class GhostModule(nn.Module):
def __init__(self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True):
super(GhostModule, self).__init__()
self.oup = oup
init_channels = math.ceil(oup / ratio)
new_channels = init_channels*(ratio-1)
# 第一次卷積:得到通道數為init_channels,是輸出的 1/ratio
self.primary_conv = nn.Sequential(
nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size//2, bias=False),
nn.BatchNorm2d(init_channels),
nn.ReLU(inplace=True) if relu else nn.Sequential())
# 第二次卷積:注意有個參數groups,為分組卷積
# 每個feature map被卷積成 raito-1 個新的 feature map
self.cheap_operation = nn.Sequential(
nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size//2, groups=init_channels, bias=False),
nn.BatchNorm2d(new_channels),
nn.ReLU(inplace=True) if relu else nn.Sequential(),
)
def forward(self, x):
x1 = self.primary_conv(x)
x2 = self.cheap_operation(x1)
# 第一次卷積得到的 feature map,被作為 identity
# 和第二次卷積的結果拼接在一起
out = torch.cat([x1,x2], dim=1)
return out[:,:self.oup,:,:]
在實際應用中,作者構建了 Ghost Bottleneck,如下圖所示。其中包含2個Ghost module,第1個Ghost module用於擴充特征的通道數,第2個Ghost module用於減少特征的通道數。
Split to be slim,IJCAI 2020
這是一篇 IJCAI 2020 的論文,在這個論文中,作者認為,卷積得到的 feature map 存在大量的冗余信息。因此,可以選擇一些有代表性的 feature map 表達目標的本征特征,剩余的只需要補充一些細節信息。
作者提出了一個 SPConv 的模塊,用來降低常規卷積中的冗余信息。在該模塊中,所有的輸入通道按比例α分為兩部分:representative部分用 k x k 的卷積提取重要信息;redundant部分用 1x1 的卷積補充細節信息。如下圖所示:
作者還認為,representative 部分仍可能存在冗余,因此,可以進一步拆分。因此,作者使用使用group-wise和point-wise卷積分別處理,再將結果融合。
對於得到的上下兩個分支的特征,使用了類似 SKNet 的處理方式進行融合(這里是比較熟悉的 self-attention),得到最終的輸出特征。
Tied Block Convolution
這篇論文是Berkeley 的 Xudong Wang 博士20年9月放在 arxiv 上的論文。作者同樣指出,在卷積當中, feature map 的冗余比較高。作者提出了 Tied Block Convolution (TBC)。
TBC 和 group conv 比較像,首先回顧一下 group conv :如果輸入 feature map 的通道數是 \(c_i\),輸出的 feature map 通道數是 \(c_o\),卷積核大小為 \(k\times k\) ,分為 \(G\) 組做卷積,那么參數量為:\(c_i\times c_o \times k \times k / G\)。
TBC 通過在不同組間重用 kernel 來減少濾波器的有效數量。直觀來說,TBC 把特征為 \(B\) 組做卷積,但是這 \(B\) 組的 kernel 是完全相同的 ( group conv 里,各組的 kernel 是不同的)。這樣,TBC 的參數量就是 \(c_i \times c_o \times k\times k / (B\times B)\) 。參數量進一步降低了。
作者認為 TBC 與 group conv 相比有三個優勢:1、參數降低了; 2、更加容易在GPU 上並行; 3、每一組 filter 都應用於所有輸入通道,可以更好的建模跨通道的依賴關系。
目前能想到的有這三個工作,再有類似的,隨時想到再繼續補充。