본문 바로가기
Papers & Research Notes/Research & Experiments

[CNN] Convolution으로 Accuracy 높이기 (Fashion MNIST, TensorFlow)

by Air’s Big Data 2021. 3. 28.

 

https://github.com/zalandoresearch/fashion-mnist

 

Fashion MNIST는 70,000개의 28x28의 greyscale 이미지로 구성이 되어 있습니다. Fashion MNIST Dataset를 활용해 Convolution가 없을 때와 있을 때를 비교하고 모델에 살짝씩 변화를 주며 파라미터, 레이어가 어떤 역할을 하는지 알아봤습니다. 

 


Fashion MNIST Dataset를 활용해 Convolution으로 Accuracy 높이기

먼저 Convolution이 없는 DNN(Deep Neural Network)로 accuracy를 확인해봅니다.

import tensorflow as tf
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images / 255.0
test_images=test_images / 255.0
model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(128, activation=tf.nn.relu),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(training_images, training_labels, epochs=5)

test_loss = model.evaluate(test_images, test_labels)

87%의 accuracy가 나왔습니다. 나쁘진 않지만 Convolution을 적용해서 더 accuracy를 높여봅시다. array (보통 3x3이나 5x5)를 가지고 image를 통과시킵니다. matrix 내 formula를 기반으로 pixel을 바꿈으로서 edge detection 등을 수행합니다. 예를 들어 -1로 둘러쌓인 8이란 middle cell을 가진 edge detection 3x3 array을 보실 수 있습니다. 이 경우 각 pixel에 대하여 8을 곱하고 주변 값들을 뺄 수 있습니다. edge가 강조된 새로운 이미지를 보실 수 있습니다.

 

Hightlight된 feature만 train할 수 있기 때문에 필요한 information의 양이 줄어듭니다. 이것이 CNN의 컨셉입니다. Dense layer 전에 convolution을 추가하고 dense layer에 전달될 information은 더 응축되고 더 정확해집니다.

 

아래의 코드는 위의 코드와 비슷하지만 처음에 convolution layer가 추가되어 있습니다. 시간은 더 오래 걸리지만, 정확도는 더 높아집니다.

import tensorflow as tf
print(tf.__version__)
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images.reshape(60000, 28, 28, 1)
training_images=training_images / 255.0
test_images = test_images.reshape(10000, 28, 28, 1)
test_images=test_images/255.0
model = tf.keras.models.Sequential([
  tf.keras.layers.Conv2D(64, (3,3), activation='relu', input_shape=(28, 28, 1)),
  tf.keras.layers.MaxPooling2D(2, 2),
  tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
  tf.keras.layers.MaxPooling2D(2,2),
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.summary()
model.fit(training_images, training_labels, epochs=5)
test_loss = model.evaluate(test_images, test_labels)

Training data엔 93%의 accuracy가, validation data엔 91%의 accuracy가 나오며 성능이 많이 좋아졌습니다. 코드를 다시 보며 차근차근 convolution이 어떻게 쌓여갔는지 알아봅시다.

 

 


Step1. Data 준비하기

import tensorflow as tf
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images.reshape(60000, 28, 28, 1)
training_images=training_images / 255.0
test_images = test_images.reshape(10000, 28, 28, 1)
test_images=test_images/255.0

Training data는 reshape되어야 합니다. 왜냐하면 첫번째 convolution은 모든 것을 포함한 single tensor를 예상하고 있기 때문입니다. 그래서 60,000x28x28x1의 4D list로 만듭니다. 이는 test image도 마찬가지 입니다. 이렇게 하지 않으면, training 과정에서 Convolution이 shape를 인식하지 못하고 error가 발생합니다.

 

Step2. Model 정의하기

input layer 대신 Convolution을 추가합니다. parameter들은 아래와 같습니다. 
  1. 생성하고 싶은 convolution의 수
    arbitrary하게 결정하지만 32로 시작하는 것이 좋습니다. 
  2. Convolution 사이즈 
    여기선 3x3를 사용합니다.
  3. Activation Function

    여기선 relu를 사용합니다.
  4. Input data의 shape

 

MaxPooling과 함께 convolution을 따라가다 보면 image는 highlight된 feature은 유지한 채 compress됩니다. MaxPooling을 2x2로 설정하면서 image의 사이즈는 1/4이 되고 가장 큰 값을 취합니다. 이것을 이미지에 반복하면 25%까지 image가 줄어듭니다. model.summary()을 통해  network의 size와 shape를 볼 수 있으며, MaxPooling 이후에는 image 사이즈가 줄어든 것을 확인할 수 있습니다.

model = tf.keras.models.Sequential([
  tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(28, 28, 1)),
  tf.keras.layers.MaxPooling2D(2, 2),

하나의 convolution을 더 추가합니다.

tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
  tf.keras.layers.MaxPooling2D(2,2)

그리고 output을 flatten하면 non convolution version과 같은 DNN structure을 얻을 수 있습니다.

tf.keras.layers.Flatten(),

pre-convolution example과 같은 128 dense layer와 10 output layer도 추가합니다.

tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dense(10, activation='softmax')
])

model을 compile하고 training을 실행하기 위해 fit method은 call합니다. 그리고 test set으로부터 loss와 accuracy를 평가합니다. 

model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(training_images, training_labels, epochs=5)
test_loss, test_acc = model.evaluate(test_images, test_labels)
print(test_acc)

 


Convolutions과 Pooling 시각화하기

 

print(test_labels[:100])

pyplot을 import하여 subplots과 어떤 이미지를 보여줄지를 정의합니다. pyplot을 import하여 subplots과 어떤 이미지를 어떻게 보여줄지를 정의합니다. pyplot에서 제공하는 plt.subplots(m,n) or (m)을 통해 figure와 axes를 동시에 반환 받을 수 있습니다. 3x4 subplot을 한꺼번에 만들고, figure와 axes도 반환을 받습니다.

import matplotlib.pyplot as plt

f, axarr = plt.subplots(3,4)
FIRST_IMAGE=0
SECOND_IMAGE=7
THIRD_IMAGE=26
CONVOLUTION_NUMBER = 1

TensorFlow의 models 모듈을 활용해 activation model을 정의합니다.

from tensorflow.keras import models
layer_outputs = [layer.output for layer in model.layers]
activation_model = tf.keras.models.Model(inputs = model.input, outputs = layer_outputs)

for문을 사용해서 이미지를 시각화합니다. axarry는 위치를 나타내며 각 3개의 figure x는 0과 4범위 내에서 돌아가며 시각화됩니다.

for x in range(0,4):
  f1 = activation_model.predict(test_images[FIRST_IMAGE].reshape(1, 28, 28, 1))[x]
  axarr[0,x].imshow(f1[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
  axarr[0,x].grid(False)
  f2 = activation_model.predict(test_images[SECOND_IMAGE].reshape(1, 28, 28, 1))[x]
  axarr[1,x].imshow(f2[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
  axarr[1,x].grid(False)
  f3 = activation_model.predict(test_images[THIRD_IMAGE].reshape(1, 28, 28, 1))[x]
  axarr[2,x].imshow(f3[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
  axarr[2,x].grid(False)


EXERCISES

  1. convolution 수정해봅시다. 32를 16이나 64로 바꿔봅시다. Accuracy나 training time에 어떤 변화가 있는지 살펴봅니다.
  2. 마지막 convolution을 삭제해보고 accuracy나 training time에 어떤 변화가 있는지 살펴봅니다.
  3. Convolution을 더 추가하고 accuracy나 training time에 어떤 변화가 있는지 살펴봅니다.
  4. 첫번째 convolution을 제외하고 모든 convolution을 삭제하고 실험을 해봅니다.
  5. Callback 기능을 사용해 training을 취소하기 위해 loss function을 확인해봅니다.
import tensorflow as tf
print(tf.__version__)
mnist = tf.keras.datasets.mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images.reshape(60000, 28, 28, 1)
training_images=training_images / 255.0
test_images = test_images.reshape(10000, 28, 28, 1)
test_images=test_images/255.0
model = tf.keras.models.Sequential([
  tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(28, 28, 1)),
  tf.keras.layers.MaxPooling2D(2, 2),
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(training_images, training_labels, epochs=10)
test_loss, test_acc = model.evaluate(test_images, test_labels)
print(test_acc)

댓글