MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications, Andrew G. Howard et al
paper
MobileNet์ depthwise separable convolution์ ์ฌ์ฉํ์ฌ ๋ชจ๋ฐ์ผ ํ๊ฒฝ์์๋ ์ฌ์ฉํ ์ ์๋ ๊ฐ๋ฒผ์ด deep neural network
์ฐ์ฐ์ด ํจ์จ์ ์ผ๋ก ์ค๊ณ๋ MobileNet์ ๋ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋๋ก width multiplier ์ resolution multiplier ๋๊ฐ์ง ํ๋ผ๋ฏธํฐ๋ฅผ ๋์
Depthwise separable Convolution
Depthwise Convolution : ๋ ์ด์ด์์ filtering ํ๋ ๋ถ๋ถ
HW C์ conv output์ C๋จ์๋ก ๋ถ๋ฆฌํ์ฌ ๊ฐ๊ฐ conv filter๋ฅผ ์ ์ฉํ์ฌ output์ ๋ง๋ค๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ค์ ํฉ์น๋ฉด conv filter๊ฐ ํจ์ฌ ๋ ์ ์ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐ์ง๊ณ ๋์ผํ ํฌ๊ธฐ์ output์ ๋ผ ์ ์์
๊ฐ ํํฐ์ ๋ํ ์ฐ์ฐ ๊ฒฐ๊ณผ๊ฐ ๋ค๋ฅธ ํํฐ๋ก๋ถํฐ ๋
๋ฆฝ์ ์ผ ํ์๊ฐ ์์ ๊ฒฝ์ฐ์ ์ฅ์
class depthwise_conv (nn .Module ):
def __init__ (self , nin , kernels_per_layer ):
super (depthwise_separable_conv , self ).__init__ ()
# groups = nin, ์
๋ ฅ ๋ ์ด์ด๋ฅผ nin ๊ฐ์ ์๋ก ๋ค๋ฅธ group์ผ๋ก ๋ง๋ค์ด์ ํด๋น ์ฐ์ฐ์ ์ํํ๊ฒ ๋ค. (group์ default = 1)
self .depthwise = nn .Conv2d (nin , nin * kernels_per_layer , kernel_size = 3 , padding = 1 , groups = nin )
def forward (self , x ):
out = self .depthwise (x )
return out
Pointwise convolution: filter๋ ๋ถ๋ถ์ comvining ํ๋ ๋ถ๋ถ
1x1 Conv๋ผ๊ณ ๋ถ๋ฆฌ๋ filter, ์ฃผ๋ก ๊ธฐ์กด์ matrix์ ๊ฒฐ๊ณผ๋ฅผ ๋
ผ๋ฆฌ์ ์ผ๋ก ๋ค์ shuffleํด์ ๋ด
์๋ด๋ ๊ฒ์ ๋ชฉ์
Channel์๋ฅผ ์ค์ด๊ฑฐ๋ ๋๋ฆฌ๋ ๋ชฉ์ ์ผ๋ก๋ ๋ง์ด ์ฐ์
class pointwise_conv (nn .Module ):
def __init__ (self , nin , nout ):
super (depthwise_separable_conv , self ).__init__ ()
self .pointwise = nn .Conv2d (nin , nout , kernel_size = 1 )
def forward (self , x ):
out = self .pointwise (x )
return out
Depthwise Separable Convolution
Depthwise convolution ํ Pointwise convolution
3x3 filter๋ฅผ ํตํด conv ์ฐ์ฐ ์งํ, ์๋ก ๋ค๋ฅธ channel๋ค์ ์ ๋ณด๋ ๊ณต์ ํ๋ฉด์ ๋์์ ํ๋ผ๋ฏธํฐ ์๋ ์ค์ด๊ธฐ ๊ฐ๋ฅ
class depthwise_separable_conv (nn .Module ):
def __init__ (self , nin , kernels_per_layer , nout ):
super (depthwise_separable_conv , self ).__init__ ()
self .depthwise = nn .Conv2d (nin , nin * kernels_per_layer , kernel_size = 3 , padding = 1 , groups = nin )
self .pointwise = nn .Conv2d (nin * kernels_per_layer , nout , kernel_size = 1 )
def forward (self , x ):
out = self .depthwise (x )
out = self .pointwise (out )
return out
class SeparableConv2d (nn .Module ):
def __init__ (self , in_channels , out_channels , stride ):
super (SeparableConv2d , self ).__init__ ()
self .depthwise = nn .Sequential (
nn .Conv2d (in_channels , in_channels , kernel_size = 3 , padding = 1 , stride = stride ),
nn .BatchNorm2d (in_channels ),
nn .ReLU (inplace = True ),
)
self .pointwise = nn .Sequential (
nn .Conv2d (in_channels , out_channels , kernel_size = 1 , stride = 1 ),
nn .BatchNorm2d (out_channels ),
nn .ReLU (inplace = True )
)
def forward (self , x ):
x = self .depthwise (x )
x = self .pointwise (x )
return x