정지홍 2025. 1. 26. 13:24

DeepLab v1

  • semantic segmentation문제를 해결하기 위해서 google에서 개발한 모델이다.
  • 주요특징
    • 1. atrous convolution 을 사용하여, pooling없이 receptive field를 확장할 수 있다.
    • 2. Fully convolutional network 기반이다.
      ( 기존의 fully connected layer를 제거하고, 모든 레이어를 convolutional layer 바꾸어서 입력 크기에 상관없이 동작하게 함. )
    • 3. Conditional Random Field ( 조건부 무작위장 )
      • 위의 fully convolutonal network기반 출력은 간혹 경계가 부정확하거나 가장자리에서 세부 사항이 손실된다.
        그래서 이를 해결하기 위해 CRF로 후처리를 하여, 세그멘테이션 결과를 정교화 시킴
    • 4. Multi-Scale Feature Extraction
      • deepLab v1에서는 고정된 단일 스케일의 receptive field만 사용하는 대신 여러 스케일에서의 특징을 학습해서 다양한 크기의 객체를 더 잘 처리할 수 있다.
  • DeepLab v1의 한계
    • atrous convolution은 해상도를 유지하며 학습이 가능하나 계산비용이 높다.
    • 실시간 응용 어려움
    • CRF는 경계를 세밀하게 보정하지만, 별도의 후처리 단계로 작동해서 시스템 전체가 느려질수 있다.
  • deeplab v1의 구성요소
    • backbone network
    • 손실함수로 cross-entropy loss를 사용하여 segmentation 정확도를 향상

 

 

DeepLab v1의 동작 원리

  • 1. atrous convolution 를 사용하여 더 넓은 문맥에서 정보를 수집함.
  • 2. fully connected layer대신에 convolution layer만을 사용하였다.
    • 즉, VGG 16의 마지막 Fully Connected Layer를 convolution layer로 바꾸어 사용함.
  • 3. 후처리 단계로 Conditional Random Field ( 조건부 무작위장 )를 사용하였다. ( Unary Potential )
    • 이는 주변 픽셀 간의 상관관계를 이용해서 각 픽셀의 클래스를 최정화한다.
      특히나 경계 근처에서 불확실한 픽셀의 클래스를 조정함.
  • 4. 다중 스케일 특징을 학습해서 다양한 크기의 객체를 처리할 수 있게한다.

 

import tensorflow as tf
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Input, Conv2DTranspose, Softmax, Concatenate
from tensorflow.keras.models import Model
from tensorflow.keras.utils import plot_model

# VGG-16 백본 모델을 구축하는 함수
# 입력: 이미지 입력 크기 (input_shape)
# 출력: VGG-16의 마지막 convolution layer (block5_conv3)
def build_vgg16_backbone(input_shape):
    inputs = Input(shape=input_shape)
    
    # Block 1
    x = Conv2D(64, (3, 3), activation='relu', padding='same')(inputs)
    x = Conv2D(64, (3, 3), activation='relu', padding='same')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2))(x)
    
    # Block 2
    x = Conv2D(128, (3, 3), activation='relu', padding='same')(x)
    x = Conv2D(128, (3, 3), activation='relu', padding='same')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2))(x)
    
    # Block 3
    x = Conv2D(256, (3, 3), activation='relu', padding='same')(x)
    x = Conv2D(256, (3, 3), activation='relu', padding='same')(x)
    x = Conv2D(256, (3, 3), activation='relu', padding='same')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2))(x)
    
    # Block 4
    x = Conv2D(512, (3, 3), activation='relu', padding='same')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2))(x)
    
    # Block 5
    x = Conv2D(512, (3, 3), activation='relu', padding='same')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x)
    
    model = Model(inputs, x, name="VGG16_Backbone")
    return model


# DeepLab v1 모델을 VGG-16 백본을 기반으로 구축하는 함수
# 입력: 이미지 크기 (input_shape), 클래스 수 (num_classes)
# 출력: DeepLab v1 모델
def build_deeplabv1_vgg16(input_shape=(512, 512, 3), num_classes=21):
    base_model = build_vgg16_backbone(input_shape)
    
    # VGG-16의 마지막 convolution layer (block5_conv3) 가져오기
    x = base_model.get_layer("block5_conv3").output
    
    # Atrous Convolution 적용 (다중 스케일 정보 추출)
    atrous_rates = [6, 12, 18, 24]
    atrous_layers = [Conv2D(512, (3, 3), padding='same', dilation_rate=rate, activation='relu')(x) for rate in atrous_rates]
    
    # Atrous Convolution 결과 합치기
    x = Concatenate()(atrous_layers)
    x = Conv2D(512, (1, 1), activation='relu', padding='same')(x)
    
    # Upsampling (16배 upsampling)
    x = Conv2DTranspose(num_classes, kernel_size=16, strides=16, padding='same')(x)
    x = Softmax()(x)
    
    model = Model(inputs=base_model.input, outputs=x)
    
    # 모델 구조 시각화 (Graphviz 사용)
    plot_model(model, to_file='deeplabv1_vgg16.png', show_shapes=True, show_layer_names=True)
    
    return model

# 모델 생성
model = build_deeplabv1_vgg16()

# 모델 구조 출력
model.summary()