본문 바로가기

AI

TensorFlow 함수형 API 로 VGGNet 논문 구현

model = tf.keras.Model(input_, x)

VGGNet (2014)

  • 16~19개의 깊은 층을 쌓아 네트워크의 깊이와 성능 간의 관계를 조사
  • 3x3 Convolution Layer 를 여러 개 쌓는 단순하고 일관된 구조를 사용

K. Simonyan and A. Zisserman, "Very Deep Convolutional Networks for Large-Scale Image Recognition," in International Conference on Learning Representations (ICLR), 2015.

  • 주요 특징
    1. 단순한 구조:
      • VGGNet의 구조는 매우 단순합니다. 3x3 크기의 작은 필터를 사용하는 합성곱 층(convolutional layer)과 최대 풀링 층(max pooling layer)을 깊게 쌓아 올린 형태로 설계되었습니다.
      • 합성곱 층의 필터 크기를 3x3으로 고정하고, 스트라이드(stride)와 패딩(padding)을 적절히 조정하여 출력 크기가 유지되도록 설계했습니다.
      • 모델의 깊이는 VGG-11, VGG-13, VGG-16, VGG-19와 같이 11개에서 19개 층으로 구성됩니다(숫자는 가중치 층의 개수).
    2. 작은 필터의 장점:
      • 3x3 필터를 여러 층 쌓으면, 같은 수의 매개변수로도 더 큰 receptive field를 커버할 수 있습니다. 예를 들어, 3x3 필터를 3개 쌓으면 7x7 필터와 같은 리셉티브 필드를 얻을 수 있습니다.
      • 작은 필터를 사용하면 매개변수 수를 줄이면서 비선형성(activation)을 추가하여 모델의 표현력을 증가시킬 수 있습니다.
    3. 레이어의 깊이:
      • VGGNet은 이전 모델(AlexNet, ZFNet)에 비해 매우 깊은 네트워크 구조를 가지고 있습니다.
      • 깊은 네트워크는 더 복잡한 특징을 학습할 수 있으며, 특히 대규모 데이터셋(ImageNet)에서 뛰어난 성능을 보였습니다.
    4. Dense Layer:
      • 네트워크의 마지막 부분에는 완전연결 층(Fully Connected Layer, FC)과 소프트맥스(softmax) 층이 추가되어 이미지의 클래스 확률을 예측합니다.
    5. 전이 학습(Transfer Learning):
      • VGGNet은 이미지넷(ImageNet)에서 학습된 가중치를 기반으로 전이 학습에 자주 사용됩니다.
      • 특히 컴퓨터 비전 작업에서 특정 도메인의 데이터를 학습시키는 데 유용합니다.

    VGGNet의 구조
    • 입력: 224x224 RGB 이미지
    • 합성곱 층: 3x3 필터, ReLU 활성화 함수 사용
    • 풀링 층: 2x2 최대 풀링
    • 완전연결 층: 3개의 FC 층
    • 출력: 1000개의 클래스 (ImageNet 기준)
    구체적인 레이어 구성은 다음과 같습니다:
    • 입력: 224x224x3 이미지
    • Conv3-64 → Conv3-64 → MaxPool
    • Conv3-128 → Conv3-128 → MaxPool
    • Conv3-256 → Conv3-256 → Conv3-256 → MaxPool
    • Conv3-512 → Conv3-512 → Conv3-512 → MaxPool
    • Conv3-512 → Conv3-512 → Conv3-512 → MaxPool
    • FC4096 → FC4096 → FC1000 → Softmax

    장점
    1. 성능:
      • 이미지 분류(ImageNet)에서 매우 높은 정확도를 달성했습니다.
      • 전이 학습에 적합한 구조를 가짐.
    2. 단순성:
      • 구조가 간단하여 이해 및 구현이 용이.
      • 딥러닝 연구에서 기본 모델로 자주 사용됨.
    3. 모듈화:
      • 작은 3x3 필터를 사용해 모듈화된 설계를 제공, 다양한 변형을 쉽게 생성 가능.

    단점
    1. 많은 매개변수:
      • 깊은 구조로 인해 모델이 매우 크고(수백 MB 이상), 많은 메모리가 필요.
      • 학습과 추론 속도가 느림.
    2. 과적합:
      • 작은 데이터셋에 사용하면 과적합 가능성이 큼.

    실제 응용
    • 이미지 분류
    • 객체 탐지
    • 특징 추출
    • 전이 학습
  • VGGNet은 이후의 딥러닝 모델(ResNet, Inception 등)에 비해 효율성은 떨어지지만, 그 단순한 설계와 뛰어난 성능 덕분에 딥러닝 연구의 기초를 닦은 모델로 여전히 중요하게 사용되고 있습니다.

VGGNet 구현

import tensorflow as tf

 

비교를 위한 tf.keras.applications.VGG16

vgg16 = tf.keras.applications.VGG16(include_top=True)
vgg16.summary()

 

Model: "vgg16"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓
┃ Layer (type)                         ┃ Output Shape                ┃         Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩
│ input_layer (InputLayer)             │ (None, 224, 224, 3)         │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block1_conv1 (Conv2D)                │ (None, 224, 224, 64)        │           1,792 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block1_conv2 (Conv2D)                │ (None, 224, 224, 64)        │          36,928 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block1_pool (MaxPooling2D)           │ (None, 112, 112, 64)        │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block2_conv1 (Conv2D)                │ (None, 112, 112, 128)       │          73,856 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block2_conv2 (Conv2D)                │ (None, 112, 112, 128)       │         147,584 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block2_pool (MaxPooling2D)           │ (None, 56, 56, 128)         │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block3_conv1 (Conv2D)                │ (None, 56, 56, 256)         │         295,168 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block3_conv2 (Conv2D)                │ (None, 56, 56, 256)         │         590,080 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block3_conv3 (Conv2D)                │ (None, 56, 56, 256)         │         590,080 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block3_pool (MaxPooling2D)           │ (None, 28, 28, 256)         │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block4_conv1 (Conv2D)                │ (None, 28, 28, 512)         │       1,180,160 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block4_conv2 (Conv2D)                │ (None, 28, 28, 512)         │       2,359,808 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block4_conv3 (Conv2D)                │ (None, 28, 28, 512)         │       2,359,808 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block4_pool (MaxPooling2D)           │ (None, 14, 14, 512)         │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block5_conv1 (Conv2D)                │ (None, 14, 14, 512)         │       2,359,808 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block5_conv2 (Conv2D)                │ (None, 14, 14, 512)         │       2,359,808 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block5_conv3 (Conv2D)                │ (None, 14, 14, 512)         │       2,359,808 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block5_pool (MaxPooling2D)           │ (None, 7, 7, 512)           │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ flatten (Flatten)                    │ (None, 25088)               │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ fc1 (Dense)                          │ (None, 4096)                │     102,764,544 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ fc2 (Dense)                          │ (None, 4096)                │      16,781,312 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ predictions (Dense)                  │ (None, 1000)                │       4,097,000 │
└──────────────────────────────────────┴─────────────────────────────┴─────────────────┘
 Total params: 138,357,544 (527.79 MB)
 Trainable params: 138,357,544 (527.79 MB)
 Non-trainable params: 0 (0.00 B)

 

VGGNet16 input layer

input_ = tf.keras.Input((224,224,3))

 

VGGNet16 model

x = tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu', name='block1_conv1')(input_)
x = tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu', name='block1_conv2')(x)
x = tf.keras.layers.MaxPool2D(2,2,name='block1_pool')(x)
x = tf.keras.layers.Conv2D(128, 3, padding='same', activation='relu', name='block2_conv1')(x)
x = tf.keras.layers.Conv2D(128, 3, padding='same', activation='relu', name='block2_conv2')(x)
x = tf.keras.layers.MaxPool2D(2, 2,name='block2_pool')(x)
x = tf.keras.layers.Conv2D(256, 3, padding='same', activation='relu', name='block3_conv1')(x)
x = tf.keras.layers.Conv2D(256, 3, padding='same', activation='relu', name='block3_conv2')(x)
x = tf.keras.layers.Conv2D(256, 3, padding='same', activation='relu', name='block3_conv3')(x)
x = tf.keras.layers.MaxPool2D(2, 2,name='block3_pool')(x)
x = tf.keras.layers.Conv2D(512, 3, padding='same', activation='relu', name='block4_conv1')(x)
x = tf.keras.layers.Conv2D(512, 3, padding='same', activation='relu', name='block4_conv2')(x)
x = tf.keras.layers.Conv2D(512, 3, padding='same', activation='relu', name='block4_conv3')(x)
x = tf.keras.layers.MaxPool2D(2, 2,name='block4_pool')(x)
x = tf.keras.layers.Conv2D(512, 3, padding='same', activation='relu', name='block5_conv1')(x)
x = tf.keras.layers.Conv2D(512, 3, padding='same', activation='relu', name='block5_conv2')(x)
x = tf.keras.layers.Conv2D(512, 3, padding='same', activation='relu', name='block5_conv3')(x)
x = tf.keras.layers.MaxPool2D(2, 2,name='block5_pool')(x)
x = tf.keras.layers.Flatten()(x)
x = tf.keras.layers.Dense(4096, name='fc1')(x)
x = tf.keras.layers.Dense(4096, name='fc2')(x)
x = tf.keras.layers.Dense(1000, activation='softmax', name='predictions')(x)
model = tf.keras.Model(input_, x)

 

구현한 모델 summary 확인

model.summary()

 

tf.keras.applications.VGG16 와 비교 확인

Model: "functional"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓
┃ Layer (type)                         ┃ Output Shape                ┃         Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩
│ input_layer_1 (InputLayer)           │ (None, 224, 224, 3)         │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block1_conv1 (Conv2D)                │ (None, 224, 224, 64)        │           1,792 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block1_conv2 (Conv2D)                │ (None, 224, 224, 64)        │          36,928 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block1_pool (MaxPooling2D)           │ (None, 112, 112, 64)        │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block2_conv1 (Conv2D)                │ (None, 112, 112, 128)       │          73,856 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block2_conv2 (Conv2D)                │ (None, 112, 112, 128)       │         147,584 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block2_pool (MaxPooling2D)           │ (None, 56, 56, 128)         │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block3_conv1 (Conv2D)                │ (None, 56, 56, 256)         │         295,168 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block3_conv2 (Conv2D)                │ (None, 56, 56, 256)         │         590,080 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block3_conv3 (Conv2D)                │ (None, 56, 56, 256)         │         590,080 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block3_pool (MaxPooling2D)           │ (None, 28, 28, 256)         │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block4_conv1 (Conv2D)                │ (None, 28, 28, 512)         │       1,180,160 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block4_conv2 (Conv2D)                │ (None, 28, 28, 512)         │       2,359,808 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block4_conv3 (Conv2D)                │ (None, 28, 28, 512)         │       2,359,808 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block4_pool (MaxPooling2D)           │ (None, 14, 14, 512)         │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block5_conv1 (Conv2D)                │ (None, 14, 14, 512)         │       2,359,808 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block5_conv2 (Conv2D)                │ (None, 14, 14, 512)         │       2,359,808 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block5_conv3 (Conv2D)                │ (None, 14, 14, 512)         │       2,359,808 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ block5_pool (MaxPooling2D)           │ (None, 7, 7, 512)           │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ flatten_1 (Flatten)                  │ (None, 25088)               │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ fc1 (Dense)                          │ (None, 4096)                │     102,764,544 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ fc2 (Dense)                          │ (None, 4096)                │      16,781,312 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ predictions (Dense)                  │ (None, 1000)                │       4,097,000 │
└──────────────────────────────────────┴─────────────────────────────┴─────────────────┘
 Total params: 138,357,544 (527.79 MB)
 Trainable params: 138,357,544 (527.79 MB)
 Non-trainable params: 0 (0.00 B)