PyTorch搭建雙向LSTM實(shí)現(xiàn)時(shí)間序列負(fù)荷預(yù)測(cè)
I. 前言
前面幾篇文章中介紹的都是單向LSTM,這篇文章講一下雙向LSTM。
系列文章:
PyTorch搭建LSTM實(shí)現(xiàn)多變量多步長(zhǎng)時(shí)序負(fù)荷預(yù)測(cè)
PyTorch搭建LSTM實(shí)現(xiàn)多變量時(shí)序負(fù)荷預(yù)測(cè)
PyTorch深度學(xué)習(xí)LSTM從input輸入到Linear輸出
PyTorch搭建LSTM實(shí)現(xiàn)時(shí)間序列負(fù)荷預(yù)測(cè)
II. 原理
關(guān)于LSTM的輸入輸出在深入理解PyTorch中LSTM的輸入和輸出(從input輸入到Linear輸出)中已經(jīng)有過(guò)詳細(xì)敘述。
關(guān)于nn.LSTM的參數(shù),官方文檔給出的解釋為:
總共有七個(gè)參數(shù),其中只有前三個(gè)是必須的。由于大家普遍使用PyTorch的DataLoader來(lái)形成批量數(shù)據(jù),因此batch_first也比較重要。LSTM的兩個(gè)常見(jiàn)的應(yīng)用場(chǎng)景為文本處理和時(shí)序預(yù)測(cè),因此下面對(duì)每個(gè)參數(shù)我都會(huì)從這兩個(gè)方面來(lái)進(jìn)行具體解釋。
- input_size:在文本處理中,由于一個(gè)單詞沒(méi)法參與運(yùn)算,因此我們得通過(guò)Word2Vec來(lái)對(duì)單詞進(jìn)行嵌入表示,將每一個(gè)單詞表示成一個(gè)向量,此時(shí)input_size=embedding_size。
- 比如每個(gè)句子中有五個(gè)單詞,每個(gè)單詞用一個(gè)100維向量來(lái)表示,那么這里input_size=100;
- 在時(shí)間序列預(yù)測(cè)中,比如需要預(yù)測(cè)負(fù)荷,每一個(gè)負(fù)荷都是一個(gè)單獨(dú)的值,都可以直接參與運(yùn)算,因此并不需要將每一個(gè)負(fù)荷表示成一個(gè)向量,此時(shí)input_size=1。
- 但如果我們使用多變量進(jìn)行預(yù)測(cè),比如我們利用前24小時(shí)每一時(shí)刻的[負(fù)荷、風(fēng)速、溫度、壓強(qiáng)、濕度、天氣、節(jié)假日信息]來(lái)預(yù)測(cè)下一時(shí)刻的負(fù)荷,那么此時(shí)input_size=7。
- hidden_size:隱藏層節(jié)點(diǎn)個(gè)數(shù)??梢噪S意設(shè)置。
- num_layers:層數(shù)。nn.LSTMCell與nn.LSTM相比,num_layers默認(rèn)為1。
- batch_first:默認(rèn)為False,意義見(jiàn)后文。
Inputs
關(guān)于LSTM的輸入,官方文檔給出的定義為:
可以看到,輸入由兩部分組成:input、(初始的隱狀態(tài)h_0,初始的單元狀態(tài)c_0)?
其中input:
input(seq_len, batch_size, input_size)
- seq_len:在文本處理中,如果一個(gè)句子有7個(gè)單詞,則seq_len=7;在時(shí)間序列預(yù)測(cè)中,假設(shè)我們用前24個(gè)小時(shí)的負(fù)荷來(lái)預(yù)測(cè)下一時(shí)刻負(fù)荷,則seq_len=24。
- batch_size:一次性輸入LSTM中的樣本個(gè)數(shù)。在文本處理中,可以一次性輸入很多個(gè)句子;在時(shí)間序列預(yù)測(cè)中,也可以一次性輸入很多條數(shù)據(jù)。
- input_size:見(jiàn)前文。
(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:見(jiàn)前文。
- batch_size:見(jiàn)前文。
- hidden_size:見(jiàn)前文。
Outputs
關(guān)于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ù)解釋見(jiàn)前文。
batch_first
如果在初始化LSTM時(shí)令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提前。
輸出提取
假設(shè)最后我們得到了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)過(guò)線性層后的output的shape為(batch_size, seq_len, output_size)。假設(shè)我們用前24個(gè)小時(shí)(1 to 24)預(yù)測(cè)后2個(gè)小時(shí)的負(fù)荷(25 to 26),那么seq_len=24, output_size=2。根據(jù)LSTM的原理,最終的輸出中包含了所有位置的預(yù)測(cè)值,也就是((2 3), (3 4), (4 5)…(25 26))。很顯然我們只需要最后一個(gè)預(yù)測(cè)值,即output[:, -1, :]。
而在雙向LSTM中,一開(kāi)始o(jì)utput(batch_size, seq_len, 2 * hidden_size),這里面包含了所有位置的兩個(gè)方向的輸出。簡(jiǎn)單來(lái)說(shuō),output[0]為序列從左往右第一個(gè)隱藏層狀態(tài)輸出和序列從右往左最后一個(gè)隱藏層狀態(tài)輸出的拼接;output[-1]為序列從左往右最后一個(gè)隱藏層狀態(tài)輸出和序列從右往左第一個(gè)隱藏層狀態(tài)輸出的拼接。
如果我們想要同時(shí)利用前向和后向的輸出,我們可以將它們從中間切割,然后求平均。比如output的shape為(30, 24, 2 * 64),我們將其變成(30, 24, 2, 64),然后在dim=2上求平均,得到一個(gè)shape為(30, 24, 64)的輸出,此時(shí)就與單向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. 訓(xùn)練和預(yù)測(cè)
數(shù)據(jù)處理、訓(xùn)練以及預(yù)測(cè)同前面幾篇文章。
這里對(duì)單步長(zhǎng)多變量的預(yù)測(cè)進(jìn)行對(duì)比,在其他條件保持一致的情況下,得到的實(shí)驗(yàn)結(jié)果如下所示:
方法LSTMBiLSTM(1)BiLSTM(2)MAPE7.439.299.29
可以看到,僅針對(duì)我所使用的數(shù)據(jù)而言,單向LSTM的效果更好。對(duì)于前面提到的兩種方法,貌似差異不大。
IV. 源碼及數(shù)據(jù)
源碼及數(shù)據(jù)我放在了GitHub上,LSTM-Load-Forecasting
以上就是PyTorch搭建雙向LSTM實(shí)現(xiàn)時(shí)間序列負(fù)荷預(yù)測(cè)的詳細(xì)內(nèi)容,更多關(guān)于雙向LSTM時(shí)序負(fù)荷預(yù)測(cè)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python語(yǔ)言的12個(gè)基礎(chǔ)知識(shí)點(diǎn)小結(jié)
這篇文章主要介紹了Python語(yǔ)言的12個(gè)基礎(chǔ)知識(shí)點(diǎn)小結(jié),包含正則表達(dá)式替換、遍歷目錄方法、列表按列排序、去重、字典排序等,需要的朋友可以參考下2014-07-07python實(shí)現(xiàn)圖書(shū)借閱系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)圖書(shū)借閱系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02python 機(jī)器學(xué)習(xí)的標(biāo)準(zhǔn)化、歸一化、正則化、離散化和白化
這篇文章主要介紹了聊聊機(jī)器學(xué)習(xí)的標(biāo)準(zhǔn)化、歸一化、正則化、離散化和白化,幫助大家更好的理解和學(xué)習(xí)使用python進(jìn)行機(jī)器學(xué)習(xí),感興趣的朋友可以了解下2021-04-04python實(shí)現(xiàn)的一個(gè)火車(chē)票轉(zhuǎn)讓信息采集器
這篇文章主要介紹了python實(shí)現(xiàn)的一個(gè)火車(chē)票轉(zhuǎn)讓信息采集器,采集信息來(lái)源是58同程或者趕集網(wǎng),需要的朋友可以參考下2014-07-07python深度學(xué)習(xí)tensorflow訓(xùn)練好的模型進(jìn)行圖像分類(lèi)
這篇文章主要為大家介紹了python深度學(xué)習(xí)tensorflow訓(xùn)練好的模型進(jìn)行圖像分類(lèi)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06