Attention please

Separable & Depthwise & Pointwise Convolution 원리 및 Pytorch 구현 본문

딥러닝/CNN

Separable & Depthwise & Pointwise Convolution 원리 및 Pytorch 구현

Seongmin.C 2022. 12. 30. 15:31

다양한 convolution 기법들


Separable Convolution

말 그대로 kernel 작업을 여러 단계로 나누어 주는 기법이다. Convolution 연산은 y = conv(x, k) 라고 표현해보자. (x : input data, y : output data, k : kernel) 이때 kernel k 가 k1.dot(k2) 로 연산되는 2D Convolution이라면 2차원 계산을 하는 대신 1차원 계산 2개로 나누어 계산하는 것이다. 즉, k 를 k1 과 k2 1D Convolution으로 나누어 계산한다. 물론 둘 모두 동일한 결과를 가져온다.

 

 

이와 같이 Separable Convolution은 하나의 kernel을 두개의 kernel로 나누어 계산한다. 이는 곱셉 연산이 줄어드는 것을 의미하는데 이로 인해 연산량이 줄어들게된다.

 

 

 

 

 

 

Depthwise Convolution

original convolution의 경우 kernel에 input data의 모든 채널의 feature가 담기게 된다. 즉, 특정한 채널의 feature를 추출하는 것이 불가능하다. 

 

Depthwise Convolution은 original convolution과 다르게 input data의 각각의 채널에 대해 수행되는 kernel을 사용하였다. 이러한 convolution 기법은 대표적으로 MobileNet에서 볼 수 있다. MobileNet은 Depthwise Convolution을 사용하여 연산량을 크게 줄여 mobile과 같이 고성능이 아닌 환경에서도 모델이 돌아갈 수 있도록 설계되었다.

 

즉, channel방향의 Convolution은 진행하지 않으며, spatial한 방향의 Convolution만을 진행하는 것이다.

 

 

 

다음과 같이 HxWxC의 크기를 가지는 input data를 C 단위로 분리한 후 각각 convolution filter를 적용하여 C개의 output을 만든 후 합쳐 input data와 동일한 크기를 가지는 output data를 만든다. 각 필터에 대한 연산이 다른 필터로부터 독립되는 것이 Depthwise Convolution 기법의 특징이다.

 

 

 

 

 

 

코드 구현

class depthwise_conv(nn.Module):
    def __init__(self, nin, kernels_per_layer):
        super(depthwise_conv, self).__init__()
        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

이 코드의 핵심은 nn.Conv2d 함수의 groups 파라미터에 있다. 몇 개의 group으로 convolution을 나눌 것인지에 대한 파라미터인데 Depthwise Convolution은 input과 output의 channel 개수가 동일하므로 groups = input channel 로 설정해준다. 

 

  • Original Convolution의 경우 groups=1 이다 : default of groups=1

 

 

 

 

 

 

Pointwise Convolution

Depthwise convolution의 경우 channel 방향의 Convolution은 진행하지 않고 공간 방향의 Convolution만을 진행한다고 하였다. Pointwise Convolution은 반대로 공간 방향의 convolution은 진행하지 않고, channel 방향의 convolution만을 진행한다. 즉, channel수를 줄이기에 Channel Reduction에 많이 사용된다.

 

 

Pointwise Convolution은 쉽게 말하면 1x1 Conv를 진행하는 것이다. 1x1xC 크기의 kernel을 사용하여 입력된 feature map을 1개의 channel로 압축시킨다. 즉, 1개의 filter는 channel별 Coefficient를 가지는 Linear Combination을 표현한다. 이는 곧 여러개의 channel을 가진 input data를 더 적은 channel의 data로 embedding하는 것으로 볼 수도 있다.

 

물론 Channel Reduction을 통해 연산량이 줄어든다는 장점이 있다. 하지만 Data가 압축되는 만큼 정보 손실이 발생하는 문제도 있다.

 

 

 

 

 

 

코드 구현

pointwise Convolution을 구현하는 것은 아주 간단하다. 

 

단지 1x1 사이즈의 kernel로 convolution하는 것이다.

 

class pointwise_conv(nn.Module):
    def __init__(self, nin, nout):
        super(pointwise_conv, self).__init__()
        self.pointwise = nn.Conv2d(nin, nout, kernel_size=1)

    def forward(self, x):
        out = self.pointwise(x)
        return out

 

 

 

 

 

 

Comments