Semantic Segmentation

3. PSPNet 네트워크 구성 및 구현

jwjwvison 2021. 11. 20. 21:46
  • PSPNet 구성 모듈

다음 그림은 PSPNet 모듈 구성을 보여준다. PSPNet은 네 개의 모듈인 Feature,Pyramid Pooling, Decoder, AuxLoss로 구성되어 있다.

 

 PSPNet의 첫 번째 모듈은 Feature 모듈이며 Encoder 모듈로도 불린다. 입력 화상의 특징을 파악하는 것이 Feature 모듈의 목적이다. 

 

 두 번째 모듈은 Pyramid Pooling 모듈이다. PSPNet의 독창성을 보여주는 모듈이다. Pyramid Pooling 모듈로 해결하려는 문제는 '어떠한 픽셀의 물체 라벨을 구하려면 다양한 크기로 해당 픽셀 주변 정보가 필요'하다. 예를 들어 하나의 픽셀만 보면 소의 등인지 말의 등인지 알 수 없지만 해당 픽셀 주위를 점진적으로 확대한 특징량을 확인하면 소인지 말인지 확인할 수 있다는 것이다. 즉 어떠한 픽셀의 물체 라벨을 구하려면 그 픽셀이나 주변의 정보뿐 아니라 더 넓은 범위의 화상 정보가 있어야 한다.

 

Pyramid Pooling 모듈에서는 네 가지 크기의 특징량 맵을 준비한다. 화상 전체를 차지하는 특징량, 화상 절반을 차지하는 특징량, 화상의 1/3을 차지하는 특징량, 화상의 1/6을 차지하는 특징량으로 Feature 모듈의 출력을 처리한다. 

 

 PSPNet의 세 번째 모듈은 Decoder 모듈이다. 업샘플링 모듈이라고도 한다. Decoder 모듈의 목적은 두가지이다. 첫째, Pyraimd Pooling 모듈의 출력을 21x60x60 텐서로 변환하는 것이다. Decoder 모듈에서는 4096 채널의 입력 정보로 60x60픽셀 크기의 화상 각 픽셀의 물체 라벨을 추정하는 클래스 분류를 한다. 출력 데이터 값은 각 픽셀이 전체 21클래스에 각기 속할 확률값(신뢰도)이다.

 

 둘째, 21x60x60 으로 변환된 텐서를 원 입력 화상 크기에 맞도록 21x475x475로 변환하는 것이다. 화상 크기가 줄어든 텐서를 원래 크기로 되돌린다.

 

 추론 시는 Decoder 모듈의 출력으로 출력에 대한 최대 확률의 물체 클래스를 찾아 각 픽셀의 라벨을 결정한다.

 

 PSPNet에서는 네트워크 결합 파라미터의 학습을 더 잘 수행하기 위해 AuxLoss 모듈을 준비한다. AuxLoss 모듈은 손실함수 계산을 보조한다. Feature 모듈로 중간 텐서를 빼내 입력 데이터로 한다. 이를 Decoder 모듈처럼 각 픽셀에 대응하는 물체 라벨 추정 클래스 분류를 실행한다. 

 

  신경망 학습 시에는 AuxLoss 모듈의 출력과 Decoder 모듈의 출력을 모두 화상의 어노테이션 데이터(정답 정보)로 대응시켜 손실 값을 계산한다. 계산 후 손실 값에 따른 오차 역전파법을 실시하여 네트워크의 결합 파라미터를 갱신한다.

 

 학습 시에는 AuxLoss 모듈을 사용하지만 추론 시에는 AuxLoss 모듈의 출력을 사용하지 않고 Decoder 모듈의 출력만으로 시맨틱 분할을 한다.

 

  • PSPNet 클래스 구현
# 패키지 import
import torch
import torch.nn as nn
import torch.nn.functional as F

class PSPNet(nn.Module):
    def __init__(self, n_classes):
        super(PSPNet, self).__init__()

        # 파라미터 설정
        block_config = [3, 4, 6, 3]  # resnet50
        img_size = 475
        img_size_8 = 60  # img_size의 1/8로 설정

        # 4개의 모듈을 구성하는 서브 네트워크 준비
        self.feature_conv = FeatureMap_convolution()
        self.feature_res_1 = ResidualBlockPSP(
            n_blocks=block_config[0], in_channels=128, mid_channels=64, out_channels=256, stride=1, dilation=1)
        self.feature_res_2 = ResidualBlockPSP(
            n_blocks=block_config[1], in_channels=256, mid_channels=128, out_channels=512, stride=2, dilation=1)
        self.feature_dilated_res_1 = ResidualBlockPSP(
            n_blocks=block_config[2], in_channels=512, mid_channels=256, out_channels=1024, stride=1, dilation=2)
        self.feature_dilated_res_2 = ResidualBlockPSP(
            n_blocks=block_config[3], in_channels=1024, mid_channels=512, out_channels=2048, stride=1, dilation=4)

        self.pyramid_pooling = PyramidPooling(in_channels=2048, pool_sizes=[
            6, 3, 2, 1], height=img_size_8, width=img_size_8)

        self.decode_feature = DecodePSPFeature(
            height=img_size, width=img_size, n_classes=n_classes)

        self.aux = AuxiliaryPSPlayers(
            in_channels=1024, height=img_size, width=img_size, n_classes=n_classes)

    def forward(self, x):
        x = self.feature_conv(x)
        x = self.feature_res_1(x)
        x = self.feature_res_2(x)
        x = self.feature_dilated_res_1(x)

        output_aux = self.aux(x)  # Feature 모듈의 중간을 Aux 모듈로

        x = self.feature_dilated_res_2(x)

        x = self.pyramid_pooling(x)
        output = self.decode_feature(x)

        return (output, output_aux)

 

 

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

6. Decoder, AuxLoss 모듈  (0) 2021.11.21
5. Pyramid Pooling 모듈  (0) 2021.11.20
4. Feature 모듈 설명 및 구현(ResNet)  (0) 2021.11.20
2. 데이터셋과 데이터 로더 구현  (0) 2021.11.20
1. 시맨틱 분할이란  (0) 2021.11.20