mnist.load_data()에 커서를 옮긴 후 Shift+Tab를 쳐본다.
그러면 그 함수에 대한 설명이 나오는데 그 중 Returns 항목을 보면
<Tuple of Numpy arrays: (x_train, y_train), (x_test, y_test)
.>라고 쓰여있다.
그것을 토대로 mnist.load_data()의 반환형식을 알 수 있으며 해당하는 형태로 값을 받아주면 된다.
import numpy as np
from keras.datasets import mnist
(X_train, y_train), (X_test, y_test) = mnist.load_data()
print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)
28x28 size의 train 이미지가 6만개, test 이미지가 1만개 있음을 확인할 수 있다.
또한 정답이 들어있는 train과 test값들도 각각 6만개와 1만개씩 있음을 확인할 수 있다.
X에 들어있는 이미지와 y에 들어있는 label값이 잘 매칭되어 있는지 확인해 보겠다.
y_train과 X_train으로부터 각각 0번부터 9번째 index의 값들을 추출해 비교해본다.
import matplotlib.pyplot as plt
%matplotlib inline
plt.gray() # mnist 데이터가 흑백이란 것을 명시
print(y_train[:10])
figures, axes = plt.subplots(nrows=2, ncols=5)
figures.set_size_inches(18, 8)
for i in range(10):
axes[i // 5][i % 5].matshow(X_train[i])
확인결과 잘 일치하고 있음을 알 수 있다.
Preprocessing¶
본격적으로 알고리즘을 작성하기에 앞서 몇가지 전처리(Preprocessing) 작업을 해주겠다.
먼저 3차원 배열로 구성되어있는 X값들을 2차원 배열의 형태로 바꿔주겠다.
그럼 X_train의 경우를 살펴보자면 6만개의 데이터와 784개의 특성을 가지고 있는 데이터셋이 되는데 이는 2차원 배열형태라서 친숙하고 쉬워보인다.
X_train = X_train.reshape(60000, 28 * 28)
X_test = X_test.reshape(10000, 28 * 28)
print(X_train.shape, X_test.shape)
다음으론 y값들을 One-hot encoding해주겠다.
앞으로 각각의 데이터 마다 가능한 모든 레이블에 대한 Squashing된 점수값들을 구하게 될텐데, 정답에 해당하는 y값들도 그것들과의 호환을 위해 형태를 맞춰주는 작업이다.
y_train_hot = np.eye(10)[y_train]
y_test_hot = np.eye(10)[y_test]
print(y_train_hot.shape)
print(y_test_hot.shape)
아래와 같이 비교해 One-hot encoding이 잘 되었음을 확인해 본다.
print(y_train[0:10])
print()
print(y_train_hot[0:10])
Classification문제를 풀기 위한 수단으로 sigmoid function을 만들어준다. sigmoid의 역할은 값을 squashing하여 0~1사이로 그 범위를 좁혀주는 역할을 한다.
def sigmoid(x):
return 1 / (1 + np.exp(-x))
잘 동작하는지 확인해보겠다.
xx = np.linspace(-10, 10, num=41)
yy = sigmoid(xx)
plt.plot(xx, yy)
전형적인 sigmoid 그래프가 그려짐을 확인할 수 있다.
또한 Gradient Descent를 통해 back propagation을 수행하는 기능 중 하나로써 sigmoid를 미분해 주는 함수도 만들어 두겠다.
# derivative of sigmoid function
def dsigmoid(s):
return s * (1 - s)
예측결과가 실제 정답과 얼마나 맞아떨어졌는지를 체크하는 것만으로는 학습이 잘 이루어진 정도를 알 수 없는 부분이 있다.
비록 예측은 실패했더라도 굉장히 망설이다가 틀렸을 수도 있고(sigmoid값이 0.5근처) 화끈하게 정반대의 오답을 정답으로 확신하는 경우도 있을 것이다. 그리고 이는 예측이 성공한 경우 또한 마찬가지다.
그렇기에 결과론적인 평가외에 과정에 대한 평가도 같이 확인해보기 위해선 cross_entropy를 구해주는 함수 또한 필요할 것이다.
def cross_entropy(actual, predict, eps=1e-15):
actual = np.array(actual)
predict = np.array(predict)
# log의 진수가 0이 되어 값이 무한대로 발산해버리는 경우를 방지한다.
clipped_predict = np.minimum(np.maximum(predict, eps), 1 - eps)
# 모든 정답값과 예측값 쌍들에 대해 cross_entropy방식으로 손실 정도를 구한다.
loss = -actual * np.log(clipped_predict) + -(1 - actual) * np.log(1 - clipped_predict)
# 구해진 모든 손실값들을 평균내어 반환한다.
return loss.mean()
이제 본격적으로 MLP(Multi-Layer Perceptron) 알고리즘 작성을 시작해보자.
num_epoch = 1000
learning_rate = 2.5
# Input layer
w1 = np.random.uniform(low=-1, high=1, size=(1000, 784))
b1 = np.random.uniform(low=-1, high=1, size=(1000, 1))
# Hidden layer
w2 = np.random.uniform(low=-1, high=1, size=(10, 1000))
b2 = np.random.uniform(low=-1, high=1, size=(10, 1))
# 전체 데이터 개수
num_data = X_train.shape[0]
# 변하지 않아서 재활용이 가능한 대형 행렬에 대한 전치값
X_train_T = X_train.T
y_train_hot_T = y_train_hot.T
# 학습
for epoch in range(num_epoch):
# Forward propagation
z1 = np.dot(w1, X_train_T) + b1
a1 = sigmoid(z1)
z2 = np.dot(w2, a1) + b2
a2 = sigmoid(z2)
y_predict_hot = a2
# 정확도 구하기
y_predict = np.argmax(y_predict_hot, axis=0)
accuracy = (y_predict == y_train).mean()
# 정확도가 95%에 도달할 때까지 학습
if accuracy > 0.95:
break
# cross_entropy로 측정된 손실정도를 구한다
loss = cross_entropy(y_train_hot_T, y_predict_hot)
# 일정 주기마다 한 번씩 학습 경과를 알려준다
if epoch % 10 == 0:
print("{0:2} accuracy = {1:.5f}, loss = {2:.5f}".format(epoch, accuracy, loss))
# Back propagation
# cross_entropy를 각각의 weight와 bias에 대해 편미분한 값으로 다시 weight와 bias를 갱신하여 학습시킨다
d2 = a2 - y_train_hot_T
d1 = np.dot(w2.T, d2) * dsigmoid(a1)
w2 = w2 - learning_rate * np.dot(d2, a1.T) / num_data
w1 = w1 - learning_rate * np.dot(d1, X_train) / num_data
b2 = b2 - learning_rate * d2.mean(axis=1, keepdims=True)
b1 = b1 - learning_rate * d1.mean(axis=1, keepdims=True)
print("----" * 10)
print("{0:2} accuracy = {1:.5f}, loss = {2:.5f}".format(epoch, accuracy, loss))
끝으로 알고리즘이 훈련과정에서는 접해보지 못했던 Test 데이터들에 대해서도 제대로 동작하는지 확인해 해보겠다.
import pandas as pd
# 구해진 weight와 bias로 예측값 구하기
z1 = np.dot(w1, X_test.T) + b1
a1 = sigmoid(z1)
z2 = np.dot(w2, a1) + b2
a2 = sigmoid(z2)
y_predict_hot = a2
y_predict = np.argmax(y_predict_hot, axis=0)
# 보기 좋게 pandas의 DataFrame으로 정리
test_result = pd.DataFrame({'actual': y_test, 'predict': y_predict})
# 예측 정확도 측정
test_accuracy = (test_result["actual"] == test_result["predict"]).mean()
print("Accuracy(test) = {0:.5f}\n".format(test_accuracy))
print(test_result.shape)
test_result.head(10)
Test 데이터에 대해서도 비교적 잘 예측한다는 것을 확인할 수 있다.
'인공지능 > 이론 적용' 카테고리의 다른 글
Single-layer Perceptron for Multi-class Classification (0) | 2020.02.10 |
---|---|
Single-layer Perceptron 적용 (0) | 2020.02.10 |