
先上結(jié)論:
output保存了最后一層,每個(gè)time step的輸出h,如果是雙向LSTM,每個(gè)time step的輸出h = [h正向, h逆向] (同一個(gè)time step的正向和逆向的h連接起來(lái))。
h_n保存了每一層,最后一個(gè)time step的輸出h,如果是雙向LSTM,單獨(dú)保存前向和后向的最后一個(gè)time step的輸出h。
c_n與h_n一致,只是它保存的是c的值。
import torch
import torch.nn as nn
lstm = nn.LSTM(10, 20, 2)
x = torch.randn(5, 3, 10)
h0 = torch.randn(2, 3, 20)
c0 = torch.randn(2, 3, 20)
output, (hn, cn)=lstm(x, (h0, c0))
##------->>
output.shape torch.Size([5, 3, 20])
hn.shape torch.Size([2, 3, 20])
cn.shape torch.Size([2, 3, 20])

舉個(gè)例子:
對(duì)句子進(jìn)行LSTM操作
假設(shè)有100個(gè)句子(sequence),每個(gè)句子里有7個(gè)詞,batch_size=64,embedding_size=300
此時(shí),各個(gè)參數(shù)為:
input_size=embedding_size=300
batch=batch_size=64
seq_len=7
另外設(shè)置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])
下面單獨(dú)分析三個(gè)輸出:
- output是一個(gè)三維的張量,第一維表示序列長(zhǎng)度,第二維表示一批的樣本數(shù)(batch),第三維是 hidden_size(隱藏層大小) * num_directions ,這里是我遇到的第一個(gè)不理解的地方,hidden_sizes由我們自己定義,num_directions這是個(gè)什么鬼?翻看源碼才明白,先貼出代碼,從代碼中可以發(fā)現(xiàn)num_directions根據(jù)是“否為雙向”取值為1或2。因此,我們可以知道,output第三個(gè)維度的尺寸根據(jù)是否為雙向而變化,如果不是雙向,第三個(gè)維度等于我們定義的隱藏層大??;如果是雙向的,第三個(gè)維度的大小等于2倍的隱藏層大小。為什么使用2倍的隱藏層大???因?yàn)樗衙總€(gè)time step的前向和后向的輸出連接起來(lái)了,后面會(huì)有一個(gè)實(shí)驗(yàn),方便我們記憶。

2. h_n是一個(gè)三維的張量,第一維是num_layers*num_directions,num_layers是我們定義的神經(jīng)網(wǎng)絡(luò)的層數(shù),num_directions在上面介紹過(guò),取值為1或2,表示是否為雙向LSTM。第二維表示一批的樣本數(shù)量(batch)。第三維表示隱藏層的大小。第一個(gè)維度是h_n難理解的地方。首先我們定義當(dāng)前的LSTM為單向LSTM,則第一維的大小是num_layers,該維度表示第n層最后一個(gè)time step的輸出。如果是雙向LSTM,則第一維的大小是2 * num_layers,此時(shí),該維度依舊表示每一層最后一個(gè)time step的輸出,同時(shí)前向和后向的運(yùn)算時(shí)最后一個(gè)time step的輸出用了一個(gè)該維度。
- 舉個(gè)例子,我們定義一個(gè)num_layers=3的雙向LSTM,h_n第一個(gè)維度的大小就等于 6 (2*3),h_n[0]表示第一層前向傳播最后一個(gè)time
step的輸出,h_n[1]表示第一層后向傳播最后一個(gè)time step的輸出,h_n[2]表示第二層前向傳播最后一個(gè)time step的輸出,h_n[3]表示第二層后向傳播最后一個(gè)time step的輸出,h_n[4]和h_n[5]分別表示第三層前向和后向傳播時(shí)最后一個(gè)time step的輸出。
3. c_n與h_n的結(jié)構(gòu)一樣,就不重復(fù)贅述了。
給出一個(gè)樣例圖(畫(huà)工太差,如有錯(cuò)誤請(qǐng)指正),對(duì)比前面的例子自己分析下

最后上一段代碼結(jié)束戰(zhàn)斗
import torch
import torch.nn as nn
定義一個(gè)兩層雙向的LSTM,input size為10,hidden size為20。
隨機(jī)生成一個(gè)輸入樣本,sequence length為5,batch size為3,input size與定義的網(wǎng)絡(luò)一致,為10。
手動(dòng)初始化h0和c0,兩個(gè)結(jié)構(gòu)一致(num_layers * 2, batch, hidden_size) = (4, 3, 20)。
如果不初始化,PyTorch默認(rèn)初始化為全零的張量。
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])
根據(jù)一開(kāi)始結(jié)論,我們來(lái)驗(yàn)證下。
1.前向傳播時(shí),output中最后一個(gè)time step的前20個(gè)與hn最后一層前向傳播的輸出應(yīng)該一致。
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.后向傳播時(shí),output中最后一個(gè)time step的后20個(gè)與hn最后一層后向傳播的輸出應(yīng)該一致。
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)