kwan's note

fashion mnist (CNN 을 이용한 fashion mnist 분류) 본문

project/others

fashion mnist (CNN 을 이용한 fashion mnist 분류)

kwan's note 2021. 2. 28. 17:52
반응형

fashion mnist classifier를 만들어 보았는데

fully connected layer로 만드니 cross validation accuracy가 생각보다 잘 안나와 cnn을 이용해 분류해 보았습니다.

 

가장 먼저 fashion mnist는 10종류의 의류 이미지(총 6만개)를 가진 데이터셋입니다.

아래 보이는것처럼 다양한 종류의 풀오버, 바지 가방, 코드 등이 제공되고 이 분류를 맞추는것 입니다.

저는 tensorflow 의 sequential model을 이용하였습니다.

 

from __future__ import absolute_import, division, print_function, unicode_literals 
import tensorflow as tf 
from tensorflow import keras
import tensorflow.keras.layers as layers
import tensorflow.keras.layers.experimental.preprocessing as preprocessing
import numpy as np
import matplotlib.pyplot as plt 
print(tf.__version__)

 

 

tensorflow를 불러오고 keras, layer 그리고 preprocessing 모듈을 불러옵니다.

 

fasion_mnist = keras.datasets.fashion_mnist

(train_X, train_y), (test_X, test_y) = fasion_mnist.load_data()

fasion_mnist = keras.datasets.fashion_mnist
(train_X, train_y), (test_X, test_y) = fasion_mnist.load_data()

train_X=train_X[...,np.newaxis]
print(train_X.shape)

 

이를 이용해 keras에 내장되어있는 fashion mnist데이터를 불러왔습니다.

trainset 와 tests set을 분리했으니 이제

cross validation set을 분리해보도록 하겠습니다.

 

여기서는 kfold를 사용하지는 않고 계층 추출을 이용하였습니다.

stratifiedshuffle을 이용하면 계층별로 추출할 수 있게 됩니다.

from sklearn.model_selection import StratifiedShuffleSplit    
split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=1004)

for train, cv in split.split(train_X,train_y):
  X_train=train_X[train]
  X_cv=train_X[cv]
  y_train=train_y[train]
  y_cv=train_y[cv]
  
print(sum(y_train==1)==sum(y_cv==1)*4)

계층적으로 잘 분류되었는지 확인하였습니다.(총 개수가 나누어 떨어지기때문에 위와 같이 확인 가능)

 

다음으로 sequential model을 구성하였습니다.

먼저 input을 설정하고 preprocessing을 통해 randomcontrast, horizontal flip을 추가하였습니다.

너무많은 augment를 진행하지는 않았습니다.

conv layer는 relu 를 activation function으로 이용하였고 

maxpooling은 한번만 진행하였습니다.

데이터가 28x28의 작은 이미지이므로 너무 많은 maxpooling은 데이터 손실량이 많을 것 이라고 생각하였습니다.

앙상블 메소드의 효과를 주기위해(사실은 넣지 않았을 때 오버피팅이 발생하였으므로) drop out을 주었습니다

model = keras.Sequential([
    keras.Input(shape=(28,28,1)),
    preprocessing.RandomContrast(factor=0.2),
    preprocessing.RandomFlip(mode='horizontal'),

    # Block One
    layers.BatchNormalization(renorm=True),
    layers.Conv2D(64,3,padding='same',activation='relu'),
    layers.MaxPooling2D(),
    layers.Dropout(0.3),

    # Block 2
    layers.BatchNormalization(renorm=True),
    layers.Conv2D(64,3,padding='same',activation='relu'),
    layers.Dropout(0.3),

    # Head
    layers.Flatten(),
    layers.Dense(10, activation='softmax'),
    ])

 

compile에서 optimizer는 adam으로 설정하여 에포크의 람다(때로는 알파)를 따로 설정하지 않도록 하였습니다.

loss 는 10개의 classification을 진행하므로 sparse_categorical_cross entropy를 이용하였습니다.

model.compile(optimizer = 'adam',
             loss = 'sparse_categorical_crossentropy',
             metrics = ['accuracy'])
model.summary()


>
Model: "sequential_22"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
random_contrast_2 (RandomCon (None, 28, 28, 1)         0         
_________________________________________________________________
random_flip (RandomFlip)     (None, 28, 28, 1)         0         
_________________________________________________________________
batch_normalization_35 (Batc (None, 28, 28, 1)         7         
_________________________________________________________________
conv2d_28 (Conv2D)           (None, 28, 28, 64)        640       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 14, 14, 64)        0         
_________________________________________________________________
dropout_45 (Dropout)         (None, 14, 14, 64)        0         
_________________________________________________________________
batch_normalization_36 (Batc (None, 14, 14, 64)        448       
_________________________________________________________________
conv2d_29 (Conv2D)           (None, 14, 14, 64)        36928     
_________________________________________________________________
dropout_46 (Dropout)         (None, 14, 14, 64)        0         
_________________________________________________________________
flatten_18 (Flatten)         (None, 12544)             0         
_________________________________________________________________
dense_44 (Dense)             (None, 10)                125450    
=================================================================
Total params: 163,473
Trainable params: 163,148
Non-trainable params: 325

만든 model을 확인하였고 학습을 진행하도록 합니다.

history = model.fit(
    X_train,
    y_train,
    batch_size=50,
    epochs=25,
    # We pass some validation for
    # monitoring validation loss and metrics
    # at the end of each epoch
    validation_data=(X_cv, y_cv),
)



>

...

Epoch 15/25
960/960 [==============================] - 4s 4ms/step - loss: 0.2167 - accuracy: 0.9208 - val_loss: 0.2372 - val_accuracy: 0.9174
Epoch 16/25
960/960 [==============================] - 4s 4ms/step - loss: 0.2072 - accuracy: 0.9247 - val_loss: 0.2271 - val_accuracy: 0.9207
Epoch 17/25
960/960 [==============================] - 4s 4ms/step - loss: 0.2130 - accuracy: 0.9226 - val_loss: 0.2263 - val_accuracy: 0.9201
Epoch 18/25
960/960 [==============================] - 4s 4ms/step - loss: 0.1990 - accuracy: 0.9268 - val_loss: 0.2258 - val_accuracy: 0.9209
Epoch 19/25
960/960 [==============================] - 4s 4ms/step - loss: 0.1976 - accuracy: 0.9244 - val_loss: 0.2197 - val_accuracy: 0.9226
Epoch 20/25
960/960 [==============================] - 4s 4ms/step - loss: 0.1988 - accuracy: 0.9264 - val_loss: 0.2174 - val_accuracy: 0.9231
Epoch 21/25
960/960 [==============================] - 4s 4ms/step - loss: 0.1930 - accuracy: 0.9304 - val_loss: 0.2245 - val_accuracy: 0.9223
Epoch 22/25
960/960 [==============================] - 4s 4ms/step - loss: 0.1858 - accuracy: 0.9312 - val_loss: 0.2156 - val_accuracy: 0.9234
Epoch 23/25
960/960 [==============================] - 4s 4ms/step - loss: 0.1831 - accuracy: 0.9306 - val_loss: 0.2202 - val_accuracy: 0.9237
Epoch 24/25
960/960 [==============================] - 4s 4ms/step - loss: 0.1868 - accuracy: 0.9304 - val_loss: 0.2190 - val_accuracy: 0.9224
Epoch 25/25
960/960 [==============================] - 4s 4ms/step - loss: 0.1809 - accuracy: 0.9332 - val_loss: 0.2119 - val_accuracy: 0.9257

이제 그래프로 확인해 보겠습니다

import pandas as pd
history_frame = pd.DataFrame(history.history)
history_frame.loc[:, ['loss', 'val_loss']].plot()
history_frame.loc[:, ['accuracy', 'val_accuracy']].plot();

아직은 오버피팅이 일어나기 전으로 보입니다.

에포크를 조금만 늘린다면 아주 작은 성능 향상이 있을 수 도 있겠습니다.

하지만 오늘은 여기서 멈추도록 하겠습니다.

 

마지막으로 test를 진행한 결과 0.92의 정확도를 보였습니다.

반응형