DenseNet(Dense Convolutional Network)은 2017년 Gao Huang 등이 발표한 딥러닝 모델로, 레이어 간의 밀집 연결(Dense Connectivity) 을 통해 네트워크의 효율성을 극대화한 구조입니다. DenseNet은 기존의 합성곱 신경망(CNN)에서 레이어 간 정보 흐름을 크게 개선하여, 파라미터 효율성과 성능 모두에서 우수한 결과를 보입니다.
DenseNet의 주요 특징 및 구조
- Dense Connectivity (밀집 연결성)
- 특징맵 재사용: DenseNet에서는 각 레이어가 이전 모든 레이어의 출력(특징맵)을 입력으로 받습니다. 즉, 레이어 l 의 입력은 이전 레이어들 의 출력이 모두 연결된 형태입니다.
- 수학적으로, l 번째 레이어의 입력은 다음과 같습니다:
- 여기서 [x0,x1,...,xl−1]는 모든 이전 레이어 출력의 연결(concatenation)을 의미하고, Hi 는 합성곱 연산 및 비선형 활성화 함수 등을 포함하는 변환 함수입니다.
- 장점
- 효율적인 파라미터 사용:
- 각 레이어는 특징맵을 공유하기 때문에 동일한 정보를 여러 번 학습하지 않아도 됩니다.
- ResNet처럼 스킵 연결이 있는 구조보다 더 적은 파라미터로도 높은 성능을 달성합니다.
- Gradient Flow 강화:
- DenseNet의 밀집 연결 구조는 역전파 시 기울기가 손실 없이 전달되도록 도와 학습을 안정적으로 만듭니다.
- 특징의 다중 계층 활용:
- 네트워크는 저수준(low-level) 및 고수준(high-level) 특징을 모두 활용할 수 있습니다. 이는 각 레이어가 모든 이전 특징맵을 사용할 수 있기 때문입니다.
- 효율적인 파라미터 사용:
- Dense Block과 Transition Layer
- Dense Block:
- 여러 개의 레이어가 서로 완전히 연결(concatenate)된 블록입니다.
- 각 블록 내에서는 레이어가 모든 이전 레이어와 연결되며, 특징맵의 크기가 유지됩니다.
- Transition Layer:
- Dense Block 간의 연결을 담당하며, 특징맵의 크기를 줄이기 위해 1 합성곱과 평균 풀링(AvgPooling)을 사용합니다.
- 모델의 복잡도를 조절하고 오버피팅을 방지합니다.
- Dense Block:
- DenseNet은 크게 Dense Block과 Transition Layer로 구성됩니다.
- Growth Rate (k)
- DenseNet에서는 각 레이어가 출력하는 특징맵의 수를 growth rate (k)로 정의합니다.
- k 가 작을수록 네트워크의 크기가 작아지고, k가 클수록 더 많은 특징을 학습할 수 있습니다.
- 일반적으로 k 는 12, 24, 32 등의 값으로 설정됩니다.
DenseNet의 이점과 단점
이점
- 파라미터 효율성:
- 특성 공유를 통해 파라미터 수를 줄이면서도 깊은 네트워크를 구현할 수 있습니다.
- 학습 안정성:
- 정보와 기울기가 네트워크 내에서 손실 없이 전달되므로 깊은 네트워크에서도 기울기 소실(Vanishing Gradient) 문제가 완화됩니다.
- 성능 향상:
- CIFAR-10, CIFAR-100, ImageNet 등 다양한 데이터셋에서 DenseNet은 기존 CNN보다 뛰어난 성능을 보였습니다.
- 특징 재사용:
- 여러 레이어에서 생성된 다양한 수준의 특징을 동시에 활용할 수 있습니다.
단점
- 메모리 사용량 증가:
- 이전 모든 레이어의 출력을 저장해야 하므로, 메모리 사용량이 증가합니다.
- 연산 비용:
- 특징맵 연결로 인해 계산량이 늘어나, 큰 네트워크에서는 연산이 느려질 수 있습니다.
- 모델 확장성 제한:
- 매우 큰 네트워크에서는 연결 수가 급격히 증가하여 구현이 비효율적일 수 있습니다.
DenseNet의 주요 변형 및 응용
- DenseNet-121, DenseNet-169, DenseNet-201, DenseNet-264
- DenseNet의 변형 모델로, Dense Block과 레이어 수에 따라 이름이 정해집니다.
- 예: DenseNet-121은 121개의 레이어로 구성.
- DenseNet for Medical Imaging
- DenseNet은 효율적인 특성 학습 덕분에 의료 영상 분석(예: X-ray, MRI)에서 널리 사용됩니다.
- DenseNet-BC (Bottleneck and Compression)
- DenseNet-BC는 Dense Block 내에서 1 합성곱을 추가하여 연산량을 줄이고, Transition Layer에서 채널 수를 압축(compression factor)하여 효율성을 더욱 개선한 모델입니다.
DenseNet과 ResNet의 비교
특징 | DenseNet | ResNet |
기본 아이디어 | 모든 레이어 간 연결 | 잔차 연결(skip connection) |
파라미터 수 | 더 적음 | 더 많음 |
특징 재사용 | 모든 이전 레이어 출력 활용 | 바로 직전 출력만 사용 |
기울기 전달 | 기울기 손실이 거의 없음 | 깊어질수록 기울기 전달이 약화될 수 있음 |
연산 비용 | 높음 | 상대적으로 낮음 |
DenseNet은 CNN 아키텍처 설계의 중요한 발전 중 하나로, 효율적인 특성 학습과 학습 안정성을 동시에 제공합니다. ResNet과 더불어 다양한 딥러닝 응용에서 널리 사용되고 있습니다.
DenseNet 구현
import tensorflow as tf
import numpy as np
DenseUnit 구현
class DenseUnit(tf.keras.Model):
def __init__(self, filter_out, kernel_size):
super(DenseUnit, self).__init__()
self.bn = tf.keras.layers.BatchNormalization()
self.conv = tf.keras.layers.Conv2D(filter_out, kernel_size, padding='same')
self.concat = tf.keras.layers.Concatenate()
def call(self, x, training=False, mask=None): # x : (Batch, H, W, Ch_in)
h = self.bn(x, training=training)
h = tf.nn.relu(h)
h = self.conv(h) # h : (Batch, H, W, filter_output)
return self.concat([x, h]) # (Batch, H, W, (Ch_in + filter_output))
DenseLayer 구현
class DenseLayer(tf.keras.Model):
def __init__(self, num_unit, growth_rate, kernel_size):
super(DenseLayer, self).__init__()
self.sequence = list()
for idx in range(num_unit):
self.sequence.append(DenseUnit(growth_rate, kernel_size))
def call(self, x, training=False, mask=None):
for unit in self.sequence:
x = unit(x, training=training)
return x
Transition Layer 구현
class TransitionLayer(tf.keras.Model):
def __init__(self, filters, kernel_size):
super(TransitionLayer, self).__init__()
self.conv = tf.keras.layers.Conv2D(filters, kernel_size, padding='same')
self.pool = tf.keras.layers.MaxPool2D()
def call(self, x, training=False, mask=None):
x = self.conv(x)
return self.pool(x)
모델 정의
class DenseNet(tf.keras.Model):
def __init__(self):
super(DenseNet, self).__init__()
self.conv1 = tf.keras.layers.Conv2D(8, (3, 3), padding='same', activation='relu') # 28 x 28 x 8
self.dl1 = DenseLayer(2, 4, (3, 3)) # 28 x 28 x 16
self.tr1 = TransitionLayer(16, (3, 3)) # 14 x 14 x 16
self.dl2 = DenseLayer(2, 8, (3, 3)) # 14 x 14 x 32
self.tr2 = TransitionLayer(32, (3, 3)) # 7 x 7 x 32
self.dl3 = DenseLayer(2, 16, (3, 3)) # 7 x 7 x 64
self.flatten = tf.keras.layers.Flatten()
self.dense1 = tf.keras.layers.Dense(128, activation='relu')
self.dense2 = tf.keras.layers.Dense(10 , activation='softmax')
def call(self, x, training=False, mask=None):
x = self.conv1(x)
x = self.dl1(x, training=training)
x = self.tr1(x)
x = self.dl2(x, training=training)
x = self.tr2(x)
x = self.dl3(x, training=training)
x = self.flatten(x)
x = self.dense1(x)
return self.dense2(x)
학습, 테스트 루프 정의
# Implement training loop
@tf.function
def train_step(model, images, labels, loss_object, optimizer, train_loss, train_accuracy):
with tf.GradientTape() as tape:
predictions = model(images, training=True)
loss = loss_object(labels, predictions)
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
train_loss(loss)
train_accuracy(labels, predictions)
# Implement algorithm test
@tf.function
def test_step(model, images, labels, loss_object, test_loss, test_accuracy):
predictions = model(images, training=False)
t_loss = loss_object(labels, predictions)
test_loss(t_loss)
test_accuracy(labels, predictions)
데이터셋 준비
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
x_train = x_train[..., tf.newaxis].astype(np.float32)
x_test = x_test[..., tf.newaxis].astype(np.float32)
train_ds = tf.data.Dataset.from_tensor_slices((x_train, y_train)).shuffle(10000).batch(32)
test_ds = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)
학습 환경 정의
모델 생성, 손실함수, 최적화 알고리즘, 평가지표 정의
# Create model
model = DenseNet()
# Define loss and optimizer
loss_object = tf.keras.losses.SparseCategoricalCrossentropy()
optimizer = tf.keras.optimizers.Adam()
# Define performance metrics
train_loss = tf.keras.metrics.Mean(name='train_loss')
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')
test_loss = tf.keras.metrics.Mean(name='test_loss')
test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='test_accuracy')
학습 루프 동작
EPOCHS = 10
for epoch in range(EPOCHS):
for images, labels in train_ds:
train_step(model, images, labels, loss_object, optimizer, train_loss, train_accuracy)
for test_images, test_labels in test_ds:
test_step(model, test_images, test_labels, loss_object, test_loss, test_accuracy)
template = 'Epoch {}, Loss: {}, Accuracy: {}, Test Loss: {}, Test Accuracy: {}'
print(template.format(epoch + 1,
train_loss.result(),
train_accuracy.result() * 100,
test_loss.result(),
test_accuracy.result() * 100))
train_loss.reset_state()
train_accuracy.reset_state()
test_loss.reset_state()
test_accuracy.reset_state()
Epoch 1, Loss: 0.11307405680418015, Accuracy: 96.75333404541016, Test Loss: 0.05511000007390976, Test Accuracy: 98.29000091552734
Epoch 2, Loss: 0.057570938020944595, Accuracy: 98.4383316040039, Test Loss: 0.0530952550470829, Test Accuracy: 98.3499984741211
Epoch 3, Loss: 0.043755121529102325, Accuracy: 98.76333618164062, Test Loss: 0.05816405266523361, Test Accuracy: 98.44999694824219
Epoch 4, Loss: 0.04333307594060898, Accuracy: 98.77333068847656, Test Loss: 0.0660046860575676, Test Accuracy: 98.61000061035156
Epoch 5, Loss: 0.030361121520400047, Accuracy: 99.1500015258789, Test Loss: 0.12039968371391296, Test Accuracy: 97.43000030517578
Epoch 6, Loss: 0.03443685546517372, Accuracy: 99.04999542236328, Test Loss: 0.04854564368724823, Test Accuracy: 98.68000030517578
Epoch 7, Loss: 0.03254585340619087, Accuracy: 99.19833374023438, Test Loss: 0.054437797516584396, Test Accuracy: 98.8699951171875
Epoch 8, Loss: 0.02431321144104004, Accuracy: 99.3116683959961, Test Loss: 0.06114092096686363, Test Accuracy: 98.6199951171875
Epoch 9, Loss: 0.027243511751294136, Accuracy: 99.29833221435547, Test Loss: 0.07321697473526001, Test Accuracy: 98.62999725341797
Epoch 10, Loss: 0.023852670565247536, Accuracy: 99.40166473388672, Test Loss: 0.06338458508253098, Test Accuracy: 98.86000061035156
'AI' 카테고리의 다른 글
Residual Network 구현 및 학습 (0) | 2024.11.24 |
---|---|
TensorFlow 함수형 API 로 VGGNet 논문 구현 (1) | 2024.11.19 |
TensorFlow 함수형 API 로 AlexNet 논문 구현 (0) | 2024.11.18 |
Colab 에서 Kaggle 데이터 API 로 받기 (3) | 2024.11.15 |
ViT 에서 언급한 CNN 의 Inductive bias 에 대해 알아보자 (3) | 2024.11.13 |