這里num_layers是同一個time_step的結構堆疊,Lstm堆疊層數與time step無關。Time step表示的是時間序列長度,它是由數據的inputsize決定,你輸的數據時序有多長,那么神經網絡會自動確定,時間序列長度只需要與你輸入的數據時序長度保持一致即可。
lstm=nn.LSTM(input_size, hidden_size, num_layers)
x seq_len, batch, input_size
h0 num_layers× \times×num_directions, batch, hidden_size
c0 num_layers× \times×num_directions, batch, hidden_size
output seq_len, batch, num_directions× \times×hidden_size
hn num_layers× \times×num_directions, batch, hidden_size
cn num_layers× \times×num_directions, batch, hidden_size
舉個例子:
對句子進行LSTM操作
假設有100個句子(sequence),每個句子里有7個詞,batch_size=64,embedding_size=300
此時,各個參數為:
input_size=embedding_size=300
batch=batch_size=64
seq_len=7
另外設置hidden_size=100, num_layers=1
import torch
import torch.nn as nn
lstm = nn.LSTM(300, 100, 1)
x = torch.randn(7, 64, 300)
h0 = torch.randn(1, 64, 100)
c0 = torch.randn(1, 64, 100)
output, (hn, cn)=lstm(x, (h0, c0))
>>
output.shape torch.Size([7, 64, 100])
hn.shape torch.Size([1, 64, 100])
cn.shape torch.Size([1, 64, 100])
---------------------
作者:huxuedan01
來源:CSDN
原文:https://blog.csdn.net/m0_37586991/article/details/88561746
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!
二、雙向LSTM模型
1、雙向LSTM的結構
雙向LSTM(Bidirectional Long-Short Term Memorry,Bi-LSTM)不僅能利用到過去的信息,還能捕捉到后續的信息,比如在詞性標注問題中,一個詞的詞性由上下文的詞所決定,那么用雙向LSTM就可以利用好上下文的信息。
雙向LSTM由兩個信息傳遞相反的LSTM循環層構成,其中第一層按時間順序傳遞信息,第二層按時間逆序傳遞信息。
沒有去找雙向LSTM的圖了,就看這個雙向RNN的結構來學習吧,理解了雙向RNN,那么把循環層的記憶細胞換成LSTM就行。
2、雙向LSTM隱狀態的計算
關鍵在於隱狀態如何計算。為了簡單,還是按照雙向RNN的公式進行理解,我們看隱狀態如何計算。可以看到t時刻第一層(順時間循環層)的隱狀態ht(1)取決於前一時刻的隱狀態ht-1(1)和輸入值xt,這一點非常容易理解。
而要注意的是第二層(逆時間循環層)的隱狀態則依然取決於前一時刻的隱狀態和輸入值x,這與堆疊的LSTM不同,堆疊的LSTM其l層的隱狀態不由輸入值x直接輸入得到,而是取決於該層前一時刻的隱狀態和當前時刻下一層的隱狀態。如下的公式就是堆疊的循環網絡層中隱狀態的計算過程。
雙向LSTM和堆疊的LSTM可以結合使用,在順時間循環層我們可以構造堆疊多層的LSTM,同樣,在逆時間循環層可以堆疊多個。
而雙向LSTM的一個循環層中有兩個隱狀態,長期狀態C用於內部傳遞信息,不拋頭露面,而短期狀態h則作為該循環層的輸出,用於其他循環層或全連接層的計算。因此在對得的雙向LSTM的最后一步,會有超過4個隱狀態存在。
先上結論:
- output保存了最后一層,每個time step的輸出h,如果是雙向LSTM,每個time step的輸出h = [h正向, h逆向] (同一個time step的正向和逆向的h連接起來)。
- h_n保存了每一層,最后一個time step的輸出h,如果是雙向LSTM,單獨保存前向和后向的最后一個time step的輸出h。
- c_n與h_n一致,只是它保存的是c的值。
下面單獨分析三個輸出:
- output是一個三維的張量,第一維表示序列長度,第二維表示一批的樣本數(batch),第三維是 hidden_size(隱藏層大小) * num_directions ,這里是我遇到的第一個不理解的地方,hidden_sizes由我們自己定義,num_directions這是個什么鬼?翻看源碼才明白,先貼出代碼,從代碼中可以發現num_directions根據是“否為雙向”取值為1或2。因此,我們可以知道,output第三個維度的尺寸根據是否為雙向而變化,如果不是雙向,第三個維度等於我們定義的隱藏層大小;如果是雙向的,第三個維度的大小等於2倍的隱藏層大小。為什么使用2倍的隱藏層大小?因為它把每個time step的前向和后向的輸出連接起來了,后面會有一個實驗,方便我們記憶。
2. h_n是一個三維的張量,第一維是num_layers*num_directions,num_layers是我們定義的神經網絡的層數,num_directions在上面介紹過,取值為1或2,表示是否為雙向LSTM。第二維表示一批的樣本數量(batch)。第三維表示隱藏層的大小。第一個維度是h_n難理解的地方。首先我們定義當前的LSTM為單向LSTM,則第一維的大小是num_layers,該維度表示第n層最后一個time step的輸出。如果是雙向LSTM,則第一維的大小是2 * num_layers,此時,該維度依舊表示每一層最后一個time step的輸出,同時前向和后向的運算時最后一個time step的輸出用了一個該維度。
- 舉個例子,我們定義一個num_layers=3的雙向LSTM,h_n第一個維度的大小就等於 6 (2*3),h_n[0]表示第一層前向傳播最后一個time
step的輸出,h_n[1]表示第一層后向傳播最后一個time step的輸出,h_n[2]表示第二層前向傳播最后一個time step的輸出,h_n[3]表示第二層后向傳播最后一個time step的輸出,h_n[4]和h_n[5]分別表示第三層前向和后向傳播時最后一個time step的輸出。
3. c_n與h_n的結構一樣,就不重復贅述了。
給出一個樣例圖(畫工太差,如有錯誤請指正),對比前面的例子自己分析下
最后上一段代碼結束戰斗
import torch
import torch.nn as nn
定義一個兩層雙向的LSTM,input size為10,hidden size為20。
隨機生成一個輸入樣本,sequence length為5,batch size為3,input size與定義的網絡一致,為10。
手動初始化h0和c0,兩個結構一致(num_layers * 2, batch, hidden_size) = (4, 3, 20)。
如果不初始化,PyTorch默認初始化為全零的張量。
bilstm = nn.LSTM(input_size=10, hidden_size=20, num_layers=2, bidirectional=True)
input = torch.randn(5, 3, 10)
h0 = torch.randn(4, 3, 20)
c0 = torch.randn(4, 3, 20)
output, (hn, cn) = bilstm(input, (h0, c0))
查看output,hn,cn的維度
print('output shape: ', output.shape)
print('hn shape: ', hn.shape)
print('cn shape: ', cn.shape)
輸出:
output shape: torch.Size([5, 3, 40])
hn shape: torch.Size([4, 3, 20])
cn shape: torch.Size([4, 3, 20])
根據一開始結論,我們來驗證下。
1.前向傳播時,output中最后一個time step的前20個與hn最后一層前向傳播的輸出應該一致。
output[4, 0, :20] == hn[2, 0]
輸出:
tensor([ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1], dtype=torch.uint8)
2.后向傳播時,output中最后一個time step的后20個與hn最后一層后向傳播的輸出應該一致。
output[0, 0, 20:] == hn[3, 0]
輸出:
tensor([ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1], dtype=torch.uint8)