Semantic Segmentation

4. Feature 모듈 설명 및 구현(ResNet)

jwjwvison 2021. 11. 20. 22:05
  • Featuer 모듈의 서브 네트워크 구성

 다음 그림은 Feature 모듈의 서브 네트워크 구성을 보여준다. Feature 모듈은 다섯 개의 서브 네트워크인 FeatureMap_convolution, 두 개의 ResidualBlockPSP, 두 개의 dilated(확장))판 ResidualBlockPSP로 구성된다.

  • 서브 네트워크 FeatuerMap_convolution

다음 그림은 FeatureMap_convolutoin 유닛(층)을 나타낸다.

 이 층은 단순히 합성곱, 배치 정규화, 최대 풀링으로 화상의 특징량을 추출하는 역할을 한다.

 

 먼저 구현하기 위해 conv2dBatchNormRelu 클래스를 만든다. ReLU 구현 부분에서 nn.ReLU(inplace=True)의 inplace는 메모리 입출력을 보존하면서 계산할 것인지 설정하는 파라미터이다. inplace=True로 설정하면 ReLU에 대한 입력을 메모리에 저장하지 않고 그대로 출력을 계산한다.

class conv2DBatchNormRelu(nn.Module):
  def __init__(self,in_channels,out_channels,kernel_size,stride,padding,dilation,bias):
    super(conv2DBatchNormRelu,self).__init__()
    self.conv=nn.Conv2d(in_channels,out_channels,
                        kernel_size,stride,padding,dilation,bias=bias)
    self.batchnorm=nn.BatchNorm2d(out_channels)
    self.relu=nn.ReLU(inplace=True)
    # inplace 설정으로 입력을 저장하지 않고 출력을 계산하여 메모리 절약

  def forward(self,x):
    x=self.conv(x)
    x=self.batchnorm(x)
    outputs=self.relu(x)

    return outputs
class FeatureMap_convolution(nn.Module):
    def __init__(self):
        '''구성할 네트워크 준비'''
        super(FeatureMap_convolution, self).__init__()

        # 합성곱 층1
        in_channels, out_channels, kernel_size, stride, padding, dilation, bias = 3, 64, 3, 2, 1, 1, False
        self.cbnr_1 = conv2DBatchNormRelu(
            in_channels, out_channels, kernel_size, stride, padding, dilation, bias)

        # 합성곱 층2
        in_channels, out_channels, kernel_size, stride, padding, dilation, bias = 64, 64, 3, 1, 1, 1, False
        self.cbnr_2 = conv2DBatchNormRelu(
            in_channels, out_channels, kernel_size, stride, padding, dilation, bias)

        # 합성곱 층3
        in_channels, out_channels, kernel_size, stride, padding, dilation, bias = 64, 128, 3, 1, 1, 1, False
        self.cbnr_3 = conv2DBatchNormRelu(
            in_channels, out_channels, kernel_size, stride, padding, dilation, bias)

        # MaxPooling 층
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)

    def forward(self, x):
        x = self.cbnr_1(x)
        x = self.cbnr_2(x)
        x = self.cbnr_3(x)
        outputs = self.maxpool(x)
        return outputs

 

  • ResidualBlockPSP

 다음 그림은 ResidualBlockPSP 구조이다.

  feature 모듈 네 개의 ResidualBlockPSP 서브 네트워크에서 bottleNeckIdentifyPSP 클래스가 반복되는 횟수는 각각 3,4,6,3회이다.

class ResidualBlockPSP(nn.Sequential):
  def __init__(self,n_blocks,in_channels,mid_channels,out_channels,stride,dilation):
    super(ResidualBlockPSP,self).__init__()

    # bottleNeckPSP 준비
    self.add_module(
        'block1',bottleNeckPSP(in_channels,mid_channels,
                               out_channels,stride,dilation)
    )
    # bottleNeckIdentifyPSP 반복 준비
    for i in range(n_blocks -1):
      self.add_module(
          'block' + str(i+2),
          bottleNeckIdentifyPSP(
              out_channels,mid_channels,stride,dilation
          )
      )

 

  • bottleNeckPSP와 bottleNeckIdentifyPSP

 다음 그림에서 두가지의 구조를 보여준다.

 서브 네트워크 ResidualBlockPSP에서는 합성곱 층에서 dilation 파라미터를 설정한다. Feature 모듈 안에 네 개 있는 ResidualBlockPSP 중에서 앞의 두개는 dilation이 1로, 뒤의 두개는 dilation이 각각 2와 4로 설정되었다.

 

 일반적인 합성곱 층은 dilation이 1이다. 합성곱 층에서 1이 아닌 값을 dilation에 사용하는 합성곱을 Dilated Convolution이라고 한다.

 동일한 필터랃고 dilation값이 크면 더욱 넓은 범위의 특징과 거시적인 특징량을 추출할 수 있다.

class conv2DBatchNorm(nn.Module):
  def __init__(self,in_channels,out_channels,kernel_size,stride,padding,dilation,bias):
    super(conv2DBatchNorm,self).__init__()
    self.conv=nn.Conv2d(in_channels,out_channels,kernel_size,stride,padding,dilation,bias=bias)
    self.batchnorm=nn.BatchNorm2d(out_channels)

  def forward(self,x):
    x=self.conv(x)
    outputs=self.batchnorm(x)

    return outputs
class bottleNeckPSP(nn.Module):
    def __init__(self, in_channels, mid_channels, out_channels, stride, dilation):
        super(bottleNeckPSP, self).__init__()

        self.cbr_1 = conv2DBatchNormRelu(
            in_channels, mid_channels, kernel_size=1, stride=1, padding=0, dilation=1, bias=False)
        self.cbr_2 = conv2DBatchNormRelu(
            mid_channels, mid_channels, kernel_size=3, stride=stride, padding=dilation, dilation=dilation, bias=False)
        self.cb_3 = conv2DBatchNorm(
            mid_channels, out_channels, kernel_size=1, stride=1, padding=0, dilation=1, bias=False)

        # 스킵 결합
        self.cb_residual = conv2DBatchNorm(
            in_channels, out_channels, kernel_size=1, stride=stride, padding=0, dilation=1, bias=False)

        self.relu = nn.ReLU(inplace=True)

    def forward(self, x):
        conv = self.cb_3(self.cbr_2(self.cbr_1(x)))
        residual = self.cb_residual(x)
        return self.relu(conv + residual)
class bottleNeckIdentifyPSP(nn.Module):
    def __init__(self, in_channels, mid_channels, stride, dilation):
        super(bottleNeckIdentifyPSP, self).__init__()

        self.cbr_1 = conv2DBatchNormRelu(
            in_channels, mid_channels, kernel_size=1, stride=1, padding=0, dilation=1, bias=False)
        self.cbr_2 = conv2DBatchNormRelu(
            mid_channels, mid_channels, kernel_size=3, stride=1, padding=dilation, dilation=dilation, bias=False)
        self.cb_3 = conv2DBatchNorm(
            mid_channels, in_channels, kernel_size=1, stride=1, padding=0, dilation=1, bias=False)
        self.relu = nn.ReLU(inplace=True)

    def forward(self, x):
        conv = self.cb_3(self.cbr_2(self.cbr_1(x)))
        residual = x
        return self.relu(conv + residual)

'Semantic Segmentation' 카테고리의 다른 글

6. Decoder, AuxLoss 모듈  (0) 2021.11.21
5. Pyramid Pooling 모듈  (0) 2021.11.20
3. PSPNet 네트워크 구성 및 구현  (0) 2021.11.20
2. 데이터셋과 데이터 로더 구현  (0) 2021.11.20
1. 시맨틱 분할이란  (0) 2021.11.20