이번 주제는 google colab에서 실행된다. google drive 가 있다면 google colab은 좋은 선택지이며, python언어와 그 안에 있는 ML 라이브러리 (sklearn, numpy, pandas.. 등등)을 지원한다.
오늘은 0 부터 9까지의 숫자를 구분하는 Neural Network를 만들어본다.
1. 먼저 sklearn 에서 지원하는 데이터를 가져오자
# Loading an example dataset & preprocessing
from sklearn.datasets import load_digits
import numpy as np
data = load_digits()
print(data.keys()) # dict_keys(['data', 'target', 'frame', 'feature_names', 'target_names', 'images', 'DESCR']) (1797, 64)
data['images'].shape # (1797, 8, 8)
data['data'].shape # (1797, 64)
data['target'].shape # (1797, )
불러온 dataset은 크게 'data' 부분과 'target' 부분으로 나눌 수 있다. 그리고 이 나눠진 부분들은 'dict_keys' 형태로 data 안에 존재하므로 attribute인 data.keys()를 통해 어떤 key가 있는지 볼 수 있다.
'images' key의 형태(shape) 을 불러오니 1797 행에 8 x 8 픽셀의 이미지가 들어있다고 이해할 수 있다. (정확한 해석은 차원으로 봐야 한다!) 'data' key는 1797행에 64열이 있기 때문에 자연스럽게 8x8 픽셀이 한 열에 들어 있다고 이해하면 된다.
'target' key는 1797 행에 각각 숫자 0~9까지가 들어있으며, 실제 숫자 값이다!
이미지가 어떤 형태로 들어 있는 지 궁금하다면 matplotlib의 imshow를 통해 알아보자.
# Data Visualization
import matplotlib.pyplot as plt
%matplotlib inline
plt.imshow(data['data'][6].reshape(8,8))
plt.show()
2. train data 와 test data로 나누기.
물론 train data 와 test data로 나눌 때는 sklearn.model_selection.train_test_split을 사용하면 랜덤 하게 나눌 수 있다. 하지만 0부터 9까지 숫자를 내가 원하는 양만큼 배치하려면? 그럴 때는 boolean index를 사용하자.
test_data = []
train_data = []
for i in range(10):
class_bool = data['target'] == i
class_bool_index = np.where(class_bool)[0]
test_class_index = class_bool_index[:25]
train_class_index = class_bool_index[25:]
test_data.append(data['data'][test_class_index])
train_data.append(data['data'][train_class_index])
class_bool 에는 i 의 값과 data ['target']의 값이 일치하는 element의 index가 boolean 형태로 들어간다. class_bool 은 따라서 boolean 값(1/0)을 갖는 array이며, np.where을 통해 실제 index를 구할 수 있다.
test data 에는 0~9에 해당하는 숫자를 각각 25개씩 넣고, train data에는 나머지를 넣는다.
test_data는 list이고, 그 안에 [array, array, ... , array] array 10개를 갖고 있다. 우리가 원하는 것은 array안에 원소이므로 np.concatenate을 통해 join 시켜주자.
test_data = np.concatenate(test_data)
train_data = np.concatenate(train_data)
test_data.shape # (250, 64)
train_data.shape # (1547, 64)
3. Machine Learning Model 만들기
여러 개의 분류(classification)을 할 때 유용한 Neural Network(Mult-Layer Perceptron Classfier)을 사용하자.
먼저 필요한 module을 전부 import 해준다.
from sklearn.neural_network import MLPClassifier
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import pandas as pd
MLPClassifier을 사용하자 모델을 정의해 준다.
NN = MLPClassifier(hidden_layer_sizes=(48, 20), learning_rate='adaptive',
learning_rate_init=0.001,random_state=245, max_iter=1000)
MLPClassfier는 여러 개의 parameter를 갖고 있다. 여기에 나온 것들만 소개해도 다양한 방식을 시도해 볼 수 있다.
먼저 hidden_layer_sizes는 tuple의 형태이며, i번째 원소가 i번째 hidden layer를 의미하고 그 원소가 갖는 값이 해당 hidden layer에 있는 unit 개수이다. hidden layer는 많다고 좋은 것이 아니며, 보통은 input 보다는 적게, output 보다는 많게 설정한다.
learning_rate 은 대표적으로 'adaptive' 'constant'가 있는데, adaptive는 training을 거듭하면서 변화가 일정 기준보다 적을 시 learning_rate을 적절하게 변형시켜 준다. 'constant'는 늘 일정하게 유지한다.
learning_rate_init 은 learning_rate의 초기 값이다. 얼마인지에 따라 training 성능이 달라짐으로 중요한 지표이다.
random_state 은 초기 bias와 weight 값을 정한다. random_state을 따로 정해주지 않는다면, 늘 값이 달라지지만 random_state 을 설정해 주면, 초기 bias와 weight 값이 정해진다.
max_iter는 training을 최대로 반복하는 숫자이다. training은 일정 숫자가 넘어가면 수렴할 수 있기에, 다다익선은 아니다.
5. Model Training
training 은 fit method를 통해 진행된다. fit을 하고 난 뒤에는 모델에 loss_curve_라는 attribute가 생기며 그래프를 그리면 파란색 선이 test_data, 빨간색 선이 train_data이다. data 수가 더 적은 test_data (파란색)가 더 많은 반복 후에 loss(에러)가 0에 가까워지는 것을 볼 수 있다. 현재 그래프처럼 안정적인 기울기를 보이며 0에 가까워지는 loss curve가 좋은 loss curve이며, 급격한 변화가 있거나, 빨간색 선이 파란색 선을 가로지르는 등 overfitting과 underfitting을 생각하며 그래프를 분석해야 한다.
NN.fit(test_data, test_target)
plt.plot(NN.loss_curve_, 'b')
NN.fit(train_data, train_target)
plt.plot(NN.loss_curve_, 'r')
plt.xlabel('epochs')
plt.ylabel('loss')
plt.show()
6. Model Prediction
모델을 train 시켰으니, test를 해볼 차례이다. (위에서 마지막에 train 시킨 게 train_data 이므로 test_data로 test 하는 것은 상관없다)
predict method를 통해 test_data와 train_data에 대해 어떤 target 값을 예측하는지 확인해 볼 수 있다.
각각의 correct_test와 correct_train은 boolean 값을 갖고 있으며, np.sum()을 통해 얼마나 많이 맞혔는지 알 수 있다.
train_acc 가 낮으면 학습이 잘 안 됐다는 뜻이므로, 더 복잡한 data가 필요하고, test_acc가 낮으면 train_data가 너무 복잡하여 test_data를 반영하지 못한다는 뜻이므로 학습을 덜 진행시킬 필요가 있다. 물론 이뿐만이 아니라, test_acc와 train_acc를 보고 분석하는 방향은 다양하다.
마지막으로 confusion matrix 그래프를 그려서 각각의 숫자마다 맞힌 개수와 틀렸다면 어떤 숫자로 잘 못 예측하여 틀렸는지를 확인한다.
test_predict = NN.predict(test_data)
train_predict = NN.predict(train_data)
fig = ConfusionMatrixDisplay.from_predictions(test_predict, test_target)
correct_test = test_predict == test_target
correct_train = train_predict == train_target
train_acc = np.sum(correct_train) / len(correct_train)
test_acc = np.sum(correct_test) / len(correct_test)
print('train_acc : ', train_acc)
print('test_acc: ', test_acc)
결과 : train_acc : 1.0 test_acc: 0.975
chat gpt의 등장으로 전 세계가 술렁인다. 기획안, ppt 등 chat gpt의 능력은 한계가 없어 보인다. 하지만 data가 없는 부분에 대해서는, 또는 data를 구할 수 없는 분야에 대해서는 무용지물이다. 고민이 필요하다.