본문 바로가기
Visual Intelligence/Image Classification

[Image Classification] DenseNet (MNIST)

by goatlab 2022. 9. 14.
728x90
반응형
SMALL

DenseNet

 

케라스 API에서는 이 아키텍처의 구현물을 공식적으로 제공하며 tf.keras.application 패키지를 통해 접근할 수 있다. 이 패키지에는 그 외에도 잘 알려진 모델이 포함되어 있으며 각 모델에 대해 ‘사전에 훈련된’ 매개변수 (특정 데이터셋에서 사전에 훈련시키는 과정에서 저장해둔 매개변수)도 제공한다. 예를 들어, 다음 명령어로 DenseNet 네트워크를 인스턴스화할 수 있다.

 

Dense_net = tf.keras.applications.DenseNet121(Include_top = True,
                                              weights = 'imagenet',
                                              input_tensor = None,
                                              Input_shape = None,
                                              pooling = None, classes = 1000)

 

이 기본 인수를 사용해 케라스는 DenseNet 네트워크를 인스턴스화하고 ImageNet에서 훈련이 끝난 후 얻게 된 매개변수 값을 로딩한다. 이 단일 명령어로 이미지를 1,000개의 ImageNet 카테고리로 분류할 준비가 된 네트워크를 갖게 됐다. 이 대신 처음부터 다시 네트워크를 훈련시키고자 한다면 weights = None으로 고정시켜야 케라스에서 무작위로 가중치를 설정한다.

 

Dense Unit

 

import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

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):
        h = self.bn(x, training=training)
        h = tf.nn.relu(h)
        h = self.conv(h)

        return self.concat([x, h])

 

Dense Layer

 

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

 

이것은 Max pooling을 해줄 때 필요하다. 예를 들어, Dense layer를 사용하게 되면, Growth_rate = 32, num_ unit = 8인 경우에는, 32x8만큼 channel의 수가 급격하게 증가하기 때문에 연산량이 너무 커질 수 있다. 이럴 경우, 이 Transition layer를 통해 pooling하기 전에 channel의 수를 조절한다.

 

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')

        self.dl1 = DenseLayer(2, 4, (3, 3))
        self.tr1 = TransitionLayer(16, (3, 3))

        self.dl2 = DenseLayer(2, 8, (3, 3))
        self.tr2 = TransitionLayer(32, (3, 3))

        self.dl3 = DenseLayer(2, 16, (3, 3))

        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)

 

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)

# 모델 생성
model = DenseNet()

# 손실함수 정의 및 최적화 기법 정의
loss_object = tf.keras.losses.SparseCategoricalCrossentropy()
optimizer = tf.keras.optimizers.Adam()

# 평가지표 정의
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))
728x90
반응형
LIST