深度可分離卷積(Depthwise Separable Convolution)和分組卷積(Group Convolution)的理解,相互關係及PyTorch實現

1. 分組卷積(Group Convolution)

分組卷積最早出現在AlexNet中,如下圖所示。在CNN發展初期,GPU資源不足以滿足訓練任務的要求,因此,Hinton採用了多GPU訓練的策略,每個GPU完成一部分卷積,最後把多個GPU的卷積結果進行融合。AlexNet結構圖
接下來回顧一下常規卷積是怎樣進行的,假設輸入的特徵圖(Tensor)的shape爲Cin×H×WC_{in} \times H \times W,輸出通道數爲CoutC_{out},那麼,卷積過程中就會有CoutC_{out}個卷積核(Convolution Kernel),每個卷積核的尺寸爲Cin×K×KC_{in} \times K \times K,其中,KK爲卷積核的大小,換句話說,就是每個卷積核會和輸入特徵圖的每個通道都進行卷積計算,每個卷積核的計算結果是各通道卷積結果的和。文字可能枯燥,下圖是是常規卷積的示意圖。
常規卷積示意圖
可以很明顯看出,常規卷積的計算結果中,特徵圖的每個通道和輸入特徵圖的所有通道都有關。下圖是分組卷積的示意圖,差別就非常明顯了。分組卷積的輸出特徵圖的每個通道,只和輸入特徵圖的一部分通道有關,而這部分通道,就是一個分組(Group)。依舊假設輸入特徵圖的尺寸爲Cin×H×WC_{in} \times H \times W,分爲3組進行分組卷積,那麼,對於每一組,輸出特徵圖的通道數都是Cout/3C_{out}/3,卷積核大小變爲Cin×K×KC_{in} \times K \times K,最後只需要將各個分組的計算結果按照通道進行連接(Cat)即可。

分組卷積可以很大程度上減少卷積所需的參數量,上述例子中,常規卷積所需的參數量(僅考慮卷積權重,不考慮偏置)爲:
Cin×K×K×CoutC_{in} \times K \times K \times C_{out}
相同的輸入輸出特徵圖,分組卷積所需的參數量爲:
Cin×K×K×Cout3\frac{C_{in} \times K \times K \times C_{out}}{3}
即,分組卷積可將參數量減少爲原來的1/G1/GGG爲分組數量。
分組卷積示意圖

2. 深度可分離卷積(Depthwise Separable Convolution)

大部分博客在介紹可分離卷積和分組卷積時,都是先介紹深度可分離卷積再介紹分組卷積。博主之所以將兩者順序做出了調換,是因爲,按照我的理解,深度可分離卷積是可以基於分組卷積進行理解和分析的。

單從名稱進行分析,Depthwise可理解爲逐深度,如此理解,深度可分離卷積就是逐個深度分開卷積,也就是逐個通道分開卷積。這樣子,深度可分離卷積就變得非常容易理解了,以分組卷積爲基礎,深度可分離卷積是分組爲CinC_{in}的分組卷積。但是,其中也是有區別的,逐深度卷子只是深度可分離卷子的第一個過程,這個過程中,輸入特徵圖和輸出特徵圖的通道數保持一致,也就是,對於輸入特徵圖的每個通道,通過一個尺寸爲K×KK \times K的卷積核,計算結果作爲輸出特徵圖的一個通道,不進行通道數的增加和減少。深度可分離卷積是通過**逐點卷積(Pointwise Convolution)**實現通道數改變的,這個過程使用大小爲Cin×1×1C_{in} \times 1 \times 1的卷積覈實現,數量爲CoutC_{out}個,深度可分離卷積所需參數量爲:
Cin×K×K+Cout×1×1.C_{in} \times K \times K + C_{out} \times 1 \times1.

3. PyTorch實現

Pytorch是2017年推出的深度學習框架,不同於Tensorflow基於靜態圖的模型搭建方式,PyTorch是完全動態的框架,推出以來很快成爲AI研究人員的熱門選擇並受到推崇。(介紹到此結束)

在PyTorch中,實現二維卷積是通過nn.Conv2d實現的,這個函數是非常強大的,其功能不僅僅是實現常規卷積,通過合理的參數選擇就可以實現分組卷積、空洞卷積。API的官方介紹如下:

CLASS torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)

 - stride: controls the stride for the cross-correlation, a single number or a tuple.
 - padding: controls the amount of implicit zero-paddings on both sides for padding number of points for each dimension.
 - dilation: controls the spacing between the kernel points; also known as the à trous algorithm. It is harder to describe, but this link has a nice visualization of what dilation does.
 - groups: controls the connections between inputs and outputs. in_channels and out_channels must both be divisible by groups. For example,
		At groups=1, all inputs are convolved to all outputs.
		At groups=2, the operation becomes equivalent to having two conv layers side by side, each seeing half the input channels, and producing half the output channels, and both subsequently concatenated.
		At groups= in_channels, each input channel is convolved with its own set of filters.

3.1 分組卷積

分組卷積只需要對nn.Conv2d中的groups參數進行設置即可,表示需要分的組數,groups的默認值爲1,即進行常規卷積。以下是實現分組卷積的代碼:

class CSDN_Tem(nn.Module):
    def __init__(self, in_ch, out_ch, groups):
        super(CSDN_Tem, self).__init__()
        self.conv = nn.Conv2d(
            in_channels=in_ch,
            out_channels=out_ch,
            kernel_size=3,
            stride=1,
            padding=1,
            groups=groups
        )

    def forward(self, input):
        out = self.conv(input)
        return out

通過以下代碼對該模型進行測試,設定輸入特徵圖通道數爲16,輸出特徵圖通道數爲32,分組數目爲4:

conv = CSDN_Tem(16, 32, 4)
print(summary(conv, (16, 64, 64), batch_size=1))

控制檯輸出爲:

----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1            [1, 32, 64, 64]           1,184
================================================================
Total params: 1,184
Trainable params: 1,184
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.25
Forward/backward pass size (MB): 1.00
Params size (MB): 0.00
Estimated Total Size (MB): 1.25
----------------------------------------------------------------

這一分組卷積過程所需參數爲1184個,其中包含了偏置(Bias).

3.2 深度可分離卷積

深度可分離卷積的PyTorch代碼如下:

class CSDN_Tem(nn.Module):
    def __init__(self, in_ch, out_ch):
        super(CSDN_Tem, self).__init__()
        self.depth_conv = nn.Conv2d(
            in_channels=in_ch,
            out_channels=in_ch,
            kernel_size=3,
            stride=1,
            padding=1,
            groups=in_ch
        )
        self.point_conv = nn.Conv2d(
            in_channels=in_ch,
            out_channels=out_ch,
            kernel_size=1,
            stride=1,
            padding=0,
            groups=1
        )

    def forward(self, input):
        out = self.depth_conv(input)
        out = self.point_conv(out)
        return out

採用和分組卷積相同的輸入和輸出通道數,測試代碼如下:

conv = CSDN_Tem(16, 32)
print(summary(conv, (16, 64, 64), batch_size=1))

控制檯輸出結果爲:

----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1            [1, 16, 64, 64]             160
            Conv2d-2            [1, 32, 64, 64]             544
================================================================
Total params: 704
Trainable params: 704
Non-trainable params: 0
----------------------------------------------------------------

深度可分離卷積實現相同的操作僅需704個參數。

如有疑問,歡迎留言!

參考

  1. https://www.cnblogs.com/shine-lee/p/10243114.html
  2. https://blog.csdn.net/luoluonuoyasuolong/article/details/81750190
  3. https://blog.csdn.net/luoluonuoyasuolong/article/details/81750190
  4. https://pytorch.org/docs/stable/nn.html?highlight=conv2#torch.nn.Conv2d
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章