2019년 2월 9일 토요일

간단한 도커 기반 케라스 LSTM 딥러닝 모델 학습 및 데이터 예측

이 글은 도커를 기반으로 케라스를 이용한 LSTM 학습 및 예측 방법을 간단히 따라해 보고, 사용방법과 코드를 익힙니다. 작년 가을부터 쌓여있던 연구행정일 어느 정도 정리되어, 쌓아 둔 글들 중 케라스 기반 LSTM과 관련 내용들을 하나씩 정리하도록 하겠습니다. 딥러닝 모델에 대한 내용은 아래 링크 참고 바랍니다.

머리말
텐서플로우, 케라스를 사용하는 방법은 크게 다음과 같습니다.
  1. 텐서플로우 및 케라스 직접 설치, 사용
  2. 아나콘다 설치 후 텐서플로우 및 케라스 설치, 사용
  3. AWS와 같은 클라우드 기반 미리 설치된 텐서플로우, 케라스 설치 및 사용
각각이 장단점 있죠.

우선, 1, 2번 같은 경우, 직접 본인 컴퓨터에서 설치부터 시작해 사용까지 경험해 본다는 측면에서 공부하기 좋으나, 수많은 관련 라이브러리 버전 의존성을 맞춰주고, 하나가 업데이트되면 다른 라이브러리 의존성이 깨져 재설치해야 하는 등 번거로움이 많은 방법입니다.

3번 같은 경우, 클라우드 제공 사이트에 회원 가입 후 몇몇 설정 클릭질만 해 주면 쉽게 사용할 수 있으나, 왠지 내공있어야 하는 일들은 남이 대신 해 주는 것 같고, 사용량이 많아지면, 업체에서 과금을 할 것이기 때문에 번거로운 점이 있습니다.

딥러닝 라이브러리 사용 편의성과 과금을 피해가는 방법 중 하나가 이 글에서 제안하는 도커를 이용한 딥러닝 라이브러리 사용 방법입니다.

도커는 사전 설치된 이미지가 있으면 다운로드 받아 컨테이너에 실행하면 되므로, 라이브러리 종속성 문제나 과금에 자유롭죠. 다만, 수많은 이미지 중 안정적인 버전을 찾기가 쉽지 않은 문제가 있습니다.

이 글에서는 Kitematic 을 사용해 딥러닝 라이브러리 설치된 이미지를 검색하고, 이를 사용해 LSTM을 실행해 보도록 하겠습니다. 도커에 대한 설명은 아래 링크 참고 바랍니다.

Kitematic 이용한 도커 딥러닝 라이브러리 이미지 설치
Kitematic은 도커 이미지 원클릭 설치를 제공한다. 그래픽 사용자 인터페이스 (GUI)에서 앱 컨테이너를 제어할 수 있어 매우 편리하다. Kitematic은 다음 링크에서 다운로드 받을 수 있다.
Kitematic (2019년 4월 도커 버전과 Kitematic 버전이 서로 문제를 일으켜서, 도커 이미지 다운로드 안되는 현상있음. 이 경우, https://github.com/docker/kitematic/releases 에서 Kitematic 0.17.3 버전을 다운로드 받아 실행해 볼것)

Kitematic 사이트에서 프로그램을 다운로드 설치한 후 실행하면 다음과 같이 도커 이미지를 검색할 수 있다. 본인은 keras로 검색하였다. 
keras 검색 결과(Kitematic)

이 글에서는 keras-full 이미지를 설치해 사용한다. 참고로, 다른 이미지들은 jupyter notebook이 안되거나, 몇몇 keras 관련 라이브러리가 설치되어 있지 않아, 이 글의 LSTM 예제를 따라하기 어렵다.

keras-full 이미지 설치는 매우 간단해, 'CREATE'버튼을 클릭하면 된다. 이후, 이미지를 다운로드하고, 도커 컨테이너에 설치하는 과정은 자동적으로 진행된다. 

설치 후 keras-full 이미지는 왼쪽 컬럼에 표시된다. 해당 이미지를 선택하고, 상단의 start 툴바 버튼을 클릭하면 실행된다. 웹이 지원되는 이미지는 WEB PREVIEW 탭이 다음 그림과 같이 보여진다. 이 탭의 문서 툴바 버튼을 클릭하면 쥬피터 노트북이 실행될 것이다. 

케라스 기반 LSTM 사용하기 
쥬피터 노트북 실행되면, 암호를 묻는다. 이 이미지의 노트북 암호는 'keras'이다.

입력 후 로긴하면 다음과 같은 창을 볼 수 있다.

여기서, New 버튼을 이용해 python3 소스 파일을 하나 만들어 본다.

실습할 LSTM 소스코드는 keras에서 실행된다. 이 코드는 여객기 탑승자 수를 날짜별로 저장한 스프레드시트 파일을 읽어, 딥러닝 모델 학습한 후 예측 모델을 만든다. 그리고, 예측 모델과 실제 값을 비교한 결과를 그래프로 출력한다.

다음 LSTM 소스코드를 복사해 붙여넣기를 한다. 참고로, 이 소스코드 내용은 Machine Learning Mastery LSTM 링크를 방문하면 좀 더 상세한 설명을 확인할 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
from google.colab import files
uploaded = files.upload()

# LSTM for international airline passengers problem with regression framing
import numpy
import matplotlib.pyplot as plt
from pandas import read_csv
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
# convert an array of values into a dataset matrix
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 numpy.array(dataX), numpy.array(dataY)
# fix random seed for reproducibility
numpy.random.seed(7)
# load the dataset
dataframe = read_csv('international-airline-passengers.csv', usecols=[1], engine='python', skipfooter=3)
dataset = dataframe.values
dataset = dataset.astype('float32')
# normalize the dataset
scaler = MinMaxScaler(feature_range=(0, 1))
dataset = scaler.fit_transform(dataset)
# split into train and test sets
train_size = int(len(dataset) * 0.67)
test_size = len(dataset) - train_size
train, test = dataset[0:train_size,:], dataset[train_size:len(dataset),:]
# reshape into X=t and Y=t+1
look_back = 1
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)
# reshape input to be [samples, time steps, features]
trainX = numpy.reshape(trainX, (trainX.shape[0], 1, trainX.shape[1]))
testX = numpy.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=100, batch_size=1, verbose=2)
# make predictions
trainPredict = model.predict(trainX)
testPredict = model.predict(testX)
# invert predictions
trainPredict = scaler.inverse_transform(trainPredict)
trainY = scaler.inverse_transform([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 = numpy.empty_like(dataset)
trainPredictPlot[:, :] = numpy.nan
trainPredictPlot[look_back:len(trainPredict)+look_back, :] = trainPredict
# shift test predictions for plotting
testPredictPlot = numpy.empty_like(dataset)
testPredictPlot[:, :] = numpy.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()

이 코드를 실행하기 위해서는 아래 링크에서 비행기 탑승자 수 CSV(,) 데이터파일을 미리 소스코드 폴더에 다운로드해 넣어야 한다.


이 데이터셋에서 67%는 훈련용, 나머지 33%는 테스트 검증용으로 사용한다.
LSTM 소스코드를 쥬피터 노트북에서 실행한 결과는 다음과 같다.

...
LSTM 학습 및 테스트 결과 그래프(청색: 원본 데이터, 적색: 훈련 데이터, 녹색: 테스트 예측 데이터)

결과 그래프에서 보여지는 것처럼, LSTM은 원본 데이터와 유사한 패턴으로, 향후 데이터를 예측해 내는 것을 확인할 수 있다.

소스코드 설명
이 코드는 LSTM 모델을 이용해 시퀀스로 배열된 시계열 데이터를 예측하는 것이다. 이런 기법은 다양한 분야에 사용될 수 있다. 주요 코드만 확인해 본다.

다음은 데이터셋을 로딩하는 코드이다.
# load the dataset
dataframe = pandas.read_csv('international-airline-passengers.csv', usecols=[1], engine='python', skipfooter=3)
dataset = dataframe.values
dataset = dataset.astype('float32')

이후 0에서 1 값으로 데이터를 정규화한다.
# normalize the dataset
scaler = MinMaxScaler(feature_range=(0, 1))
dataset = scaler.fit_transform(dataset)

데이터세트에서 67%는 훈련용, 33%는 테스트용으로 분리한다.
# split into train and test sets
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))

LSTM 모델 입력은 현재 주어진 시간(T) 승객수이며, 출력 Y는 다음 시간(T + 1)의 승객수가 되도록 한다. 이 배열을 numpy.array 형 dataX, dataY로 리턴하는 함수를 만든다.
# convert an array of values into a dataset matrix
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 numpy.array(dataX), numpy.array(dataY)

참고로, 이 함수를 호출하면 다음과 같이, 첫번째 데이터의 Y는 두번째 데이터의 X가 된다.
X Y
112 118
118 132
132 129
129 121
121 135

이제, 입력 데이터셋을 LSTM 모델 학습에 맞게 행렬 모양으로 변환하고, LSTM 시퀀스 모델을 생성해, trainX, trainY 데이터를 입력한다.
# 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=100, batch_size=1, verbose=2)

다음 코드를 이용해 학습된 모델을 예측한 출력값을 얻는다. 그리고, 원본 데이터 trainY와 훈련용 데이터셋 예측값 trainPredict, 테스트용 데이터 예측값 testPredict 편차를 RMSE로 확인한다. 참고로, 본인 컴퓨터에서는 각각 RMSE가 22.92, 47.53 이었다.
# make predictions
trainPredict = model.predict(trainX)
testPredict = model.predict(testX)
# invert predictions
trainPredict = scaler.inverse_transform(trainPredict)
trainY = scaler.inverse_transform([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))

나머지 코드는 원본 데이터, 학습 데이터, 테스트 데이터를 그래프로 출력하는 코드이다.

마무리
이 글은 좀 더 간편한 방식으로 딥러닝 모델을 학습하고 테스트할 수 있는 도커 이미지를 이용해, 간단한 LSTM 모델을 케라스 기반으로 실행해 보았다. 도커를 이용하면, 라이브러리 종속성 문제로 삽질할 필요 없이, 딥러닝 모델 개발 본연의 목적에만 집중할 수 있고, 사용량이 많아지면 과금되는 클라우드 플랫폼을 사용할 필요도 없다.

참고로 설명한 LSTM코드는 매우 일반적인 패턴 학습 모델이므로, 약간만 수정하면, 다양한 예측 모델에 사용할 수 있다.

레퍼런스

댓글 5개:

  1. 안녕하세요. 최근에 관심가지게 된 초짜입니다. 결과 그래프를 보면 청색 원본 실제값과 녹색 예측값이 나와있는데요. 주어진 데이터셋 내에서 둘 사이를 평가하는 그래프라고 생각됩니다. 그러면 실제 다음날의 예측값은 어디에 나오나요??

    제가 생각하기에 그래프에서 맨 우측 미래 부분에 예측값만 표시된 부분이 있어야 될 것 같은데, 저 그래프는 그냥 과거 실제값이랑 과거 예측값이 나란히 그려저 있어서요 ㅜㅜㅜ

    아니면 더 추가적인 어떠한 코딩을 통해 실제로 미래의 예측값을 나타내야 하나요?

    답글삭제
    답글
    1. LSTM에 승객수 변화(t-1, t)를 예측모델로 만든 것이기 때문에, 이 모델은 승객수를 입력해 이후 예측을 할 수 있습니다. 다른 입력에 대한 출력을 만들려면 LSTM 입력 및 출력형식을 수정해야 합니다.

      삭제
  2. 안녕하세요 AI를 전공하는 학생은 아니지만 AI 관련해서 자료가 필요해서 방문하게 됐습니다. 좋은 정보 공유 감사합니다.

    답글삭제