내가 하고싶은 건 다 하는 공간
혼자 만들면서 공부하는 딥러닝 3-1 DenseNet 모델 준비 | 이미지 분류 모델의 효율성 최적화하기 본문
서론
이번 장에서는 ResNet 모델의 업그레이드 버전인 DenseNet에 대해 공부합니다. 이 글에서는 DenseNet의 개념 및 종류에 대해 살펴보고, 밀집 연결과 전환 연결을 케라스로 구현해보았습니다.
DenseNet 모델

DenseNet은 층의 개수에 따라 DenseNet-121, DenseNet-169, DenseNet-201, DenseNet-264가 있습니다. 층의 개수가 다를 뿐, 기본 구조는 같습니다. 위 그림은 DenseNet-121입니다.

각 숫자는 모델에 포함된 밀집 블록 개수를 나타냅니다. 숫자가 커지면서 복잡한 패턴을 학습할 수 있다는 장점이 있지만, 연산량도 증가한다는 단점이 있습니다.
밀집 연결 Dense Connectivity
DenseNet의 가장 큰 특징은 밀집 연결입니다. 이전 층의 모든 출력을 현재의 입력 층으로 사용하는 특징을 가지고 있습니다. 마치 어렸을 적에 뭔가를 잘못해서 혼나면 1년 전, 2년 전에 잘못했던 것들도 다 끌어모아서 혼나던 기억과 비슷하네요..

밀집 연결을 통해 1) 그레디언트 소실 문제를 해결하고 2) 깊은 층의 모델을 만들 수 있습니다.
밀집 블록 Dense Block

ResNet에서 잔차 블록 개념이 있었듯이, DenseNet에서도 밀집 블록 개념이 있습니다.
한 밀집 블록의 구조를 살펴보면 아래와 같습니다.
- 배치 정규화층
- 렐루 활성화 함수
- 첫 번째 합성곱층: 1 x 1 필터 128개, 특성 맵의 크기 변화 없음, 채널의 차원만 128개로 증가
- 배치 정규화층
- 렐루 활성화 함수
- 두 번째 합성곱층: 3 x 3 필터 32개, 세임 패딩을 이용해서 특성 맵의 크기 변화 없음, 채널의 차원만 32개로 감소
- 연결층: 밀집블록의 입력과 두 번째 합성곱층의 출력을 연결, 64 + 32 = 96개의 차원
밀집 블록을 케라스를 이용해서 구현했습니다.
import keras
from keras import layers
def dense_block(x, blocks):
for _ in range(blocks):
x1 = layers.BatchNormalization()(x)
x1 = layers.Activation('relu')(x1)
x1 = layers.Conv2D(filters = 128, kernel_size = 1, use_bias = False)(x1) # 절편이 불필요. 어차피 그 다음 배치 정규화층에서 평균을 0으로 만들어버린다.
x1 = layers.BatchNormalization(epsilon = 1e-5)(x1)
x1 = layers.Activation('relu')(x1)
x1 = layers.Conv2D(filters = 32, kernel_size = 3, padding = 'same', use_bias = False)(x1)
x = layers.Concatenate()([x, x1])
return x
크기가 (56, 56, 64)인 입력층을 넣어서 실제로 출력층의 크기가 책 속과 동일한지 확인합니다.

전환 블록 Transition Block
이렇게 밀집 블록이 반복된 후에 전환 블록이 등장합니다. 밀집 블록을 반복해서 쌓으면 층수가 늘어남에 따라 연산이 복잡해지는 문제가 발생하는데요, 이를 해결하고자 밀집 블록들 사이에 전환 블록 하나씩 넣어줍니다.

전환 블록은 특성 맵의 너비, 높이, 채널을 줄여줍니다. 전환 블록은 총 4개의 층으로 이루어져 있습니다.
- 배치 정규화 층
- 렐루 활성화 함수
- 합성곱층: 1 x 1 크기의 필터를 사용, 필터의 크기는 입력 채널의 절반
- 풀링층: 2 x 2 평균 풀링 사용
전환 블록을 케라스를 이용해서 구현했습니다.
import keras
from keras import layers
def transition_block(x):
x = layers.BatchNormalization(epsilon=1e-5)(x)
x = layers.Activation('relu')(x)
x = layers.Conv2D(filters = int(x.shape[-1]/2), kernel_size = 1, use_bias = False)(x)
x = layers.AveragePooling2D(pool_size = 2)(x)
return x
크기가 (56, 56, 256)인 입력층을 넣어서 실제로 출력층의 크기가 책 속과 동일한지 확인합니다.

마무리
이렇게 DenseNet의 구조에 대해서 살펴보았습니다. 다음 글에서는 DenseNet의 전체적인 흐름을 파이썬 코드로 짜보고, 실제로 입력값으로 고양이 or 강아지 사진을 넣어서 잘 분류하는지 성능을 확인해보겠습니다.
'인공지능' 카테고리의 다른 글
| 혼자 만들면서 공부하는 딥러닝 3-1 MoblieNet 모델, 깊이별 합성곱 | 이미지 분류 모델의 효율성 최적화하기 (1) | 2025.07.27 |
|---|---|
| 혼자 만들면서 공부하는 딥러닝 3-1 DenseNet 모델 구현 | 이미지 분류 모델의 효율성 최적화하기 (0) | 2025.07.27 |
| 혼자 만들면서 공부하는 딥러닝 2-3 GoogLeNet : 인셉션 모듈 Inception Module (0) | 2025.07.20 |
| 혼자 만들면서 공부하는 딥러닝 2-3 ResNet : 분류 모델 성능 개선하는 CNN 모델 (0) | 2025.07.20 |
| 혼자 만들면서 공부하는 딥러닝 2-2 강아지와 고양이 사진 분류하기 (2) | 2025.07.20 |