데이터 준비 → 딥러닝 네트워크 설계 → 학습 → 테스트(평가)
tf.keras : 텐서플로우(TensorFlow)의 표준 API
아래 코드는 숫자 손글씨 데이터베이스인 MNIST 데이터셋을 읽어서 분류하는 코드이다.
import tensorflow as tf
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt
mnist = keras.datasets.mnist
# MNIST 데이터를 로드. 다운로드하지 않았다면 다운로드까지 자동으로 진행된다.
(x_train, y_train), (x_test, y_test) = mnist.load_data()
print(len(x_train)) # x_train 배열의 크기를 출력
# 60000
잘 로드되었는지 이미지 테스트
X항목에 들어있는 이미지에 대응하는 실제 숫자 값이 담겨 있는 것을 확인할 수 있다.
plt.imshow(x_train[1],cmap=plt.cm.binary)
plt.show()
print(y_train[1])
# 0
Matplotlib이란?
파이썬에서 제공하는 시각화(Visualization)패키지
차트(chart), 플롯(plot) 등 다양한 형태로 데이터를 시각화하는 기능을 제공
학습용 데이터 체크
print(x_train.shape)
# (60000, 28, 28) - 28x28 크기의 숫자 이미지가 60,000장이 있다는 뜻
print(x_test.shape)
# (10000, 28, 28)
print('최소값:',np.min(x_train), ' 최대값:',np.max(x_train))
# 최소값: 0 최대값: 255
인공지능 모델을 훈련시키고 사용할 때, 일반적으로 입력은 0~1 사이의 값으로 정규화 시켜주는 것이 좋다. MNIST 데이터는 각 픽셀의 값이 0~255 사이 범위에 있으므로 데이터들을 255.0 으로 나누어주면 최소값이 0, 최대값이 1에 근접하게 된다.
x_train_norm, x_test_norm = x_train / 255.0, x_test / 255.0
print('최소값:',np.min(x_train_norm), ' 최대값:',np.max(x_train_norm))
# 최소값: 0.0 최대값: 1.0
왜 0-1사이로 해야하는가? 왜 정규화를 시켜주어야 하는가?
딥러닝 레이어(layer)를 설계하는 것.
텐서플로우 케라스(tf.keras)에서 모델을 만드는 방법
model=keras.models.Sequential()
model.add(keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(28,28,1)))
model.add(keras.layers.MaxPool2D(2,2))
model.add(keras.layers.Conv2D(32, (3,3), activation='relu'))
model.add(keras.layers.MaxPooling2D((2,2)))
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(32, activation='relu'))
model.add(keras.layers.Dense(10, activation='softmax'))
print('Model에 추가된 Layer 개수: ', len(model.layers))
# Model에 추가된 Layer 개수: 7
딥러닝 모델 확인
model.summary()
위에서 만든 네트워크의 입력은 (데이터갯수, 이미지 크기 x, 이미지 크기 y, 채널수) 와 같은 형태를 가진다. 그런데 print(x_train.shape)
을 해보면, (60000, 28, 28)
로 채널수에 대한 정보가 없다. 따라서 (60000, 28, 28, 1)
로 만들어 주어야 한다. 여기서 채널수 1은 흑백 이미지를 의미한다. 컬러 이미지라면 RGB 세 가지 값이 있기 때문에 3이다.
print("Before Reshape - x_train_norm shape: {}".format(x_train_norm.shape))
print("Before Reshape - x_test_norm shape: {}".format(x_test_norm.shape))
x_train_reshaped=x_train_norm.reshape( -1, 28, 28, 1) # 데이터갯수에 -1을 쓰면 reshape시 자동계산됩니다.
x_test_reshaped=x_test_norm.reshape( -1, 28, 28, 1)
print("After Reshape - x_train_reshaped shape: {}".format(x_train_reshaped.shape))
print("After Reshape - x_test_reshaped shape: {}".format(x_test_reshaped.shape))
Before Reshape - x_train_norm shape: (60000, 28, 28)
Before Reshape - x_test_norm shape: (10000, 28, 28)
After Reshape - x_train_reshaped shape: (60000, 28, 28, 1)
After Reshape - x_test_reshaped shape: (10000, 28, 28, 1)
모델을 학습시키기 전에 compile
메소드를 통해 학습 방식에 대한 환경설정을 해야 한다.
complie
메소드는 세가지의 인자를 받는다.
학습하기
아래 코드는 60,000개의 데이터를 10번 반복해서 학습하라는 뜻이다.
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(x_train_reshaped, y_train, epochs=10)
Epoch 1/10
1875/1875 [==============================] - 2s 1ms/step - loss: 0.1975 - accuracy: 0.9395
Epoch 2/10
1875/1875 [==============================] - 2s 1ms/step - loss: 0.0670 - accuracy: 0.9799
Epoch 3/10
1875/1875 [==============================] - 2s 1ms/step - loss: 0.0489 - accuracy: 0.9844
Epoch 4/10
1875/1875 [==============================] - 2s 1ms/step - loss: 0.0395 - accuracy: 0.9880
Epoch 5/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.0318 - accuracy: 0.9897
Epoch 6/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.0265 - accuracy: 0.9919
Epoch 7/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.0215 - accuracy: 0.9936
Epoch 8/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.0186 - accuracy: 0.9941
Epoch 9/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.0160 - accuracy: 0.9948
Epoch 10/10
1875/1875 [==============================] - 2s 1ms/step - loss: 0.0130 - accuracy: 0.9959
<tensorflow.python.keras.callbacks.History at 0x7f10e80cfc50>
epoch 별로 accuracy가 올라가는 것을 볼 수 있다.
test_loss, test_accuracy = model.evaluate(x_test_reshaped,y_test, verbose=2)
print("test_loss: {} ".format(test_loss))
print("test_accuracy: {}".format(test_accuracy))
313/313 - 2s - loss: 0.0344 - accuracy: 0.9899
test_loss: 0.0344112291932106
test_accuracy: 0.9898999929428101
학습했을 때 accuracy는 99.59가 나왔지만 실제로 테스트해보았을 때는 98.99가 나왔다. 테스트 손글씨에는 처음 쓰인 손글씨가 섞여있을 가능성이 있기 때문이다.
model.predict()
를 사용하면 model이 입력값을 보고 실제로 추론한 확률분포를 출력할 수 있다. model이란 사실 10개의 숫자 중 어느 것일지에 대한 확률값을 출력하는 함수이다. 이 함수의 출력값 즉 확률값이 가장 높은 숫자가 바로 model이 추론한 숫자가 된다.
predicted_result = model.predict(x_test_reshaped) # model이 추론한 확률값.
predicted_labels = np.argmax(predicted_result, axis=1)
idx=0 #1번째 x_test를 살펴보자.
print('model.predict() 결과 : ', predicted_result[idx])
print('model이 추론한 가장 가능성이 높은 결과 : ', predicted_labels[idx])
print('실제 데이터의 라벨 : ', y_test[idx])
model.predict() 결과 : [9.8947801e-11 1.0196472e-11 4.9176936e-08 1.6367677e-07 1.9609570e-12
1.9836343e-11 1.5060793e-18 9.9999976e-01 3.0529048e-09 3.4305444e-08]
model이 추론한 가장 가능성이 높은 결과 : 7
실제 데이터의 라벨 : 7
7이 1.00에 근접하고 있는데 이는 모델이 7을 인식할 확률이 아주 높다는 것을 뜻한다.
실제로 확인해보면.
plt.imshow(x_test[idx],cmap=plt.cm.binary)
plt.show()
model이 추론해 낸 숫자와 실제 라벨의 값이 다른 경우
import random
wrong_predict_list=[]
for i, _ in enumerate(predicted_labels):
# i번째 test_labels과 y_test이 다른 경우만 모아 봅시다.
if predicted_labels[i] != y_test[i]:
wrong_predict_list.append(i)
# wrong_predict_list 에서 랜덤하게 2개만 뽑아봅시다.
samples = random.choices(population=wrong_predict_list, k=2)
for n in samples:
print("예측확률분포: " + str(predicted_result[n]))
print("라벨: " + str(y_test[n]) + ", 예측결과: " + str(predicted_labels[n]))
plt.imshow(x_test[n], cmap=plt.cm.binary)
plt.show()
Conv2D 레이어에서 입력 이미지의 특징 수를 늘리거나 줄여 보거나, Dense 레이어에서 뉴런수를 바꾸어 보거나, 학습 반복 횟수인 epoch 값을 변경해 볼 수 있다.
# 바꿔 볼 수 있는 하이퍼파라미터들
n_channel_1=16
n_channel_2=32
n_dense=25
n_train_epoch=10
model=keras.models.Sequential()
model.add(keras.layers.Conv2D(n_channel_1, (3,3), activation='relu', input_shape=(28,28,1)))
model.add(keras.layers.MaxPool2D(2,2))
model.add(keras.layers.Conv2D(n_channel_2, (3,3), activation='relu'))
model.add(keras.layers.MaxPooling2D((2,2)))
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(n_dense, activation='relu'))
model.add(keras.layers.Dense(10, activation='softmax'))
model.summary()
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 모델 훈련
model.fit(x_train_reshaped, y_train, epochs=n_train_epoch)
# 모델 시험
test_loss, test_accuracy = model.evaluate(x_test_reshaped, y_test, verbose=2)
print("test_loss: {} ".format(test_loss))
print("test_accuracy: {}".format(test_accuracy))
테스트 해보았더니, 나머지 값은 그대로 두고, d_dense = 20 으로 변경했을 때 가장 높은 99.08이 나왔다.