본문 바로가기

하루 30분 컴퓨터 비전 공부하기

CV(5) CNN 정복하기 GoogLeNet - 심화된 CNN 구조

01. Inception Module (Naïve Version) “GoogLeNet”

https://itrepo.tistory.com/35

  • 좋은 성능을 얻기 위해서는 딥러닝 구조를 깊게 만들어야한다.
  • error가 잘 전달 되지 않는 vanishing gradient의 문제를 극복하면서...

1. GoogLeNet의 구조

  • convolution과 max pooling이 섞여있음.
  • Inception Module을 사용하여 vanishing gradient의 문제를 극복.
  • 왜 한 입력 image에 한 종류의 filter size만 적용할까?  ➞ Filter size를 여러개 사용한 후 그 결과를 concat하자!!
    • 1*1, 3*3, 5*5, max poolig을 다 해보자~ 
  • 큰 사이즈의 Receptive Field가 제공하는 장점은 수용하면서 파라미터의 수를 줄일 수 있는 구조를 만들었다.
    • 다양한 크기의 filter를 사용하면서 큰 사이즈의 장점과 작은 사이즈의 장점을 모두 사용함 
    • 여러 사이즈의 필터들이 서로 다른 공간 기반으로 feature들을 추출하고 이를 결합하면서 보다 풍부한 Feature Extractor layer구성이 가능함.
  • 적절한 커널의 필터 사이즈와 Pooling을 고민해서 찾아내기 보단 여러가지 사이즈의 필터들을 한꺼번에 결합하는 방식을 제공
  • Global Average Pooling을 통해 전체 feature map의 평균값을 뽑아 pooling 한다. 
더보기

✔️ vanishing gradient problem이란? 

딥러닝 분야에서 layer를 많이 쌓을수록 기울기 소실(vanishing gradient)현상이 일어나 학습이 잘 되지 않는 것을 말한다. 기울기 소실이란 역전파과정에서 출력층에서 멀어질수록 gradient의 값이 매우 작아지는 현상을 말한다. 

https://heytech.tistory.com/388

Inception Module은 어떻게 vanishing gradient 문제를 완하할까? 

  • 다양한 필터 크기
    • Inception Module은 서로 다른 컨볼루션 필터 크기를 사용한다.
    • 이렇게 하면 네트워크는 작은 객체나 세부적인 특징을 감지하는 데 더 민감한 필터와 큰 객체나 전체적인 구조를 감지하는 데 더 민감한 필터를 동시에 사용할 수 있다.
    • 그래서 네트워크는 다양한 정보를 추출할 수 있으며, 그래디언트가 특정 필터 크기에 집중되는 것을 완화한다. 
  • 병렬 연산
    • Inception Module은 여러 컨볼루션 연산을 병렬로 수행하는데 이것은 네트워크가 다양한 특징을 추출하고 그래디언트가 여러 경로를 통해 흐를 수 있도록 한다.
    • 그래서 그래디언트가 더 빠르게 전파되고 소실되지 않도록 한다.
  • 1x1 컨볼루션
    • Inception Module 내에서 1x1 컨볼루션을 사용하여 차원을 줄이거나 늘리는 데 사용된다.
    • 이것은 차원 축소와 비선형성 추가를 통해 그래디언트를 효과적으로 전파하는 데 도움이 된다.

참고 

chat gpt

https://heytech.tistory.com/388

 

그럼 코드를 통해 한번 실습해 봅시당 

# 인셉션 모듈을 만드는 데에 필요한 모듈 불러오기
import tensorflow as tf
import tensorflow.keras as keras
from tensorflow.keras.utils import plot_model # 모델 시각화

# Naïve Inception 블록을 만들기 위한 함수
def naive_inception(input_layer, conv1_filter, conv3_filter, conv5_filter):
    # 1x1 사이즈의 kernel을 이용한 convolution2d layer
    conv1 = keras.layers.Conv2D(conv1_filter, (1,1), padding='same', activation='relu')(input_layer)


    # 3x3 사이즈의 kernel을 이용한 convolution2d layer를 만들어 보세요.
    conv3 = keras.layers.Conv2D(conv3_filter, (3,3), padding = 'same', activation = 'relu')(input_layer)
    
    # 5x5 사이즈의 kernel을 이용한 convolution2d layer를 만들어 보세요.
    conv5 = keras.layers.Conv2D(conv5_filter, (5,5), apdding = 'same', activation = 'relu')(input_layer)
    

    # 3x3 max pooling layer (데이터의 가로 세로를 3x3로 살펴보고 가장 큰 값만 뽑아낸다)
    pool = keras.layers.MaxPooling2D((3,3), strides=(1,1), padding='same')(input_layer)
    # 위에서 언급한 4개의 layer 통해서 나온 feature map들을 모두 concatenation 한다.
    out_layer = keras.layers.Concatenate()([conv1, conv3, conv5, pool])
    return out_layer
    
input_data = keras.layers.Input(shape=(256, 256, 3))
naive_inception_out = naive_inception(input_data, 64, 128, 32)
print(naive_inception_out)

 

KerasTensor(type_spec=TensorSpec(shape=(None, 256, 256, 227), dtype=tf.float32, name=None), name='concatenate/concat:0', description="created by layer 'concatenate'")

input layer와 navïve Inception 블록을 연결해서 모델을 만든다. 

# 모델 만들기
model = keras.models.Model(inputs=input_data, outputs=naive_inception_out)
# 생성한 모델의 구조 확인하기
model.summary()
 
 
Model: "model"
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_4 (InputLayer)            [(None, 256, 256, 3) 0                                            
__________________________________________________________________________________________________
conv2d_6 (Conv2D)               (None, 256, 256, 64) 256         input_4[0][0]                    
__________________________________________________________________________________________________
conv2d_7 (Conv2D)               (None, 256, 256, 128 3584        input_4[0][0]                    
__________________________________________________________________________________________________
conv2d_8 (Conv2D)               (None, 256, 256, 32) 2432        input_4[0][0]                    
__________________________________________________________________________________________________
max_pooling2d (MaxPooling2D)    (None, 256, 256, 3)  0           input_4[0][0]                    
__________________________________________________________________________________________________
concatenate (Concatenate)       (None, 256, 256, 227 0           conv2d_6[0][0]                   
                                                                 conv2d_7[0][0]                   
                                                                 conv2d_8[0][0]                   
                                                                 max_pooling2d[0][0]              
==================================================================================================
Total params: 6,272
Trainable params: 6,272
Non-trainable params: 0
______________________________

tensorflow.keras.utils 라이브러리의 plot_model 함수로 모델의 구조를 시각화해보자 

# 모델 구조 시각화하기
plot_model(model, show_shapes=True, to_file='naive_inception_module.png')

02. Inception Module (1x1 convolution) “GoogLeNet”

 

1. 1*1 filter

  • feature map의 depth를 감소시켜 연산량을 감소시킴 
  • input의 channel 수 == filter channel 수 
  • filter의 수  == output channel의 수 
  • 연산량을 감소시킨다는 것은 무슨 말일까? 
    • 연산량 = 찾아야하는 값의 개수 (featuer map크기 (depth도 포함)* 입력 데이터 크기 (depth도 포함))
    • ex) 1 * 1 conv + 5 * 5 conv 수행한다고 가정 
      • 1 * 1 conv의 연산량 : (14 * 14 * 16) * (1 * 1 * 480) = 1.5m
      • 5 * 5 conv의 연산량 : (14 * 14 * 48) * (5 * 5 * 16) = 3.8m
      • 총연산량 : 5.3M ➞  5 * 5 conv 수행한 112.9M보다 월등히 적음
      • ReLU를 한번 사용할 것을 두번 사용하여 비선형성을 강화 

2. Auxiliary Classifier (가짜 분류기)

  • 엄청나게 깊은 네트워크에서 vanishing gradient 문제 발생 
  • Auxiliary Classifier를  덧붙여서 중간 중간에 classifier을 넣어줌
  • 결과적으로 loss를 맨 끝 뿐만 아니라 중간에서도 구하기 때문에 기울기 역전파 될 수 있음
  • 대신 지나치게 영향을 주는 것을 막기위해  Auxiliary Classifier의 loss는 0.3을 곱함
  • 물론 실제로 테스트하는 과정에서는  Auxiliary Classifier를 제거하고 맨끝의 softmax만을 사용
    • training 과정에서만 사용 

코드 실습 

# 인셉션 모듈을 만드는 데에 필요한 모듈 불러오기
import tensorflow as tf
import tensorflow.keras as keras
from tensorflow.keras.utils import plot_model # 모델 시각화

# Inception 블록을 만들기 위한 함수
def inception(input_layer, conv1_filter, conv3_in, conv3_out, conv5_in, conv5_out, pooling_out):
    # 1x1 사이즈의 kernel을 이용한 convolution2d layer
    conv1 = keras.layers.Conv2D(conv1_filter, (1,1), padding='same', activation='relu')(input_layer)
    # 3x3 사이즈의 kernel을 이용한 convolution2d layer
    conv3 = keras.layers.Conv2D(conv3_in, (1,1), padding='same', activation='relu')(input_layer) # Naive 버전과 가장 차별화되는 부분: 1x1 convolution
    conv3 = keras.layers.Conv2D(conv3_out, (3,3), padding='same', activation='relu')(conv3)
    

    # 5x5 사이즈의 kernel을 이용한 convolution2d layer 를 만들어 보세요.
    conv5 = keras.layers.Conv2D(conv5_in, (1,1), padding = 'same', activation = 'relu')(input_layer)
    conv5 = keras.layers.Conv2D(conv5_out, (5,5), padding = 'same', activation = 'relu')(conv5)
    
    
    # 3x3 max pooling layer (데이터의 가로 세로를 3x3로 살펴보고 가장 큰 값만 뽑아낸다)
    pool = keras.layers.MaxPooling2D((3,3), strides=(1,1), padding='same')(input_layer)
    pool = keras.layers.Conv2D(pooling_out, (1,1), padding='same', activation='relu')(pool)
    # 위에서 언급한 4개의 layer 통해서 나온 feature map들을 모두 concatenation 한다.
    out_layer = keras.layers.Concatenate()([conv1, conv3, conv5, pool])
    return out_layer
    
# input layer를 정의하고 Inception 블록을 생성   
input_data = keras.layers.Input(shape=(256, 256, 3))
inception_out = inception(input_data, 64, 96, 128, 16, 32, 32)

# 모델 만들기
model = keras.models.Model(inputs=input_data, outputs=inception_out)
# 생성한 모델의 구조 확인하기
model.summary()
Model: "model_1"
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_6 (InputLayer)            [(None, 256, 256, 3) 0                                            
__________________________________________________________________________________________________
conv2d_14 (Conv2D)              (None, 256, 256, 96) 384         input_6[0][0]                    
__________________________________________________________________________________________________
conv2d_16 (Conv2D)              (None, 256, 256, 16) 64          input_6[0][0]                    
__________________________________________________________________________________________________
max_pooling2d_1 (MaxPooling2D)  (None, 256, 256, 3)  0           input_6[0][0]                    
__________________________________________________________________________________________________
conv2d_13 (Conv2D)              (None, 256, 256, 64) 256         input_6[0][0]                    
__________________________________________________________________________________________________
conv2d_15 (Conv2D)              (None, 256, 256, 128 110720      conv2d_14[0][0]                  
__________________________________________________________________________________________________
conv2d_17 (Conv2D)              (None, 256, 256, 32) 12832       conv2d_16[0][0]                  
__________________________________________________________________________________________________
conv2d_18 (Conv2D)              (None, 256, 256, 32) 128         max_pooling2d_1[0][0]            
__________________________________________________________________________________________________
concatenate_1 (Concatenate)     (None, 256, 256, 256 0           conv2d_13[0][0]                  
                                                                 conv2d_15[0][0]                  
                                                                 conv2d_17[0][0]                  
                                                                 conv2d_18[0][0]                  
==================================================================================================
Total params: 124,384
Trainable params: 124,384
Non-trainable params: 0
__________________________________________________________________________________________________
# 모델 구조 시각화하기
plot_model(model, show_shapes=True, to_file='inception.png')