우연한 기회로 회사를 이직할 기회를 얻었고, 이직한 회사에선 인공지능 파트를 담당하게 되었습니다. 대략 9개월정도 인공지능 공부를 하지 않은 상태에서 다시금 복습하자는 의미에서 이번 글을 포스팅하게 되었습니다.
이번 글은 케라스(Keras)에 대한 간단한 설명과 케라스를 사용한 예제(Fashion Mnist)를 하는 과정을 소개할 예정입니다.
케라스 다큐먼트(Link)에 의하면 케라스는 파이썬으로 작성된 고수준의 신경망 API
로 Tensorflow
, CNTK
, Theano
와 함께 사용할 수 있다고 적혀있습니다. 텐서플로(2.2.0 기준) 내에서 케라스를 import 할 수 있으며, 기존 개발된 신경망 및 기법들이 API로 제공되어 사용이 용이하기 때문에 빠른 개발을 할 수 있습니다.
캐글에 게재되어 있는 Deep Learning Framework Power Scores(Link)에선 Online Job Listings, Google Search Volume, Medium Articles, Amazon Books, ArXiv Articles 등으로 딥러닝 프레임워크의 점수를 매겨났습니다. 그 중에서 케라스는 2위를 차지하는 모습을 보여주고 있습니다. 텐서플로 다음으로 딥러닝 프레임워크 생태계가 활발한 것으로 볼 수 있습니다.
케라스를 활용한 예제를 통해서 사용 방법을 알아보도록 하겠습니다.
Fashion Mnist
는 옷, 바지 등 10가지 종류의 의류로 구성된 데이터입니다. 이 데이터는 (28, 28) 크기로 구성되어 있으며 Training Set 5만장, Test Set 1만장으로 총합 6만장으로 이루어져 있습니다. Keras에서 dataset을 import 할 수 있고, 처음 import 시 다운로드 하는 과정이 추가됩니다.
데이터 분석 및 딥러닝에 사용될 라이브러리를 import 합니다.
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense, Flatten, Dropout
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, classification_report
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
(x_train, y_train), (x_test, y_test) = fashion_mnist.load_data()
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz
32768/29515 [=================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz
26427392/26421880 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz
8192/5148 [===============================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz
4423680/4422102 [==============================] - 0s 0us/step
print(x_train.shape)
print(y_train.shape)
print(x_test.shape)
print(y_test.shape)
(60000, 28, 28)
(60000,)
(10000, 28, 28)
(10000,)
item = {
0: 'T-shirt/top'
, 1: 'Trouser'
, 2: 'Pullover'
, 3: 'Dress'
, 4: 'Coat'
, 5: 'Sandal'
, 6: 'Shirt'
, 7: 'Sneaker'
, 8: 'Bag'
, 9: 'Ankle boot'
}
Fashion Mnist 데이터에 대한 분석을 진행합니다. 직관적인 분석을 위해 데이터를 그래프로 그려줍니다.
레이블 별로 데이터가 모두 존재하는 지 확인합니다.
plt.figure(figsize=(10, 3))
plt.subplot(1, 2, 1)
sns.countplot(y_train, palette=['#' + ('{}'.format(i))*6 for i in range(10)])
plt.title('train labels count')
plt.subplot(1, 2, 2)
sns.countplot(y_test, palette=['#fb'+ ('{}'.format(i))*4 for i in range(10)])
plt.title('test labels count')
plt.plot()
이미지의 모습을 직관적으로 확인하기 위해 이미지를 화면에 그립니다.
plt.figure(figsize=(12, 12))
for i in range(36):
plt.subplot(6, 6, i+1)
plt.suptitle('Train Images', fontsize=20)
plt.title(item[y_train[i]])
plt.imshow(x_train[i], cmap=plt.cm.gray)
plt.axis("off")
plt.show()
plt.figure(figsize=(12, 12))
for i in range(36):
plt.subplot(6, 6, i+1)
plt.suptitle('Test Images', fontsize=20)
plt.title(item[y_test[i]])
plt.imshow(x_test[i], cmap=plt.cm.gray)
plt.axis("off")
plt.show()
신경망에 데이터를 입력하기 전, 전처리를 통해 올바르게 신경망에 들어갈 수 있도록 합니다.
x_train = x_train.reshape(-1, 28, 28, 1)
x_train = x_train.astype('float32')
x_train = x_train/255
x_test = x_test.reshape(-1, 28, 28, 1)
x_test = x_test.astype('float32')
x_test = x_test/255
기존에 3차원이던 데이터를 4차원으로 변경 후, Data Type을
Float32
로 변경 및Normalization
을 진행했습니다.
y_onehot_train = to_categorical(y_train, num_classes=10)
y_onehot_test = to_categorical(y_test, num_classes=10)
데이터를
원 핫 인코딩(One-hot Encoding)
하여 10개의 레이블이 0과 1로 표현되도록 변경하였습니다.
for i in [x_train, y_onehot_train, x_test, y_onehot_test]:
print(i.shape)
(60000, 28, 28, 1)
(60000, 10)
(10000, 28, 28, 1)
(10000, 10)
이미지 데이터는 3차원에서 4차원으로 변경된 것을 볼 수 있고, 레이블 데이터는 One-Hot Encoding을 통해 2차원으로 변한 것을 볼 수 있습니다.
Keras를 사용하여 옷 종류를 분류하는 신경망을 구성합니다.
신경망 모델에 들어가는 Hyper Parameter
을 설정해줍니다.
INPUT_SHAPE = (28, 28, 1) # 입력 데이터가 들어가는 포멧 설정
OUTPUT_SHAPE = 10 # 출력 데이터가 나오는 포멧 설정
BATCH_SIZE = 128 # 한 번에 처리할 데이터량 설정
EPOCHS = 10 # 신경망을 학습할 횟수
VERBOSE = 1 # 학습 진행 상황 출력 모드 설정
model = Sequential([
Conv2D(filters=32, kernel_size=(3, 3), activation='relu', input_shape=INPUT_SHAPE),
MaxPooling2D(pool_size=(2, 2)),
Flatten(),
Dense(128, activation='relu'),
Dropout(0.25),
Dense(64, activation='relu'),
Dropout(0.25),
Dense(10, activation='softmax')
])
model.compile(
optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy']
)
모델을 생성 후 구조에 대해 summary()
를 사용하여 확인해볼 수 있습니다.
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 26, 26, 32) 320
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 13, 13, 32) 0
_________________________________________________________________
flatten (Flatten) (None, 5408) 0
_________________________________________________________________
dense (Dense) (None, 128) 692352
_________________________________________________________________
dropout (Dropout) (None, 128) 0
_________________________________________________________________
dense_1 (Dense) (None, 64) 8256
_________________________________________________________________
dropout_1 (Dropout) (None, 64) 0
_________________________________________________________________
dense_2 (Dense) (None, 10) 650
=================================================================
Total params: 701,578
Trainable params: 701,578
Non-trainable params: 0
_________________________________________________________________
위에서 설계한 신경망을 가지고 학습을 진행합니다.
history = model.fit(
x_train, y_onehot_train,
epochs=EPOCHS,
batch_size=BATCH_SIZE,
verbose=VERBOSE,
validation_split=0.3
)
Epoch 1/10
329/329 [==============================] - 18s 55ms/step - loss: 0.6393 - accuracy: 0.7751 - val_loss: 0.3787 - val_accuracy: 0.8633
Epoch 2/10
329/329 [==============================] - 18s 54ms/step - loss: 0.3886 - accuracy: 0.8641 - val_loss: 0.3330 - val_accuracy: 0.8766
Epoch 3/10
329/329 [==============================] - 18s 54ms/step - loss: 0.3318 - accuracy: 0.8827 - val_loss: 0.2928 - val_accuracy: 0.8951
Epoch 4/10
329/329 [==============================] - 18s 53ms/step - loss: 0.2923 - accuracy: 0.8955 - val_loss: 0.2695 - val_accuracy: 0.9023
Epoch 5/10
329/329 [==============================] - 18s 53ms/step - loss: 0.2711 - accuracy: 0.9024 - val_loss: 0.2660 - val_accuracy: 0.9031
Epoch 6/10
329/329 [==============================] - 18s 54ms/step - loss: 0.2525 - accuracy: 0.9086 - val_loss: 0.2588 - val_accuracy: 0.9072
Epoch 7/10
329/329 [==============================] - 18s 53ms/step - loss: 0.2340 - accuracy: 0.9143 - val_loss: 0.2496 - val_accuracy: 0.9121
Epoch 8/10
329/329 [==============================] - 17s 53ms/step - loss: 0.2192 - accuracy: 0.9208 - val_loss: 0.2504 - val_accuracy: 0.9121
Epoch 9/10
329/329 [==============================] - 17s 53ms/step - loss: 0.2042 - accuracy: 0.9238 - val_loss: 0.2542 - val_accuracy: 0.9125
Epoch 10/10
329/329 [==============================] - 17s 53ms/step - loss: 0.1924 - accuracy: 0.9289 - val_loss: 0.2492 - val_accuracy: 0.9147
신경망 학습 후 성능에 대한 결과를 확인합니다.
plt.figure(figsize=(14, 5))
plt.subplot(1, 2, 1)
plt.plot(history.history['accuracy'], label='Training Accuracy')
plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.subplot(1, 2, 2)
plt.plot(history.history['loss'], label='Training Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
model.evaluate(x_test, y_onehot_test)
313/313 [==============================] - 2s 5ms/step - loss: 0.2678 - accuracy: 0.9053
[0.2678438723087311, 0.9053000211715698]
테스트 데이터에 대한 성능이 90.53% 이 나오는 것을 확인할 수 있습니다.
y_pred_enc = model.predict(x_test)
y_pred = [np.argmax(i) for i in y_pred_enc]
fig, ax = plt.subplots(figsize=(18, 8))
for idx, row in enumerate(x_test[:8]):
plt.subplot(2, 4, idx+1)
plt.title(item[y_pred[idx]])
img = row.reshape(28, 28)
fig.suptitle("Predicted values", fontsize=20)
plt.axis('off')
plt.imshow(img, cmap=plt.cm.gray)
모델에 대한 평가를 싸이킷 런(sklearn)
라이브러리 내에 있는 classification_report
를 통해 한눈에 볼 수 있습니다.
print(classification_report(y_test, y_pred))
precision recall f1-score support
0 0.87 0.84 0.85 1000
1 1.00 0.97 0.98 1000
2 0.81 0.88 0.85 1000
3 0.89 0.92 0.91 1000
4 0.87 0.83 0.85 1000
5 0.99 0.97 0.98 1000
6 0.74 0.73 0.74 1000
7 0.94 0.98 0.96 1000
8 0.98 0.98 0.98 1000
9 0.97 0.95 0.96 1000
accuracy 0.91 10000
macro avg 0.91 0.91 0.91 10000
weighted avg 0.91 0.91 0.91 10000
모델이 예측한 결과를 분류결과표를 사용해 분석할 수 있습니다. 분류 결과를 봤을 때, 형태가 비슷한 옷들(T-short/top, Shirt, Dress, Coat)에 대해 오판단이 많았습니다.
fig, ax = plt.subplots(figsize=(10, 10))
sns.heatmap(
confusion_matrix(y_test, y_pred),
annot=True,
cbar=False,
fmt='3d',
cmap='Blues',
ax=ax
)
ax.set_title(
'Confusion Matrix',
loc='left',
fontsize=16
)
ax.set_xlabel('Predicted')
ax.set_ylabel('Actual')
ax.set_xticklabels(item.values())
ax.set_yticklabels(item.values(), rotation=0)
plt.show()
케라스를 사용하여 간단한 분류 모델을 생성 후 평가를 진행했습니다. 간단한 신경망을 사용해 분류했기 때문에 성능이 크게 좋진 않습니다. 하지만, 차후에 이뤄지는 포스팅에는 이미지 분류 및 검출에서 좋은 성능을 보여준 모델들을 리뷰하고 구현하는 포스팅을 작성하도록 하겠습니다.