본문 바로가기
Study/시계열

3. 딥러닝을 이용한 시계열 예측 (TensorFlow, LSTM)

by 까망우동 2024. 7. 8.
반응형

 

 


단변량 (univariate) & 단일 시점 (single step)

 

1. (단변량) 시계열 데이터셋 만들기 

  • 우선 예제의 단변량 시계열 데이터의 형태는 아래와 같음. (시간에 따른 기온 데이터) 

  • 시계열 데이터를 슬라이딩 윈도우 형태로 변환해 준다. 
  • 윈도 형태 데이터셋 변환 함수에는 train, valid, test 데이터셋 구분을 위한 start ~ end index , window 사이즈, 예측하고자 하는 타깃시점 (= 몇 step 후를 예측할지)을 입력한다.
  • 아래 코드는 single step 예측 기준. target_size 를 크게 잡을수록 먼 시점을 예측
# Define a specific window for training Neural Network
def univariate_data(dataset, start_index, end_index, history_size, target_size):
    data = []
    labels = []

    start_index = start_index + history_size   # start_index 에 윈도우사이즈를 더해줌.
    if end_index is None:
        end_index = len(dataset) - target_size   # end_index 안주면 끝까지

    for i in range(start_index, end_index):
        indices = range(i - history_size, i)   # start 부터 end index 에 해당하는 타임 윈도우에 대한 인덱스 만들어줌
        data.append(np.reshape(dataset[indices], (history_size, 1)))    # Reshape data from (history_size,) to (history_size, 1)
        labels.append(dataset[i+target_size])  # [i - history ~ i - 1] 까지를 학습데이터로 해서 [i+target_size] 를 예측
    return np.array(data), np.array(labels)
    
# Standardization
uni_data = uni_data.values  # series -> ndarray 변환
uni_train_mean = uni_data[:TRAIN_SPLIT].mean()
uni_train_std = uni_data[:TRAIN_SPLIT].std()
uni_data = (uni_data - uni_train_mean) / uni_train_std  # Standardization

# univariate_data 함수를 이용한 학습/검증 데이터셋 생성 
univariate_past_history = 20
univariate_future_target = 0

x_train_uni, y_train_uni = univariate_data(uni_data, 0, TRAIN_SPLIT,
                                         univariate_past_history,
                                         univariate_future_target)
x_val_uni, y_val_uni = univariate_data(uni_data, TRAIN_SPLIT, None,
                                     univariate_past_history,
                                     univariate_future_target)

print('Single window of past history')
print(x_train_uni[1])
print('\n Target temperature to predict')
print(y_train_uni[1])

 

  • Tensor Flow의 iterable 한 Dataset 만들기
BATCH_SIZE = 256
BUFFER_SIZE = 10000

train_univariate = tf.data.Dataset.from_tensor_slices((x_train_uni, y_train_uni))
train_univariate = train_univariate.cache().shuffle(BUFFER_SIZE).batch(BATCH_SIZE).repeat()

# cache() 는 데이터를 메모리에 저장시켜, epoch 마다 데이터를 새로 읽을필요없이 캐시로 부터 저장된 값을 더 빠르게 불러올수 있게 해줌.
# repeat() 을 통해, 매 epoch 마다 batch 를 새로 shuffling 하게 해줌


val_univariate = tf.data.Dataset.from_tensor_slices((x_val_uni, y_val_uni))
val_univariate = val_univariate.batch(BATCH_SIZE)

# 한 epoch 내에서 총 배치 개수 회수만큼만 학습할거면 repeat()을 굳이 사용하지 않아도 된다.

 

2. LSTM 모델 생성, 학습, 검증

  • LSTM을 생성할 때는 유닛의 개수 (= 출력 차원 크기)와 입력 데이터의 형태를 입력해 준다. 
  • return sequence 가 False 이면 : (배치사이즈, 윈도우 사이즈, 피쳐 개수) →  (유닛 개수) 
  • True 이면 : (배치사이즈, 윈도우윈도 사이즈, 피쳐 개수) →  (배치사이즈, 윈도 사이즈, 유닛 개수) 
# Keras 를 이용한 LSTM 모델 생성 

simple_lstm_model = tf.keras.models.Sequential([
    tf.keras.layers.LSTM(8, input_shape=np.array(x_train_uni).shape[-2:]),
    # LSTM 의 유닛 수 (8) 은 출력차원 크기와 같음
    # LSTM 의 입력데이터 shape은 기본적으로 (batch_size, time_steps, features) 인데, input_shape 은 뒤에 2개 (time_steps, features) 의미함
    # return_sequences 을 지정하지 않으면 디폴트로 False, return_sequences=True 로 하면 입력 텐서의 time_steps 마다의 output을 출력함
    # 즉 False 일때의 output = (batch_size, units) 의 2D 텐서이고, True 일때는 (batch_size, time_steps, units) 의 3D 텐서
    # 예를들어 다음날 주가를 예측하는 시계열 모델은 False 를 쓰면되고, 문장의 각 단어에 대한 번역을 필요로하는 모델은 True를 쓰면 됨
    tf.keras.layers.Dense(1)
])

simple_lstm_model.compile(optimizer='adam', loss='mae')

 

  • 모델 학습 
EVALUATION_INTERVAL = 200
EPOCHS = 10

simple_lstm_model.fit(train_univariate, epochs=EPOCHS,
                      steps_per_epoch=EVALUATION_INTERVAL,
                      validation_data=val_univariate, validation_steps=50)

# step 수 지정은, 총 배치중에 몇개를 학습할지 뜻함. batch 가 1117개 인데 200으로 설정하면 200개만 학습함
# 위에서 train_univariate 를 repeat() 으로 무한대로 반복하게 만들어줬으면 steps_per_epoch 파라미터 필수로 지정해줘야함.
# repeat() 안했으면 steps_per_epoch 필수 지정 안해도 되는데, 이때는 batch 의 총 개수만큼 학습함

 

  • 예측 및 성능 검증 
x_test_uni = x_val_uni[:10000]
y_test_uni = y_val_uni[:10000]
# 원래는 시작 단계부터 val, test 데이터셋 분리해야함 

print(x_test_uni.shape, y_test_uni.shape)

# 예측 성능 평가 (MAE)
mae_loss = tf.keras.losses.MeanAbsoluteError()
test_loss = mae_loss(y_test_uni, predictions.flatten()).numpy() # flatten()에 유의할것.. 타겟과 예측값 shape 이 동일해야함

print(f"Test MAE Loss: {test_loss}")

plt.figure(figsize=(10, 6))
plt.plot(y_test_uni[:100], label='True Values')
plt.plot(predictions[:100], label='Predictions')
plt.legend()
plt.show()

 

 

다변량 & 다중시점 

 

1. (다변량) 시계열 데이터셋 만들기 

  • 앞선 같은 예제를 기준. 다변량 시계열 데이터셋의 모습은 아래와 같다. (기압,온도,밀도 3 변수에 타깃은 온도)

  • 다변량 데이터 변수별 시각화 및 표준화 
# visualization
features.plot(subplots=True)

# standardization
dataset = features.values
data_mean = dataset[:TRAIN_SPLIT].mean(axis=0)
data_std = dataset[:TRAIN_SPLIT].std(axis=0)
dataset = (dataset-data_mean)/data_std
print(dataset, dataset.shape, type(dataset))

 

  • 다변량 시계열 데이터셋을 슬라이딩 윈도우 형태로 생성 
  • 앞선 예제와 동일하나, multi step (구간 예측 = 다중시점 예측)이 가능하도록 설정. 아래 코드에서는 과거 720개 시점을 6개 step으로 추출해서 타임 윈도를 구성하여 인풋으로 하고, 미래 72개 시점을 아웃풋으로 예측.
def multivariate_data(dataset, target, start_index, end_index, history_size, target_size, step, single_step=False):   # 다변량은 타겟을 따로 명시해줘야한다.
    data = []
    labels = []

    start_index = start_index + history_size
    if end_index is None:
        end_index = len(dataset) - target_size

    for i in range(start_index, end_index):
        indices = range(i - history_size, i, step)  # window size = history_size // step
        data.append(dataset[indices])

        if single_step:
            labels.append(target[i + target_size])   # single step 예측이라면
        else:
            labels.append(target[i:i + target_size])   # multi step 이라면 (=구간예측)
    return np.array(data), np.array(labels)
    
    past_history = 720
    
past_history = 720
future_target = 72
STEP = 6

x_train_multi, y_train_multi = multivariate_data(dataset, dataset[:, 1], 0,
                                                 TRAIN_SPLIT, past_history, future_target, STEP)
x_val_multi, y_val_multi = multivariate_data(dataset, dataset[:, 1],
                                             TRAIN_SPLIT, None, past_history, future_target, STEP)

print('Single window of past history : {}'.format(x_train_multi[0].shape))
print('\n Target temperature to predict : {}'.format(y_train_multi[0].shape)) # multi step 이기 때문에 target이 72개 값    

print(x_train_single.shape, y_train_single.shape, x_val_single.shape, y_val_single.shape)

BATCH_SIZE = 256
BUFFER_SIZE = 10000

train_multivariate = tf.data.Dataset.from_tensor_slices((x_train_multi, y_train_multi))
train_multivariate = train_multivariate.cache().shuffle(BUFFER_SIZE).batch(BATCH_SIZE).repeat()

val_multivariate = tf.data.Dataset.from_tensor_slices((x_val_multi, y_val_multi))
val_multivariate = val_multivariate.batch(BATCH_SIZE)

 

 

2. LSTM 모델 생성, 학습, 검증

  • 다중시점 구간 예측이기 때문에 LSTM 의 dense lyaer의 최종 output의 차원은 예측하고자 하는 구간의 길이 여야함
multi_step_model = tf.keras.models.Sequential()
multi_step_model.add(tf.keras.layers.LSTM(32, input_shape=x_train_multi.shape[-2:]))
multi_step_model.add(tf.keras.layers.Dense(future_target))
multi_step_model.compile(optimizer=tf.keras.optimizers.RMSprop(), loss='mae')

for x, y in val_multivariate.take(1):     # Dateset을 배치단위로 만들었기 때문에, 검증 데이터셋의 첫번째 batch 에 대한 예측 결과를 출력함 => (256,72,1)
    print(multi_step_model.predict(x).shape)

print(f'예측과 타겟 shape 비교 : 타겟값 : {y_val_multi[0].shape} ')

 

  • LSTM 모델 학습 및 예측 결과 확인
  • epoch 별 학습,검증 데이터셋의 예측 오차는 History 객체로 반환할 수 있다. 
multi_step_history = multi_step_model.fit(train_multivariate, epochs=EPOCHS,
                                          steps_per_epoch=EVALUATION_INTERVAL,
                                          validation_data=val_multivariate,
                                          validation_steps=50)
                                          
# multi_step_history.history 로 검증오차 반환가능
                                          

# 예측값과 타겟값 형태 확인 
for x, y in val_multivariate.take(1):
  true_values = y
  multi_step_predictions = multi_step_model.predict(x)
  
print(true_values.shape, multi_step_predictions.shape, type(true_values), type(multi_step_predictions))

true_values = np.concatenate(true_values, axis=0)
predicted_values = np.concatenate(multi_step_predictions, axis=0)

print(true_values.shape, predicted_values .shape, type(true_values), type(predicted_values ))

mae = mae_loss(true_values, predicted_values)
print(f'Mean Absolute Error: {mae}')

 

  • 예측 결과 시각화 
# Plotting the results
def plot_multi_step(history, true_future, prediction):
    plt.figure(figsize=(8, 4))
    num_in = list(range(-len(history), 0))
    num_out = len(true_future)

    plt.plot(num_in, np.array(history[:, 1]), label='History')
    plt.plot(np.arange(num_out), np.array(true_future), 'bo', label='True Future')
    if prediction.any():
        plt.plot(np.arange(num_out), np.array(prediction), 'ro', label='Predicted Future')
    plt.legend(loc='upper left')
    plt.show()

# Visualize the prediction
for x, y in val_multivariate.take(3): # Displaying first examples :3개의 배치의 각 첫번째 데이터셋 결과 시각화
    for i in range(1):
        plot_multi_step(x[i], y[i], multi_step_model.predict(np.expand_dims(x[i], axis=0))[0])
반응형

댓글