데이터 스톡 예측을위한지도 학습을 통해 LSTM (RNN) 신경망을 만들었습니다. 문제는 자체 교육 데이터에서 잘못 예측하는 이유는 무엇입니까? (참고 : 아래의 재현 가능한 예 )
다음 5 일 주가를 예측하기 위해 간단한 모델을 만들었습니다.
model = Sequential()
model.add(LSTM(32, activation='sigmoid', input_shape=(x_train.shape[1], x_train.shape[2])))
model.add(Dense(y_train.shape[1]))
model.compile(optimizer='adam', loss='mse')
es = EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True)
model.fit(x_train, y_train, batch_size=64, epochs=25, validation_data=(x_test, y_test), callbacks=[es])
올바른 결과는 y_test
(5 개의 값)에 있으므로 모델 열차는 90 일 전을 되돌아 본 후 다음을 사용하여 최상의 val_loss=0.0030
결과 ( ) 에서 가중치를 복원합니다 patience=3
.
Train on 396 samples, validate on 1 samples
Epoch 1/25
396/396 [==============================] - 1s 2ms/step - loss: 0.1322 - val_loss: 0.0299
Epoch 2/25
396/396 [==============================] - 0s 402us/step - loss: 0.0478 - val_loss: 0.0129
Epoch 3/25
396/396 [==============================] - 0s 397us/step - loss: 0.0385 - val_loss: 0.0178
Epoch 4/25
396/396 [==============================] - 0s 399us/step - loss: 0.0398 - val_loss: 0.0078
Epoch 5/25
396/396 [==============================] - 0s 391us/step - loss: 0.0343 - val_loss: 0.0030
Epoch 6/25
396/396 [==============================] - 0s 391us/step - loss: 0.0318 - val_loss: 0.0047
Epoch 7/25
396/396 [==============================] - 0s 389us/step - loss: 0.0308 - val_loss: 0.0043
Epoch 8/25
396/396 [==============================] - 0s 393us/step - loss: 0.0292 - val_loss: 0.0056
예측 결과는 정말 대단하지 않습니까?
알고리즘이 # 5 시대에서 최고의 가중치를 복원했기 때문입니다. 자, 이제이 모델을 .h5
파일로 저장 하고 -10 일 뒤로 이동하고 지난 5 일을 예측합시다 (첫 번째 예에서는 주말을 포함하여 4 월 17-23 일에 모델을 만들고 유효성을 검사 한 후 4 월 2-8 일에 테스트하겠습니다). 결과:
절대적으로 잘못된 방향을 보여줍니다. 보시다시피, 모델이 훈련되었고 4 월 17-23 일에 설정된 유효성 검사에 5 위를 차지했지만 2-8에서는 그렇지 않았습니다. 더 많은 훈련을 시도하고, 내가 선택하는 신기원을 가지고 무엇을하든, 과거에는 항상 잘못된 예측을하는 많은 시간 간격이 있습니다.
훈련 된 데이터에서 모델이 왜 잘못된 결과를 보여줍니까? 나는 데이터를 훈련시켰다. 그것은이 세트의 데이터를 예측하는 방법을 기억해야하지만, 잘못 예측한다. 내가 시도한 것 :
- 50k + 행, 20 년 주가로 대규모 데이터 세트를 사용하여 더 많거나 적은 기능 추가
- 더 많은 숨겨진 레이어 추가, 다른 batch_sizes, 다른 레이어 활성화, 드롭 아웃, 배치 정규화와 같은 다른 유형의 모델 생성
- 사용자 정의 EarlyStopping 콜백을 만들고 많은 유효성 검사 데이터 세트에서 평균 val_loss를 얻고 가장 적합한 것을 선택하십시오.
어쩌면 내가 뭔가를 그리워? 무엇을 개선 할 수 있습니까?
다음은 매우 간단하고 재현 가능한 예입니다. yfinance
S & P 500 주식 데이터를 다운로드합니다.
"""python 3.7.7
tensorflow 2.1.0
keras 2.3.1"""
import numpy as np
import pandas as pd
from keras.callbacks import EarlyStopping, Callback
from keras.models import Model, Sequential, load_model
from keras.layers import Dense, Dropout, LSTM, BatchNormalization
from sklearn.preprocessing import MinMaxScaler
import plotly.graph_objects as go
import yfinance as yf
np.random.seed(4)
num_prediction = 5
look_back = 90
new_s_h5 = True # change it to False when you created model and want test on other past dates
df = yf.download(tickers="^GSPC", start='2018-05-06', end='2020-04-24', interval="1d")
data = df.filter(['Close', 'High', 'Low', 'Volume'])
# drop last N days to validate saved model on past
df.drop(df.tail(0).index, inplace=True)
print(df)
class EarlyStoppingCust(Callback):
def __init__(self, patience=0, verbose=0, validation_sets=None, restore_best_weights=False):
super(EarlyStoppingCust, self).__init__()
self.patience = patience
self.verbose = verbose
self.wait = 0
self.stopped_epoch = 0
self.restore_best_weights = restore_best_weights
self.best_weights = None
self.validation_sets = validation_sets
def on_train_begin(self, logs=None):
self.wait = 0
self.stopped_epoch = 0
self.best_avg_loss = (np.Inf, 0)
def on_epoch_end(self, epoch, logs=None):
loss_ = 0
for i, validation_set in enumerate(self.validation_sets):
predicted = self.model.predict(validation_set[0])
loss = self.model.evaluate(validation_set[0], validation_set[1], verbose = 0)
loss_ += loss
if self.verbose > 0:
print('val' + str(i + 1) + '_loss: %.5f' % loss)
avg_loss = loss_ / len(self.validation_sets)
print('avg_loss: %.5f' % avg_loss)
if self.best_avg_loss[0] > avg_loss:
self.best_avg_loss = (avg_loss, epoch + 1)
self.wait = 0
if self.restore_best_weights:
print('new best epoch = %d' % (epoch + 1))
self.best_weights = self.model.get_weights()
else:
self.wait += 1
if self.wait >= self.patience or self.params['epochs'] == epoch + 1:
self.stopped_epoch = epoch
self.model.stop_training = True
if self.restore_best_weights:
if self.verbose > 0:
print('Restoring model weights from the end of the best epoch')
self.model.set_weights(self.best_weights)
def on_train_end(self, logs=None):
print('best_avg_loss: %.5f (#%d)' % (self.best_avg_loss[0], self.best_avg_loss[1]))
def multivariate_data(dataset, target, start_index, end_index, history_size, target_size, step, single_step=False):
data = []
labels = []
start_index = start_index + history_size
if end_index is None:
end_index = len(dataset) - target_size
for i in range(start_index, end_index):
indices = range(i-history_size, i, step)
data.append(dataset[indices])
if single_step:
labels.append(target[i+target_size])
else:
labels.append(target[i:i+target_size])
return np.array(data), np.array(labels)
def transform_predicted(pr):
pr = pr.reshape(pr.shape[1], -1)
z = np.zeros((pr.shape[0], x_train.shape[2] - 1), dtype=pr.dtype)
pr = np.append(pr, z, axis=1)
pr = scaler.inverse_transform(pr)
pr = pr[:, 0]
return pr
step = 1
# creating datasets with look back
scaler = MinMaxScaler()
df_normalized = scaler.fit_transform(df.values)
dataset = df_normalized[:-num_prediction]
x_train, y_train = multivariate_data(dataset, dataset[:, 0], 0,len(dataset) - num_prediction + 1, look_back, num_prediction, step)
indices = range(len(dataset)-look_back, len(dataset), step)
x_test = np.array(dataset[indices])
x_test = np.expand_dims(x_test, axis=0)
y_test = np.expand_dims(df_normalized[-num_prediction:, 0], axis=0)
# creating past datasets to validate with EarlyStoppingCust
number_validates = 50
step_past = 5
validation_sets = [(x_test, y_test)]
for i in range(1, number_validates * step_past + 1, step_past):
indices = range(len(dataset)-look_back-i, len(dataset)-i, step)
x_t = np.array(dataset[indices])
x_t = np.expand_dims(x_t, axis=0)
y_t = np.expand_dims(df_normalized[-num_prediction-i:len(df_normalized)-i, 0], axis=0)
validation_sets.append((x_t, y_t))
if new_s_h5:
model = Sequential()
model.add(LSTM(32, return_sequences=False, activation = 'sigmoid', input_shape=(x_train.shape[1], x_train.shape[2])))
# model.add(Dropout(0.2))
# model.add(BatchNormalization())
# model.add(LSTM(units = 16))
model.add(Dense(y_train.shape[1]))
model.compile(optimizer = 'adam', loss = 'mse')
# EarlyStoppingCust is custom callback to validate each validation_sets and get average
# it takes epoch with best "best_avg" value
# es = EarlyStoppingCust(patience = 3, restore_best_weights = True, validation_sets = validation_sets, verbose = 1)
# or there is keras extension with built-in EarlyStopping, but it validates only 1 set that you pass through fit()
es = EarlyStopping(monitor = 'val_loss', patience = 3, restore_best_weights = True)
model.fit(x_train, y_train, batch_size = 64, epochs = 25, shuffle = True, validation_data = (x_test, y_test), callbacks = [es])
model.save('s.h5')
else:
model = load_model('s.h5')
predicted = model.predict(x_test)
predicted = transform_predicted(predicted)
print('predicted', predicted)
print('real', df.iloc[-num_prediction:, 0].values)
print('val_loss: %.5f' % (model.evaluate(x_test, y_test, verbose=0)))
fig = go.Figure()
fig.add_trace(go.Scatter(
x = df.index[-60:],
y = df.iloc[-60:,0],
mode='lines+markers',
name='real',
line=dict(color='#ff9800', width=1)
))
fig.add_trace(go.Scatter(
x = df.index[-num_prediction:],
y = predicted,
mode='lines+markers',
name='predict',
line=dict(color='#2196f3', width=1)
))
fig.update_layout(template='plotly_dark', hovermode='x', spikedistance=-1, hoverlabel=dict(font_size=16))
fig.update_xaxes(showspikes=True)
fig.update_yaxes(showspikes=True)
fig.show()
답변
OP는 흥미로운 발견을 가정합니다. 다음과 같이 원래 질문을 단순화하겠습니다.
모델이 특정 시계열에 대해 훈련 된 경우 모델이 이미 훈련 된 이전 시계열 데이터를 재구성 할 수없는 이유는 무엇입니까?
답은 훈련 과정 자체에 포함되어 있습니다. 이후 EarlyStopping
overfitting 방지하기 위해 여기에 사용되는, 최고의 모델이 저장됩니다 epoch=5
곳 val_loss=0.0030
으로 OP에 의해 언급했다. 이 경우 훈련 손실은 0.0343
, 즉 훈련의 RMSE와 같습니다 0.185
. 데이터 세트는 다음을 사용하여 조정되므로MinMaxScalar
RMSE의 크기 조정을 취소하여 진행 상황을 이해해야합니다.
시간 순서의 최소값과 최대 값은 2290
및 3380
입니다. 따라서 0.185
훈련의 RMSE를 갖는 것은 훈련 세트에 대해서도 예측 된 값이 대략 실제 단위와 평균 0.185*(3380-2290)
, 즉 ~200
단위로 다를 수 있음을 의미합니다 .
이것은 이전 시간 단계에서 훈련 데이터 자체를 예측할 때 큰 차이가있는 이유를 설명합니다.
교육 데이터를 완벽하게 에뮬레이트하려면 어떻게해야합니까?
나는이 질문을 나 자신에게 물었다. 간단한 대답은 훈련 손실이 가까워 0
지도록하는 것입니다.
일부 훈련 후, 32
셀이있는 1 LSTM 레이어 만있는 모델 이 훈련 데이터를 재구성하기에 충분히 복잡하지 않다는 것을 깨달았습니다 . 따라서 다음과 같이 다른 LSTM 레이어를 추가했습니다.
model = Sequential()
model.add(LSTM(32, return_sequences=True, activation = 'sigmoid', input_shape=(x_train.shape[1], x_train.shape[2])))
# model.add(Dropout(0.2))
# model.add(BatchNormalization())
model.add(LSTM(units = 64, return_sequences=False,))
model.add(Dense(y_train.shape[1]))
model.compile(optimizer = 'adam', loss = 'mse')
그리고이 모델은 1000
고려하지 않고 신기원을 위해 훈련되었습니다 EarlyStopping
.
model.fit(x_train, y_train, batch_size = 64, epochs = 1000, shuffle = True, validation_data = (x_test, y_test))
1000
에포크가 끝나면 0.00047
훈련 손실이 귀하의 경우 훈련 손실보다 훨씬 낮습니다. 따라서 모델이 훈련 데이터를 더 잘 재구성 할 것으로 기대합니다. 다음은 4 월 2 일 -8 일에 대한 예측 도표입니다.
마지막 메모 :
특정 데이터베이스에 대한 교육이 모델이 교육 데이터를 완벽하게 재구성 할 수 있어야한다는 의미는 아닙니다. 특히, 조기 정지, 정규화 및 드롭 아웃과 같은 방법이 과적 합을 피하기 위해 도입 될 때 모델은 훈련 데이터를 암기하는 것보다 더 일반화되는 경향이 있습니다.
답변
훈련 된 데이터에서 모델이 왜 잘못된 결과를 보여줍니까? 나는 데이터를 훈련시켰다. 그것은이 세트의 데이터를 예측하는 방법을 기억해야하지만, 잘못 예측한다.
모델이 암기 대신 입력과 출력의 관계를 배우기를 원합니다. 모델이 각 입력에 대한 올바른 출력을 기억하는 경우 훈련 데이터가 적합하지 않다고 말할 수 있습니다. 데이터의 작은 하위 집합을 사용하여 모델이 과적 합되도록 할 수있는 경우가 종종 있으므로 원하는 동작을 시도하면됩니다.
답변
기본적으로 훈련 데이터에 대한 더 나은 결과를 얻으려면 훈련 정확도가 가능한 높아야합니다. 보유한 데이터와 관련하여 더 나은 모델을 사용해야합니다. 기본적으로 테스트 정확도에 관계없이이 목적에 대한 훈련 정확도를 확인해야합니다. 이것을 과적 합이라고도하며, 이는 시험 데이터보다는 훈련 데이터의 정확도를 향상시킵니다.
훈련 정확도보다는 최상의 테스트 / 검증 정확도를 취하는이 시나리오에서는 조기 중지가 영향을받을 수 있습니다.
답변
짧은 대답 :
세트:
batch_size = 1
epochs = 200
shuffle = False
직감 : 훈련 데이터에서 높은 정확도의 우선 순위를 설명하고 있습니다. 이것은 과적 합을 설명합니다. 이렇게하려면 배치 크기를 1, 에포크가 높고 셔플 오프로 설정하십시오.
답변
훈련 된 데이터에서 모델이 왜 잘못된 결과를 보여줍니까? 나는 데이터를 훈련시켰다. 그것은이 세트의 데이터를 예측하는 방법을 기억해야하지만, 잘못 예측한다.
당신이하고있는 것을보십시오 :
- 일부 레이어로 모델 만들기
- training_data를 사용한 훈련 모델
- 모델을 훈련하면 모든 훈련 가능한 매개 변수가 훈련됩니다 (예 : 모델의 무게가 저장 됨)
- 이 가중치는 이제 입력과 출력 사이의 관계를 나타냅니다.
- 동일한 training_data를 다시 예측하면이 시간 훈련 된 모델은 가중치를 사용하여 출력을 얻습니다.
- 이제 모델의 품질에 따라 예측이 결정되므로 데이터가 동일하더라도 원래 결과와 다릅니다.
답변
몸에 잘 맞지 않아서 숨겨진 레이어에 뉴런을 추가해야한다는 점을 개선했습니다. !! 또 다른 요점은 ‘relu’활성화 기능입니다. S 자형은 좋은 결과를 제공하지 않습니다. 또한 출력 레이어에서 ‘softmax’를 정의해야합니다.!
답변
모델 아키텍처와 옵티 마이저를 Adagrad로 변경 한 후 결과를 어느 정도 개선 할 수있었습니다.
Adagrad 옵티 마이저를 사용하는 이유는 다음과 같습니다.
학습 속도를 매개 변수에 적용하여 자주 발생하는 기능과 관련된 매개 변수에 대해 더 작은 업데이트 (즉, 낮은 학습 속도)를 수행하고 드문 기능과 관련된 매개 변수에 대해 더 큰 업데이트 (즉, 높은 학습 속도)를 수행합니다. 이러한 이유로 희소 데이터를 처리하는 데 적합합니다.
아래 코드를 참조하십시오 :
model = Sequential()
model.add(LSTM(units=100,return_sequences=True, kernel_initializer='random_uniform', input_shape=(x_train.shape[1], x_train.shape[2])))
model.add(Dropout(0.2))
model.add(LSTM(units=100,return_sequences=True, kernel_initializer='random_uniform'))
model.add(LSTM(units=100,return_sequences=True, kernel_initializer='random_uniform'))
model.add(Dropout(0.20))
model.add(Dense(units=25, activation='relu'))
model.add(Dense(y_train.shape[1]))
# compile model
model.compile(loss="mse", optimizer='adagrad', metrics=['accuracy'])
model.summary()
주식 예측은 단일 모델의 예측을 고수하기보다는 매우 까다로운 작업이므로, 여러 모델을 함께 사용하여 예측을 수행 한 다음 앙상블 학습 방식과 유사하게 최대 투표 결과를 기반으로 전화를 걸 수 있습니다. 또한 다음과 같이 몇 가지 모델을 함께 쌓을 수 있습니다.
-
차원을 줄이기위한 딥 피드 포워드 자동 인코더 신경망 + 딥 재발 신경망 + ARIMA + 극한 증감 그라디언트 회귀
-
Adaboost + Bagging + Extra Trees + Gradient Boosting + Random Forest + XGB
강화 학습 에이전트는 다음과 같이 주식 예측에서 꽤 잘하고 있습니다.
- 거북이 무역 에이전트
- 이동 평균 에이전트
- 신호 롤링 에이전트
- 정책 그라디언트 에이전트
- Q- 러닝 에이전트
- 진화 전략 요원