이번에는 Xception 모델에 대해 알아보겠습니다.

 

Xception의 구조는 Inception V3와 비교했을때, parameters의 수는 같지만, 더 나은 성능을 보였습니다.

 

Inception

먼저 위의 사진은 Inception module의 구조입니다.

 

Xception의 concept

Xception 논문에서는 Inception과 같이 애매하게 3, 4개로 나누는게 아니라 channel 별로 완벽하게 분리하는 것을 제안합니다.

 

그래서 Depthwise separable convolution을 제안합니다.

 

 

 


Depthwise Separable Convolution

 

Depthwise Separable Convolution Construction

Depthwise Separable Convolution은 Inception과는 다르게

먼저 channel 별 Convolution을 먼저 진행하고, 1 x 1 Convolution을 진행해줍니다.

 

또, Inception module에서는 ReLU를 사용했지만, Xception에서는 사용하지 않습니다.

 

Depthwise Separable Convolution은

  1.  Depthwise Convolution
  2.  Pointwise Convolution

이렇게 두가지로 나누어 볼 수 있습니다.

 

 

 


1. Depthwise Convolution

 

일반적으로 CNN은 M채널을 가진 하나의 필터가 모든 채널에서 연산이 이루어 졌습니다.

여기서 핵심은 필터의 채널값입니다.

Depthwise Convolution은 필터의 채널값을 1로 바꾼것입니다.

 

\(D_{k}\) x \(D_{k}\) x 1 필터의 수를 Input Data의 채널과 같게 만들어서

각 채널마다 \(D_{k}\) x \(D_{k}\) x 1 필터를 적용한 것입니다.

쉽게 얘기하면 Input Data의 각 채널마다의 전용 필터가 생긴것입니다.

그렇다면 연산량을 계산해보면

\(D_{g}^{2}\) x \(D_{k}^{2}\) x M   이 되겠습니다.

비교를 해보겠습니다.

  • 기존 Convolution:    \(D_{g}^{2}\) x \(D_{k}^{2}\) x M x N
  • Depthwise Convolution:    \(D_{g}^{2}\) x \(D_{k}^{2}\)D^2g x D^2k x M 

한눈에 봐도 N이 사라지고 연산량이 줄어든걸 확인할 수 있습니다.

다음은 Pointwise Convolution입니다.

 

 

 


Pointwise Convolution

 

Pointwise Convolution은 커널의 모양이 1 x 1 x M 입니다.

연산량 계산을 해보겠습니다.

\(D_{g}^{2}\) x M x N

기존의 Convolution의 연산량과 비교해보겠습니다.

  • 기존 Convolution:   \(D_{g}^{2}\) x \(D_{k}^{2}\) x M x N
  • Pointwise Convolution:    \(D_{g}^{2}\) x M x N

여기서는 무려 D^2k가 사라졌습니다.

 

이제 Depthwise Separable Convolution의 연산량을 구해보겠습니다.

그냥 위의 Depthwise Convolution과 Pointwise Convolution의 연산량을 더해주면 됩니다!

Depthwise Separable Convolution:    \(D_{g}^{2}\) x \(D_{k}^{2}\) x M + \(D_{g}^{2}\) x M x N

\(D_{g}^{2}\) x M x ( \(D_{k}^{2}\) +N)

 

연산량을 비교해보면

연산량이 1/9까지 줄어든것을 알 수 있습니다. N과 Dk는 임의의 수를 대입해준것입니다.

Depthwise Convolution과 Pointwise Convolution은 여러곳에서 사용되니 알아두는 것이 좋습니다.

 

 

 


Xception 구조

 

Xception의 구조

구조안의 SeparableConv에는 Depthwise Separable Convolution을 적용해주면 됩니다.

 

 

코드

더보기

1. Depthwise Separable Convolution

def depthwise_separable_conv(input_dim, output_dim):
   
    depthwise_convolution = nn.Conv2d(input_dim, input_dim, kernel_size=3, padding=1, groups=input_dim, bias=False)
    pointwise_convolution = nn.Conv2d(input_dim, output_dim, kernel_size=1, bias=False)
   
    model = nn.Sequential(
        depthwise_convolution,
        pointwise_convolution
       
    )
       
    return model

 

2. Entry flow

class entry_flow(nn.Module):
    def __init__(self):
        super(entry_flow, self).__init__()
       
        self.conv2d_init_1 = nn.Conv2d(in_channels = 3,
                                       out_channels = 32,
                                       kernel_size = 3,
                                       stride = 2,
                                      )
       
        self.conv2d_init_2 = nn.Conv2d(in_channels = 32,
                                       out_channels = 64,
                                       kernel_size = 3,
                                       stride = 1,
                                      )
       
       
        self.layer_1 = nn.Sequential(
            depthwise_separable_conv(input_dim = 64, output_dim = 128),
            nn.ReLU(),
            depthwise_separable_conv(input_dim = 128, output_dim = 128),
            nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
           
        )
                                                             
        self.conv2d_1 = nn.Conv2d(in_channels = 64,
                                  out_channels = 128,
                                  kernel_size = 1,
                                  stride = 2
                                  )
       
        self.layer_2 = nn.Sequential(
            depthwise_separable_conv(input_dim = 128, output_dim = 256),
            nn.ReLU(),
            depthwise_separable_conv(input_dim = 256, output_dim = 256),
            nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
           
        )
                                                             
        self.conv2d_2 = nn.Conv2d(in_channels = 128,
                                  out_channels = 256,
                                  kernel_size = 1,
                                  stride = 2
                                  )
       
        self.layer_3 = nn.Sequential(
            depthwise_separable_conv(input_dim = 256, output_dim = 728),
            nn.ReLU(),
            depthwise_separable_conv(input_dim = 728, output_dim = 728),
            nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
           
        )
                                                             
        self.conv2d_3 = nn.Conv2d(in_channels = 256,
                                  out_channels = 728,
                                  kernel_size = 1,
                                  stride = 2
                                  )
       
        self.relu = nn.ReLU()
       
    def forward(self, x):
        x = self.conv2d_init_1(x)
        x = self.relu(x)
        x = self.conv2d_init_2(x)
        x = self.relu(x)
       
        output1_1 = self.layer_1(x)
        output1_2 = self.conv2d_1(x)
        output1_3 = output1_1 + output1_2
       
       
        output2_1 = self.layer_2(output1_3)
        output2_2 = self.conv2d_2(output1_3)
        output2_3 = output2_1 + output2_2
       
       
        output3_1 = self.layer_3(output2_3)
        output3_2 = self.conv2d_3(output2_3)
        output3_3 = output3_1 + output3_2
        y = output3_3
       
        return y

 

 3. Middle flow

class middle_flow(nn.Module):
    def __init__(self):
        super(middle_flow, self).__init__()
       
        self.module_list = nn.ModuleList()
       
        layers = nn.Sequential(
                nn.ReLU(),
                depthwise_separable_conv(input_dim = 728, output_dim = 728),
                nn.ReLU(),
                depthwise_separable_conv(input_dim = 728, output_dim = 728),
                nn.ReLU(),
                depthwise_separable_conv(input_dim = 728, output_dim = 728)
            )
       
        for i in range(7):
            self.module_list.append(layers)
           
    def forward(self, x):
        for layer in self.module_list:
            x_temp = layer(x)
            x = x + x_temp
       
        return x

 

 4. Exit flow

class exit_flow(nn.Module):
    def __init__(self, growth_rate=32):
        super(exit_flow, self).__init__()
       
        self.separable_network = nn.Sequential(
            nn.ReLU(),
            depthwise_separable_conv(input_dim = 728, output_dim = 728),
            nn.ReLU(),
            depthwise_separable_conv(input_dim = 728, output_dim = 1024),
            nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        )
       
        self.conv2d_1 = nn.Conv2d(in_channels = 728,
                                  out_channels = 1024,
                                  kernel_size = 1,
                                  stride = 2
                                  )
       
        self.separable_conv_1 = depthwise_separable_conv(input_dim = 1024, output_dim = 1536)
        self.separable_conv_2 = depthwise_separable_conv(input_dim = 1536, output_dim = 2048)
       
        self.relu = nn.ReLU()
        self.avgpooling = nn.AdaptiveAvgPool2d((1))
       
        self.fc_layer = nn.Linear(2048, 10)
       
    def forward(self, x):
        output1_1 = self.separable_network(x)
        output1_2 = self.conv2d_1(x)
        output1_3 = output1_1 + output1_2
 
        y = self.separable_conv_1(output1_3)
        y = self.relu(y)
        y = self.separable_conv_2(y)
        y = self.relu(y)
        y = self.avgpooling(y)
       
        y = y.view(-1, 2048)
        y= self.fc_layer(y)
       
       
        return y

 

5. Xception

class Xception(nn.Module):
    def __init__(self):
        super(Xception, self).__init__()
        self.entry_flow = entry_flow()
        self.middle_flow = middle_flow()
        self.exit_flow = exit_flow()
       
       
       
    def forward(self, x):
        x = self.entry_flow(x)
        x = self.middle_flow(x)
        x = self.exit_flow(x)
       
        return x

 

 

출처:

https://coding-yoon.tistory.com/81

'Deep Learning > Pytorch' 카테고리의 다른 글

C++, Pytorch 사용 예시 - Visual Studio 2019  (0) 2022.11.15
C++, Pytorch 적용하기 02 (.pt 만들기) - Visual Studio 2019  (0) 2022.11.02
32_DenseNet  (0) 2022.04.11
31_ResNext  (0) 2022.04.08
25_Pytorch_GoogLeNet 1x1 Convolution  (0) 2022.03.15

+ Recent posts