지난해 겨울 텐서플로우 OpenCV 출간 이후 7개월 만에 2권에 해당하는 “Scikit PyTorch 머신러닝”을 출간하게 되었다. 각권이 450 페이지이므로 합 900 페이지에 달하는 내용이라 무슨 머신러닝을 공부하는데 분량이 왜 이렇게 많은가? 하고 의문을 가질 수도 있겠으나 그 내용이 튜토리얼성에 가까워 사실 그렇게 큰 부담은 없는 책이다. 물론 책 내부에 파이선 코드를 끼워 넣는 먹통 짓은 지금 세상에서는 할 필요가 없을 것이다. 해당 책의 머리말에 써둔 하이퍼링크 목차를 다운받으면 블로그를 직접 열어 볼 수 있으며 거기서 예제 코드를 다운 받을 수 있다.
1권에 해당하는 텐서플로우 OpenCV 머신러닝에서는 2017년 9월경부터 2018년 12월 사이에 머신러닝을 이해하고자 하는 필자의 열공(?) 내용을 담아 보았다면 2권에서는 1권에서 제기되었던 여러 내용들에 대해서 해답을 찾아가는 내용들을 꽤 많이 포함하였다. 2권이라고 해서 내용적으로 완전히 정리된 것은 아니기 때문에 다시 3권의 출발점이 될 수도 있을 것이다.
다소 아쉬운 점은 흥미 위주로 시작했던 1, 2권의 Softmax 관련 내용을 완전히 정리하지는 못했는데 이 그 이유는 R&D 영역으로 넘어갔기 때문이다. 2020년에는그 내용까지도 포함하여 출간할 계획이다.
본 서의 출간 목적은 작가들과 출판사가 염원하는 베스트셀러 화가 목표가 아니다. 사회적으로 인공지능(머신러닝)에 대한 이해 필요성이 점증하는 시기이며, 인공지능 분야의 발전 속도가 상당히 빠르기 때문에 그에 맞춰서 비전공자라 할지라도 머신러닝에 입문해 볼 수 있도록 경험과 생각을 공유해 보고자 하는 것이다.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
민간 항공은 세계 2차 대전이 끝난 이 후 1960년대에 들어서서 미국 국내 항공운송업계의 혹독한 구조조정을 거치면서 국제항공승객의 급격한 증가를 가져왔다. 위 그래프에서 볼 수 있듯이 이 국제 항공승객 증가 패턴은 단순하면서도 랜덤한 regression 유형이 아니라 특정한 패턴을 유지하면서 지속적으로 증가하는 경향을 나타내는데 시계열 방식에 의한 예측만이 최선의 합리적인 수단이 될 수 있을 것이다.
머신러닝에서 시계열 데이터 분석은 RNN 기법에 의해서 가능하며 이미 랜덤한 증권가격 데이터를 대상으로 종가 예측문제를 TensorFlow를 사용하여 다루었다. 물론 증권가격이란 것은 단순한 예측의 대상이 아니라 악의적인 의미의 작전의 영역이라 실제적으로는 그 예측이 쉽지않다라는 점을 지적해 둔다. 반면에 여기서는 TensorFlow가 아닌 Keras 방식에 의해서 시계열 문제를 다뤄 보도록 한다. Keras 머신 러닝이 가능하다면 당연히 TensorFlow 코딩화도 가능하다. Keras가 특히 GPU 컴퓨팅에 상당히 효과적인 특성을 보여주므로 TensorFlow처럼 익숙하게 사용할 수 있도록 시계열 문제를 다루어 보기로 한다.
헤더 영역에서 3가지 영역의 라이브러리 모듈들이 필요하다. 수치 데이터 계산을 지원하는 NumPy, 그래픽 처리를 위한 matPlotLib, 및 데이터 입출력지원 Pandas들이다. Keras에서 사용하는 Sequential, Dense, LSTM 은 필수적이다. 그밖에 입출력 데이터의 normalization을 위한 MinMaxScaler, cost 함수를 최소제곱법으로 다루기 위한 mean_squared_error 들이다.
CSV 데이터 포맷으로 저장되어 있는 ‘airline-passengers.txt’파일을 읽어 들이자. 데이터는 아래 그림에서처럼 연도와 월별 데이터로서 정수형태로 기술되어 있으며 그 단위는 1,000 이다.
dataframe.values 처리는 위 그림의 첫 번째 열의 “Month” 와 “Passenges” 와 같은 name을 제거하고 순수한 정수형 숫자 값만을 뽑은 후 astype(‘float32’) 명령에 의해 부동 소숫점 형식으로 바꾼다.
월별 데이터는 숫자 크기의 변동이 심할수 있으므로 MinMaxScaler 에 의해 (0,1) 사이의 값을 가지도록 normaization 후 다시 fit_transform 명령에 의해 표준화 한다. 표준화 과정에서는 데이터 전체의 평균과 분산 값을 구해 변환해야 한다. LSTM Cell을 사용하여 학습시키기 위한 룰을 살펴 보자. 시간 흐름에 따라 144개의 데이터가 112, 118, 132, ∙∙∙ 순서로 변해 나간다. 예측을 위한 학습 룰을 그림과 같이 대으시키자. 즉 입력 데이터가 112 라면 그 다음 스텝인 118을, 입력 데이터가 118 이라면 그 다음 스텝의 132를, ∙∙∙와 같이 대응시키도록 한다.
이와 같이 충분히 많은 수의 데이터를 학습시키면 학습 데이터를 제외한 나머지 테스트 데이터 입력에 대해서 LSTM 의 메모리 기능을 사용하면서 적절한 예측이 이루어질 것이다.
총 데이터 수가 144개이므로 for looping 의 인덱스 i 를 기준으로 하면 0∼143에 해당한다. 즉 range(len(dataset)-look_back-1) 은 range(142)가 되며 인덱스 i 를 기준으로 하면 0∼141까지에 해당한다. 따라서 마지막 데이터인 143번 데이터를 당겨서 142번 예측 값으로 학습시켜야 한다면 dataset[i:i+look_back, 0]에서 입력 데이타는 2개씩 짝을 지어야 하므로 마지막 짝은 141:142 이 되어야 한다. 왜냐하면 142:143을 쓰려면 그다음 144에 해당하는 데이터 값이 없기 때문이다.
실제로는 144개 데이터 모두를 학습에 사용하는 것은 아니라 일부를 사용한다. 예를 들면 144개의 67% 인 96.48개 반올림해서 96개를 train_size로 사용하는 방식이다.
한편 LSTM 루틴의 입력데이타 구조는 [samples, time steps, features] 형태로 구성할 것을 요한다. samples는 학습 데이타의 수이며 현재 기술하고 있는 이 문제에서의 time steps 는 1 이다. 이 time steps 는 시계열 관계를 설정함에 있어서 시간 간격이라고 볼 수도 있을 것이다. 아울러 예측 학습을 통해 테스트 입력 데이터에 대한 그 다음 예측 값 하나를 예측해야 하므로 features 는 1이 된다. 따라서 텐서인 trainX 와 testX 에 time step 1을 부과하여 아래와 같이 reshape 하도록 한다. 아울러 학습 데이터 수를 규정함에 있어서 추가로 지정해야 할 파라메터가 batch_sixe 이며 현재의 airline market 문제에서는 144개의 데이터를 한 묶음 즉 batch_size=1 로 보면 된다.
Keras 코드 구조를 살펴보자. input_shape 이 ( 1, 1)의 2D shape 형태로 주어지고 있는데 이 부분은 결국 time steps 와 입력 데이터 크기 즉 증권가격 예측 문제에서처럼 seq_length 로 보면 된다.
LSTM의 출력 크기는 4로 설정되었으며 Dense(1) 이라 함은 출력 4개를 받아 처리하여 1개의 출력을 얻음을 뜻한다. 그밖에 batch_size 는 앞서 설명하였다.
model.fit 실행으로 학습이 완료되면 다시 trainX 와 testX를 model.predict 에 입력하여 예측 결과를 얻어 보자. 얻어진 예측 결과들도 fit_transform 된 상태이므로 다시 inverse_transform을 적용하여 숫자 자리수를 회복시킨 후 그래픽 처리 하도록 한다.
학습이 완료되면 예측으로 넘어가도록 하자. 이 부분에서 trainY 의 inverse_transform 처리 과정에서 [trainY]를 사용하고 있는데 그 이유는 ㅅrainY 는 그 shpae 특성이 출력해 보면 (96,)으로 나타난다. 즉 머신 러닝 처리를 위한 최소한의 요건인 2차원 텐서화가 이루어지지 않았다는 점에 유의하자.
이 점을 확인해 보기 위해서 중간 중간에 tX, tY, ttY를 넣어서 Shell에서 shape 값을 출력해 보도록 한다.
아래 코드 사례에서처럼 별도로 reshape 과정을 거치던지 아니면 [tarinY]를 사용하는 방법이 있을 수 있다. [trainY]를 사용하는 기법이 reshaping 기법으로 잘 알려지지 않아서 알고 있는 기법으로 환원시켜본 과정이다. 마찬가지로 inverse_transform을 사용하려면 testY에 대해서도 동일한 방법을 사용해야 할 것이다.
최종 예측에 앞서 학습 및 테스트의 정답과 학습내용을 사용하여 예측한 테스트 값과의 mean_square_error 스코어를 조사해 보자. 학습과정에서의 에러 값보다 테스트과정에서의 에러 값이 당연히 좀 큰 편이다. 하지만 트렌드는 괜찮게 예측이 이루어졌다.
지금까지의 내용은 아래 url 주소의 튜토리얼 내용을 앞 부분만을 참조로 해설하였다.
Time Series Prediction with LSTM Recurrent Neural Networks in Python with Keras
#rnn_airline_01.py
import numpy as np
import matplotlib.pyplot as plt
import pandas
import math
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
np.random.seed(7)
dataframe = pandas.read_csv('airline-passengers.txt', usecols=[1])
dataset = dataframe.values
dataset = dataset.astype('float32')
scaler = MinMaxScaler(feature_range=(0, 1))
dataset = scaler.fit_transform(dataset)
train_size = int(len(dataset) * 0.67)
test_size = len(dataset) - train_size
train, test = dataset[0:train_size,:], dataset[train_size:len(dataset),:]
print(len(train), len(test))
def create_dataset(dataset, look_back=1):
dataX, dataY = [], []
for i in range(len(dataset)-look_back-1):
a = dataset[i:(i+look_back), 0]
dataX.append(a)
dataY.append(dataset[i + look_back, 0])
return np.array(dataX), np.array(dataY)
look_back = 1
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)
trainX = np.reshape(trainX, (trainX.shape[0], 1, trainX.shape[1]))
testX = np.reshape(testX, (testX.shape[0], 1, testX.shape[1]))
# create and fit the LSTM network
model = Sequential()
model.add(LSTM(4, input_shape=(1, look_back)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(trainX, trainY, epochs=20, batch_size=1, verbose=2)
tX=trainX
tY=trainY
# make predictions
trainPredict = model.predict(trainX)
testPredict = model.predict(testX)
# invert predictions
trainPredict = scaler.inverse_transform(trainPredict)
trainY = trainY.reshape([-1,train_size-2])
trainY = scaler.inverse_transform(trainY)
#trainY = scaler.inverse_transform([trainY])
ttY = trainY
testPredict = scaler.inverse_transform(testPredict)
testY = scaler.inverse_transform([testY])
# calculate root mean squared error
trainScore = math.sqrt(mean_squared_error(trainY[0], trainPredict[:,0]))
print('Train Score: %.2f RMSE' % (trainScore))
testScore = math.sqrt(mean_squared_error(testY[0], testPredict[:,0]))
print('Test Score: %.2f RMSE' % (testScore))
# shift train predictions for plotting
trainPredictPlot = np.empty_like(dataset)
trainPredictPlot[:, :] = np.nan
trainPredictPlot[look_back:len(trainPredict)+look_back, :] = trainPredict
# shift test predictions for plotting
testPredictPlot = np.empty_like(dataset)
testPredictPlot[:, :] = np.nan
testPredictPlot[len(trainPredict)+(look_back*2)+1:len(dataset)-1, :] = testPredict
# plot baseline and predictions
plt.plot(scaler.inverse_transform(dataset))
plt.plot(trainPredictPlot)
plt.plot(testPredictPlot)
plt.show()
'머신러닝' 카테고리의 다른 글
6-28 RNN 알고리듬에 의한 MNIST 머신러닝 (0) | 2019.09.22 |
---|---|
2-1 Fermi-Dirac 확률분포와 Sigmoid 함수와의 관계 (0) | 2019.09.14 |
6-23 Keras LSTM에 의한 Airline Market RNN 오픈소스 튜토리얼(1) (0) | 2019.09.04 |
3-2 Covariance Softmax 뉴럴 네트워크 적용MNIST 문자 인식률 계산 (0) | 2019.08.26 |
3-1 MNIST 인식률 계산을 위한 Covariance Softmax 알고리듬 (0) | 2019.08.24 |