2022-08-04,   김혜원

이번 포스팅에서는 CNN 모델의 한 종류인 VGGNet에 대해 알아보겠습니다.


VGGNet?

에러율변화

VGGNet(Visual Geometry Group Network)은 영국 옥스포드 대학의 연구팀 VGG에서 개발한 모델로 2014년에 이미지넷 인식 대회에서 준우승을 차지한 모델입니다. 이전에 나왔던 모델들이 8 layer인걸 생각하면 VGGNet은 19 layer로 깊은 신경망을 구현했는데도 오류율이 확연히 낮아진것을 위 그림에서 확인 할 수 있습니다. 같은 해 나온 GoogLeNet이 더 좋은 성능으로 우승을 차지했음에도 불구하고 VGGNet이 인기를 얻은 이유는 성능이 우수한데 구조가 단순하여 변형시키기 쉽기때문입니다.

모델 구조 & 종류

vggnet_종류

위 그림은 논문에서 진행한 실험들을 표로 정리한 것입니다. 깊이에 따른 학습률을 확인하기 위한 것으로 convolution layer의 갯수에 따라 VGG11(A), VGG11-LRN(A-LRN), VGG13(B), VGG16(C), VGG16(D), VGG19(E)입니다. A-LRN은 Normalization을 적용한 것과 아닌것의 성능을 비교하기 위해 만들어진 모델로 비교 결과 성능의 차이가 별로 없어서 B-E는 LRN을 적용한 모델이 없습니다. 현재 모델 구성할 때 BN(Batch Normalization, 배치 정규화)을 적용하여 사용하고 있습니다.

vgg_filter_7X7 vgg_filter_3X3

위 그림은 7X7필터와 3X3필터를 적용한 예시입니다. 논문에서 저자는 커널 사이즈를 제일 작은 3X3으로 고정시켰습니다. 예를 들어 7X7 필터와 3X3의 예시를 보겠습니다. 7X7 필터를 사용했을때는 한 번 연산하던 것을 3X3 필터를 사용하면 세 번 계산하게 됩니다. 그 결과 연산 할 때 발생하는 파라미터 수는 49에서 27로 줄어들고, ReLU의 수는 1개에서 3개로 늘어서 성능이 향상됐습니다.

vggnet_구조

VGG16의 구조를 살펴보면 Convolution - Pooling - Fully_connected로 되어있습니다. 5개의 블럭을 거친 후 FC층에 도달하는데 한 블럭에 2개 ~ 3개의 convolution과 max pooling이 있습니다. 마지막은 활성화함수로 softmax를 사용하여 이미지를 분류합니다.


구현 예제

다음은 VGG-16(D) 모델의 구성을 구현한 예제입니다. 3X3 kernel을 64개 사용했으며, padding은 하지않고, ReLU 활성화 함수를 사용하였습니다. 모델 구성 후 summary()를 통해 전체 구조를 확인할 수 있습니다.


input = keras.Input(shpae=(244,244,3))
model = Sequential()
model.add(Conv2D(input,filters=64,kernel_size=(3,3),padding="same", activation="relu"))
model.add(Conv2D(filters=64,kernel_size=(3,3),padding="same", activation="relu"))
model.add(MaxPool2D(pool_size=(2,2),strides=(2,2)))
model.add(Conv2D(filters=128, kernel_size=(3,3), padding="same", activation="relu"))
model.add(Conv2D(filters=128, kernel_size=(3,3), padding="same", activation="relu"))
model.add(MaxPool2D(pool_size=(2,2),strides=(2,2)))
model.add(Conv2D(filters=256, kernel_size=(3,3), padding="same", activation="relu"))
model.add(Conv2D(filters=256, kernel_size=(3,3), padding="same", activation="relu"))
model.add(Conv2D(filters=256, kernel_size=(3,3), padding="same", activation="relu"))
model.add(MaxPool2D(pool_size=(2,2),strides=(2,2)))
model.add(Conv2D(filters=512, kernel_size=(3,3), padding="same", activation="relu"))
model.add(Conv2D(filters=512, kernel_size=(3,3), padding="same", activation="relu"))
model.add(Conv2D(filters=512, kernel_size=(3,3), padding="same", activation="relu"))
model.add(MaxPool2D(pool_size=(2,2),strides=(2,2)))
model.add(Conv2D(filters=512, kernel_size=(3,3), padding="same", activation="relu"))
model.add(Conv2D(filters=512, kernel_size=(3,3), padding="same", activation="relu"))
model.add(Conv2D(filters=512, kernel_size=(3,3), padding="same", activation="relu"))
model.add(MaxPool2D(pool_size=(2,2),strides=(2,2)))
model.add(Flatten())
model.add(Dense(units=4096,activation="relu"))
model.add(Dense(units=4096,activation="relu"))
model.add(Dense(units=1000, activation="softmax"))

model.summary()


참고자료

업데이트: