LSTM 類神經網路學習紀錄

常說深度學習有三大網路,分別是 DNN、 CNN 與 RNN。DNN 就是一般類神經網路的多層網路,廣泛的應用在一般資料的機器學習任務。CNN 則是擁有捲積層的特化類神經網路,捲積層的特性使得這類網路在圖像辨識的應用上表現非常突出,一般有關圖像的任務大多使用 CNN 處理,至於 RNN 就是所謂的遞歸神經網路,擁有對過去歷史記錄記憶的能力,可以找出不同時間點記錄的行為模式,因此常應用於序列資料模式學習等相關任務,像是時間序列預測,語言翻譯等等。

而 LSTM 是其中一種 RNN ,由於其改進了傳統 RNN 的缺點,因此現在一般來說 LSTM 算是最常使用的 RNN 了,以下記錄我使用 kreas 實作 LSTM 的學習記錄:
資料我使用網路上參考的 sine-wave 資料,5001 筆記錄與 1 個特徵維度,視覺化資料為下圖所示:

要做的是對 sine-wave 預測資料走勢的任務,而要給 LSTM 的 input 資料必須要經過轉換才可做後續的訓練,參考 keras 的官方文檔可以得知 recurrent layers 接受的 input shape 為 (batch_size, timesteps, input_dim)batch_size 表示每次 LSTM 收到多少筆序列資料來執行梯度下降的序列資料筆數,換句話說 LSTM 基本的數入單位就是一筆序列記錄,timesteps 就是指該筆序列記錄從時間點 t 往回看多少單位時間點的長度,像是 timesteps=3 表示往回看了 t-2, t-1, t 共三筆記錄,而 input_dim 就是這個序列記錄的維度數,即有多少特徵,像是本資料的例子只有 1 個特徵,因此 input_dim =1

而要如何將原本的資料轉換成序列資料的形式呢?這裡的例子很簡單,概念就是去做 time slice window 轉換。如以下的程式碼所示設定window_size = 50將原本維度為 (5001, 1) 資料轉換乘 (4951, 51) 維度,這裡的 51 就是 timesteps 數,50 多了 1 是要做為預測目標變數 y 之用。

1
2
3
4
5
window_size = 50
series_s = series.copy()
for i in range(window_size):
series = pd.concat([series, series_s.shift(-(i+1))], axis = 1)
series.dropna(axis=0, inplace=True)

之後將轉換後的資料切分 train 與 test 資料:

1
2
3
4
5
6
7
8
9
10
11
12
nrow = round(0.8*series.shape[0])
train = series.iloc[:nrow, :]
test = series.iloc[nrow:,:]

train_X = (train.iloc[:,:-1]).values
train_y = (train.iloc[:,-1]).values
test_X = (test.iloc[:,:-1]).values
test_y = (test.iloc[:,-1]).values

# reshape to (batch_size, timesteps, input_dim)
train_X = train_X.reshape(train_X.shape[0],train_X.shape[1],1)
test_X = test_X.reshape(test_X.shape[0],test_X.shape[1],1)

接下來就是建立 model 的部分了,這裡建立了一個很簡單的 LSTM 模型,新版 keras 2.0 的 recurrent layers API 已可以不限制 input timesteps 的長度,所以 input_shape=(None,1),而 batch size 這裏則是在 fit 資料時設定。

1
2
3
4
5
6
# Define the LSTM model
model = Sequential()
model.add(LSTM(10, input_shape=(None,1)))
model.add(Dense(1))
model.compile(loss="mse", optimizer="adam")
model.summary()
1
2
3
4
5
6
7
8
9
10
-----------------------------------------------------------------
Layer (type) Output Shape Param #
=================================================================
lstm_47 (LSTM) (None, 10) 480
-----------------------------------------------------------------
dense_33 (Dense) (None, 1) 11
=================================================================
Total params: 491
Trainable params: 491
Non-trainable params: 0

經過一番參數調整後,最後模型的預測結果挺不錯的,連 mse 都小到趨近於 0 無法顯示而溢位了。

1
2
3
4
model.fit(train_X, train_y, batch_size=128, epochs=20, validation_split=0.1)
preds = model.predict(test_X)
actuals = test_y
mean_squared_error(actuals,preds)
1
6.0673873664723943e-06

視覺化出來預測結果與實際測試資料的預測變數 Y 分佈可以發現幾乎一模一樣重疊在一起了,證明了這個 LSTM 模型學習成功。

1
2
3
pyplot.plot(actuals)
pyplot.plot(preds)
pyplot.show()

reference:
https://machinelearningmastery.com/timedistributed-layer-for-long-short-term-memory-networks-in-python/