這是我參與8月更文挑戰的第11天,活動詳情查看: 8月更文挑戰html
一個RNN Layer以下圖所示 python
假設x的shape是[10, 3, 100]
,翻譯一下就是,10個單詞,每次訓練3句話,每一個單詞用一個100維的tensor來表達markdown
那麼對於輸入
來講,
的shape就是[3 100]
app
接着再看上面的運算過程,其中hidden len
就是memory的維度,假設是20。所以:函數
用代碼定義一個RNN Layer,而後查看其參數信息oop
import torch
import torch.nn as nn
rnn = nn.RNN(100, 20)
print(rnn._parameters.keys())
print(rnn.weight_ih_l0.shape) # w_{xh} [20, 100]
print(rnn.weight_hh_l0.shape) # w_{hh} [20, 20]
print(rnn.bias_ih_l0.shape) # b_{xh} [20]
print(rnn.bias_hh_l0.shape) # b_{hh} [20]
複製代碼
解釋上面的代碼前先看一下PyTorch中RNN類的參數(參考於PyTorch官網RNN API)post
input_size
,指定輸入序列中單個樣本的尺寸大小,例如可能用一個1000長度的向量表示一個單詞,則input_size=1000
hidden_size
,指的是隱藏層中輸出特徵的大小num_layers
,指的是縱向的隱藏層個數,通常設置爲1~10,default=1如今上面的代碼就很好理解了,nn.RNN(100, 20)
中100指的是用一個長度爲100的向量表示一個單詞,20指的是hidden_sizeui
RNN的forward函數與CNN定義的方式有點不太同樣,具體見下圖spa
參數中的 不是 ,就是直接把 帶進去翻譯
若是不寫默認就是0,若是寫的話, 的維度是
看下代碼
import torch
import torch.nn as nn
rnn = nn.RNN(input_size=100, hidden_size=20, num_layers=1)
x = torch.randn(10, 3, 100)
out, h_t = rnn(x, torch.zeros(1, 3, 20))
print(out.shape) # [10, 3, 20]
print(h_t.shape) # [1, 3, 20]
複製代碼
每一個地方參數的shape都是有關聯的,必需要把上面我寫的內容看懂了才能理解
和 很容易搞混,咱們先看一個2層的RNN模型
在解釋 和 以前要先理解一個概念——時間戳,時間戳是針左右而不是上下,什麼意思呢,就是上圖是一個兩層的RNN,假設這兩層的RNN右邊分別又各接一層,那這樣的左右結構就是時間戳,基於此,給出 和 的定義:
而第幾個memory是針對層來講的,比方說第一層的memory就是第一個memory,最後一層的memory就是最後一個memory
看下代碼
import torch
import torch.nn as nn
rnn = nn.RNN(input_size=100, hidden_size=20, num_layers=4)
x = torch.randn(10, 3, 100)
out, h_t = rnn(x)
print(out.shape) # [10, 3, 20]
print(h_t.shape) # [4, 3, 20]
複製代碼
若是理解了上面 和 的shape,這裏的輸出也就不難想到了
上面nn.RNN()
的定義方式是直接把整個
輸入,自動完成循環。下面再介紹一種定義RNN的方式,須要手動完成循環
先看一下PyTorch的官方API
參數和nn.RNN
大致類似,可是注意input_size的shape是(batch, input_size),並且hidden_size的shape也是(batch, hidden_size),這就致使forward也不同
看下代碼
import torch
import torch.nn as nn
cell1 = nn.RNNCell(100, 20)
x = torch.randn(10, 3, 100)
h1 = torch.zeros(3, 20)
for xt in x:
h1 = cell1(xt, h1)
print(h1.shape) # [3, 20]
複製代碼
上面就就是一層的RNN,用RNNCell的方式,手動循環進行訓練
下面在看一個兩層的RNN,用RNNCell的方式怎麼作
import torch
import torch.nn as nn
cell1 = nn.RNNCell(100, 30) # 100 -> 30
cell2 = nn.RNNCell(30, 20)
x = torch.randn(10, 3, 100)
h1 = torch.zeros(3, 30)
h2 = torch.zeros(3, 20)
for xt in x:
h1 = cell1(xt, h1)
h2 = cell2(h1, h2)
print(h2.shape) # [3, 20]
複製代碼
第一層的做用是將一個100維的輸入變爲30維的memory輸出,而後將輸出帶入到第二層,第二層的輸出是一個20維的memory。最重要的代碼是for中的兩句話,第一層的輸入是xt和memory h1,第二層的輸入是第一層的memory h1,以及第二層的memory h2