PyTorch中的循環神經網絡(RNN+LSTM+GRU)

一、RNN網絡

在這裏插入圖片描述

1、Pytorch中的RNN參數詳解

rnn = nn.RNN(*arg,**kwargs)
(1)input_size:輸入xtx_t的維度
(2)hidden_size:輸出hth_t的維度
(3)num_layers:網絡的層數,默認爲1層
(4)nonlinearity:非線性激活函數,默認是tanh,也可以選擇relu等
(5)bias:是否有偏置。默認爲True
(6)batch first:決定網絡輸入的維度順序,默認爲(seq,batch,feature),如果參數設置爲True,順序變爲(batch,seq,feature)。RNN batch在第二個維度,CNN batch在第一個維度。
(7)dropout:接受一個0-1之間的數值,會在網絡中除了最後一層外的其他輸出層加上dropout層。
(8)bidirectional:默認爲False,表示單項循環神經網絡;如果設置爲True,就是雙向循環神經網絡。

2、輸入、輸出的維度

(1)網絡節後一個序列輸入xtx_t和記憶輸入h0h_0xtx_t的維度是(seq,batch,feature);h0h_0隱狀態的維度(layersdirection,batch,hidden)(layers*direction,batch,hidden),表示層數乘以方向(單項爲1,雙向爲2),批量,輸出的維度
(2)網絡會輸出output和hth_t。output表示網絡實際的輸出,維度是(seq,batch,hidden*direction),表示序列長度、批量和輸出維度乘以方向;hth_t表示記憶單元,維度(layersdirection,batch,hidden)(layers*direction,batch,hidden),表示層數乘以方向,批量,輸出的維度

3、需要注意的問題:

(1)網絡輸出是(seq,batch,hiddendirection)(seq,batch,hidden*direction),direction=1或2。如果是雙向的網絡結構,相當於網絡從左往右計算一次,再從右往左計算依次,這樣會有兩個結果。將兩個結果按最後一個維度拼接起來,就是輸出的維度
(2)隱藏狀態的網絡大小、輸入和輸出都是(layer*direction,batch,hidden)時,因爲如果網絡有多層,那麼每一層都有一個新的記憶單元,而雙向網絡結構在每一層左右會有兩個不同的記憶單元,所以維度的第一位是layerdirectionlayer*direction

4、RNN代碼實現

import torch
from torch.autograd import Variable
import torch.nn as nn

rnn = nn.RNN(input_size=20,hidden_size=50,num_layers=2)
input_data = Variable(torch.randn(100,32,20))  #seq,batch,feature
#如果傳入網絡時,不特別註明隱狀態,那麼輸出的隱狀態默認參數全是0
h_0 = Variable(torch.randn(2,32,50))  #layer*direction,batch,hidden_size
output,h_t = rnn(input_data,h_0)

print(output.size())  #seq,batch,hidden_size
print(h_t.size())   #layer*direction,batch,hidden_size
print(rnn.weight_ih_l0.size())

打印結果:
torch.Size([100, 32, 50])
torch.Size([2, 32, 50])
torch.Size([50, 20]

二、LSTM網絡

在這裏插入圖片描述

1、LSTM介紹

rnn = nn.LSTM(*arg,**kwargs)
LSTM在本質上和標準 RNN一樣的,下面主要介紹兩者的不同:

(1)LSTM參數是RNN的四倍
因爲LSTM中間比標準RNN多了三個線性變換,多的三個線性變換的權主拼在一起, 所以一共是 4 倍,同理偏置也是4倍。
(2)輸入和輸出多了一個記憶單元
LSTM的輸入也不再只有序列輸入和隱藏狀態,隱藏狀態除了h0h_0以外,還多了一個C0C_0它們合在一起成爲網絡的隱藏狀態,而且它們的大小完全一樣,第一事故(layer*direction,batch,hidden),當然輸出也會有hth_tCtC_t

2、LSTM代碼實現

#定義網絡
lstm = nn.LSTM(input_size=20,hidden_size=50,num_layers=2)
#輸入變量
input_data = Variable(torch.randn(100,32,20))
#初始隱狀態
h_0 = Variable(torch.randn(2,32,50))
#輸出記憶細胞
c_0 = Variable(torch.randn(2,32,50))
#輸出變量
output,(h_t,c_t) = lstm(input_data,(h_0,c_0)) 
print(output.size())
print(h_t.size())
print(c_t.size())
#參數大小爲(50x4,20),是RNN的四倍
print(lstm.weight_ih_l0)
print(lstm.weight_ih_l0.size())

打印結果:
torch.Size([100, 32, 50])
torch.Size([2, 32, 50])
torch.Size([2, 32, 50])
tensor([[ 0.0068, -0.0925, -0.0343, …, -0.1059, 0.0045, -0.1335],
[-0.0509, 0.0135, 0.0100, …, 0.0282, -0.1232, 0.0330],
[-0.0425, 0.1392, 0.1140, …, -0.0740, -0.1214, 0.1087],
…,
[ 0.0217, -0.0032, 0.0815, …, -0.0605, 0.0636, 0.1197],
[ 0.0144, 0.1288, -0.0569, …, 0.1361, 0.0837, -0.0021],
[ 0.0355, 0.1045, 0.0339, …, 0.1412, 0.0371, 0.0649]],
requires_grad=True)
torch.Size([200, 20])

三、GRU網絡

在這裏插入圖片描述

1、GRU介紹

rnn = nn.GRU(*arg,**kwargs)
GRU將LSTM的輸入門和遺忘門合併。與LSTM有如下2個不同:
(1)GRU參數是RNN的三倍
(2)隱狀態是有h0h_0
從結構圖可以看出,GRU隱狀態不再是h0h_0C0C_0,只有一個h0h_0,輸出也只有一個hth_t

2、代碼實現

gru = nn.GRU(input_size=20,hidden_size=50,num_layers=2)
#輸入變量
input_data = Variable(torch.randn(100,32,20))
#初始隱狀態
h_0 = Variable(torch.randn(2,32,50))
#輸出變量
output,(h_n,c_n) = gru(input_data)  #lstm(input_data,h_0) 不定義初始隱狀態默認爲0
print(output.size())
print(h_n.size())
print(gru.weight_ih_l0)
print(gru.weight_ih_l0.size())

打印結果:
torch.Size([100, 32, 50])
torch.Size([32, 50])
Parameter containing:
tensor([[ 0.0878, 0.0383, -0.0261, …, 0.0801, -0.0932, -0.1267],
[ 0.0275, 0.1129, -0.0306, …, -0.0837, 0.0824, -0.1332],
[ 0.1061, -0.0786, -0.0163, …, -0.0622, -0.0350, -0.0417],
…,
[-0.0923, -0.0106, -0.0196, …, 0.0944, 0.0085, 0.0387],
[-0.0181, 0.0431, -0.1382, …, -0.1383, 0.0229, 0.1021],
[-0.0962, 0.0980, -0.0306, …, 0.0871, -0.0827, -0.0811]],
requires_grad=True)
torch.Size([150, 20])

PyTorch 中還提供了RNNCell、LSTMCell、GRUCell,這三個分別是上面介紹的三個函數的單步版木,也就是說它們的輸入不再是一個 序列,而是一個序列中的一步,也可以說是循環神經網絡的一個循環,在序列的應用上更加靈活,因爲序列中每一步都是手動實現的,能夠在基礎上添加更多自定義的操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章