2022-11-30,   권재우

LSTM이 시계열 기본 모델로 간주되어 왔으며 CNN 모델은 보통 이미지 데이터를 처리하는 알고리즘으로 간주되어 왔습니다. 이번 포스팅에서는 CNN과 LSTM을 결합해서 시계열 모델을 만들고 LSTM 예측 결과와 CNN-LSTM모델로 예측한 결과를 비교해보는 포스팅을 작성해보겠습니다.

해당 포스팅은 아래 링크의 코드를 참고했습니다 (코드 출처)

  • https://github.com/jasonwei20/eda_nlp
  • https://codinglilly.tistory.com/9

CNN + LSTM 시계열 모델

CNN과 LSTM모델의 성능이 기존 LSTM보다 성능이 우수한지 실험해보고자 하는게 이번 포스팅의 목적입니다. 실험에 사용되는 CNN-LSTM 결합 방법은 CNN과 LSTM의 기본 모델을 사용하여 상호 독립적으로 모델을 구성하고 두 모델이 하나의 네트워크로 동작합니다. 데이터는 AI-Factory에 올라온 수돗물 사용량 예측 데이터를 사용해서 진행하겠습니다.

(data 출처)
https://aifactory.space/competition/detail/2198

  • 필요한 라이브러리 임포트
import pandas as pd
import numpy as np
import tensorflow_addons as tfa
import random
from tqdm import tqdm
import tensorflow as tf
from keras.models import Sequential
from keras.layers import Dense, LSTM, Dropout
from IPython.display import clear_output
  • 데이터 불러와서 합치기

데이터는 2017년 1월 1일 ~ 2021 12월 17일 기간의 데이터로 분포되어있고 산업단지 수돗물 유출유량 적산차를 타겟값으로 가집니다.

# 랜덤 시드 고정
SEED = 42
np.random.seed(SEED)
tf.random.set_seed(SEED)
random.seed(SEED)

train = pd.read_csv('data/task3/data_tr_4dist.csv')
test = pd.read_csv('data/task3/data_ts_4dist.csv')

data = pd.concat([train, test]).reset_index(drop=True)
data.shape

target = '4단지배수지 공업 유출유량 적산차'
  • data

Screenshot_1

  • 모델예측 시작, 끝 설정
start = data.index[(data['datetime']=='2021-01-01 01:00:00')]
end = data.index[(data['datetime']=='2021-11-30 23:00:00')]
  • 시계열 모델 학습, 라벨 데이터 분리 2021-12-01일 00시부터 2021-12-17일 13시까지 총 17일 분량을 예측
train_data = []
train_label = []

data = data.replace(" ", np.nan)
data = data.interpolate(method = 'values')
data = data.fillna(0)
# print(data.shape)

p_step = 408
f_step = 408 * 3
for j in tqdm(range(start[0]-f_step-2)):
    train_data.append(np.array(data[target][j:j + f_step]))
    train_label.append(np.array(data[target][j+f_step:j + p_step + f_step]))
print(np.shape(train_data), np.shape(train_label))
  • data scaler(스케일링)
from sklearn.preprocessing import RobustScaler

# scaler 스케일링

scaler = RobustScaler()

test = data[target]
test = np.array(test).reshape(-1, 1)

test = scaler.fit_transform(test)
test = test.reshape(-1)
data[target] = test
data
  • 데이터 형식 변경
train_data = np.array(train_data)
train_label = np.array(train_label)
  • Earlystopping 함수 정의
class DisplayCallback(tf.keras.callbacks.Callback):
    def on_epoch_end(self, epoch, logs=None):
        if epoch % 10 == 0:
            clear_output(wait=True)
callbacks = [DisplayCallback(),
            tf.keras.callbacks.EarlyStopping(monitor="loss", mode="min", verbose=0, patience=5),
            tf.keras.callbacks.ModelCheckpoint("result/221124_tcn_ckpt.h5", mode="min", save_best_only=True)]   

def scale_fn(x):
    return 1/(2.**(x-1))            
  • LSTM 모델링 후 학습

epochs=20, batch_size=256로 파라미터를 설정하고 모델 학습을 진행했습니다.

tf.keras.mixed_precision.set_global_policy("mixed_float16")

input_shape = (x_train.shape[1], x_train.shape[2])

# LSTM Model
lstm_model = Sequential()
lstm_model.add(LSTM(128, input_shape=input_shape, return_sequences=True))
lstm_model.add(Dropout(0.3))
lstm_model.add(LSTM(128))
lstm_model.add(Dropout(0.3))
lstm_model.add(Dense(408))
lstm_model.compile(loss="mae", optimizer='adam')

# 모델 구성 출력
lstm_model.summary()

# 모델 학습
lstm_model.fit(x_train, y_train, epochs=20, batch_size=256, callbacks=callbacks)  

Screenshot_2

Screenshot_3

  • CNN-LSTM 모델
from keras.layers import Conv1D, MaxPooling1D, Dense
tf.keras.mixed_precision.set_global_policy("mixed_float16")

input_shape = (x_train.shape[1], x_train.shape[2])

# LSTM Model
cnnlstm_model = Sequential()
cnnlstm_model.add(Conv1D(128, 3, padding='same', activation='tanh', strides=1, input_shape=input_shape))
cnnlstm_model.add(MaxPooling1D(2))
cnnlstm_model.add(LSTM(128, recurrent_dropout=0.5))
cnnlstm_model.add(Dropout(0.5))
cnnlstm_model.add(Dense(408))

# 모델 구성 출력
cnnlstm_model.summary()

# 모델 학습
cnnlstm_model.fit(x_train, y_train, epochs=20, batch_size=256, callbacks=callbacks)  

Screenshot_4

Screenshot_5

  • test데이터 구축
test_data = []

for j in tqdm(range(start[0]-f_step-2, len(data)-f_step)):
    test_data.append(np.array(data[target][j:j + f_step]))

test_data = np.array(test_data)
test_data = test_data.reshape(test_data.shape[0], test_data.shape[1], 1)
  • 성능 검정

성능 평가 기준은 MAE로 설정했고 LSTM과 CNN-LSTM모델 예측 결과로 MAE값을 구해서 성능을 비교해보겠습니다.

pred_lstm = lstm_model.predict(test_data)
pred_cnnlstm = cnnlstm_model.predict(test_data)

def MAE(true, pred):
    return np.mean(np.abs(true-pred))

MAE(np.array(test[35062:]), np.array(preds_lstm)) # 결과 : 0.5077965183154429
MAE(np.array(test[35062:]), np.array(preds_cnnlstm)) # 결과 : 0.5229102320025742

Screenshot_6

  • 결론

이번 포스팅의 결과로는 CNN-LSTM결합모델의 성능이 기존 LSTM보다 낮은 결과가 나왔습니다. 학습시간도 LSTM보다 약 5배 정도 오래걸렸습니다. 구글링을 통해서 다른 데이터에 CNN-LSTM 결합모델을 비교한 결과를 찾아봤는데 데이터가 많으면 많을수록 LSTM보다 CNN-LSTM모델이 더 좋은 결과를 낸다고 합니다 제가 가져온 데이터에서는 데이터 양이 적어서 그런지 기존모델인 LSTM이 더 좋은 효율을 보였습니다.

이상으로 오늘 포스팅을 마치겠습니다.

업데이트: