논문 리뷰, 구현

4.GoogleNet 논문 리뷰, 구현

jwjwvison 2022. 6. 29. 21:23

 이번 포스팅에서는 GoogleNet논문(Going deeper with convolutions)을 리뷰하고 구현해 보겠다.

 

 이 논문의 저자들은 Inception이라고 불리는 깊은 합성곱 신경망을 제안했다. 이는 ILSVRC-2014에서 classification과 detection 부분에서 최첨단의 기술을 보였다. 

 

Introduction

 논문의 저자들의 GoogleNet은 AlexNet보다 12배 적은 파라미터를 사용했는데 더 정확했다.

이 논문에서 이들은 computer vision분야의 효율적인 deep neural network architecture에 focus를 맞추었다. Inception이라고 불리는 구조를 사용했다.

 

Related Work

 network-in-network방법은 1x1 합성곱 필터와 ReLU 함수를 사용하는 방법인데 이 논문의 저자들은 이방법을 많이 사용했다. 이들의 1x1필터는 두가지 목적이 있다. 첫번째는 이 필터들은 차원 감소 모듈로 주로 사용되었는데 컴퓨팅 병목 현상을 제거하기 위해 사용된다는 점이다. 그렇지 않다면 네트워크의 크기가 제한될 것이다. 이것은 깊이가 증가할수 있게 해줄 뿐만 아니라, 성능 저하 없이 이들의 network의 넓이도 늘릴수 있게 해준다.

 

Motivation and High Level Considerations

 Deep neural networks의 성능을 확실히 개선시키는 방법은 network의 사이즈를 증가시는 것이다. 그러나 이러한 방법은 두가지 중요한 단점을 가지고 있다.

 일반적으로 크기가 클수록 파라미터의 수가 많아지므로 확대된 네트워크가 과대적합될 가능성이 커지며, 특히 training set에 라벨링된 data가 제한될 경우 더욱 그렇다. 이는 중요한 장애물이 될수 있는데 왜냐하면 training set에 일일히 라벨을 다는것은 매우 힘든 일이기 때문이다.

 또다른 단점은 컴퓨팅 리소스의 사용이 대폭 증가한다는 것이다. 예를 들어서 deep vision network에서 만약 두개의 합성곱층이 연결되어있다면 4배의 연상량이 증가하게 된다.

 

 이 두가지 문제를 해결하는 근본적인 방법은 궁극적으로 완전히 연결된 아키텍쳐에서 sparsely connected architectures로 전환하는 것이다. 심지어 합성곱층에서도 마찬가지이다.

 

Architectural Details

 Inception module을 보면 1x1 convolution이 보이는데, 이것이 inception module의 핵심이다. 1x1 convolution의 목적은 dimmension reduction을 적용하여 필요한 연산량을 감소시키는 것이다. 3x3와 5x5 convolution 연산 이전에 1x1 convolution이 적용되었는데 이는 dimmension reduction을 통해 input filter의 수를 조절하기 위함입니다. 예를 들어, 이전 layer에서 256개의 channel을 가진 output이 생성됬으면 64개의 1x1 convolution filter를 이용해서 64 channel로 줄일 수 있다. 이를 통해 다양한 크기의 filter(1x1, 3x3, 5x5)를 적용하여 여러 특징을 추출하지만 연산량을 낮출 수 있게 됩니다. 모든 layer에서 inception module이 이용되는 것은 아니다. 효율적인 메모리 사용을 위해 낮은 layer에서는 기본적인 convolution layer를 적용하고 높은 layer에서는 inception module을 사용한다.

 

 결론적으로 inception module을 통해 두 가지 효과를 얻을 수 있다.

 

1. 계산 복잡도에서 계산양의 폭발없이 각 단계에서 unit의 수를 상당히 증가시킬 수 있다. dimension reduction을 통해 다음 계층의 input의 수를 조절할 수 있기 때문이다.

 

2. 시각 정보가 다양한 규모로 처리되고 다음 계층은 동시에 서로 다른 규모에서 특징을 추출할 수 있게 된다. 1x1, 3x3, 5x5 convolution 연산을 통해 다양한 특징을 추출할 수 있기 때문이다.

 

 

GoogleNet

 모든 합성곱층, 인셉션 모듈에 있는 층들도 ReLU 활성화 함수를 사용했다.

 Input 이미지의 shape은 (224,224,3)이다.

 

 #3x3, #5x5는 1x1 필터가 사용된 후 바로 연결되어 있다는 의미이다.

 

 Classifier 전에 average pooling층이 사용되었다.

 

 이 모델에서 한가지 흥미로운 점은 상대적으로 더 낮은 네트워크의 강력한 성능은 네트워크 중간에 있는 층에 의해 생성되는 특성이 매우 차별적이어야 한다는 것을 시사한다는 것이다. auxiliary classifiers를 이러한 중간층에 연결하면, classifier 내에서 lower stage 에서 차별을 조장하고, propagated back을 얻게해주는 gradient signal을 증가시키고, 추가적인 regularization을 기대하게 해준다. 훈련 중에는 이 auxiliary classifiers 의 loss가 main loss에 더해진다.

 

GoogleNet의 정확한 구조는 다음과 같다.

 

Performance

 

 

구현

def inception(x, filters):
    # 1x1
    path1 = Conv2D(filters=filters[0], kernel_size=(1,1), strides=1, padding='same', activation='relu')(x)

    # 1x1->3x3
    path2 = Conv2D(filters=filters[1][0], kernel_size=(1,1), strides=1, padding='same', activation='relu')(x)
    path2 = Conv2D(filters=filters[1][1], kernel_size=(3,3), strides=1, padding='same', activation='relu')(path2)
    
    # 1x1->5x5
    path3 = Conv2D(filters=filters[2][0], kernel_size=(1,1), strides=1, padding='same', activation='relu')(x)
    path3 = Conv2D(filters=filters[2][1], kernel_size=(5,5), strides=1, padding='same', activation='relu')(path3)

    # 3x3->1x1
    path4 = MaxPool2D(pool_size=(3,3), strides=1, padding='same')(x)
    path4 = Conv2D(filters=filters[3], kernel_size=(1,1), strides=1, padding='same', activation='relu')(path4)

    return Concatenate(axis=-1)([path1,path2,path3,path4])
def auxiliary(x,name=None):
  layer=AveragePooling2D((5,5),strides=3,padding='valid')(x)
  layer=Conv2D(128,(1,1),1,padding='same',activation='relu')(layer)
  layer=Flatten()(layer)
  layer=Dense(256,activation='relu')(layer)
  layer=Dropout(0.4)(layer)
  layer=Dense(10,activation='softmax',name=name)(layer)
  return layer
def GoogleNet():
    layer_in = Input(shape=(224,224,3))
    
    # stage-1
    layer = Conv2D(filters=64, kernel_size=(7,7), strides=2, padding='same', activation='relu')(layer_in)
    layer = MaxPooling2D(pool_size=(3,3), strides=2, padding='same')(layer)
    layer = BatchNormalization()(layer)

    # stage-2
    layer = Conv2D(filters=64, kernel_size=(1,1), strides=1, padding='same', activation='relu')(layer)
    layer = Conv2D(filters=192, kernel_size=(3,3), strides=1, padding='same', activation='relu')(layer)
    layer = BatchNormalization()(layer)
    layer = MaxPooling2D(pool_size=(3,3), strides=2, padding='same')(layer)

    # stage-3
    layer = inception(layer, [ 64,  (96,128), (16,32), 32]) #3a
    layer = inception(layer, [128, (128,192), (32,96), 64]) #3b
    layer = MaxPooling2D(pool_size=(3,3), strides=2, padding='same')(layer)
    
    # stage-4
    layer = inception(layer, [192,  (96,208),  (16,48),  64]) #4a
    aux1  = auxiliary(layer, name='aux1')
    layer = inception(layer, [160, (112,224),  (24,64),  64]) #4b
    layer = inception(layer, [128, (128,256),  (24,64),  64]) #4c
    layer = inception(layer, [112, (144,288),  (32,64),  64]) #4d
    aux2  = auxiliary(layer, name='aux2')
    layer = inception(layer, [256, (160,320), (32,128), 128]) #4e
    layer = MaxPooling2D(pool_size=(3,3), strides=2, padding='same')(layer)
    
    # stage-5
    layer = inception(layer, [256, (160,320), (32,128), 128]) #5a
    layer = inception(layer, [384, (192,384), (48,128), 128]) #5b
    layer = AveragePooling2D(pool_size=(7,7), strides=1, padding='valid')(layer)
    
    # stage-6
    layer = Flatten()(layer)
    layer = Dropout(0.4)(layer)
    layer = Dense(units=256, activation='linear')(layer)
    main = Dense(units=10, activation='softmax', name='main')(layer)
    
    model = Model(inputs=layer_in, outputs=[main, aux1, aux2])
    
    return model

 

 

참고: https://arxiv.org/abs/1409.4842

'논문 리뷰, 구현' 카테고리의 다른 글

6. ResNet 논문 리뷰, 구현  (0) 2022.07.03
5.Network in Network 논문 리뷰  (0) 2022.07.03
3.VGG 논문 리뷰,구현  (0) 2022.06.29
2. AlexNet 논문 리뷰,구현  (0) 2022.06.28
1. LeNet-5 논문 리뷰, 구현(tensorflow)  (0) 2022.06.27