MNIST 숫자 인식을 해 보자. 꼭 CNN이 아니라도 됨. Multinomial Classifier.
시작은 당연하게! mnist를 또! 읽어 봅시다.
읽어보면 60000개 train과 10000개 test가 나옵니다. 이젠 외울 지경이군요.
import tensorflow as tf
from keras.datasets import mnist
# mnist 가즈아.
(train_x, train_y), (test_x, test_y) = mnist.load_data()
# MNIST 데이터를 정규화 하고요, 784로 맞춰 주고요
train_x = train_x.astype('float32') / 255.
test_x = test_x.astype('float32') / 255.
train_x = train_x.reshape((len(train_x), 784))
test_x = test_x.reshape((len(test_x), 784))
print (train_x.shape)
print (test_x.shape)
2024-02-01 11:38:59.552895: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1
(60000, 784) (10000, 784)
각 숫자의 그림 사이즈는 28x28, 즉 784 크기로군요.
from keras.layers import Input, Dense
from keras.models import Model
from keras.utils import to_categorical
from keras import models, layers
그리고, train_y와 test_y를 categorical label (one-hot-encoding)으로 만들어 봅시다~! 이렇게 하면 one-hot-encoding된 것으로 Label을 바꿔줍니다. 세상 편리.
train_y_cat_labels = to_categorical(train_y)
test_y_cat_labels = to_categorical(test_y)
자, 이제 중요한 모형을 만들건데, model은 입력이 28x28=784이고, hidden layer는 128 node로 만들고, 마지막 출력은 10개로 softmax출력을 보면 어떨까 합니다.
이런 식으로 생겼습니다. 간단하죠?
➊ 은 28x28=784 의 이미지고요,
➋ 는 Feature를 extract하기 위한 신경망 모형입니다. 마지막엔 Softmax를 통해서 출력을 냅니다. 이 모형을 학습하는 것이고요,
➌ 은 ➋뒤에 argmax를 붙여서 Softmax➋ 출력 중 어느 것이 가장 큰지를 골라내어 출력을 합니다.
➍ 는 모형의 마지막 출력은 Softmax로 출력을 하고, 최종 출력은 argmax를 통해서 출력합니다만 학습은 Softmax 출력과 레이블간의 분포차이를 Loss로 두고 학습을 합니다.
참고로, 그림엔 보이지 않지만, Hidden layer는 relu로 activation하고요, argmax 다음의 출력은 10개의 node처럼 보이지만 실제로는 이중 가장 큰 1개의 index를 return합니다.
model = models.Sequential([
layers.Flatten(input_shape=(784,)),
layers.Dense(128, activation='relu'),
layers.Dense(10, activation='softmax')])
아, 여튼 이제 컴파일 해 봅시다. optimizer는 adam, loss는 categorical_crossentropy입니다요.
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
flatten (Flatten) (None, 784) 0
_________________________________________________________________
dense (Dense) (None, 128) 100480
_________________________________________________________________
dense_1 (Dense) (None, 10) 1290
=================================================================
Total params: 101,770
Trainable params: 101,770
Non-trainable params: 0
자, 이제 미련 없이 훈련! 훈련 내용은 너무 길어서 지웠습니다. 5 epoch정도로 해 보겠습니다.
model.fit(train_x, train_y_cat_labels, epochs=5)
자, 훈련이 끝났으니 잘 동작하는지 테스트도 해 보구요~!
test_loss, test_acc = model.evaluate(test_x, test_y_cat_labels)
313/313 [==============================] - 0s 772us/step - loss: 0.0701 - accuracy: 0.9786
정확도가 97.8%나 됩니다. 이거 실화인가요? 대략 만들었는데도 이런 결과라니.. 신경망 정말 대단한 놈 같습니다. 잘 되는지 눈으로 한번 확인하면 좋겠다는 생각이 불현듯 들어버렸습니다.
import random
import matplotlib.pyplot as plt
import numpy as np
# 랜덤한 index의 숫자를 하나 골라 봅시다.
random_number = random.randrange(0, 10000, 1) # 0~10000 사이 숫자 난수
# 임의의 해당 숫자 이미지 출력하고요,
showImage = test_x[random_number]
plt.imshow(showImage.reshape(28,28), cmap='gray')
plt.show()
predicted = model.predict(test_x)
print("{}th number => Predicted = {}, {} : {}".format(random_number, predicted[random_number] , np.argmax(predicted[random_number], 1), test_y[random_number]))
Random Number Predict Test
5490th number => Predicted = [3.2884181e-08 9.9934798e-01 4.0284030e-07 3.2888292e-06 5.4231123e-06 2.1904407e-09 1.7653175e-08 6.3124090e-04 1.1334526e-05 3.5927971e-07], [0. 1. 0. 0. 0. 0. 0. 0. 0. 0.] : 1
헤헷! 랜덤으로 5490번째 데이터로 확인해 보니, 1을 softmax 결과로 보니 제대로 1로 판단 했군요. 와웅. 판단한 분포를 그래프로 살펴보면, 1의 자리가 제일 크고, 분포를 보니까 약간 7이랑 헷갈렸나봅니다. 7일 확률이 조금 있군요. (높네요 X)
# 그래프다~ 이 그래프를 그리는 방법은 snippet 코너에 따로 포스팅 되어 있으니 참고해 주세욥!
이런 식으로 분류 모형을 만들게 되는데, 원리같은 것들은 강좌를 통해 만날까 합니다. 후후.
분류 모형을 만들 때 이런 식의 순서라는 것을 대략 머리속에 그리고 있다면 다음번에 모형을 만들 때 대략 할 수 있을 거라 생각합니다.
댓글