사람의 손 글씨로 적힌 숫자를 보고 숫자를 인식해내는 MLP 모델을 만들어보고자 한다.
데이터셋, 개발 환경은 이전 글과 동일하다. 하지만 이번에는 Sequential API 방법을 사용해볼 것이다.
각 행은 하나의 손글씨 숫자 이미지이고 형식은 [label, pixel1, pixel2, ..., pixel784]와 같이 숫자와 그에 해당하는 각 픽셀의 밝기 값이 저장되어 있다. 우리는 라벨과 픽셀값을 분류해줘야 한다.
#train의 전체 행 저장+Y만 출력, 앞에 빼고 출력(X train)
Y_train, X_train = utils.to_categorical(train[:,0]), train[:,1:]
#test의 전체 행 중 Y만 출력, 앞에 Y빼고 저장
Y_test, X_test = utils.to_categorical(test[:,0]), test[:,1:]
#정규화
X_train = X_train / 255.0
X_test = X_test / 255.0
placeholder, Variable, matmul 등 모든 연산을 명시적으로 정의🔧 구조 (example)
필자는 이번 코드에서 Keras를 사용할 것이다.
🔧 구조 (example)
먼저 MLP 구조를 만들어준다.
mlp_model = Sequential()
mlp_model.add(Dense(512, activation='sigmoid', input_shape=(784,))) # 입력층
mlp_model.add(Dense(256, activation='sigmoid'))
mlp_model.add(Dense(10, activation='softmax')) # 출력층 (0~9)
mlp_model.summary()
#sigmoid대신 relu 사용 가능
그럼 다음과 같이 학습 파라미터의 수가 시각적인 표와 함께 나온다.

relu vs. sigmoid
- relu : 학습이 빠르고 vanishing gradient 문제 없음
- sigmoid : 입력이 크면 gradient vanishing 발생. 간단한 MLP에서 잘 작동
mlp_model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
model_history = mlp_model.fit(X_train, Y_train, validation_data=(X_test, Y_test),\
epochs=15, batch_size=512, shuffle=True, verbose=2)
다음과 같은 코드를 통해 학습/검증 데이터에 대한 정확도와 손실을 볼 수 있다.

이후 정확도와 손실 그래프를 확인하기 위해 다음과 같이 시각화하였다.
import matplotlib.pyplot as plt
plt.plot(model_history.history['accuracy'])
plt.plot(model_history.history['val_accuracy'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='right')
plt.show()

import matplotlib.pyplot as plt
plt.plot(model_history.history['loss'])
plt.plot(model_history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='right')
plt.show()

우리가 만든 Keras 모델의 예측 결과를 실제 정답과 비교해 confusion matrix로도 보여줄 수 있다.
import itertools
from sklearn.metrics import confusion_matrix
def plot_confusion_matrix(model_input, feature, label, class_info):
#예측값 얻음
pred = model_input.predict(feature)
#confusion matrix 계산
cnf_matrix = confusion_matrix(np.argmax(label, axis=1), np.argmax(pred, axis=1))
plt.figure()
#matplotlib로 시각화
plt.imshow(cnf_matrix, interpolation='nearest', cmap=plt.cm.Blues)
tick_marks = np.arange(len(class_info))
# confusion matrix 축에 숫자 표시
plt.xticks(tick_marks, class_info, rotation=45)
plt.yticks(tick_marks, class_info)
thresh = cnf_matrix.max() / 2.0
# 각 셀 안에 숫자 출력, 값이 큰 경우는 하얀색으로 표시
for i, j in itertools.product(range(cnf_matrix.shape[0]), range(cnf_matrix.shape[1])):
plt.text(j, i, str(cnf_matrix[i, j]), horizontalalignment="center",\
color="white" if cnf_matrix[i, j] > thresh else "black")
# 레이블 정리
plt.tight_layout()
plt.ylabel('True label')
plt.xlabel('Predicted label')
plt.show()
labels = ['0','1','2','3','4','5','6','7','8','9']
plot_confusion_matrix(mlp_model, X_test, Y_test, class_info=labels)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from tensorflow.keras import utils
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras.layers import Input, Dense, Conv2D, MaxPool2D, UpSampling2D, Flatten, Reshape, Embedding, LSTM
from tensorflow.keras.callbacks import EarlyStopping
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.optimizers import SGD
mnist_csv = pd.read_csv('./mnist_train.csv', header=None, skiprows=1).values
train, test = train_test_split(mnist_csv, test_size=0.3, random_state=1)
#train의 전체 행 저장+Y만 출력, 앞에 빼고 출력(X train)
Y_train, X_train = utils.to_categorical(train[:,0]), train[:,1:]
#test의 전체 행 중 Y만 출력, 앞에 Y빼고 저장
Y_test, X_test = utils.to_categorical(test[:,0]), test[:,1:]
#정규화
X_train = X_train / 255.0
X_test = X_test / 255.0
mlp_model = Sequential()
mlp_model.add(Dense(512, activation='sigmoid', input_shape=(784,))) # 입력층
mlp_model.add(Dense(256, activation='sigmoid'))
mlp_model.add(Dense(10, activation='softmax')) # 출력층 (0~9)
mlp_model.summary()
mlp_model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
model_history = mlp_model.fit(X_train, Y_train, validation_data=(X_test, Y_test),\
epochs=15, batch_size=512, shuffle=True, verbose=2)
