Sequences, Time Series and Prediction - 03. Recurrent Neural Networks for Time Series
Recurrent Neural Networks for Time Series
Intro
- Recurrent Neural Networks 와 Long Short Term Memory Networks 는 시계열 데이터의 예측과 분류에 매우 유용함
- Lambda Layer : 신경망 내 임의의 코드를 레이어로 활용할 수 있음 (전처리와 후처리)
- 명시적인 전처리 단계로 데이터를 스케일링한 다음 신경망에 넣는 게 아니라 Lambda 레이어를 사용할 수 있음
Conceptual overview
- RNN : 순환 레이어를 포함한 신경망
- 시퀀스 입력값을 순차적으로 처리하도록 설계
- 입력값의 형태 : 배치 사이즈, 타임스탬프 (윈도우사이즈), 컬럼디멘전 (다변량) = 3차원
- 지금까지 사용한 입력값 형태 : 배치 사이즈, 입력값 특징 수 (윈도우 사이즈)
- RNN Cell
- 겉으로 보기에는 셀이 많은 것 같지만, 셀은 하나 뿐이고 이를 반복적으로 사용하여 출력값을 산출
- 입력값이 2개 (X 값과 상태벡터 H 값) - 상태벡터값을 이용해 이전 입력값의 잔존 데이터를 전달받음
- 입력차원 (예: 타임스탬프가 30개) 만큼 반복
RNN Notebook
- jupyter notebook 자료
Shape of the inputs to the RNN
- 데이터의 형태, 데이터를 분할한 배치
- 예시
- Window size 가 30 : 시간 단계가 30
- 4개로 일괄 처리 : 배치값 4
- 입력 형태는 4 * 30 * 1
- 셀의 관점
- 하나의 셀은 고정된 시간 단계에서 (Batch Size : 4 * 1) 의 입력을 받음
- 레이어 내 메모리셀이 3개의 뉴런으로 구성된다면
- 출력값 행렬은 4 * 3
- 출력 형태는 4(Batch Size) * 30(Window Size) * 3(Unit Size)
- 단순 RNN 에서의 상태 출력값 H 는 출력값 행렬 Y 와 동일함
- 일부 경우에는 시퀀스를 입력하되, 출력값의 경우 배치 내 각 인스턴스에 대한 단일 벡터를 얻고 싶은 경우가 있음
- 마지막 (마지막 시퀀스 스텝-Window) 을 제외하고 모든 출력값을 무시
- 시퀀스 출력값을 도출하려면 레이어를 생성할 때 return_sequences 를 True 로 지정해야 함
- 하나의 RNN 레이어를 다른 레이어 위에 스태킹 할때 이 작업이 반드시 필요
- 예시
Outputting a sequence
-
적층 예시
model = tf.keras.models.Sequential([ tf.keras.layers.SimpleRNN(40, return_sequences=True, input_shape = [None,1]), tf.keras.layers.SimpleRNN(40), tf.keras.layers.Dense(1), ])
- 타 RNN 레이어에 입력으로 들어가야 하는 RNN 레이어에 return_sequences 를 True 로 설정
- Dense 레이어에 입력으로 들어가야 하는 RNN 레이어는 마지막 시퀀스 단계의 결과값만을 출력
- input_shape (배치 사이즈) 를 설정하지 않음 : 어떤 크기든 상관이 없으니 정의할 필요가 없음
- Timestamp 값을 None 으로 설정 : 시퀀스 길이와 관계 없이 입력값을 받음
- 마지막 차원이 1로 되어있는 이유 : 일변량 시계열을 다루기 때문
- 두번째 층 RNN 레이어에 return_sequences 값을 True 로 설정할 경우
- 시퀀스 값이 출력됨
- Keras 는 각 시간 단계별로 동일한 Dense 레이어를 독립적으로 활용함
- 입력값이 시퀀스이고 출력값 또한 시퀀스일 경우 : 시퀀스 to 시퀀스 RNN
- 차원의 값은 RNN 레이어의 유닛 값에 따라 변동될 수 있음
Lambda layers
-
예시
model = tf.keras.models.Sequential([ tf.keras.layers.Lambda(lambda x: tf.expand_dims(x, axis=-1), input_shape=[window_size]), tf.keras.layers.SimpleRNN(40, return_sequences=True), tf.keras.layers.SimpleRNN(40), tf.keras.layers.Dense(1), tf.keras.layers.Lambda(lambda x: x * 100.0) ])
- 첫 lambda 레이어
tf.expand_dims(x, axis=-1)
: 기존 window 생성 function 을 그대로 활용하기 위해 차원을 하나 늘림 (2차원->3차원) - 마지막 lambda 레이어
lambda x: x * 100.0
: RNN 의 기본 활성함수 tanh 의 출력값 -1 ~ 1 > 시계열 값은 10개 단위로 구성되고, 비슷한 값으로 출력값을 올리면 학습에 도움이 됨
- 첫 lambda 레이어
Adjusting the learning rate dynamically
-
예시
train_set = windowed_dataset(x_train, window_size, batch_size=128, shuffle_buffer=shuffle_buffer_size) model = tf.keras.models.Sequential([ tf.keras.layers.Lambda(lambda x: tf.expand_dims(x, axis=1), input_shape=[None]), tf.keras.layers.SimpleRNN(40, return_sequences=True), tf.keras.layers.SimpleRNN(40), tf.keras.layers.Dense(1), tf.keras.layers.Lambda(lambda x: x * 100.0) ]) lr_schedule = tf.keras.callbacks.LearningRateScheduler(lambda epoch: 1e-8 * 10**(epoch / 20)) optimizer = tf.keras.optimizers.SGD(learning_rate=1e-8, momentum=0.9) model.compile(loss=tf.kears.losses.Huber(), optimizer=optimizer, metrics=["mae"]) history = model.fit(train_set, epochs=100, callbacks=[lr_schedule])
- callback 함수를 활용, epoch 진행 별로 학습률을 약간 변경
- Huber 손실함수 : 이상치에 덜 민감하게 반응하는 손실함수, 데이터에 노이즈가 많이 섞여있을 때 시도해볼만 함
- squared error loss 보다 이상치에 덜 민감함
LSTM
- RNN
- X 가 셀에 투입되면 Y 결과값과 H 상태벡터가 출력되고, 이는 다음 셀에 영향을 줌
- Step 이 진행되면서 초기 H 상태벡터의 영향도는 점점 작아짐
- LSTM
- 전체 훈련 기간 동안 상태를 유지해주는 셀 상태를 추가함
- 상태 값이 셀 간에 이동을 하고 Step 사이를 이동하면서 더 잘 유지될 수 있게함 - 앞 단계에 있던 데이터가 전체 추정치에 더 큰 영향을 줌
- 상태는 양방향으로 움직일 수 있음
Coding LSTMs
-
예시
tf.keras.backend.clear_session() dataset = windowed_dataset(x_train, window_size, batch_size, shuffle_buffer_size) model = tf.keras.models.Sequential([ tf.keras.layers.Lambda(lambda x: tf.expand_dims(x, axis=-1), input_shape=[None]), tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32)), tf.keras.layers.Dense(1), tf.keras.layers.Lambda(lambda x: x * 100.0) ]) model.compile(loss="mse", optimizer=tf.keras.optimizers.SGD(learning_rate=1e-6, momentum=0.9)) model.fit(dataset, epochs=100, verbose=0)
tf.keras.backend.clear_session()
: 내부 변수를 초기화. 이후 버전에 영향을 주지 않고 여러 모델을 시험해 볼 수 있음tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32))
: 32개 셀의 단일 LSTM 레이어 추가. 예측에 미치는 영향을 파악할 수 있도록 양방향으로 만듦
-
예시
tf.keras.backend.clear_session() dataset = windowed_dataset(x_train, window_size, batch_size, shuffle_buffer_size) model = tf.keras.models.Sequential([ tf.keras.layers.Lambda(lambda x: tf.expand_dims(x, axis=-1), input_shape=[None]), tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32, return_sequences=True)), tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32)), tf.keras.layers.Dense(1), tf.keras.layers.Lambda(lambda x: x * 100.0) ]) model.compile(loss="mse", optimizer=tf.keras.optimizers.SGD(learning_rate=1e-6, momentum=0.9)) model.fit(dataset, epochs=100, verbose=0)
tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32, return_sequences=True))
: LSTM 레이어를 한층 더 쌓음, retrun_sequences 를 True 로 설정해야만 함
댓글남기기