VGG 구조를 참고한 경량 CNN 설계
이번 글에서는 Food-101 음식 이미지 분류 프로젝트에서 사용한 VGG 구조를 참고한 경량 CNN을 정리한다. VGG-16은 Simonyan과 Zisserman이 제안한 CNN 구조로, 작은 3×3 convolution filter를 반복적으로 쌓아 깊은 네트워크를 구성하는 방식이 이미지 분류에서 효과적임을 보였다 [2]. 본 프로젝트에서는 해당 설계 아이디어를 참고하여, 프로젝트 환경에 맞게 더 작은 CNN 구조로 재구성하였다.
1. VGG-16이란?
VGG는 Simonyan과 Zisserman이 제안한 CNN 구조이다 [2]. 핵심 아이디어는 큰 convolution filter를 사용하는 대신, 작은 3×3 convolution filter를 여러 층에 반복적으로 쌓는 것이다. 이를 통해 이미지의 지역적인 특징을 단계적으로 학습할 수 있다.
흔히 VGG-16이라고 부르지만, 여기서 16은 convolution layer만 16개라는 뜻이 아니다. VGG-16은 일반적으로 13개의 convolution layer와 3개의 fully connected layer를 포함하여 총 16개의 학습 가능한 weight layer를 갖는 구조를 의미한다. MaxPooling layer는 중간중간 사용되지만, 학습되는 가중치가 없기 때문에 16개 layer 수에 포함하지 않는다.
VGG-16 = 13개 Conv layer + 3개 Fully Connected layer
핵심 아이디어 = 작은 3×3 Conv를 반복적으로 쌓아 깊이를 늘리는 구조
2. 왜 VGG-16을 그대로 사용하지 않았는가?
Food-101은 101개 음식 클래스를 가진 대규모 이미지 데이터셋이다. 그러나 이번 프로젝트의 목적은 사전학습된 복잡한 모델을 사용하는 것이 아니라, 직접 설계한 CNN을 통해 이미지 데이터 분류 과정을 이해하는 것이었다. 따라서 VGG-16 전체 구조를 그대로 사용하지 않고, VGG의 핵심 아이디어만 가져와 경량 CNN으로 설계하였다.
즉, 본 프로젝트의 모델은 다음과 같이 이해할 수 있다.
| 구분 | 설명 |
|---|---|
| VGG-16 | 13개 Conv layer와 3개 FC layer를 갖는 깊은 CNN 구조 |
| 본 프로젝트 모델 | VGG의 3×3 Conv 반복 아이디어를 참고한 경량 CNN |
| 차이점 | VGG-16 전체 구조를 사용하지 않고 Conv block 수와 파라미터 수를 줄임 |
3. Baseline CNN 구조
먼저 기준 모델로 단순한 Baseline CNN을 구성하였다. Baseline CNN은 각 단계에서 Conv2D를 한 번 적용한 뒤 MaxPooling을 수행하는 구조이다.
Input
→ Rescaling
→ Conv2D + MaxPooling
→ Conv2D + MaxPooling
→ Conv2D + MaxPooling
→ Conv2D
→ GlobalAveragePooling2D
→ Dense
→ Softmax
이 구조는 비교적 단순하기 때문에 기준 모델로 사용하기 좋다. 하지만 Food-101처럼 클래스 수가 많고 음식 간 시각적 유사성이 큰 데이터셋에서는 더 풍부한 특징 추출이 필요할 수 있다.
4. VGG 구조를 참고한 경량 CNN
VGG 구조를 참고한 경량 CNN에서는 pooling을 하기 전에 Conv2D를 두 번 적용하였다. 즉, 이미지 크기를 줄이기 전에 같은 해상도에서 특징을 한 번 더 추출하도록 구조를 바꾸었다. 3×3 Conv를 반복한 뒤 pooling을 수행하는 설계 방향을 참고하여 프로젝트 환경에 맞는 CNN을 설계하였다.
Input
→ Rescaling
→ Conv2D → BatchNorm → ReLU
→ Conv2D → BatchNorm → ReLU
→ MaxPooling
→ Conv2D → BatchNorm → ReLU
→ Conv2D → BatchNorm → ReLU
→ MaxPooling
→ Conv2D → BatchNorm → ReLU
→ Conv2D → BatchNorm → ReLU
→ MaxPooling
→ Conv2D → BatchNorm → ReLU
→ GlobalAveragePooling2D
→ Dense
→ Softmax
이 구조를 짧게 표현하면 다음과 같다.
(Conv2D + BatchNorm + ReLU) × 2 → MaxPooling
여기서 중요한 점은 Conv2D → Conv2D → BatchNorm 순서가 아니라는 것이다. 실제 구조는 각 Conv2D 뒤에 Batch Normalization과 ReLU를 적용하는 형태이다. 즉, Conv2D → BatchNorm → ReLU 단위를 반복한 뒤 MaxPooling을 수행한다.
5. Batch Normalization을 함께 사용한 이유
convolution layer 수를 늘리면 모델이 더 많은 특징을 학습할 수 있지만, 동시에 학습이 불안정해질 수도 있다. 실제 실험에서도 Batch Normalization을 적용하지 않은 경량 CNN은 거의 무작위 예측에 가까운 성능을 보였다.
Batch Normalization은 Conv2D 이후 생성된 feature map의 값 분포를 mini-batch 단위로 정리하는 층이다 [3]. 이를 통해 학습 과정에서 중간 출력값이 지나치게 흔들리는 문제를 완화하고, 깊어진 CNN 구조가 더 안정적으로 학습되도록 돕는다.
Batch Normalization에는 학습되는 값이 있다. 대표적으로 gamma와 beta가 학습 가능한 파라미터이며, 정규화된 값을 다시 조정하는 역할을 한다.
6. GlobalAveragePooling2D의 역할
마지막 convolution layer의 출력은 예를 들어 16×16×128 형태의 feature map이다. 이는 16×16 크기의 feature map이 128장 있다는 의미이다.
GlobalAveragePooling2D는 각 feature map의 모든 위치값을 평균내어 하나의 값으로 요약한다. 따라서 16×16×128 형태의 출력을 128개의 값으로 줄일 수 있다. Global Average Pooling은 Network in Network 논문에서 feature map을 요약하는 방식으로 제안되었다 [4].
16 × 16 × 128
→ 각 feature map의 평균 계산
→ 128
이 방식은 Flatten을 사용해 모든 위치값을 그대로 펼치는 방식보다 Dense layer로 전달되는 입력 크기를 줄일 수 있다. 따라서 모델을 더 간결하게 구성하는 데 도움이 된다.
7. Keras 구현 코드
아래는 실제 프로젝트에서 사용한 VGG 구조 참고 경량 CNN의 핵심 구현이다.
from tensorflow import keras
from tensorflow.keras import layers
IMG_SIZE = 128
NUM_CLASSES = 101
def conv_unit_bn(x, filters, idx):
x = layers.Conv2D(
filters,
kernel_size=3,
padding="same",
use_bias=False,
name=f"conv_{idx}"
)(x)
x = layers.BatchNormalization(name=f"bn_{idx}")(x)
x = layers.ReLU(name=f"relu_{idx}")(x)
return x
def build_model():
inputs = keras.Input(shape=(IMG_SIZE, IMG_SIZE, 3), name="input_image")
x = layers.Rescaling(1./255, name="rescaling")(inputs)
# Block 1
x = conv_unit_bn(x, 32, idx=1)
x = conv_unit_bn(x, 32, idx=2)
x = layers.MaxPooling2D(pool_size=2, name="pool_1")(x)
# Block 2
x = conv_unit_bn(x, 64, idx=3)
x = conv_unit_bn(x, 64, idx=4)
x = layers.MaxPooling2D(pool_size=2, name="pool_2")(x)
# Block 3
x = conv_unit_bn(x, 128, idx=5)
x = conv_unit_bn(x, 128, idx=6)
x = layers.MaxPooling2D(pool_size=2, name="pool_3")(x)
# Final Conv
x = conv_unit_bn(x, 128, idx=7)
x = layers.GlobalAveragePooling2D(name="global_average_pooling")(x)
x = layers.Dense(128, activation="relu", name="dense_1")(x)
outputs = layers.Dense(
NUM_CLASSES,
activation="softmax",
name="class_output"
)(x)
model = keras.Model(inputs=inputs, outputs=outputs)
return model
8. Label Smoothing 적용
최종 모델에서는 Label Smoothing도 함께 적용하였다. 일반적인 one-hot encoding은 정답 클래스만 1이고 나머지 클래스는 0으로 둔다. 반면 Label Smoothing은 정답 클래스의 값을 조금 낮추고, 나머지 클래스에도 작은 확률을 나누어 주는 방식이다 [5].
일반 one-hot encoding
정답 클래스: 1.0
오답 클래스: 0.0
Label Smoothing
정답 클래스: 0.9
오답 클래스: 작은 확률 분배
Food-101은 101개 음식 클래스를 갖고 있으며, 서로 시각적으로 유사한 음식도 많다. 따라서 모델이 특정 정답 클래스에 지나치게 확신하는 것을 줄이기 위해 Label Smoothing을 적용하였다.
loss_fn = keras.losses.CategoricalCrossentropy(
label_smoothing=0.1
)
9. 실험 결과
실험 결과, 단순 Baseline CNN보다 VGG 구조를 참고한 경량 CNN에 Batch Normalization과 Label Smoothing을 적용한 모델이 가장 좋은 validation 성능을 보였다. 특히 Batch Normalization을 적용하지 않은 경량 CNN은 거의 무작위 예측에 가까운 성능을 보였지만, Batch Normalization을 추가한 뒤 성능이 크게 향상되었다.
| 모델 | Val Accuracy | Val Top-5 Accuracy |
|---|---|---|
| Baseline CNN | 0.3399 | 0.6230 |
| 경량 CNN | 0.0099 | 0.0495 |
| 경량 CNN + BatchNorm | 0.4646 | 0.7491 |
| 경량 CNN + BatchNorm + Label Smoothing | 0.4952 | 0.7684 |
최종 test set 평가에서는 다음과 같은 성능을 확인하였다.
| 지표 | 값 |
|---|---|
| Test Accuracy | 0.5354 |
| Test Top-5 Accuracy | 0.8128 |
| Macro F1-score | 0.5384 |
10. 정리
이번 실험에서 가장 중요한 점은 모델을 단순히 깊게 만드는 것만으로는 충분하지 않았다는 점이다. 실제로 Batch Normalization을 적용하지 않은 경량 CNN은 거의 무작위 예측에 가까운 성능을 보였다. 반면 VGG의 3×3 Conv 반복 구조를 참고하되, 각 Conv 뒤에 Batch Normalization과 ReLU를 추가한 모델은 성능이 크게 개선되었다. 여기에 Label Smoothing을 적용하자 validation accuracy와 validation top-5 accuracy가 모두 가장 높게 나타났다.
VGG 구조의 핵심 아이디어인 3×3 Conv 반복 구조를 적용하여 경량 CNN을 설계하고,
Batch Normalization으로 학습을 안정화하며,
Label Smoothing으로 과도한 확신을 줄였을 때 Food-101 분류 성능이 가장 좋았다.
Reference
- L. Bossard, M. Guillaumin, and L. Van Gool, Food-101 – Mining Discriminative Components with Random Forests, Computer Vision – ECCV 2014 Workshops, 2014.
- K. Simonyan and A. Zisserman, Very Deep Convolutional Networks for Large-Scale Image Recognition, International Conference on Learning Representations, 2015.
- S. Ioffe and C. Szegedy, Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift, International Conference on Machine Learning, 2015.
- M. Lin, Q. Chen, and S. Yan, Network in Network, International Conference on Learning Representations, 2014.
- C. Szegedy, V. Vanhoucke, S. Ioffe, J. Shlens, and Z. Wojna, Rethinking the Inception Architecture for Computer Vision, IEEE Conference on Computer Vision and Pattern Recognition, 2016.
'AI_Machine_Learning' 카테고리의 다른 글
| AEPC(Adaptive Excess-Preserving Clipping) 제안 (0) | 2026.05.18 |
|---|