Saya membuat jaringan saraf LSTM (RNN) dengan pembelajaran terawasi untuk prediksi stok data. Masalahnya adalah mengapa ia memprediksi data pelatihannya sendiri salah? (catatan: contoh yang dapat direproduksi di bawah)
Saya membuat model sederhana untuk memprediksi harga saham 5 hari ke depan:
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])
Hasil yang benar adalah dalam y_test
(5 nilai), jadi model melatih, melihat ke belakang 90 hari sebelumnya dan kemudian mengembalikan bobot dari yang terbaik ( val_loss=0.0030
) hasil dengan 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
Hasil prediksi cukup mengagumkan, bukan?
Itu karena algoritma mengembalikan bobot terbaik dari # 5 jaman. Oke, sekarang mari kita simpan model ini ke .h5
file, mundur -10 hari dan prediksi 5 hari terakhir (pada contoh pertama kami membuat model dan memvalidasi pada 17-23 April termasuk hari libur akhir pekan, sekarang mari kita uji pada 2-8 April). Hasil:
Ini menunjukkan arah yang benar-benar salah. Seperti yang kita lihat itu karena model dilatih dan mengambil # 5 zaman terbaik untuk validasi ditetapkan pada 17-23 April, tetapi tidak pada 2-8. Jika saya mencoba melatih lebih banyak, bermain dengan zaman apa yang harus dipilih, apa pun yang saya lakukan, selalu ada banyak interval waktu di masa lalu yang memiliki prediksi salah.
Mengapa model menunjukkan hasil yang salah pada data terlatihnya sendiri? Saya melatih data, harus ingat bagaimana memprediksi data pada set ini, tetapi memprediksi salah. Apa yang saya coba:
- Gunakan kumpulan data besar dengan baris 50k +, harga saham 20 tahun, menambah lebih banyak fitur
- Buat berbagai jenis model, seperti menambahkan lebih banyak lapisan tersembunyi, ukuran batch_size yang berbeda, aktivasi lapisan yang berbeda, dropout, batchnormalisasi
- Buat callback EarlyStopping kustom, dapatkan val_loss rata-rata dari banyak set data validasi dan pilih yang terbaik
Mungkin saya melewatkan sesuatu? Apa yang bisa saya tingkatkan?
Ini adalah contoh yang sangat sederhana dan dapat direproduksi . yfinance
mengunduh data saham 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)
, itu menunjukkan hasil buruk yang sama seperti yang saya miliki.Jawaban:
OP mendalilkan temuan yang menarik. Biarkan saya menyederhanakan pertanyaan awal sebagai berikut.
Jika model dilatih pada deret waktu tertentu, mengapa model tidak dapat merekonstruksi data deret waktu sebelumnya, yang sudah dilatih sebelumnya?
Nah, jawabannya tertanam dalam kemajuan pelatihan itu sendiri. Karena
EarlyStopping
digunakan di sini untuk menghindari overfitting, model terbaik disimpan diepoch=5
, di manaval_loss=0.0030
sebagaimana disebutkan oleh OP. Pada contoh ini, kehilangan pelatihan sama dengan0.0343
, yaitu, RMSE pelatihan0.185
. Karena dataset diskalakan menggunakanMinMaxScalar
, kita perlu membatalkan penskalaan RMSE untuk memahami apa yang terjadi.Nilai minimum dan maksimum dari urutan waktu ditemukan menjadi
2290
dan3380
. Oleh karena itu, memiliki0.185
sebagai RMSE pelatihan berarti bahwa, bahkan untuk set pelatihan, nilai-nilai yang diprediksi dapat berbeda dari nilai-nilai kebenaran tanah sekitar0.185*(3380-2290)
, yaitu~200
unit rata-rata.Ini menjelaskan mengapa ada perbedaan besar ketika memprediksi data pelatihan itu sendiri pada langkah waktu sebelumnya.
Apa yang harus saya lakukan untuk meniru data pelatihan dengan sempurna?
Saya mengajukan pertanyaan ini dari diri saya sendiri. Jawaban sederhananya adalah, buat kehilangan latihan semakin dekat
0
, yaitu overfit modelnya.Setelah beberapa pelatihan, saya menyadari bahwa model dengan hanya 1 lapisan LSTM yang memiliki
32
sel tidak cukup kompleks untuk merekonstruksi data pelatihan. Oleh karena itu, saya telah menambahkan lapisan LSTM lainnya sebagai berikut.Dan model itu dilatih untuk
1000
zaman tanpa mempertimbangkanEarlyStopping
.Pada akhir
1000
zaman kita mengalami kehilangan pelatihan0.00047
yang jauh lebih rendah daripada hilangnya pelatihan dalam kasus Anda. Jadi kita akan mengharapkan model untuk merekonstruksi data pelatihan dengan lebih baik. Berikut ini adalah plot prediksi untuk 2-8 April.Catatan Akhir:
Pelatihan pada basis data tertentu tidak berarti bahwa model tersebut harus dapat merekonstruksi data pelatihan dengan sempurna. Terutama, ketika metode seperti penghentian awal, regularisasi dan dropout diperkenalkan untuk menghindari overfitting, model cenderung lebih digeneralisasikan daripada menghafal data pelatihan.
sumber
Anda ingin model mempelajari hubungan antara input dan output alih-alih menghafal. Jika suatu model menghafal output yang benar untuk setiap input, kita dapat mengatakan itu terlalu pas dengan data pelatihan. Seringkali Anda dapat memaksa model untuk berpakaian berlebihan dengan menggunakan subkumpulan kecil data, jadi jika itu perilaku yang ingin Anda lihat, Anda bisa mencobanya.
sumber
Tersangka # 1 - Regularisasi
Jaringan saraf sangat bagus dalam overfitting data pelatihan, sebenarnya ada percobaan mengganti label CIFAR10 (tugas klasifikasi gambar) (nilai y) dengan label acak pada set data pelatihan dan jaringan sesuai dengan label acak yang menghasilkan kehilangan hampir nol.
Jadi mengapa itu tidak terjadi setiap saat? regularisasi .
regularisasi adalah (kira-kira) mencoba memecahkan masalah yang lebih sulit daripada masalah optimisasi (kerugian) yang kita tentukan untuk model.
beberapa metode pengaturan umum dalam jaringan saraf:
metode ini membantu mengurangi overfitting dan biasanya menghasilkan validasi dan kinerja tes yang lebih baik, tetapi menghasilkan kinerja kereta yang lebih rendah (yang sebenarnya tidak masalah seperti yang dijelaskan pada paragraf terakhir).
melatih kinerja data biasanya tidak begitu penting dan untuk itu kami menggunakan set validasi.
Suspect # 2 - Ukuran Model
Anda menggunakan lapisan LSTM tunggal dengan 32 unit. itu cukup kecil. coba tambah ukuran dan bahkan letakkan dua layer LSTM (atau dua bidirectional) dan saya yakin model dan optimizer akan menyesuaikan data Anda selama Anda membiarkannya - yaitu menghapus penghentian awal, restore_last_weights dan regularisasi lain yang ditentukan di atas.
Catatan tentang Kompleksitas Masalah
mencoba untuk memprediksi harga saham di masa depan hanya dengan melihat sejarah bukanlah tugas yang mudah, dan bahkan jika model dapat (lebih) pas dengan pelatihan yang ditetapkan itu mungkin tidak akan melakukan apa pun yang berguna pada set tes atau di dunia nyata.
ML bukan ilmu hitam, x sampel perlu dikorelasikan dengan beberapa cara dengan tag y, kita biasanya menganggap bahwa (x, y) diambil dari beberapa distribusi bersama.
Cara yang lebih intuitif untuk memikirkannya, ketika Anda perlu menandai gambar secara manual untuk kelas anjing / kucing - itu cukup mudah. tetapi bisakah Anda secara manual "menandai" harga saham dengan melihat sejarah saham itu saja?
Itulah beberapa intuisi tentang betapa sulitnya masalah ini.
Catatan tentang Overfitting
Seseorang seharusnya tidak mengejar kinerja pelatihan yang lebih tinggi , hampir tidak berguna untuk mencoba menyesuaikan data pelatihan, karena kami biasanya mencoba untuk melakukan dengan baik dengan model pada data baru yang tidak terlihat dengan sifat yang mirip dengan data kereta. ide semua adalah untuk mencoba menggeneralisasi dan mempelajari sifat-sifat data dan korelasi dengan target, itulah pembelajarannya :)
sumber
Seperti yang sudah dikatakan orang lain, Anda seharusnya tidak berharap banyak dari ini.
Namun demikian, saya menemukan yang berikut ini dalam kode Anda:
Anda memasang kembali scaler setiap kali selama pelatihan dan pengujian. Anda perlu menyimpan sacler dan hanya mengubah data selama pengujian, jika tidak, hasilnya akan sedikit berbeda:
Setel
shuffle=False
. Karena Anda memang perlu menjaga urutan dataset Anda.Setel
batch_size=1
. Karena itu akan kurang rawan overfitting dan pembelajaran akan lebih berisik dan kesalahan kurang rata-rata.Atur
epochs=50
atau lebih.Dengan pengaturan yang disebutkan di atas, model tercapai
loss: 0.0037 - val_loss: 3.7329e-04
.Periksa sampel prediksi berikut:
Dari 17/04/2020 -> 23/04/2020:
Dari 02/04/2020 -> 08/04/2020:
Dari 25/03/2020 -> 31/03/2020:
sumber
Pada dasarnya Jika Anda ingin mendapatkan hasil yang lebih baik untuk data pelatihan, akurasi pelatihan Anda harus setinggi mungkin. Anda harus menggunakan model yang lebih baik sehubungan dengan data yang Anda miliki. Pada dasarnya Anda harus memeriksa apakah akurasi pelatihan Anda untuk tujuan ini terlepas dari akurasi tes. Ini juga disebut sebagai overfitting yang memberikan akurasi yang lebih baik dalam data pelatihan daripada data uji.
Menghentikan lebih awal mungkin mempengaruhi skenario ini di mana akurasi tes / validasi terbaik diambil daripada akurasi pelatihan.
sumber
Jawaban singkatnya:
Set:
Intuisi: Anda menggambarkan prioritas akurasi tinggi dalam data pelatihan. Ini menggambarkan overfitting. Untuk melakukan itu, atur ukuran bets ke 1, zaman tinggi, dan mundur.
sumber
Setelah mengubah arsitektur model dan pengoptimal ke Adagrad, saya dapat meningkatkan hasilnya sampai batas tertentu.
Alasan menggunakan pengoptimal Adagrad di sini adalah:
Ini menyesuaikan tingkat pembelajaran dengan parameter, melakukan pembaruan yang lebih kecil (yaitu tingkat belajar yang rendah) untuk parameter yang terkait dengan fitur yang sering terjadi, dan pembaruan yang lebih besar (yaitu tingkat pembelajaran yang tinggi) untuk parameter yang terkait dengan fitur yang jarang terjadi. Untuk alasan ini, sangat cocok untuk berurusan dengan data yang jarang.
Silakan lihat kode di bawah ini:
Prediksi stok adalah tugas yang sangat menantang sehingga daripada tetap berpegang pada prediksi model tunggal, kita dapat meminta beberapa model bekerja sama untuk membuat prediksi dan kemudian berdasarkan hasil pemungutan suara yang maksimum, seperti pendekatan pembelajaran ensemble. Selain itu, kami dapat menumpuk beberapa model bersama seperti:
Deep Feed-forward Auto-Encoder Neural Network untuk mengurangi dimensi + Deep Neural Network Deep Recurrent + ARIMA + Regulator Gradien Penguat Ekstrim
Adaboost + Mengantongi + Pohon Ekstra + Meningkatkan Gradien + Hutan Acak + XGB
Agen pembelajaran Reinforcement melakukan cukup baik dalam Prediksi Saham seperti:
Silakan temukan tautan yang sangat banyak akal di sini .
sumber
Lihat apa yang kamu lakukan:
sumber
Ini kurang pas dan untuk meningkatkan hal itu Anda perlu menambahkan neuron ke dalam lapisan tersembunyi Anda. !! Poin lainnya adalah mencoba fungsi aktivasi 'relu'. Sigmoid tidak memberikan hasil yang baik. Anda juga perlu mendefinisikan 'softmax' di lapisan output Anda.!
sumber