ฉันสร้างเครือข่ายประสาท 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 วันล่าสุด (ในตัวอย่างแรกที่เราสร้างแบบจำลองและตรวจสอบในวันที่ 17-23 เมษายนรวมถึงวันหยุดสุดสัปดาห์วันนี้ลองทดสอบวันที่ 2-8 เมษายน) ผลลัพธ์:
มันแสดงให้เห็นถึงทิศทางที่ผิดอย่างแน่นอน อย่างที่เราเห็นนั่นเป็นเพราะแบบจำลองได้รับการฝึกฝนและได้รับการจัดอันดับให้ดีที่สุดสำหรับการตรวจสอบในวันที่ 17-23 เมษายน แต่ไม่ใช่ในวันที่ 2-8 ถ้าฉันลองฝึกให้มากขึ้นเล่นกับสิ่งที่ยุคให้เลือกไม่ว่าฉันจะทำอะไรจะมีช่วงเวลามากมายในอดีตที่มีการทำนายผิด
ทำไมแบบจำลองแสดงผลลัพธ์ที่ไม่ถูกต้องกับข้อมูลที่ผ่านการฝึกอบรมของตัวเอง ฉันฝึกข้อมูลแล้วมันต้องจำไว้ว่าจะทำนายข้อมูลในชุดนี้ได้อย่างไร แต่ทำนายผิด สิ่งที่ฉันพยายาม:
- ใช้ชุดข้อมูลขนาดใหญ่พร้อมแถว 50k + ราคาหุ้น 20 ปีเพิ่มคุณสมบัติมากขึ้นหรือน้อยลง
- สร้างรูปแบบที่แตกต่างกันเช่นเพิ่มเลเยอร์ที่ซ่อนอยู่มากขึ้น, batch_size ที่แตกต่างกัน, การเปิดใช้งานเลเยอร์ที่แตกต่างกัน, การดรอป, การแบทช์การทำให้ปกติ
- สร้างการเรียกกลับก่อนกำหนดที่กำหนดเองรับค่า 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()
df.drop(df.tail(10).index, inplace=True)
มันแสดงผลลัพธ์ที่ไม่ดีเหมือนที่ฉันมี