이번 강의에서는 합성 시계열 데이터가 아닌 실제 흑점 데이터를 기반으로 해서 시계열 예측 모델 신경망 모델을 구축한다.
저번에는 단순 RNN, LSTM을 기반으로 신경망을 구축했다면,
이번에는 Convolution에 LSTM을 조합하는 신경망을 구축한다.
실제 데이터를 기반으로 딥러닝 모델을 구축한다.
여기서는 32개의 필터를 학습할 Conv1D로 1차원 컨볼루션이다.
다섯 개의 숫자로 구성된 window에 필터의 값을 구한다.
https://www.coursera.org/programs/learning-program-qth60/my-learning?myLearningTab=IN_PROGRESS
convolution에 관련된 자세한 강의는 위의 강의를 참고하면 된다.
LSTM의 입력값을 재구성하는 Lambda layer가 없어졌다는 것이다.
여기서는 Conv1D의 input_shape를 명시하고 있다.
기존에 작업한 windowed_dataset 헬퍼 함수를 사용한다.
컨볼루션 및 LSTM 기반 신경망으로 아래와 같은 플로팅이 가능하다.
10^-5쯤에서 최저값을 기록한 다음에 그 이후로는 살짝 불안정해진다.
저 값을 이상적인 학습률이라고 가정한다.
옵티마이저에서 학습률을 1e-5로 정의한다.
500 epochs 만큼 학습하면 아래와 같은 플로팅이 가능하다.
솟아오르는 부분도 없고 이전보다 훨씬 개선되었지만 아직 데이터와 크게 관련성이 없다. 노이즈로 인한 심한 변동폭이 보인다.
MAE는 5 아래이지만 첫 번째 정점을 제외하면 훨씬 낮아질 수 있다.
한 가지 솔루션은 더 오래 학습하는 것이다
MAE 손실곡선이 500 epoch 이후 평평해 보이긴 하지만,
확대 해보면 오른쪽과 같이 천천히 감소하는 것이 보일 것이다.
느리지만 학습이 되고 있다는 것이다.
이러한 LSTM을 양방향으로 만드는 방법이 있는데,
Bi-directional LSTM을 사용하는 것이다.
MAE 값도 매우 낮고 때로는 1미만이다.
그러나 검증 세트에 예측을 플로팅해보면 과적합이 나오고,
개선된 부분이 보이지 않는다.
과적합을 피하기 위해서 일부 파라미티에 변화를 줘야 한다.
MAE 로 손실을 플로팅하면 몇 가지 문제를 눈으로 쉽게 파악할 수 있다.
노이즈가 많고 불안정성이 많다. 살짝 삐죽삐죽한 이유는 배치 크기가 작아서 무작위 노이즈가 많기 때문이다.
아래에서 배치와 경사하강법에 대한 강의를 참고하면 좋다.
배치 크기를 살펴보면서 데이터에 적합하게끔 만드는 것이 중요하다.
이 경우라면 다른 배치 크기를 실험해 보는 것이 좋다.
원래 32 보다 크거나 작게 다양한 배치 크기를 실험해 보는 것이다.
16을 시도 했을 때 검증 세트에 이러한 경향이 나타났다.
훈련 및 MAE 데이터에도 변화가 나타났다.
CNN과 LSTM을 조합하면 다듬어야 하긴 하지만 지금까지 만들었던 것 중에서 가장 좋은 모델을 만들 수 있다.
https://www.youtube.com/watch?v=4qJaSmvhxi8
1749년 부터 2018년의 흑점을 추적한 자료이다.
흑점은 계절별 주기가 있고, 약 11년 주기로 반복된다.
이 데이터를 가지고 예측하는 것이다.
csv 데이터 세트로 첫 번째 열은 인덱스, 두번쨰 열은 연월일 순의 날짜, 세 번째 열은 측정을 했던 달의 날짜이다. 해당 월 말에 확인되는 월간 평균치이다.
colab 에서 사용한다면 위의 코드를 통해서 해당 데이터를 다운 받을 수 있다.
csv 파일을 확인하고, 흑점과 시간 단계의 목록으로 데이터를 확보한다.
csv 라이브러리를 불러오고 파일을 열어 본다.
next(reader)로 row와 reader를 반복시킨다.
첫 번째 라인을 읽고 버리는 역할인데, 파일 첫 번째 줄에는 열 제목이 있기 때문이다.
이제 reader를 통해 파일을 라인별로 읽는다.
흑점 컬러는 2번째 열에 있고 이것을 float로 변환한다.
파일을 읽을 때 모든 항목은 string으로 읽히게 되고,
후에 목록을 통해 반복하는 대신 변환할 수 있다.
다음으로 시간 단계를 정수로 읽는다.
해당 데이터들을 numpy 배열로 바꾼다.
리스트를 numpy 목록으로 바꾸는데,
throw away 리스트로 데이터를 구축하고 numpy 배열로 바꾼다.
numpy에 항목을 추가할 때마다 list를 복사하면서 메모리 관리 과정이 많이 진행되므로, 데이터 양이 많으면 느려질 수 있따.
데이터를 플로팅하면 아래와 같다.
이 데이터는 계절성이 있지만 더 크게 솟아오른 부분도 있는 만큼 규칙적이라고 보기에는 어렵다.
노이즈도 많지만 전체적인 추세는 없다.
이전과 마찬가지로 시계열을 훈련 및 검증 데이터 세트로 분할한다.
시간은 1000으로 분할하고 window_size는 20 ,
batch_size는 32 , shuffle_buffer_size 는 1000이다.
아래의 windowed_dataset 해당 함수로 훈련이 가능한 데이터 세트로 전환한다.
2주차에 훈련을 위해 다뤘던 단순 DNN의 결과는
아래와 같은 차트가 나오고 시각화 했을 때는 괜찮지만
MAE 수치가 너무 크다.
결과를 확대해보면 원본 데이터에서 예측이 어떻게 나오는지 자세히 살펴볼 수 있다.
문제를 해결할 단서는 winodw_size이다.
위에서는 훈련 창 크기를 20개의 시간 슬라이드로 잡았는데,
각각의 시간 슬라이스는 현실로는 한달이다. 여기서의 창은 2년이 약간 안되는 것이다.
하지만 이 차트를 보면 흑점의 계절성은 2년이 훨씬 넘는다.
11년에 가깝다. 사실 일부 과학자들은 서로 다른 주기가 얽히면서 22년의 주기일 수도 있다고 본다.
window_size 를 11년에 해당하는 132에 두고 다시 훈련한다면?
이 차트가 상당히 비슷해보이지만 MAE는 더 나빠져서,
창 크기를 높이는 것으로는 해결이 되지 않는 다는 것을 알 수 있다.
데이터를 되돌아보면 11년 주기의 계절성을 갖지만
창 안에 계절 전체가 있어야 할 필요가 없다.
데이터를 다시 확대해보면 전형적인 시계열 같은 모습이 보인다.
여기에 오는 값이 앞선 값과 연관이 있지만 노이즈가 많다.
그래서 훈련 시에 창 크기가 클 필요는 없을 수도 있다.
초기의 20과 비슷한 수준이어도 괜찮을 것이다.
윈도우 사이즈를 30으로 변경한다.
split_time은 데이터 세트에 3,500개의 데이터가 있는데 1000을 훈련으로 2500을 검증으로 설정하면, 좋지 못한 분할이다. 훈련 데이터가 부족하다.
다시 훈련하고 플로팅하면 MAE가 15로 개선되었다.
신경망 설계와 파라미터 크기를 변경해보자.
10, 10, 1개의 뉴런이 있는 3개의 레이어를 활용했는데,
input_shape가 30보다 더 커졌다.
30, 15, 1로 바꿔서 다시 훈련해본다.
다시 10,10,1로 되돌리고 학습한다.
그리고 학습률을 수정해본다.
다시 학습하니 MAE가 낮아진다.
창 크기는 30이고 데이터 세트는 3,235개가 있다.
데이터 세트가 종료된 후 다음 값을 예측하고 싶다면 해당 코드를 사용한다.
결과는 7.0773993
2018년 8월에는 7.077개의 흑점을 예상한다.
관측 자료에서 데이터 세트와는 약간 다른 데이터이긴 하지만,
실제로 2018년 8월에 기록된 흑점의 개수는 8.7개이다.
예측이 나쁘지 않지만 이를 좀 더 개선해보자.
이 설정애서 MAE를 13.75까지 낮추고, 예측은 8.13이 나와 실제값인 8.7과 비슷해졌다.
모델 생성 시 무작위 요소가 있어서 결과가 서로 다를 수 있다.
이처럼 단일 예측을 기반으로 정확성을 측정하는 것도 실망스러운 결과가 나올 수 있어, 여러 개의 값으로 평균을 내는 것이 좋다.
여기서는 DNN을 활용해 흑점을 예측했고 약간 조정하는 것으로 MAE가 내려갔다. 이 모델로 다음 달의 값을 예측하려 한다면 실제 값과 상당히 가까워진다.
이제 모든 도구를 활용해서 머신러닝을 활용해 괜찮은 예측 코드를 살펴본다.
먼저 첫 번째 코드이다.
배치 사이즈는 64, 윈도우 사이즈는 60,
32개의 필터를 학습하는 1D 컨볼루션이다.
출력값은 각각 32개의 셀을 갖춘 몇 개의 LSTM이 될 것이다.
DNN에 넣기 전 30, 10, 1개의 뉴런으로 나오게 된다.
마지막으로 숫자가 1~400 범위에 있어 x를 400배 해주는 Lambda 레이어도 있다.
첫 번째 테스트 실행 시에 최적의 학습률을 찾아내면 아래의 차트가 나온다.
여기서는 해당 네트워크의 최적 학습률은 10^-5라는 것이다.
이 설정으로 500 epochs를 훈련하면 MAE도 낮고 괜찮은 결과가 나온다.
그러나, 훈련 도중의 손실 함수를 찾아보면 노이즈가 많다.
즉 최적화의 여지가 있다는 것이다.
이 때 수정해볼 수 있는 것이 배치 사이즈이다.
이것을 256으로 높인 다음 다시 훈련해본다.
500 에포크 후에 예측치가 좀 더 나아졌다.
올바른 방향에 가까워 진것이다.
훈련 노이즈는 훈련 말미에 가면 노이즈가 많아진다.
그러나 상당히 규칙적인 파동이다.
즉, 배치 크기를 올린 것은 좋은 생각이었지만 살짝 벗어난 결과이다.
그렇게 변동 폭이 아주 작아서 나쁜 결과는 아니다.
하지만 손실을 조금 균일화 할 수 있으면 더 좋을 것이다.
다른 것을 시도해봐서, 훈련 데이터에는 3,000개의 데이터가 있다.
그렇다면 윈도우 사이즈와 배치 사이즈를 거듭 제곱시켜서
3,000으로 균일하게 나뉘지 않도록 해보자.
파라미터를 윈도우 사이즈와 배치 사이즈에 맞춰 변화시키는 것이 아니라
필터도 변경해보자.
필터를 60으로 변경하고 LSTM도 60으로 변경해본다.
DNN은 나쁘지 않아보이니 그대로 둔다.
그 후에 500 에포크 만큼 훈련하면
흥미로운 점은 노이즈와 손실함수가 약간 증가한것이다
그렇다면 배치사이즈를 100으로 낮춰서 다시 실험해본다.
여기서는 MAE가 약간 증가했다.
앞선 결과보다 정점 부분에서는 더 나은 결과가 나왔지만
전체적인 정확도가 떨어졌다.
일시적으로 나타나는 큰 폭의 변화 외에는 손실이 매끄럽게 다듬어졌다.
이런 하이퍼 파라미터를 실험하는 것은 머신러닝의 입력값 및 출력값을 학습할 수 있는 좋은 방법이다.