Sequences, Time Series and Prediction - 04. Real-world time series data
Real-world time series data
Intro
- 실사용 데이터 (태양의 흑점활동) 이용하기
- Conv1D, LSTM, DNN 을 결합한 모델을 활용할 것
Convolutions
-
예시
model = tf.keras.models.Sequential([ tf.keras.layers.Conv1D(filters=32, kernel_size=5, // 32개의 필터를 학습할 1D Conv strides=1, padding="casual", activation="relu", input_shape=[None, 1]), tf.keras.layers.LSTM(32, return_sequences=True), tf.keras.layers.LSTM(32), tf.keras.layers.Dense(1), tf.keras.layers.Lambda(lambda x: x * 200) ]) optimizer = tf.keras.optimizers.SGD(learning_late=1e-5, momentum=0.9) model.compile(loss=tf.keras.losses.Huber(), optimizer=optimizer, metrics=["mae"]) model.fit(dataset, epochs=500)
Bi-directional LSTMs
-
예시
model = tf.keras.models.Sequential([ tf.keras.layers.Conv1D(filters=32, kernel_size=5, strides=1, padding="casual", activation="relu", input_shape=[None, 1]), // LSTM 의 입력값을 재구성하는 Lambda 레이어를 없앰 tf.keras.layers.LSTM(32, return_sequences=True), tf.keras.layers.LSTM(32), tf.keras.layers.Dense(1), tf.keras.layers.Lambda(lambda x: x * 200) ]) optimizer = tf.keras.optimizers.SGD(learning_late=1e-5, momentum=0.9) // 플로팅한 결과 불안정해지기 전의 학습률 model.compile(loss=tf.keras.losses.Huber(), optimizer=optimizer, metrics=["mae"]) model.fit(dataset, epochs=500) // epoch 늘리기
-
windowed_dataset 헬퍼 함수
def windowed_dataset(series, window_size, batch_size, shuffle_buffer): ds = tf.data.Dataset.from_tensor_slices(series) ds = ds.window(window_size + 1, shift=1, drop_remainder=True) ds = ds.flat_map(lambda w: w.batch(window_size + 1)) ds = ds.shuffle(shuffle_buffer) ds = ds.map(lambda w: (w[:-1], w[-1])) return ds.batch(batch_size).prefetch(1)
-
Bi-directional LSTM
model = tf.keras.models.Sequential([ tf.keras.layers.Conv1D(filters=32, kernel_size=5, strides=1, padding="casual", activation="relu", input_shape=[None, 1]), 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 * 200) ]) optimizer = tf.keras.optimizers.SGD(learning_late=1e-5, momentum=0.9) // 플로팅한 결과 불안정해지기 전의 학습률 model.compile(loss=tf.keras.losses.Huber(), optimizer=optimizer, metrics=["mae"]) model.fit(dataset, epochs=500)
- 결과수치는 긍정적이나 검증세트에 예측을 플로팅 해보면 과적합이 보여 일부 파라미터에 변화를 줄 필요가 있음
- MAE 로 손실을 플로팅하면 문제점을 확인할 수 있음
- 스파이크 현상은 배치 크기가 작아서 무작위 노이즈가 많기 때문임
- 배치사이즈를 줄이거나 늘이는 것에 따라 학습과 예측이 달라짐
More on batch sizing
- 신경망을 더 빠르게 학습하도록 하는 최적화 알고리즘
- 머신러닝 : 잘 작동되는 모델을 찾기 위해 많은 훈련을 거쳐야 하는 반복적인 과정
- 모델을 빠르게 훈련시키는 것이 매우 중요함
- 딥러닝은 빅데이터에서 가장 잘 작동됨 -> 훈련이 어려움 (큰 데이터 세트에서 훈련하는 것은 매우 느린과정)
- 좋은 최적화 알고리즘을 찾는 것은 효율성을 향상시켜준다.
- 머신러닝 : 잘 작동되는 모델을 찾기 위해 많은 훈련을 거쳐야 하는 반복적인 과정
- 미니배치 경사 하강법
- 벡터화 : m개의 샘플에 대한 계산을 효율적으로 만들어줌. 명시적인 반복문 없이도 훈련 세트를 진행할 수 있도록 함.
- 훈련 샘플을 받아서 큰 벡터에 저장함
X = [x^1, x^2, ..., x^m]
: shape : (n_x,m)Y = [y^1, y^2, ..., y^m]
: shape : (1,m)- 하지만 m 의 수치가 크면 여전히 학습은 느리다.
- 예를들어 m 의 수치가 500만 이라면?
- 전체 훈련 세트에 대한 경사 하강법을 구현하면 경사 하강법의 작은 한 단계를 밟기 전에 모든 훈련 세트를 처리해야 함
- 즉, 경사하강법의 다음 단계를 밟기 전에 500만 개의 전체 훈련 샘플을 처리해야 함
- 500만 개의 전체 훈련 샘플을 모두 훈련하기 전에 경사 하강법이 진행되도록 하면 더 빠른 알고리즘을 얻을 수 있음
- 훈련 세트를 더 작은 훈련세트 (미니배치) 로 나눔
- mini-batch 가 1000개의 샘플을 갖는다고 가정
X = [x^1, x^2, ..., x^1000 | x^1001, ..., x^2000 | ... | ... x^m]
X = X^{1}, X^{2}, ... , X^{5000}
: shape : (n_x, 1000)Y = Y^{1}, Y^{2}, ... , Y^{5000}
: shape : (1, 1000)- Mini-batch t : X^{t}, Y^{t}
- 표기법 정의
x^(i)
: i 번째 훈련 샘플z^[l]
: l 번째 신경망의 z 값X^{t}
: t 번째 미니배치 X
- Batch Gradient Descent : 일반적인 경사하강법, 모든 훈련 세트를 동시에 훈련시킴, 훈련 샘플의 모든 배치를 진행시킨다는 관점
- 미니배치 : 전체 훈련 세트 X,Y 를 한번에 진행시키지 않고, 하나의 미니배치 X^{t}, Y^{t} 를 동시에 진행시키는 알고리즘
for t=1 ,..., 5000 : 총 미니배치의 수 (5000개) // 1 step of gradient descent using X^{t}, Y^{t} // (as if m=1000) // 모든 1000개의 샘플에 대해 명시적인 반복문을 갖는 것보다 벡터화를 사용해 모든 1000개의 샘플을 동시에 진행함 Forward prop on X^{t} Z^[1] = W^[1] * X^{t} + b^[1] : Vectorized Implementation (1000 examples) A^[1] = g^[1] * (Z^[1]) : Vectorized Implementation (1000 examples) ... A^[l] = g^[l] * (Z^[l]) : Vectorized Implementation (1000 examples) Compute cost J^{t} = 1/1000 * Sum (( i = 1 to l) Loss(expect(y^(i)), y^(i))) + 정규화 항 Backprop to compute Gradients cost J^(t) using X^{t}, Y^{t} W^[l] = W^[l] - adW^[l], b^[l] = b^[l] - adb^[l] ... 1 epoch : pass through training set (5000 개의 경사하강단계)
Convolutions with LSTM notebook
- Jupyter notebook 자료
Convolutions with LSTM
- Jupyter notebook 자료
Real data - sunspots
-
소스 내려받기 : 케글에서 내려받거나, 이번학습을 위한 데이터 제공 저장소를 사용 (후자)
!wget --no-check-certificate https://storage.googleapis.com/laurencemoroney-blog.appspot.com/Sunspots.csv -O /tmp/sunspots.csv
-
CSV 읽기
import csv time_step = [] sunspots = [] with open('/tmp/sunspots.csv') as csvfile: reader = csv.reader(csvfile, delimiter=',') next(reader) for row in reader : sunspots.append(float(row[2])) time_step.append(int(row[0]))
-
numpy 배열로 전환
series = np.array(sunspots) // numpy 에 항목을 추가할 때마다 목록을 복제하는데, time = np.array(time_step) // 메모리 관리 과정이 많이 진행되기 때문에 데이터 양이 많으면 느려질 수 있음
-
시계열을 훈련 및 검증 데이터 세트로 분할
split_time = 1000 time_train = time[:split_time] x_train = series[:split_time] time_valid = time[split_time:] x_valid = series[split_time:] window_size = 20 batch_size = 32 shuffle_buffer_size = 1000
-
이전 windowed_dataset 함수와 동일 코드를 사용
def windowed_dataset(series, window_size, batch_size, shuffle_buffer): dataset = tf.data.Dataset.from_tensor_slices(series) dataset = dataset.window(window_size + 1, shift=1, drop_remainder=True) dataset = dataset.flat_map(lambda window: window.batch(window_size + 1)) dataset = dataset.shuffle(shuffle_buffer).map(lambda window: (window[:-1], window[-1])) dataset = dataset.batch(batch_size).prefetch(1) return dataset
Train and tune the model
- 이전 수업에서 배웠던 모델로 예측하여 플로팅하면, 결과는 괜찮아보이나 MAE 가 매우 큼
- 이는 이전 window_size 가 20 (여기서는 약 2년이 안되는 시간) 이나, 사실 흑점 데이터의 주기는 11년 혹은 22년으로 추정됨
- window_size 를 11년에 해당하는 132로 두고 다시 훈련을 하면 차트는 더 잘 나오나 MAE는 더 커짐
- 데이터를 되돌아보면 11년 주기의 계절성을 갖지만 창 안에 계절 전체가 있어야 할 필요는 없음
- 플롯을 확대해보면 전형적인 시계열 형태 데이터임
- 나중에 오는 값이 앞선 값과 연관이 있지만 노이즈가 많음
- 그래서 훈련 시에 창 크기가 클 필요는 없을 수도 있음
- data 의 분할을 1000을 훈련, 2500을 검증으로 설정하였는데 이는 좋지 못한 분할임
- 3500과 500으로 지정
- 신경망 설계와 파라미터의 크기 변경
- 10, 10, 1 레이어 를 30, 15, 1 로 값을 바꿔서 훈련 (입력 Shape 값이 30)
Prediction
-
예측
model.predict(series[3205:3235][np.newaxis])
: 7.077 개의 흑점 예상 (실 데이터 8.7 개) -
설정 변경 : MAE 13.7
split_time = 3000 window_size = 60 model = tf.keras.models.Sequential([ tf.keras.layers.Dense(20, input_shape=[window_size], activation="relu"), tf.keras.layers.Dense(10, activation="relu"), tf.keras.layers.Dense(1) ]) model.compile(loss="mse", optimizer=tf.keras.optimizers.SGD(lr=1e-7, momentum=0.9))
- 8.13 예측 (실제값 8.7)
Sunspots notebooks (Lab 2 & Lab 3)
- jupyter notebook 으로 대체
Sunspots
- 입력 창의 크기를 60으로 함
- DNN 을 Dense 20, 10, 1 로 학습
Combining our tools for analysis
-
예시
window_size = 60 batch_size = 64 train_set = windowed_dataset(x_train, window_size, batch_size, shuffle_buffer_size) model = tf.keras.models.Sequential([ tf.keras.layers.Conv1D(filters=32, kernel_size=5, strides=1, padding="casual", activation="relu", input_shape=[None, 1]), tf.keras.layers.LSTM(32, return_sequences=True), tf.keras.layers.LSTM(32), tf.keras.layers.Dense(30, activation="relu"), tf.keras.layers.Dense(10, activation="relu"), tf.keras.layers.Dense(1), tf.keras.layers.Lambda(lambda x: x * 400) ]) lr_schedule = tf.keras.callbacks.LearningRateScheduler(lambda epoch: 1e-5 * 10**(epoch / 20)) optimizer = tf.keras.optimizers.SGD(learning_rate = 1e-8, momentum=0.9) model.compile(loss=tf.keras.losses.Huber(), optimizer = optimizer, metrics=["mae"]) history = model.fit(train-set, epochs=100, callbacks=[lr_schedule])
- batch_size 의 변경 (256) : loss 에 노이즈가 생길 경우 고려해볼 파라미터
- 하이퍼파라미터를 다양하게 실험해 봐야 함
댓글남기기