10장 시계열 데이터와 순환 신경망

감사말: 프랑소와 숄레의 Deep Learning with Python, Second Edition 10장에 사용된 코드에 대한 설명을 담고 있으며 텐서플로우 2.6 버전에서 작성되었습니다. 소스코드를 공개한 저자에게 감사드립니다.

tensorflow 버전과 GPU 확인

주요내용

10.1 시계열 데이터 예제

시계열(timeseries)은 일정 간격으로 측정된 값들로 이루어진 데이터이다.

시계열은 자연현상 및 사람들의 일상에서 쉽게 구할 수 있다.

시계열과 관련된 대표적인 과제는 예측(forcasting)이다. 예를 들어, 몇 시간 후의 소비 전력, 몇 달 후의 영업 이익, 며칠 뒤의 날씨 등을 예측하는 일이다. 이외에 시계열과 관련된 과제는 다음과 같다.

10.2 예제: 온도 예측

나머지 이야기는 24시간 이후의 온도를 예측하는 모델을 구현하는 것이다. 적절한 모델 구현과정을 통해 기존에 사용했던 밀집 연결 모델, 합성곱 모델 등은 적절하지 않고 시계열 데이터에 대한 새로운 접근방식을 사용하는 순환 신경망(recurrent neural network, RNN)이 훨씬 잘 작동함을 보게 될 것이다.

데이터셋 준비

독일 예나(Jena)시에 위치한 막스-플랑크(Max-Planck) 생지화확(Biogeochemistry) 연구소가 수 년동안 온도, 기압, 풍향 등 14 종류의 기상 데이터를 10분 단위로 측정해서 수집한 데이터셋이다. 원래 2003년부터 측정하였지만 여기서는 2009-2016년 데이터만 이용한다.

zip 파일 다운로드 및 압축풀기

"jena_climate_2009_2016.csv" 파일이 생성된다.

예나(Jena) 날씨 데이터셋 살펴보기

파일을 열어 줄(line) 단위로 쪼갠다.

첫째 줄은 날짜와 시간 이외에 14개의 특성명이 쉼표(콤마)로 구분되어 있으며, 총 420,451개의 데이터를 포함한다.

첫째 데이터는 2009년 1월 1일 0시 10분에 측정되었다.

2번 인덱스 항목이 섭씨 온도이다.

넘파이 어레이로 변환

온도 변화 그래프

처음 10일동안의 온도 변화

한 시간에 6번, 하루 24시간, 10일동안 측정 횟수는 6 * 24 * 10 = 1,440이다.

주기성(periodicity)은 시계열 데이터의 기본 특성 중 하나이다. 월별 주기성은 매우 일관성을 갖는다. 지난 몇 달동안의 데이터를 이용하여 다음 달의 평균 온도를 예측하는 일은 상대적으로 쉽다. 반면에 일 단위의 예측은 아래 그래프에서 보듯이 훨씬 혼잡하다.

훈련셋, 검증셋, 테스트셋 크기

미래에 대한 예측을 실행하므로 훈련셋, 검증셋, 테스트셋 순으로 보다 오래된 데이터를 사용한다.

데이터 전처리

시계열 데이터를 전처리 하려면 해결해야 할 문제를 명확히 지정해야 한다. 여기서는 지난 5일치의 날씨 데이터를 이용하여 앞으로 24시간 후의 온도를 예측하는 모델을 구현하고자 한다. 따라서 이 목적을 위한 시계열 데이터의 입력 샘플은 지난 5일치의 날씨 데이터를 하나의 시퀀스로 묶은 데이터이고, 타깃은 해당 시퀀스보다 24시간 앞선 데이터의 온도이어야 한다.

5일 단위의 시퀀스와 타깃을 정하기 전에 먼저 기존 데이터셋을 정규화 한다. 즉, 특성별로 평균은 0, 표준편차는 1로 변환한다.

주의사항: 훈련셋의 평균값과 표준편차를 이용하여 모든 데이터셋을 정규화해야 한다. 앞서 언급한 것처럼 시계열 데이터의 훈련셋은 이른 시점에서의 데이터를 활용한다.

데이터 정규화

5일 단위 시퀀스 데이터 준비

앞서 언급한 문제의 해결을 위한 모델을 구현하려면 5일 단위 시퀀스 데이터를 준비해야 하지만 timeseries_dataset_from_array() 함수를 활용하면 아주 쉽게 해결된다. 함수에 사용된 인자의 역할은 다음과 같다.

생성된 새로운 데이터셋은 훈련셋의 샘플과 타깃을 함께 배치 단위로 묶여있다. 예를 들어, 훈련셋의 첫째 배치의 모양은 다음과 같다.

참고: timeseries_dataset_from_array() 활용법

아래 코드는 넘파이 어레이를 이용하여 timeseries_dataset_from_array() 함수의 작동법을 설명한다.

길이가 3인 시퀀스 샘플을 2개씩 묶은 배치 3개가 만들어진다.

배치 별 샘플과 타깃을 확인하면 다음과 같다.

베이스라인 설정

모델 성능의 최저 기준선으로 24시간 후의 온도를 현재 온도로 예측하는 것을 사용한다. 즉, 내일 이 시간 온도가 현재 온도와 별 차이가 없다는 가정을 이용한다. 그러면 검증셋과 테스트셋에 대한 평균절대오차는 각각 2.44와 2.62이다.

밀집 연결 모델 성능

밀집층만을 사용하는 모델의 성능은 베이스라인과 비슷하게 나온다.

학습과정을 그래프로 나타내면 다음과 같다. 진동에도 불구하고 베이스라인에 가까운 성능이 나오지만 하루 사이에 온도가 그리 급격히 바뀌지 않는다는 베이스라인 모델에 사용된 직관이 활용된 것 같아 보이지는 않다.

1D 합성곱 신경망 모델 성능

Conv1D 층은 Conv2D 층에서 사용된 필터 개념을 1차원 텐서에 대해 동일한 방식으로 적용한다. MaxPooling1D 층 또한 MaxPooling2D와 동일한 방식으로 작동한다.

아래 모델은 Conv1DMaxPooling1D 층을 이용한 합성곱 신경망 모델을 온도 예측에 활용한 결과를 보여준다.

학습과정을 그래프로 나타내면 매우 실망스러운 결과를 확인하게 된다.

간단한 순환 모델 성능

가장 간단한 순환 신경망 모델이더라도 베이스라인보다 좋은 성능을 보여준다는 것을 확인할 수 있다.

학습과정을 그래프로 나타내면 다음과 같으며, 드디어 베이스라인보다 (조금이나마) 좋은 성능을 보인다.

10.3 순환 신경망 이해

순방향 신경망

밀집 연결 모델은 시퀀스 샘플을 모두 풀어서 시퀀스 내의 순서를 무시한다. 합성곱 신경망 모델은 시퀀스 샘플을 통으로 하나의 값으로 처리하면서 시퀀스에 포함된 값들 사이의 순서 특성을 제대로 활용하지 못한다. 즉, 두 모델 모두 모델에 입력된 이전 샘플의 정보를 이후 샘플이 전혀 활용하지 못하고, 하나의 샘플이 입력되면 바로 변환하고 다음 층으로 전달한다. 이런 이유로 밀집 연결 모델과 합성곱 신경망과 같이 작동하는 모델을 순방향 신경망(feedforward network)라 부른다.

순환 신경망(recurrent neural network)

순환 신경망 모델은 시퀀스을 한 번에 처리하는 대신 포함된 항목들을 차례대로 처리할 때마다 얻은 정보를 바로 다음 층에 그대로 전달하지 않고 다음 항목을 처리할 때 함께 활용한다. 즉, 아래 그림이 보여주듯이 시퀀스 샘플을 항목에 대한 일종의 반복작업(loop)으로 처리하며, 하나의 항목을 처리할 때 이전 항목을 처리한 결과를 활용한다.

시퀀스 항목을 하나 처리할 때마다 다음 항목에 활용되는 정보를 상태(state)라 부른다. 상태는 하나의 시퀀스를 처리할 때마다 초기화되며, 이런 식으로 순환 신경망의 입력값은 시퀀스 샘플 단위로 처리된다.

그림 출처: Deep Learning with Python(Manning MEAP)

SimpleRNN 층 작동법

앞서 설명한 순환 신경망 아이디어를 가장 간단하게 구현한 모델이며 작동과정은 아래 그림과 같다.

그림 출처: Deep Learning with Python(Manning MEAP)

케라스 순환층 기본 사용법

순환층은 임의의 길이의 시퀀스를 처리할 수 있다.

하지만 일정한 길이의 시퀀스만을 다룬다면 시퀀스 길이(steps)를 지정하는 것이 좋다. 이유는 모델을 구성한 후에 summary() 메서드를 활용하여 모델 훈련과정에 변환되는 텐서들의 모양을 정확히 추적할 수 있기 때문이다.

순환층의 출력값은 층 생성자의 return_sequences 키워드 인자의 값에 따라 시퀀스의 마지막 항목에 대한 출력값만 출력할지를 지정한다.

순환층 또한 스택으로 쌓을 수 있다.

LSTM 층 작동법

SimpleRNN 층은 실전에서 거의 사용되지 않는다. 이유는 이론과는 달리 시퀀스 내의 초기 상태(state)가 제대로 전달되지 않기 때문이다. 이 또한 역전파 과정에서 그레이디언트 소실이 발생하기 때문이다. 이에 대한 해결책으로 잔차 연결과 유사한 아이디어가 적용된 LSTM(Long Short Term Memory) 층이 1997년에 제시되었다.

LSTM 층은 아래 그림에서 보듯이 장단기 메모리 모두 항목의 훈련에 활용된다.

그림 출처: Deep Learning with Python(Manning MEAP)

참고: c_t 계산에 사용되는 값들의 의미와 기능 확정적이지 않기에 세세한 내용 보다는 장단기 메모리가 순환층에서 어떻게 활용되는가에 대한 기본적인 이해가 중요하다.

10.4 순환 신경망 고급 활용법

순환 신경망의 성능을 끌어 올리는 세 가지 기법을 소개한다.

순환 드랍아웃 적용

앞서 한 개의 LSTM 층을 사용한 모델 훈련은 매우 빠르게 과대적합이 발생했다. 과대적합 발생을 늦추기 위해 드랍아웃 기법을 순환층에 대해서도 효율적으로 적용할 수 있음이 2016년에 밝혀졌다.

아래 코드는 LSTM 층에 recurrent_dropout=0.25 옵션을 사용해서 모델을 훈련한다.

주의사항: 아래 코드를 실행하면 이전보다 훈련시간이 훨씬 오래 걸린다. 단순히 에포크 수가 늘어나서가 아니라 하나의 에포크에 걸리는 시간이 몇 십배 느려진다. 이유는 드랍아웃을 사용하는 LSTM, GRU 모델은 cuDNN에서 제대로 지원되지 않는다. 이유는 순환층에 사용되는 for 반복문이 기본 설정에 대해서만 최적화되었기 때문이다. 기타 옵션을 사용하는 경우 unroll=True 옵션을 사용하면 제한적(타임스텝이 100 이하로 지정된 경우)으로 cuDNN을 잘 활용할 수 있다. 사용법은 다음과 같다.

inputs = keras.Input(shape=(sequence_length, num_features))
x = layers.LSTM(32, recurrent_dropout=0.2, unroll=True)(inputs)

학습과정을 그래프로 나타내면 다음과 같으며, 과대적합이 20 에포크 이후에 발생함을 확인할 수 있다. 동시에 모델의 성능도 좋아졌다.

그림 출처: Deep Learning with Python(Manning MEAP)

순환층 쌓기

순환층으로 스택으로 쌓아서 활용할 수도 있다. 아래 모델은 LSTM의 변종이면서 좀 더 가벼운 GRU(Gated Recurrent Unit) 층을 사용한다. 마지막 순환층을 제외한 모든 순환층에서 return_sequences=True 옵션을 지정해야 함에 주의해야 한다.

학습과정을 그래프로 나타내면 다음과 같으며 모델의 성능이 좀 더 좋아졌다. 하지만 층을 더 이상 쌓는다고 해서 성능이 반드시 더 좋아진다는 보장은 없으며 오히려 나빠질 수도 있다.

그림 출처: Deep Learning with Python(Manning MEAP)

양방향 RNN 적용

자연어 처리(NLP, Natural language processing) 등에서는 한쪽 방향으로 뿐만 아니라 반대 방향으로 시퀀스의 타임스텝을 처리하는 과정을 동시에 진행하는 양방향 RNN(bidirectional RNN) 층이 매우 효율적으로 적용된다.

그림 출처: Deep Learning with Python(Manning MEAP)

하지만 날씨 예측 등과 같이 시간의 순서가 결정적인 경우에는 별 도움되지 않음을 아래 코드를 통해 확인할 수 있다.

성능 최대한 끌어올리기

모델의 성능을 끌어 올리는 기본적인 접근법은 다음과 같다.