Video Pengenalan LSTM
Code dari lesson ini dapat di akses di Link berikut (wajib login ke Google/Gmail): Code Lesson Pengenalan LSTM
Di link tersebut anda langsung bisa merubah code dan menjalankannya. Keterangan lebih lanjut di video yang disertakan.
Sangat disarankan untuk membuka code dan video "side-by-side" untuk mendapatkan pengalaman belajar yang baik (Gambar dibawah). Silahkan modifikasi (coba-coba) hal lain, selain yang ditunjukkan di video untuk mendapatkan pengalaman belajar yang lebih mendalam. Tentu saja juga silahkan akses berbagai referensi lain untuk memperkaya pengetahuan lalu diskusikan di forum yang telah disediakan.
Code Lesson Pengenalan LSTM
Acknowledgement: Sebagian besar gambar animasi dalam module ini bersumber dari: Illustrated Guide to LSTM’s and GRU’s: A step by step explanation | by Michael Phi | Towards Data Science.
Outline ¶
- Pendahuluan - Long Short Term Memory (LSTM)
- LSTM for forecasting
- Studi Kasus: LSTM Forecasting
Pendahuluan - Long Short Term Memory (LSTM) ¶
- Long short-term memory (LSTM) merupakan arsitektur dari Recurrent Neural Network (RNN).
- Tidak seperti feed forward neural network biasa, LSTM memiliki koneksi umpan balik sehingga LSTM cocok untuk memperoses data sekuensial.
- LSTM mampu melakukan tugas-tugas seperti handwriting recognition, speech recognition, forecasting, anomaly detection dan lain sebagainya yang memiliki input data sekuensial.
Feed-forward Neural Network Vs Recurrent Neural Network¶
image source: https://www.researchgate.net/figure/Comparison-of-FFNN-and-RNN_fig1_320944634
- Pada arsitektur FFNN input hanya dijadikan sebagai kombinasi linear dan dimasukan ke fungsi aktivasi.
- Input pada arsitektur RNN adalah data sekuensial sehingga tidak tepat jika dijadikan sebagai kombinasi linear.
- Saat unit RNN dibentangkan, kita akan melihat node-node RNN yang disebut dengan blok memori.
- Blok memori ini berfungsi untuk mengalirkan informasi dari data urutan pertama hingga terakhir, sehingga output tiap-tiap bloknya akan bergantung pada data di blok tersebut dan seluruh data pada blok sebelumnya.
Perhatikan Data Berikut¶
- Pada Data 1, tiap sampelnya merupakan vektor yang terdiri dari beberapa variabel. vektor tersebut langsung diumpankan ke neuron pada layer berikutnya sebagai kombinasi linear dan dimasukan ke fungsi aktivasi sebagai berikut:
- RNN¶
- Sedangkan pada Data 2, tiap sampelnya terdiri dari data sekuensial yaitu data terurut yang tiap urutannya merupakan vektor yang terdiri dari beberapa variabel. vektor-vektor tersebut diumpankan ke tiap-tiap blok memori secara berurutan.
Blok Memori¶
- Vektor $x_t$ pada urutan ke $t$ yang diumpankan ke blok memori akan menghasilkan output sementara $h_t$ berupa skalar dengan menggunakan rumus berikut:
$h_t=\tanh{([x_t,h_{t-1}])}$ - Fungsi aktivasi tanh pada blok memori tersebut akan memaksa nilai outputnya berada di interval -1 dan 1
- Selain menjadi output sementara, nilai $h_t$ tersebut diteruskan ke blok memori selanjutnya sebagai pembawa informasi dari blok-blok memori sebelumnya
image source: https://towardsdatascience.com/illustrated-guide-to-lstms-and-gru-s-a-step-by-step-explanation-44e9eb85bf21
Arsitektur RNN¶
- Seperti yang telah dijelaskan sebelumnya bahwa ouput sementara $h_t$ merupakan skalar. maka dari itu apabila kita ingin output sementara tersebut berupa vektor maka kita perlu menambahkan beberapa unit RNN seperti pada gambar 6. tanda loop pada unit RNN tersebut mengisyaratkan proses seperti yang telah dijelaskan pada gambar 4 dan 5.
- 1 hidden layer dengan 1 unit RNN¶
- Pada Arsitektur RNN berikut karena hanya menggunakan satu unit RNN maka ouput sementara $h_t$ yang dihasilkan berupa skalar
- Kemudian karena pada layer berikutnya bukan layer RNN, maka hanya ouput sementara $h_t$ pada blok memori terakhir yang diteruskan ke layer berikutnya
Gambar 7. Arsitektur RNN (1)
- 1 hidden layer dengan 2 unit RNN¶
- Pada Arsitektur RNN berikut karena menggunakan dua unit RNN maka ouput sementara $h_t$ yang dihasilkan berupa vektor berdimensi dua.
- Kemudian karena pada layer berikutnya bukan layer RNN, maka hanya ouput sementara $h_t$ pada blok memori terakhir yang diteruskan ke layer berikutnya
Gambar 8. Arsitektur RNN (2)
- 2 hidden layer dengan 1 unit RNN¶
- Pada Arsitektur RNN berikut karena hanya menggunakan satu unit RNN maka ouput sementara $h_t$ yang dihasilkan berupa skalar
- Kemudian karena pada layer berikutnya adalah layer RNN lagi, maka tiap-tiap ouput sementara $h_t$ tersebut dijadikan sebagai input untuk layer RNN berikutnya
Gambar 9. Arsitektur RNN (3)
- Hidden layer 1 dengan 2 unit RNN dan hidden layer 2 dengan 1 unit RNN¶
- Pada Arsitektur RNN berikut karena menggunakan dua unit RNN maka ouput sementara $h_t$ yang dihasilkan berupa vektor berdimensi dua.
- Kemudian karena pada layer berikutnya adalah layer RNN lagi, maka tiap-tiap ouput sementara $h_t$ tersebut dijadikan sebagai input untuk layer RNN berikutnya
Gambar 10. Arsitektur RNN (4)
LSTM Vs RNN¶
- Perbedaan antara LSTM dan RNN hanya terdapat pada struktur blok memorinya saja
- Pada RNN, nilai $h_t$ yang dihasilkan pada blok memori ke $t$ sepenuhnya akan bergantung dengan seluruh blok-blok memori sebelumnya
- Sedangkan pada LSTM, terdapat beberapa fungsi yang disebut dengat forget gate, input gate, dan output gate yang berfungsi untuk mereset, menambahkan, dan membaca infromasi pada cell state.
- Cell state pada LSTM adalah komponen yang membawa informasi dari blok memori ke blok memori berikutnya.
- Pada ilustrasi di atas, LSTM mampu memilih kata-kata mana saja yang perlu diingat dan yang dilupakan.
Cara kerja LSTM¶
- Informasi yang dibawa oleh cell state sebelumnya $c_{t−1}$ akan diputuskan untuk dilupakan atau diteruskan dengan mengalikan nilai $c_{t−1}$ dan forget gate dengan input $x_t$ dan $h_{t−1}$.
- Hal tersebut dapat dilakukan karena fungsi sigmoid pada forget gate akan menghasilkan nilai pada interval [0,1].
- Apabila nilai forget gate sama dengan 0, akibatnya informasi dari $c_{t−1}$ tidak diteruskan.
- Sebaliknya apabila nilai forget gate lebih dari 0, maka akan ada informasi yang diteruskan dari $c_{t−1}$.
- Kemudian informasi baru dari $x_t$ dan $h_{t-1}$ akan diubah menjadi kandidat cell state $\tilde{c}_t$ dengan fungsi aktivasi tanh.
- Informasi baru tersebut akan diputuskan apakah akan digunakan atau tidak dengan melewati input gate seperti cara kerja forget gate.
Setelah itu, nilai dari $c_t$ diperbarui dengan menjumlahkan informasi $c_{t−1}$ yang telah melewati forget gate dan informasi baru $x_t$ dan $h_{t-1}$ yang telah melewati input gate.
Terakhir, nilai hidden ouput $h_t$ dihitung dengan mengalikan nilai output gate dan $\tanh{(c_t)}$.
image source: https://towardsdatascience.com/illustrated-guide-to-lstms-and-gru-s-a-step-by-step-explanation-44e9eb85bf21
LSTM for forecasting(LSTM) ¶
Misalkan kita memiliki data time series sebagai berikut:
Untuk melakukan forecasting menggunakan LSTM pada data tersebut, hal yang perlu dilakukan adalah menjadikan data tersebut menjadi data sub sekuensial menggunakan sliding window.
Sliding Window: Misalkan window size = w, data ke $t$ diprediksi dengan melihat w data sebelumnya.
Sebagai ilustrasi, perhatikan animasi berikut:
Apabila kita memilih window size = 5, setelah dilakukan sliding window pada data time series yang diperlihatkan di awal, maka akan kita dapatkan data sebagai berikut:
Studi Kasus: LSTM Forecasting ¶
Sebagai contoh kita akan membuat model forecasting sederhana dengan menggunakan dataset
"Hourly Energy Consumption: Over 10 years of hourly energy consumption data from PJM in Megawatts"
PJM Interconnection LLC (PJM) is a regional transmission organization (RTO) in the United States. It is part of the Eastern Interconnection grid operating an electric transmission system serving all or parts of Delaware, Illinois, Indiana, Kentucky, Maryland, Michigan, New Jersey, North Carolina, Ohio, Pennsylvania, Tennessee, Virginia, West Virginia, and the District of Columbia.
The hourly power consumption data comes from PJM's website and are in megawatts (MW).
The regions have changed over the years so data may only appear for certain dates per region.
Source: https://www.kaggle.com/robikscube/hourly-energy-consumption
Terdapat 14 data pada dataset tersebut. yang digunakan pada contoh ini adalah data AEP_hourly.csv yaitu data konsumsi energi dari American Electric Power (AEP) dalam satuan megawatt (MW)
Import Modul Standar¶
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
sns.set_theme(style="whitegrid")
import warnings
warnings.filterwarnings("ignore")
Import Data Konsumsi Energi dari American Electric Power (AEP)¶
- Data konsumsi energi dari American Electric Power (AEP) diimport menggunakan pandas
- Karena format datanya csv maka untuk mengimportnya menggunakan
pd.read_csv()
- Setelah diimport dan simpan dalam variabel df, kita coba lihat 10 data teratas menggunakan
df.head()
file_ = 'data/AEP_hourly.csv'
try: # Running Locally
df = pd.read_csv(file_)
except: # Running in Google Colab
!mkdir data
!wget -P data/ https://raw.githubusercontent.com/taudata-indonesia/elearning/main/{file_}
df = pd.read_csv(file_)
df.head(10)
Datetime | AEP_MW | |
---|---|---|
0 | 2004-12-31 01:00:00 | 13478.0 |
1 | 2004-12-31 02:00:00 | 12865.0 |
2 | 2004-12-31 03:00:00 | 12577.0 |
3 | 2004-12-31 04:00:00 | 12517.0 |
4 | 2004-12-31 05:00:00 | 12670.0 |
5 | 2004-12-31 06:00:00 | 13038.0 |
6 | 2004-12-31 07:00:00 | 13692.0 |
7 | 2004-12-31 08:00:00 | 14297.0 |
8 | 2004-12-31 09:00:00 | 14719.0 |
9 | 2004-12-31 10:00:00 | 14941.0 |
Melihat informasi singkat dari dataframe¶
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 121273 entries, 0 to 121272 Data columns (total 2 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Datetime 121273 non-null object 1 AEP_MW 121273 non-null float64 dtypes: float64(1), object(1) memory usage: 1.9+ MB
- Dari informasi singkat di atas, kita dapat mengetahui bahwa df terdiri dari 121273 baris.
- Selain itu, pada kolom Datetime, tipe datanya masih berupa object (string) sehingga perlu diubah menjadi tipe data datetime dengan cara berikut.
# merubah tipe data object to datetime
df['Datetime'] = df['Datetime'].astype('datetime64')
# melihat tipe data dataframe
print(df.dtypes)
Datetime datetime64[ns] AEP_MW float64 dtype: object
Perhatikan waktu terawal dari kolom Datetime dan 5 data teratas dari df¶
print('waktu terawal dari kolom Datetime adalah:', df['Datetime'].min())
df.head()
waktu terawal dari kolom Datetime adalah: 2004-10-01 01:00:00
Datetime | AEP_MW | |
---|---|---|
0 | 2004-12-31 01:00:00 | 13478.0 |
1 | 2004-12-31 02:00:00 | 12865.0 |
2 | 2004-12-31 03:00:00 | 12577.0 |
3 | 2004-12-31 04:00:00 | 12517.0 |
4 | 2004-12-31 05:00:00 | 12670.0 |
- Dapat kita lihat bahwa waktu pada baris pertama dari kolom tidak sama dengan waktu terawalnya.
- Maka dari itu perlu kita urutkan df berdasarkan Datetime menggunakan
df.sort_values()
.
# mengurutkan data berdasarkan waktu
df.sort_values('Datetime', inplace=True, ignore_index=True)
df.head()
Datetime | AEP_MW | |
---|---|---|
0 | 2004-10-01 01:00:00 | 12379.0 |
1 | 2004-10-01 02:00:00 | 11935.0 |
2 | 2004-10-01 03:00:00 | 11692.0 |
3 | 2004-10-01 04:00:00 | 11597.0 |
4 | 2004-10-01 05:00:00 | 11681.0 |
Plot Data df¶
plt.figure(figsize=(15,8))
sns.lineplot(data=df, x='Datetime', y='AEP_MW')
<AxesSubplot:xlabel='Datetime', ylabel='AEP_MW'>
Memilih Data Setahun Terakhir¶
- Pada contoh ini kita hanya akan gunakan data setahun terakhir dari data AEP_hourly
- Karena data yang diobservasi per jam, maka kita akan mengambil 24*365=8760 baris terakhir dari df dan dimasukan kedalam variabel df1
df1 = df[-24*365:].reset_index(drop=True)
df1.head()
Datetime | AEP_MW | |
---|---|---|
0 | 2017-08-03 01:00:00 | 13682.0 |
1 | 2017-08-03 02:00:00 | 12841.0 |
2 | 2017-08-03 03:00:00 | 12443.0 |
3 | 2017-08-03 04:00:00 | 12213.0 |
4 | 2017-08-03 05:00:00 | 12286.0 |
Plot Data df1¶
plt.figure(figsize=(15,8))
sns.lineplot(data=df1, x='Datetime', y='AEP_MW')
<AxesSubplot:xlabel='Datetime', ylabel='AEP_MW'>
Melihat Statistika Deskriptif dari Data¶
- Sebelum melakukan pembuatan model, sebaiknya dilakukan analisa terhadap statistika deskriptif dari data
- Dari statistika deskriptif tersebut, kita dapat meilhat range dari data dan ukuran pusat data
df1.describe()
AEP_MW | |
---|---|
count | 8760.000000 |
mean | 14963.130708 |
std | 2438.848843 |
min | 9801.000000 |
25% | 13260.750000 |
50% | 14721.500000 |
75% | 16421.750000 |
max | 22759.000000 |
- Dari statistika deskriptif di atas terlihat bahwa data AEP_MW cukup besar dan berada pada range 9801 dan 22759 sehingga nanti kita akan lakukan feature scalling menggunakan MinMaxScaler agar range dari seluruh data tersebut berada di antara 0 dan 1
Split Data¶
- Split data dilakukan agar model yang telah dilatih dapat dievaluasi kemampuannya.
- Karena data yang digunakan adalah data time series, maka split data tidak dilakukan secara acak
- Kita juga akan melakukan cross validation menggunakan data train sehingga pastikan data train yang digunakan cukup besar.
- Pada contoh ini kita gunakan 70% baris pertama sebagai data train dan 30% sisanya sebagai data test.
# split data
train_size = int(len(df1) * 0.7) # Menentukan banyaknya data train yaitu sebesar 70% data
train = df1[:train_size]
test =df1[train_size:].reset_index(drop=True)
Feature Scalling Menggunakan MinMaxScaler¶
- MinMaxScaler difit pada data train agar dapat digunakan kembali pada data test maupun data observasi baru.
- Hasil scalling disimpan pada kolom baru yaitu
'scaled'
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
scaler.fit(train[['AEP_MW']])
train['scaled'] = scaler.transform(train[['AEP_MW']])
test['scaled'] = scaler.transform(test[['AEP_MW']])
Mari kita lihat 5 data pertama pada data train untuk melihat data yang sudah discalling¶
train.head()
Datetime | AEP_MW | scaled | |
---|---|---|---|
0 | 2017-08-03 01:00:00 | 13682.0 | 0.299506 |
1 | 2017-08-03 02:00:00 | 12841.0 | 0.234604 |
2 | 2017-08-03 03:00:00 | 12443.0 | 0.203889 |
3 | 2017-08-03 04:00:00 | 12213.0 | 0.186140 |
4 | 2017-08-03 05:00:00 | 12286.0 | 0.191773 |
Membuat fungsi sliding window¶
- Selanjutnya kita akan membuat fungsi sliding window dengan input data (bertipe data numpy array) dan window size
- Fungsi ini akan menghasilkan variabel input (X) dan variabel target (y)
def sliding_window(data, window_size):
sub_seq, next_values = [], []
for i in range(len(data)-window_size):
sub_seq.append(data[i:i+window_size])
next_values.append(data[i+window_size])
X = np.stack(sub_seq)
y = np.array(next_values)
return X,y
Berapa window size yang tepat untuk digunakan?¶
- Pada penerapannya kita dapat menentukan window size berapa saja.
- Untuk mencapai hasil yang maksimal dapat dilakukan percobaan dengan menggunakan beberapa window size.
- Perlu diperhatikan juga bahwa semakin besar window size yang digunakan akan memerlukan waktu yang cukup lama dalam proses training data
- Pada contoh ini kita hanya menggunakan window size = 24 atau sama dengan 1 hari dan kita terapkan pada data train dan test yang telah discalling
window_size = 24
X_train, y_train = sliding_window(train[['scaled']].values, window_size)
X_test, y_test = sliding_window(test[['scaled']].values, window_size)
Penting!!!¶
- Data input LSTM harus 3D : [samples, timesteps, feature]
- Maka dari itu kita perlu cek dimensi data kita menggunakan np.shape
print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)
(6108, 24, 1) (6108, 1) (2604, 24, 1) (2604, 1)
LSTM menggunakan Tensorflow dan Keras¶
- tensorflow: https://www.tensorflow.org/overview
- keras: https://keras.io/about/
- Untuk membuat LSTM() layer menggunakan Keras, perhatikan parameter-parameter berikut untuk membuat LSTM layer sederhana seperti yang telah dijelaskan sebelumnya:
- units: menentukan banyaknya LSTM unit
- input_shape: menentukan ukuran timesteps dan feature, diperlukan pada layer pertama
- return_sequences: jika layer berikutnya berupa LSTM layer maka return_sequences=True (default = False)
Paramaeter-parameter lainnya dapat dilihat pada link berikut: https://keras.io/api/layers/recurrent_layers/lstm/
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, LSTM
2. Membuat Fungsi Model Forecasting Menggunakan LSTM¶
Fungsi model yang akan dibuat terdiri:
- LSTM layer dengan input_shape = (window_size, 1)
- Dense layer dengan 32 neuron dengan fungsi aktivasi ReLu
- Dropout antara Dense layer dan Dense output layer
- Dense output layer dengan 1 neuron
- loss function yang digunakan adalah Mean Squared Error (MSE)
- optimizer yang digunakan adalah adam
- metric yang digunakan adalah Mean Absolute Error (MAE)
Parameter-parameter yang dijadikan sebagai input dari fungsi tersebut adalah:
- LSTM_unit: banyaknya LSTM unit (default = 64)
- dropout: persentase dropout (default = 0.2)
def create_model(LSTM_unit=64, dropout=0.2):
# create model
model = Sequential()
model.add(LSTM(units=LSTM_unit, input_shape=(window_size, 1)))
model.add(Dense(32, activation='relu'))
model.add(Dropout(dropout))
model.add(Dense(1))
# Compile model
model.compile(loss='mse', optimizer='adam', metrics=['mae'])
return model
3. Membuat Model¶
Kita coba lakukan hypertuning pada parameter berikut seperti yang dilakukan pada Modul ke 13:
- LSTM_unit = [16,32,64,128]
- dropout = [0.1,0.2]
Selain itu, kita juga gunakan early stopping pada saat proses training
from sklearn.model_selection import GridSearchCV
from keras.wrappers.scikit_learn import KerasRegressor
from keras.callbacks import EarlyStopping
# Early Stopping
es = EarlyStopping(monitor = 'val_loss', mode = "min", patience = 5, verbose = 0)
# create model
model = KerasRegressor(build_fn=create_model, epochs=50, validation_split=0.1, batch_size=32, callbacks=[es], verbose=1)
# define the grid search parameters
LSTM_unit = [16,32,64,128]
dropout=[0.1,0.2]
param_grid = dict(LSTM_unit=LSTM_unit, dropout=dropout)
4. Membuat Variabel GridSearchCV¶
Variabel GridSearchCV dibuat dengan memasukan beberapa parameter yaitu:
- estimator: model yang ingin dilakukan gridsearch
- param_grid: parameter yang ingin diuji
- n_jobs: Jumlah pekerjaan untuk dijalankan secara paralel. (-1 artinya menggunakan seluruh core processor)
- cv: banyaknya k-fold cross validation
grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1, cv=5)
5. Training Model dengan GridSearchCV¶
grid_result = grid.fit(X_train, y_train)
Epoch 1/50 172/172 [==============================] - 7s 25ms/step - loss: 0.0189 - mae: 0.1028 - val_loss: 0.0042 - val_mae: 0.0525 Epoch 2/50 172/172 [==============================] - 3s 19ms/step - loss: 0.0070 - mae: 0.0645 - val_loss: 0.0019 - val_mae: 0.0341 Epoch 3/50 172/172 [==============================] - 3s 19ms/step - loss: 0.0052 - mae: 0.0540 - val_loss: 0.0014 - val_mae: 0.0277 Epoch 4/50 172/172 [==============================] - 3s 19ms/step - loss: 0.0044 - mae: 0.0493 - val_loss: 9.7781e-04 - val_mae: 0.0230 Epoch 5/50 172/172 [==============================] - 3s 19ms/step - loss: 0.0034 - mae: 0.0434 - val_loss: 0.0016 - val_mae: 0.0325 Epoch 6/50 172/172 [==============================] - 3s 19ms/step - loss: 0.0031 - mae: 0.0408 - val_loss: 7.5688e-04 - val_mae: 0.0207 Epoch 7/50 172/172 [==============================] - 4s 23ms/step - loss: 0.0025 - mae: 0.0367 - val_loss: 9.0058e-04 - val_mae: 0.0243 Epoch 8/50 172/172 [==============================] - 3s 19ms/step - loss: 0.0024 - mae: 0.0353 - val_loss: 8.6620e-04 - val_mae: 0.0232 Epoch 9/50 172/172 [==============================] - 3s 19ms/step - loss: 0.0021 - mae: 0.0332 - val_loss: 7.0610e-04 - val_mae: 0.0207 Epoch 10/50 172/172 [==============================] - 3s 19ms/step - loss: 0.0018 - mae: 0.0308 - val_loss: 4.8409e-04 - val_mae: 0.0169 Epoch 11/50 172/172 [==============================] - 3s 19ms/step - loss: 0.0015 - mae: 0.0288 - val_loss: 5.4704e-04 - val_mae: 0.0181 Epoch 12/50 172/172 [==============================] - 4s 23ms/step - loss: 0.0015 - mae: 0.0280 - val_loss: 4.3368e-04 - val_mae: 0.0158 Epoch 13/50 172/172 [==============================] - 3s 20ms/step - loss: 0.0015 - mae: 0.0278 - val_loss: 4.7830e-04 - val_mae: 0.0171 Epoch 14/50 172/172 [==============================] - 3s 20ms/step - loss: 0.0014 - mae: 0.0272 - val_loss: 4.6444e-04 - val_mae: 0.0168 Epoch 15/50 172/172 [==============================] - 4s 22ms/step - loss: 0.0013 - mae: 0.0262 - val_loss: 3.3847e-04 - val_mae: 0.0140 Epoch 16/50 172/172 [==============================] - 4s 21ms/step - loss: 0.0012 - mae: 0.0258 - val_loss: 3.2648e-04 - val_mae: 0.0135 Epoch 17/50 172/172 [==============================] - 4s 25ms/step - loss: 0.0012 - mae: 0.0251 - val_loss: 3.1407e-04 - val_mae: 0.0134 Epoch 18/50 172/172 [==============================] - 4s 23ms/step - loss: 0.0011 - mae: 0.0247 - val_loss: 3.7216e-04 - val_mae: 0.0145 Epoch 19/50 172/172 [==============================] - 389s 2s/step - loss: 0.0012 - mae: 0.0249 - val_loss: 4.1237e-04 - val_mae: 0.0167 Epoch 20/50 172/172 [==============================] - 5s 30ms/step - loss: 0.0011 - mae: 0.0247 - val_loss: 5.0606e-04 - val_mae: 0.0189 Epoch 21/50 172/172 [==============================] - 5s 26ms/step - loss: 0.0012 - mae: 0.0249 - val_loss: 2.9599e-04 - val_mae: 0.0131 Epoch 22/50 172/172 [==============================] - 4s 24ms/step - loss: 0.0011 - mae: 0.0242 - val_loss: 3.1131e-04 - val_mae: 0.0133 Epoch 23/50 172/172 [==============================] - 4s 24ms/step - loss: 0.0011 - mae: 0.0246 - val_loss: 4.4775e-04 - val_mae: 0.0174 Epoch 24/50 172/172 [==============================] - 4s 23ms/step - loss: 0.0011 - mae: 0.0241 - val_loss: 3.1092e-04 - val_mae: 0.0138 Epoch 25/50 172/172 [==============================] - 4s 24ms/step - loss: 0.0010 - mae: 0.0238 - val_loss: 3.1630e-04 - val_mae: 0.0139 Epoch 26/50 172/172 [==============================] - 4s 23ms/step - loss: 0.0011 - mae: 0.0240 - val_loss: 3.1004e-04 - val_mae: 0.0137
6. Melihat Hasil Parameter Terbaik¶
# summarize results
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
print("%f (%f) with: %r" % (mean, stdev, param))
# Mengambil model terbaik
best_model = grid_result.best_estimator_.model
Best: -0.000353 using {'LSTM_unit': 128, 'dropout': 0.2} -0.000501 (0.000086) with: {'LSTM_unit': 16, 'dropout': 0.1} -0.000538 (0.000135) with: {'LSTM_unit': 16, 'dropout': 0.2} -0.000429 (0.000062) with: {'LSTM_unit': 32, 'dropout': 0.1} -0.000519 (0.000089) with: {'LSTM_unit': 32, 'dropout': 0.2} -0.000394 (0.000031) with: {'LSTM_unit': 64, 'dropout': 0.1} -0.000428 (0.000058) with: {'LSTM_unit': 64, 'dropout': 0.2} -0.000370 (0.000051) with: {'LSTM_unit': 128, 'dropout': 0.1} -0.000353 (0.000053) with: {'LSTM_unit': 128, 'dropout': 0.2}
Dari Hasil Training menggunakan GridSearchCV, kita peroleh:
- parameter terbaiknya adalah: {'LSTM_unit': 128, 'dropout': 0.2}
- Rata-rata Loss Function dari hasil Cross Validation adalah 0.000353
Kemudian coba kita lihat grafik loss function MSE dan metric MAE terhadap epoch untuk melihat performa model terbaik kita dengan cara sebagai berikut
Kita dapat melihat grafik loss function MSE dan metric MAE terhadap epoch untuk melihat performa model kita dengan cara sebagai berikut
history = best_model.history
# grafik loss function MSE
plt.plot(history.history['loss'], label='Training loss')
plt.plot(history.history['val_loss'], label='Validation loss')
plt.title('loss function MSE')
plt.ylabel('MSE')
plt.xlabel('Epoch')
plt.legend()
<matplotlib.legend.Legend at 0x25d30ce2ca0>
# grafik metric MAE
plt.plot(history.history['mae'], label='Training MAE')
plt.plot(history.history['val_mae'], label='Validation MAE')
plt.title('metric MAE')
plt.ylabel('MAE')
plt.xlabel('Epoch')
plt.legend()
<matplotlib.legend.Legend at 0x25d1fb4a250>
7. Evaluasi Model¶
- Melakukan prediksi pada data train dan data test
# Prediksi data train
predict_train = scaler.inverse_transform(best_model.predict(X_train))
true_train = scaler.inverse_transform(y_train)
# Prediksi data test
predict_test = scaler.inverse_transform(best_model.predict(X_test))
true_test = scaler.inverse_transform(y_test)
- Setelah melakukan prediksi barulah kita melakukan evaluasi terhadap nilai prediksi tersebut menggunakan metric yang digunakan yaitu MAE
# Mean Absolute Error (MAE) data train
mae_train = np.mean(np.abs(true_train-predict_train))
print('MAE data train sebesar:', mae_train)
# Mean Absolute Error (MAE) test data
mae_test = np.mean(np.abs(true_test-predict_test))
print('MAE data test sebesar:', mae_test)
MAE data train sebesar: 181.03042388696178 MAE data test sebesar: 175.0919656358007
Apakah Nilai MAE Tersebut Bagus???¶
Melihat boxplot dari nilai error mutlak
abs_error_train = np.abs(true_train-predict_train)
sns.boxplot(y=abs_error_train)
<AxesSubplot:>
abs_error_test = np.abs(true_test-predict_test)
sns.boxplot(y=abs_error_test)
<AxesSubplot:>
Melihat range data
print('range data train', true_train.max()-true_train.min())
print('range data test', true_test.max()-true_test.min())
range data train 12957.999999999996 range data test 12438.0
Plot prediksi data train¶
train['predict'] = np.nan
train['predict'][-len(predict_train):] = predict_train[:,0]
plt.figure(figsize=(15,8))
sns.lineplot(data=train, x='Datetime', y='AEP_MW', label = 'train')
sns.lineplot(data=train, x='Datetime', y='predict', label = 'predict')
<AxesSubplot:xlabel='Datetime', ylabel='AEP_MW'>
Plot prediksi data test¶
test['predict'] = np.nan
test['predict'][-len(predict_test):] = predict_test[:,0]
plt.figure(figsize=(15,8))
sns.lineplot(data=test, x='Datetime', y='AEP_MW', label = 'test')
sns.lineplot(data=test, x='Datetime', y='predict', label = 'predict')
<AxesSubplot:xlabel='Datetime', ylabel='AEP_MW'>
Plot prediksi data test sebulan terakhir¶
plt.figure(figsize=(15,8))
sns.lineplot(data=test[-24*30:], x='Datetime', y='AEP_MW', label = 'test')
sns.lineplot(data=test[-24*30:], x='Datetime', y='predict', label = 'predict')
<AxesSubplot:xlabel='Datetime', ylabel='AEP_MW'>
Melakukan forecasting
# forecasting data selanjutnya
y_test = scaler.transform(test[['AEP_MW']])
n_future = 24*7
future = [[y_test[-1,0]]]
X_new = y_test[-window_size:,0].tolist()
for i in range(n_future):
y_future = best_model.predict(np.array([X_new]).reshape(1,window_size,1))
future.append([y_future[0,0]])
X_new = X_new[1:]
X_new.append(y_future[0,0])
future = scaler.inverse_transform(np.array(future))
date_future = pd.date_range(start=test['Datetime'].values[-1], periods=n_future+1, freq='H')
# Plot Data sebulan terakhir dan seminggu ke depan
plt.figure(figsize=(15,8))
sns.lineplot(data=test[-24*30:], x='Datetime', y='AEP_MW', label = 'test')
sns.lineplot(data=test[-24*30:], x='Datetime', y='predict', label = 'predict')
sns.lineplot(x=date_future, y=future[:,0], label = 'future')
plt.ylabel('AEP_MW');
Referensi
- http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.676.4320&rep=rep1&type=pdf
- https://www.asimovinstitute.org/neural-network-zoo/
- https://www.rsisinternational.org/journals/ijrsi/digital-library/volume-5-issue-3/124-129.pdf
- http://ruder.io/optimizing-gradient-descent/
- Animated RNN, LSTM and GRU. Recurrent neural network cells in GIFs | by Raimi Karim | Towards Data Science
- Illustrated Guide to LSTM’s and GRU’s: A step by step explanation | by Michael Phi | Towards Data Science
- https://github.com/chasingbob/deep-learning-resources
- https://www.coursera.org/specializations/deep-learning
- What are the best resources to learn about deep learning? - Quora
Tidak ada komentar:
Posting Komentar
Relevant & Respectful Comments Only.