ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Depthwise Separable Convolution (Pytorch) - CNN 파라미터 줄이기
    Study/ML 2021. 7. 2. 01:44

     

    Depthwise Separable Convolution이란 연산량을 줄이기 위한 convolution기법 중 하나로  Depthwise Convolution과 Pointwise Convolution을 혼합하여 사용한 것이다.

     

     

    Fig.1

     

     

     위 이미지에서 (a), (b), (c) 는 차례대로 기존 Convoltion, Depthwise convolution, Pointwise convolution을 나타낸것으로 특징을 잘나타내고 있다. 

     

     기존 Convoltion은 잘 아시겠지만 Input channel과 커널 1개의 channel이 동일하며 channel의 개수 (위 그림에서 N)이 output의 channel을 결정한다. 그래서 대략적인 전체 연산량을 계산해보면 커널 1개 와 Input관의 연산은 (커널 크기) x (채널) x (Input 크기) 가 될것이고 아래와 같다.

    (K · K) · (M) · (H · W)

    여기서 이제 커널개수가 N개 이므로 N을 곱해줘야 하고 최종 연산량을 아래와 같다.

    K · K · M · H · W · N

     

     

    # Depthwise convoultion

    Fig. 2

     이번에는 Depthwise convoultion에 대해 살펴 보겠다. 기존 Conv는 커널과 Input사이 곱,합 연산을 한 뒤 모든 channel의 값을 하나로 합 해준다. 하지만 Depthwise conv에서는  K·K·1 크기의 커널을 같은 channel에서 연산 후 합치지 않고 output으로 내놓는다. 즉 Output의 channel은 기존 Conv과 다르게 N이 아닌 M이 된다. 그래서 전체 연산량은 (INPUT 크기) x (커널크기) x (채널)이 된다.

    K · K · M · H · W

     

     

    # Pointwise convoultion

    Fig.3

    Pointwise convoultion은 채널간의 값을 합쳐주는 과정이라 볼 수 있다. 1x1xM의 커널이 N개 존재하고 각 커널은 같은 위치, 채널들간의 값을 하나로 합치는 연산을 한다. 그래서 H x W x 1 의 결과가 나오게된다. 이러한 커널이 N개 있으므로 Output은 H x W x N 의 shape를 가지게 된다. 마찬가지로 연산량을 계산해보면 (채널) x (Input 크기) x (output 채널)이 되고 아래와 같다.

    M · H · W · N

     

     

     

    그럼 Depthwise Separable Convolution은 Depthwise convoultion 와 Pointwise convoultion을 합친것이라 했으니 전체 연산량을 구해보면 아래와 같다. 

     

    K·K·M·H·W + M·H·W·N

     

    위 값을 기존 Conv연산량(K·K·M·H·W·N)으로 나누어 보면 1/N + 1/K2 이 나오는것을 확인할수 있다. N은 K제곱에 비해 아주 클테니 전체 연산량이 K2만큼 줄어드는것을 알 수 있다.

    물론 정확도도 떨어지게 되지만 1/K2만큼 줄어드는 아주 큰 변화이므로 적절히 사용해주면 최적화된 모델을 구현할 수 있다.

     

     

    #Pytorch

    파이토치로 Depthwise Separable Convolution은 아래처럼 구현할 수 있다.

    class depthwise_separable_conv(nn.Module):
        def __init__(self, nin, nout, kernel_size=3, kernels_per_layer=1):
          super(depthwise_separable_conv, self).__init__()
          self.depthwise = nn.Conv2d(nin, nin * kernels_per_layer, kernel_size=kernel_size, 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

    https://github.com/DOWN-LEE/Depthwise-Separable-Convolution/blob/main/dw_Conv/DW_conv.py

     

     

     

    출처

    Fig.1 - https://link.springer.com/article/10.1007/s11082-020-02500-8

    Fig.2,3 - https://towardsdatascience.com/a-basic-introduction-to-separable-convolutions-b99ec3102728

     
     
     
     
     
     
     
     
     

    댓글

Designed by Tistory.