본문 바로가기
의료 AI/[02] - 모델

[03] - 빠르면서도 정확한 SegNet

by AI-BT 2024. 11. 14.
728x90
반응형

SegNet 이란??

SegNet은 특히 도로 장면을 이해하기 위해 설계된 Semantic Segmentation 모델이다. SegNet의 주요 목표는 차량, 도로, 차선, 건물, 보도, 하늘, 사람과 같은 객체들을 빠르고 정확하게 구분하는 것이다. 이 글에서는 SegNet이 어떤 발전 동기와 구조를 가지고 있으며, 유사한 네트워크와 어떤 차이점이 있는지 알아보자.


 

SegNet의 발전 동기

SegNet은 자율 주행과 같은 Road Scene Understanding Applications를 위한 모델로 개발되었다. 이 분야에서는 다양한 객체들을 명확하게 분류할 수 있는 세그멘테이션 모델이 필수적이다. SegNet은 기존 모델들이 기능적으로 뛰어난 성능을 제공하더라도 속도가 부족한 문제를 해결하고자 개발되었으며, 빠르면서도 정확한 세그멘테이션 성능을 목표로 삼았다.

  • SegNet은 특히 자동차, 도로, 차선, 건물, 보도, 하늘, 사람과 같은 중요한 클래스를 빠르고 정확하게 구분하는 데 초점을 맞추고 있다.
  • 자율 주행 환경에서는 실시간 성능이 요구되기 때문에 SegNet은 속도에 많은 개선을 이루어 기존 모델보다 효율적으로 작동한다.


SegNet의 장점

SegNet은 다음과 같은 강점을 가지고 있다.

  • 실시간 처리 가능: SegNet은 효율적인 아키텍처 설계를 통해 실시간에 가까운 속도를 제공한다.
  • 다양한 클래스 구분 가능: Cityscapes와 같은 데이터셋에 대해 SegNet은 각 객체를 효과적으로 구분할 수 있다.
  • 간결한 구조: 불필요한 파라미터를 최소화하고, 필요한 연산만 포함하여 최적화된 구조를 갖추고 있다.

SegNet과 DeconvNet 구조 비교

SegNet은 DeconvNet이라는 초기 구조에서 발전한 모델이다. DeconvNet은 기본적으로 Conv(합성곱), Pooling(풀링), Unpooling(업샘플링) 층을 가지고 있으며, SegNet은 이를 발전시켜 보다 최적화된 구조를 갖췄다. 두 모델 간의 구조적인 차이점은 다음과 같다.

 

DeconvNet

  • Encoder/Decoder 구조: DeconvNet은 인코더와 디코더 네트워크로 이루어져 있다.
  • Encoder Network: VGG 16 구조를 기반으로 13개의 합성곱 층으로 구성되며, 7x7 Convolution1x1 Convolution을 포함하여 더 많은 연산을 필요로 한다.
  • Decoder Network: 업샘플링 과정에서 Unpooling, Deconvolution, ReLU 연산을 수행하여 복잡하고 많은 계산이 필요하다.

SegNet

  • Encoder/Decoder 구조: SegNet 역시 인코더와 디코더 네트워크로 이루어져 있다.
  • Encoder Network: VGG 16 구조를 사용하지만, DeconvNet과 달리 1x1 Convolution 계층을 제거하여 연산 파라미터 수를 줄이고 학습 및 추론 시간을 감소시킨다.
  • Decoder Network: 업샘플링 과정에서 Unpooling과 Convolution, ReLU 연산을 수행하여 더 간소화된 구조로 실시간 성능을 향상시킨다.

그렇다면 성능차이가 있을까?? 

 

 

1) Segmentation 정확도

DeconvNet은 복잡한 디코더 구조로 인해 더 세밀한 특징을 복원할 가능성이 있다. 따라서 정확도가 높은 데이터셋에서는 SegNet보다 약간 더 나은 성능을 보일 수 있다.

하지만, 일반적인 의료 영상 데이터나 자연 이미지에서는 SegNet이 간결한 구조로도 충분한 성능을 낸다는 연구가 많다.

 

2) 속도 및 효율성

SegNet은 Unpooling 인덱스를 재사용하므로 계산 속도와 메모리 사용량에서 DeconvNet보다 유리하다.

특히, 대규모 데이터셋 또는 고해상도 이미지를 처리할 때 SegNet이 더 효율적이다.

 

3) 응용 분야에 따른 차이

DeconvNet은 더 복잡한 구조로 인해 세밀한 경계 복원이 필요한 작업에서 더 나은 성능을 낼 가능성이 있다.

SegNet은 실시간 처리나 메모리 제한이 있는 환경에서 더 적합하다.


 

SegNet 코드

아래는 위의 아키텍처를 기반으로 작성된 pytorch 코드이다.

# 모델 참고 코드
# https://github.com/wkentaro/pytorch-fcn/

class SegNet(nn.Module):
    def __init__(self, num_classes=len(CLASSES)):
        super(SegNet, self).__init__()
        def CBR(in_channels, out_channels, kernel_size=3, stride=1, padding=1):
            layers = []
            layers += [nn.Conv2d(in_channels=in_channels, out_channels=out_channels,
                                 kernel_size=kernel_size, stride=stride, padding=padding)]
            layers += [nn.BatchNorm2d(num_features=out_channels)]
            layers += [nn.ReLU()]

            cbr = nn.Sequential(*layers)
            return cbr

        # conv1
        self.cbr1_1 = CBR(3, 64, 3, 1, 1)
        self.cbr1_2 = CBR(64, 64, 3, 1, 1)
        self.pool1 = nn.MaxPool2d(2, stride=2, ceil_mode=True, return_indices=True)

        # conv2
        self.cbr2_1 = CBR(64, 128, 3, 1, 1)
        self.cbr2_2 = CBR(128, 128, 3, 1, 1)
        self.pool2 = nn.MaxPool2d(2, stride=2, ceil_mode=True, return_indices=True)

        # conv3
        self.cbr3_1 = CBR(128, 256, 3, 1, 1)
        self.cbr3_2 = CBR(256, 256, 3, 1, 1)
        self.cbr3_3 = CBR(256, 256, 3, 1, 1)
        self.pool3 = nn.MaxPool2d(2, stride=2, ceil_mode=True, return_indices=True)

        # conv4
        self.cbr4_1 = CBR(256, 512, 3, 1, 1)
        self.cbr4_2 = CBR(512, 512, 3, 1, 1)
        self.cbr4_3 = CBR(512, 512, 3, 1, 1)
        self.pool4 = nn.MaxPool2d(2, stride=2, ceil_mode=True, return_indices=True)

        # conv5
        self.cbr5_1 = CBR(512, 512, 3, 1, 1)
        self.cbr5_2 = CBR(512, 512, 3, 1, 1)
        self.cbr5_3 = CBR(512, 512, 3, 1, 1)
        self.pool5 = nn.MaxPool2d(2, stride=2, ceil_mode=True, return_indices=True)

        # deconv5
        self.unpool5 = nn.MaxUnpool2d(2, stride=2)
        self.dcbr5_3 = CBR(512, 512, 3, 1, 1)
        self.dcbr5_2 = CBR(512, 512, 3, 1, 1)
        self.dcbr5_1 = CBR(512, 512, 3, 1, 1)

        # deconv4
        self.unpool4 = nn.MaxUnpool2d(2, stride=2)
        self.dcbr4_3 = CBR(512, 512, 3, 1, 1)
        self.dcbr4_2 = CBR(512, 512, 3, 1, 1)
        self.dcbr4_1 = CBR(512, 256, 3, 1, 1)

        # deconv3
        self.unpool3 = nn.MaxUnpool2d(2, stride=2)
        self.dcbr3_3 = CBR(256, 256, 3, 1, 1)
        self.dcbr3_2 = CBR(256, 256, 3, 1, 1)
        self.dcbr3_1 = CBR(256, 128, 3, 1, 1)

        # deconv2
        self.unpool2 = nn.MaxUnpool2d(2, stride=2)
        self.dcbr2_2 = CBR(128, 128, 3, 1, 1)
        self.dcbr2_1 = CBR(128, 64, 3, 1, 1)

        # deconv1
        self.unpool1 = nn.MaxUnpool2d(2, stride=2)
        self.dcbr1_2 = CBR(64, 64, 3, 1, 1)
        self.dcbr1_1 = CBR(64, 64, 3, 1, 1)
        self.score_fr = nn.Conv2d(64, num_classes, kernel_size = 1)

    def forward(self, x):
        h = self.cbr1_1(x)
        h = self.cbr1_2(h)
        dim1 = h.size()
        h, pool1_indices = self.pool1(h)

        h = self.cbr2_1(h)
        h = self.cbr2_2(h)
        dim2 = h.size()
        h, pool2_indices = self.pool2(h)

        h = self.cbr3_1(h)
        h = self.cbr3_2(h)
        h = self.cbr3_3(h)
        dim3 = h.size()
        h, pool3_indices = self.pool3(h)

        h = self.cbr4_1(h)
        h = self.cbr4_2(h)
        h = self.cbr4_3(h)
        dim4 = h.size()
        h, pool4_indices = self.pool4(h)

        h = self.cbr5_1(h)
        h = self.cbr5_2(h)
        h = self.cbr5_3(h)
        dim5 = h.size()
        h, pool5_indices = self.pool5(h)

        h = self.unpool5(h, pool5_indices, output_size = dim5)
        h = self.dcbr5_3(h)
        h = self.dcbr5_2(h)
        h = self.dcbr5_1(h)

        h = self.unpool4(h, pool4_indices, output_size = dim4)
        h = self.dcbr4_3(h)
        h = self.dcbr4_2(h)
        h = self.dcbr4_1(h)

        h = self.unpool3(h, pool3_indices, output_size = dim3)
        h = self.dcbr3_3(h)
        h = self.dcbr3_2(h)
        h = self.dcbr3_1(h)

        h = self.unpool2(h, pool2_indices, output_size = dim2)
        h = self.dcbr2_2(h)
        h = self.dcbr2_1(h)

        h = self.unpool1(h, pool1_indices, output_size = dim1)
        h = self.dcbr1_2(h)
        h = self.dcbr1_1(h)
        h = self.score_fr(h)
        return h

 

 

SegNet은 이러한 간결한 구조 덕분에 기존의 DeconvNet보다 빠르게 작동하며, 자율 주행을 포함한 다양한 실시간 애플리케이션에서 유용하게 활용될 수 있다. 특히 SegNet은 DeconvNet에 비해 속도를 높이는 데 중점을 두고 설계되었으며, 실제로 학습과 추론 시간이 크게 줄어들어 실시간 환경에서 더 적합한 모델로 자리 잡았다. 다.

 

 

SegNet은 도로 환경에서 객체를 빠르게 구분할 수 있는 강력한 세그멘테이션 모델이다. 자율 주행과 같은 실시간 처리가 요구되는 분야에서 유용하게 사용될 수 있으며, 앞으로도 다양한 응용 분야에서 확장 가능성이 높다.

 

 

728x90
반응형

댓글