튜토리얼: 순환 신경망
이 튜토리얼에서는 순차 데이터와 시계열을 분류할 수 있는 순환 신경망(RNN, Recurrent Neural Network)을 소개하고, 날씨 예측을 위한 모델을 직접 구현합니다. 이 글은 AI 번역본입니다. 오역이 있을 경우 댓글로 알려주세요.
Created on September 15|Last edited on September 15
Comment
이 영상에서는 순차 데이터와 시계열을 분류하는 데 유용한 순환 신경망(RNN, Recurrent Neural Network)을 소개합니다.
프로젝트
https://github.com/lukas/ml-class/tree/master/projects/6-rnn-timeseries 에서 날씨 예측 RNN을 만들어 보세요
주제
- 시계열 데이터를 다루는 방법
- 데이터를 시계열 데이터로 변환하기
- RNN의 직관
- RNN 디버깅 방법
순환 신경망(RNN)
이 튜토리얼에서는 순환 신경망(RNN)과 시계열 데이터를 살펴보겠습니다. 앞으로의 영상에서는 이러한 RNN을 텍스트 데이터에 적용하는 방법도 보여 드릴 예정입니다.
시계열 데이터
우선, 시계열 데이터란 무엇일까요? 현실 세계의 데이터는 시간이 지나면서 변합니다. 예를 들어, 1949–1969년 항공기 판매량으로 유명한 이 데이터셋을 보면 전체적으로 상승하는 추세와 해마다 반복되는 주기가 있다는 것을 알 수 있습니다. 1960년의 항공사 매출을 정확히 예측하려면 시간에 따른 추세를 반영할 수 있는 방법이 필요합니다.

1949–1969년 항공사 매출 데이터셋
그렇다면 시간이 흐르며 생성된 이 데이터를 어떻게 머신러닝 API에 맞게 변환할 수 있을까요(고정 길이의 입력과 고정 길이의 출력)? 아주 단순하면서도 효과적인 방법인 슬라이딩 윈도우를 사용합니다. 크기가 고정된 윈도우를 예를 들어 10개 요소로 잡고, 이를 학습 데이터의 첫 번째 행에 넣습니다. 이 10개 요소로부터 11번째 요소를 예측하는데, 이를 레이블이라고 부릅니다. 그런 다음 윈도우를 계속 한 칸씩 옮겨가며 반복하면, 이 시리즈의 첫 번째 튜토리얼에서 했던 것과 같은 방식으로 퍼셉트론에 입력할 수 있는 데이터셋을 얻게 됩니다.

슬라이딩 윈도우는 시계열 데이터를 머신러닝 API 형식으로 변환합니다
코드
ml-class의 time series 디렉터리로 이동한 뒤 perceptron.py를 여세요. 이 코드는 시계열 데이터를 준비해 퍼셉트론에 입력합니다. 함께 코드를 살펴보겠습니다.

perceptron.py의 코드
순환 신경망
간단한 퍼셉트론으로도 꽤 좋은 정확도를 얻었지만, 순환 신경망(RNN)을 사용하면 더 향상시킬 수 있습니다. RNN이 퍼셉트론보다 나은 점은 무엇일까요? 핵심 차이는 시간의 인과성입니다. 이전 퍼셉트론의 20개 입력을 뒤섞어도 예측에는 영향을 주지 않습니다. 하지만 그래프만 봐도 그 20개 사건의 순서가 중요하다는 것을 알 수 있습니다. RNN은 입력의 순서를 고려하므로, 특히 더 큰 데이터셋에서 그 중요성이 커집니다.
순환 신경���은 일반적으로 밀집 신경망과 동일한 형태의 입력을 받습니다. 즉, 시간에 따른 숫자 벡터를 입력으로 받아 하나의 숫자 또는 숫자 벡터를 출력합니다. 차이점은 내부 상태를 유지하고, 이 상태를 시점 간에 전달한다는 점입니다.

RNN 다이어그램
그렇다면 RNN 내부에서는 무엇이 일어날까요? RNN은 숫자 목록(예: 1, 3, 4, 7)을 입력으로 받고, 각 시점마다 상태를 전달하며 동시에 그 상태를 출력합니다. 여기서 상태는 단일 숫자입니다. 이 도식의 두 번째 단계에서는 네트워크가 입력 3과 이전 셀에서 전달된 상태 0.4를 함께 받습니다. 이 두 입력을 사용해 네트워크는 퍼셉트론 계산, 즉 가중합과 쌍곡탄젠트 활성화 함수를 수행한 뒤 단일 숫자 0.9를 출력합니다. 이 출력은 해당 셀의 출력이자 다음 셀로 전달되는 상태가 됩니다. 동일한 계산을 윈도우 길이에 맞춰 10번(또는 윈도우 길이만큼) 반복한 뒤, 마지막 출력을 레이블의 예측값으로 사용합니다.

RNN 내부: 다음 상태 계산
쌍곡탄젠트 활성화 함수란 무엇인가요?
쌍곡탄젠트 활성화 함수는 시그모이드와 유사하게 동작하지만, 값의 범위가 0에서 1이 아니라 -1에서 1입니다.
퍼셉트론에서와 마찬가지로 동일한 튜닝을 수행합니다. 즉, 우리가 원하는 출력이 나오도록 최적의 매개변수 집합을 구하기 위해 역전파를 수행합니다.
이제 코드를 통해 확인해 봅시다. RNN.py를 열어 보세요. 전반적으로는 거의 동일하지만, 이전에 입력을 평탄화해 밀집 레이어에 넣던 62행과 63행에서 이제 간단한 RNN 레이어를 추가합니다:
// line 62model.add(SimpleRNN(1, input_shape=(config.look_back, 1)))
첫 번째 1은 각 시점의 출력과 상태가 1차원 수(단일 스칼라)임을 의미합니다.
RNN 디버깅
첫 번째 1은 각 시점의 출력과 상태가 1차원 수(단일 스칼라)임을 의미합니다. rnn.py를 실행해 보면, 이 모델은 퍼셉트론보다 훨씬 성능이 떨어집니다. 무언가 제대로 작동하지 않는 것 같습니다. 모델을 디버그해 봅시다.
우리 모델의 성능이 나쁜 이유는 셀에서 셀로 단 하나의 숫자만 전달해서는 데이터의 패턴을 학습하기에 충분하지 않기 때문입니다. 상태로서 단일 숫자 하나가 아니라 더 많은 정보를 전달해야 합니다. 대신 5개의 숫자로 이루어진 벡터를 전달해 봅시다. 코드에서 62행을 다음과 같이 변경하세요:
// line 62model.add(SimpleRNN(5, input_shape=(config.look_back, 1)))
이제 모델은 시간 상태를 인코딩하기 위해 5개의 숫자를 전달합니다. 그런데 잠깐만요—출력은 상태와 동일하므로 상태 차원을 5로 늘리면 출력도 5개의 숫자가 됩니다. 하지만 우리가 예측하려는 라벨은 하나의 숫자입니다. 따라서 5개 숫자로 된 출력을 단일 숫자로 변환하기 위해 마지막에 밀집 레이어 퍼셉트론을 추가합니다.

다차원 상태/출력을 갖는 RNN
63행에 밀집 레이어를 추가하세요:
// line 63model.add(Dense(1, activation=’sigmoid’))
이제 완전하게 동작하는 RNN이 준비되었습니다.
Add a comment