PyTorch搭建雙向LSTM實現(xiàn)時間序列負荷預測
I. 前言
前面幾篇文章中介紹的都是單向LSTM,這篇文章講一下雙向LSTM。
系列文章:
PyTorch搭建LSTM實現(xiàn)多變量多步長時序負荷預測
PyTorch搭建LSTM實現(xiàn)多變量時序負荷預測
PyTorch深度學習LSTM從input輸入到Linear輸出
II. 原理
關于LSTM的輸入輸出在深入理解PyTorch中LSTM的輸入和輸出(從input輸入到Linear輸出)中已經(jīng)有過詳細敘述。
關于nn.LSTM的參數(shù),官方文檔給出的解釋為:

總共有七個參數(shù),其中只有前三個是必須的。由于大家普遍使用PyTorch的DataLoader來形成批量數(shù)據(jù),因此batch_first也比較重要。LSTM的兩個常見的應用場景為文本處理和時序預測,因此下面對每個參數(shù)我都會從這兩個方面來進行具體解釋。
- input_size:在文本處理中,由于一個單詞沒法參與運算,因此我們得通過Word2Vec來對單詞進行嵌入表示,將每一個單詞表示成一個向量,此時input_size=embedding_size。
- 比如每個句子中有五個單詞,每個單詞用一個100維向量來表示,那么這里input_size=100;
- 在時間序列預測中,比如需要預測負荷,每一個負荷都是一個單獨的值,都可以直接參與運算,因此并不需要將每一個負荷表示成一個向量,此時input_size=1。
- 但如果我們使用多變量進行預測,比如我們利用前24小時每一時刻的[負荷、風速、溫度、壓強、濕度、天氣、節(jié)假日信息]來預測下一時刻的負荷,那么此時input_size=7。
- hidden_size:隱藏層節(jié)點個數(shù)。可以隨意設置。
- num_layers:層數(shù)。nn.LSTMCell與nn.LSTM相比,num_layers默認為1。
- batch_first:默認為False,意義見后文。
Inputs
關于LSTM的輸入,官方文檔給出的定義為:

可以看到,輸入由兩部分組成:input、(初始的隱狀態(tài)h_0,初始的單元狀態(tài)c_0)?
其中input:
input(seq_len, batch_size, input_size)
- seq_len:在文本處理中,如果一個句子有7個單詞,則seq_len=7;在時間序列預測中,假設我們用前24個小時的負荷來預測下一時刻負荷,則seq_len=24。
- batch_size:一次性輸入LSTM中的樣本個數(shù)。在文本處理中,可以一次性輸入很多個句子;在時間序列預測中,也可以一次性輸入很多條數(shù)據(jù)。
- input_size:見前文。
(h_0, c_0):
h_0(num_directions * num_layers, batch_size, hidden_size) c_0(num_directions * num_layers, batch_size, hidden_size)
h_0和c_0的shape一致。
- num_directions:如果是雙向LSTM,則num_directions=2;否則num_directions=1。
- num_layers:見前文。
- batch_size:見前文。
- hidden_size:見前文。
Outputs
關于LSTM的輸出,官方文檔給出的定義為:

可以看到,輸出也由兩部分組成:otput、(隱狀態(tài)h_n,單元狀態(tài)c_n)
其中output的shape為:
output(seq_len, batch_size, num_directions * hidden_size)
h_n和c_n的shape保持不變,參數(shù)解釋見前文。
batch_first
如果在初始化LSTM時令batch_first=True,那么input和output的shape將由:
input(seq_len, batch_size, input_size) output(seq_len, batch_size, num_directions * hidden_size)
變?yōu)椋?/p>
input(batch_size, seq_len, input_size) output(batch_size, seq_len, num_directions * hidden_size)
即batch_size提前。
輸出提取
假設最后我們得到了output(batch_size, seq_len, 2 * hidden_size),我們需要將其輸入到線性層,有以下兩種方法可以參考:
(1)直接輸入
和單向一樣,我們可以將output直接輸入到Linear。在單向LSTM中:
self.linear = nn.Linear(self.hidden_size, self.output_size)
而在雙向LSTM中:
self.linear = nn.Linear(2 * self.hidden_size, self.output_size)
模型:
class BiLSTM(nn.Module):
def __init__(self, input_size, hidden_size, num_layers, output_size, batch_size):
super().__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.num_layers = num_layers
self.output_size = output_size
self.num_directions = 2
self.batch_size = batch_size
self.lstm = nn.LSTM(self.input_size, self.hidden_size, self.num_layers, batch_first=True, bidirectional=True)
self.linear = nn.Linear(self.num_directions * self.hidden_size, self.output_size)
def forward(self, input_seq):
h_0 = torch.randn(self.num_directions * self.num_layers, self.batch_size, self.hidden_size).to(device)
c_0 = torch.randn(self.num_directions * self.num_layers, self.batch_size, self.hidden_size).to(device)
# print(input_seq.size())
seq_len = input_seq.shape[1]
# input(batch_size, seq_len, input_size)
input_seq = input_seq.view(self.batch_size, seq_len, self.input_size)
# output(batch_size, seq_len, num_directions * hidden_size)
output, _ = self.lstm(input_seq, (h_0, c_0))
# print(self.batch_size * seq_len, self.hidden_size)
output = output.contiguous().view(self.batch_size * seq_len, self.num_directions * self.hidden_size) # (5 * 30, 64)
pred = self.linear(output) # pred()
pred = pred.view(self.batch_size, seq_len, -1)
pred = pred[:, -1, :]
return pred
(2)處理后再輸入
在LSTM中,經(jīng)過線性層后的output的shape為(batch_size, seq_len, output_size)。假設我們用前24個小時(1 to 24)預測后2個小時的負荷(25 to 26),那么seq_len=24, output_size=2。根據(jù)LSTM的原理,最終的輸出中包含了所有位置的預測值,也就是((2 3), (3 4), (4 5)…(25 26))。很顯然我們只需要最后一個預測值,即output[:, -1, :]。
而在雙向LSTM中,一開始output(batch_size, seq_len, 2 * hidden_size),這里面包含了所有位置的兩個方向的輸出。簡單來說,output[0]為序列從左往右第一個隱藏層狀態(tài)輸出和序列從右往左最后一個隱藏層狀態(tài)輸出的拼接;output[-1]為序列從左往右最后一個隱藏層狀態(tài)輸出和序列從右往左第一個隱藏層狀態(tài)輸出的拼接。
如果我們想要同時利用前向和后向的輸出,我們可以將它們從中間切割,然后求平均。比如output的shape為(30, 24, 2 * 64),我們將其變成(30, 24, 2, 64),然后在dim=2上求平均,得到一個shape為(30, 24, 64)的輸出,此時就與單向LSTM的輸出一致了。
具體處理方法:
output = output.contiguous().view(self.batch_size, seq_len, self.num_directions, self.hidden_size) output = torch.mean(output, dim=2)
模型代碼:
class BiLSTM(nn.Module):
def __init__(self, input_size, hidden_size, num_layers, output_size, batch_size):
super().__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.num_layers = num_layers
self.output_size = output_size
self.num_directions = 2
self.batch_size = batch_size
self.lstm = nn.LSTM(self.input_size, self.hidden_size, self.num_layers, batch_first=True, bidirectional=True)
self.linear = nn.Linear(self.hidden_size, self.output_size)
def forward(self, input_seq):
h_0 = torch.randn(self.num_directions * self.num_layers, self.batch_size, self.hidden_size).to(device)
c_0 = torch.randn(self.num_directions * self.num_layers, self.batch_size, self.hidden_size).to(device)
# print(input_seq.size())
seq_len = input_seq.shape[1]
# input(batch_size, seq_len, input_size)
input_seq = input_seq.view(self.batch_size, seq_len, self.input_size)
# output(batch_size, seq_len, num_directions * hidden_size)
output, _ = self.lstm(input_seq, (h_0, c_0))
output = output.contiguous().view(self.batch_size, seq_len, self.num_directions, self.hidden_size)
output = torch.mean(output, dim=2)
pred = self.linear(output)
# print('pred=', pred.shape)
pred = pred.view(self.batch_size, seq_len, -1)
pred = pred[:, -1, :]
return pred
III. 訓練和預測
數(shù)據(jù)處理、訓練以及預測同前面幾篇文章。
這里對單步長多變量的預測進行對比,在其他條件保持一致的情況下,得到的實驗結果如下所示:
方法LSTMBiLSTM(1)BiLSTM(2)MAPE7.439.299.29
可以看到,僅針對我所使用的數(shù)據(jù)而言,單向LSTM的效果更好。對于前面提到的兩種方法,貌似差異不大。
IV. 源碼及數(shù)據(jù)
源碼及數(shù)據(jù)我放在了GitHub上,LSTM-Load-Forecasting
以上就是PyTorch搭建雙向LSTM實現(xiàn)時間序列負荷預測的詳細內(nèi)容,更多關于雙向LSTM時序負荷預測的資料請關注腳本之家其它相關文章!
相關文章
Python基于wordcloud及jieba實現(xiàn)中國地圖詞云圖
這篇文章主要介紹了Python基于wordcloud及jieba實現(xiàn)中國地圖詞云圖,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-06-06
Python使用pylab庫實現(xiàn)畫線功能的方法詳解
這篇文章主要介紹了Python使用pylab庫實現(xiàn)畫線功能的方法,結合具體實例分析了Python使用pylab庫的相關函數(shù)實現(xiàn)畫線功能的操作技巧,并附帶說明了相關函數(shù)與參數(shù)功能,需要的朋友可以參考下2017-06-06
Python使用__new__()方法為對象分配內(nèi)存及返回對象的引用示例
這篇文章主要介紹了Python使用__new__()方法為對象分配內(nèi)存及返回對象的引用,結合實例形式分析了Python對象初始化及內(nèi)存操作相關使用技巧,需要的朋友可以參考下2019-09-09
VSCODE配置Markdown及Markdown基礎語法詳解
這篇文章主要介紹了VSCODE配置Markdown及Markdown基礎語法詳解,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01
用Python獲取攝像頭并實時控制人臉的實現(xiàn)示例
這篇文章主要介紹了用Python獲取攝像頭并實時控制人臉的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-07-07
PyTorch中 tensor.detach() 和 tensor.data 的區(qū)別詳解
今天小編就為大家分享一篇PyTorch中 tensor.detach() 和 tensor.data 的區(qū)別詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-01-01
Django利用elasticsearch(搜索引擎)實現(xiàn)搜索功能
這篇文章主要介紹了Django利用elasticsearch(搜索引擎)實現(xiàn)搜索功能,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-11-11

