針對單變量時間序列使用Vanilla LSTM, Stacked LSTM, Bidirectional LSTM, CNN+LSTM的的模型架構與介紹
單變量的時間序列資料
首先單變量的時間序列不論因、果,都應該只有一個變數。而因為是時間序列,所以形式會如下所示:
X= [10, 20, 30], y = [40]
X裡面的3個元素不代表3個不同的變量,而是單一變量在不同時間步的數值。
Vanilla LSTM
首先我們會可以用一個最為單純的LSTM(Vanilla LSTM)來進行預測,視為BaseLine,或者也可以先用昨天提到的Zero-Rule Algorithm做一個BaseLine。
Note: 這是一個回歸(Regression)問題,所以Zero-Rule Algorithm可能會是取y的平均值或中位數進行預測。
Vanilla LSTM的架構如下所示:
# define model
model = Sequential()
model.add(LSTM(50, activation=’relu’, input_shape=(n_steps, n_features)))
model.add(Dense(1))
model.compile(optimizer=’adam’, loss=’mse’)
要特別注意的是Input-shape
假設你是使用Keras來搭建LSTM Layer,其預設的Input-shape應該要是
[Batch-size, TimeSteps, Features]
這邊需要確定時間序列的產生是否符合規範。
但最單純的LSTM也許效果不夠好,這時候我們可以考慮採用Stacked LSTM。
Stacked LSTM
Stack LSTM是把兩個LSTM的模型連續的串接在一起。
需要注意,我們必須把第一層LSTM Layer的return_sequence
參數設成True
,因為LSTM預設的輸入會是3維,包含batch_size, timesteps, features
,但預設的LSTM輸出是最後一個TimeStep的時間序列,所以會變成
[batch_size, units]
這樣的輸出,units
表示LSTM Layer中的神經元數量。
而如果有把return_sequence
設成True
,輸出會是n個2維的陣列(n = TimeSteps),這滿足了LSTM對於3維輸入的需求。
Stacked LSTM的優點
儘管沒有明確的理論表示Stacked的優勢,但根據經驗,他有幾個優點:
- 能夠對輸入的時間序列資料產生更複雜的特徵表示
- 由於LSTM不論是否Stacked,最後一層LSTM的輸出總是一個序列的常數項,這表示在這個過程是在壓縮一個序列,而我們相信透過Stacked LSTM可以更好的對序列進行壓縮
Stacked LSTM的架構如下所示
# define model
model = Sequential()
model.add(LSTM(50, activation=’relu’, return_sequences=True, input_shape=(n_steps, n_features)))
model.add(LSTM(50, activation=’relu’))
model.add(Dense(1))
model.compile(optimizer=’adam’, loss=’mse’)
Bidirectional LSTM(雙向LSTM)
他可以讓時間序列同時以順向和反向的方式輸入LSTM Layer並進行訓練。
他是否具有優勢需視問題而定,但我們可以討論他應該產生的效果:
不只是理解從過去的資料如何產生現在的資料,同時也會分析未來的資料如何對應到過去的資料。
這在翻譯或文本問題上是很需要的功能,事實上,他在image caption, future prediction, language translation等等的問題上都已被證明比單純的Vanilla LSTM或Stacked LSTM有更好的效果。
Bidirectional LSTM的模型架構如下所示
# define model
model = Sequential()
model.add(Bidirectional(LSTM(50, activation=’relu’), input_shape=(n_steps, n_features)))
model.add(Dense(1))
model.compile(optimizer=’adam’, loss=’mse’)
CNN LSTM
CNN與LSTM的結合是一種很有效率的模型架構。
CNN可以有效地在一維序列上萃取特徵,例如在單變量時間序列的資料上,也就是從每個時間步中分別進行特徵萃取,並找出跨時間步的特徵。
LSTM可以學習不同時間步之間的資料相關性,並可以視為將資料時間序列的資料跨時間步的壓縮成一個低維表示。
為了讓CNN能夠讀取時間序列資料,我們需要使用TimeDistributed封裝器來讓每個時間步的資料可以被卷積層處理。
但由於TimeDistributed的輸入需要加上一個TimeStep的參數,表示有幾個TimeSteps,而CNN預設的輸入是3維的,所以要先把原始的時間序列資料轉換成如下格式:
[samples, subsequences, timesteps, features]
每一個sample就是每一個Timestep的輸入資料,會一個一個Timestep輸入CNNLayer中。
一個簡單的Timedistributed CNN+LSTM的架構如下所示:
# define model
model = Sequential()
model.add(TimeDistributed(Conv1D(filters=64, kernel_size=1, activation=’relu’), input_shape=(None, n_steps, n_features)))
model.add(TimeDistributed(MaxPooling1D(pool_size=2)))
model.add(TimeDistributed(Flatten()))
model.add(LSTM(50, activation=’relu’))
model.add(Dense(1))
model.compile(optimizer=’adam’, loss=’mse’)