pytorch lstm gru rnn 得到每個state輸出的操作
默認(rèn)只返回最后一個state,所以一次輸入一個step的input
# coding=UTF-8 import torch import torch.autograd as autograd # torch中自動計算梯度模塊 import torch.nn as nn # 神經(jīng)網(wǎng)絡(luò)模塊 torch.manual_seed(1) # lstm單元輸入和輸出維度都是3 lstm = nn.LSTM(input_size=3, hidden_size=3) # 生成一個長度為5,每一個元素為1*3的序列作為輸入,這里的數(shù)字3對應(yīng)于上句中第一個3 inputs = [autograd.Variable(torch.randn((1, 3))) for _ in range(5)] # 設(shè)置隱藏層維度,初始化隱藏層的數(shù)據(jù) hidden = (autograd.Variable(torch.randn(1, 1, 3)), autograd.Variable(torch.randn((1, 1, 3)))) for i in inputs: out, hidden = lstm(i.view(1, 1, -1), hidden) print(out.size()) print(hidden[0].size()) print("--------") print("-----------------------------------------------") # 下面是一次輸入多個step的樣子 inputs_stack = torch.stack(inputs) out,hidden = lstm(inputs_stack,hidden) print(out.size()) print(hidden[0].size())
print結(jié)果:
(1L, 1L, 3L)
(1L, 1L, 3L)
--------
(1L, 1L, 3L)
(1L, 1L, 3L)
--------
(1L, 1L, 3L)
(1L, 1L, 3L)
--------
(1L, 1L, 3L)
(1L, 1L, 3L)
--------
(1L, 1L, 3L)
(1L, 1L, 3L)
--------
----------------------------------------------
(5L, 1L, 3L)
(1L, 1L, 3L)
可見LSTM的定義都是不用變的,根據(jù)input的step數(shù)目,一次輸入多少step,就一次輸出多少output,但只輸出最后一個state
補(bǔ)充:pytorch中實(shí)現(xiàn)循環(huán)神經(jīng)網(wǎng)絡(luò)的基本單元RNN、LSTM、GRU的輸入、輸出、參數(shù)詳細(xì)理解
前言:這篇文章是對已經(jīng)較為深入理解了RNN、LSTM、GRU的數(shù)學(xué)原理以及運(yùn)算過程的人而言的,如果不理解它的基本思想和過程,可能理解起來不是很簡單。
一、先從一個實(shí)例看起
這是官網(wǎng)上面的一個例子,本次以LSTM作為例子而言,實(shí)際上,GRU、LSTM、RNN的運(yùn)算過程是很類似的。
import torch import torch.nn as nn lstm = nn.LSTM(10, 20, 2) # 序列長度seq_len=5, batch_size=3, 數(shù)據(jù)向量維數(shù)=10 input = torch.randn(5, 3, 10) # 初始化的隱藏元和記憶元,通常它們的維度是一樣的 # 2個LSTM層,batch_size=3,隱藏元維度20 h0 = torch.randn(2, 3, 20) c0 = torch.randn(2, 3, 20) # 這里有2層lstm,output是最后一層lstm的每個詞向量對應(yīng)隱藏層的輸出,其與層數(shù)無關(guān),只與序列長度相關(guān) # hn,cn是所有層最后一個隱藏元和記憶元的輸出 output, (hn, cn) = lstm(input, (h0, c0)) print(output.size(),hn.size(),cn.size()) # 分別是: # torch.Size([5, 3, 20]) # torch.Size([2, 3, 20]) # torch.Size([2, 3, 20]))
后面我會詳細(xì)解釋上面的運(yùn)算過程,我們先看一下LSTM的定義,它是一個類
二、LSTM類的定義
class LSTM(RNNBase): '''參數(shù)Args: input_size: 輸入數(shù)據(jù)的特征維度,比如我對時間序列建模,特征為1,我對一個句子建模,每一個單詞的嵌入向量為10,則它為10 hidden_size: 即循環(huán)神經(jīng)網(wǎng)絡(luò)中隱藏節(jié)點(diǎn)的個數(shù),這個是自己定義的,多少都可以,后面會詳說 num_layers: 堆疊的LSTM的層數(shù),默認(rèn)是一層,也可以自己定義 Default: 1 bias: LSTM層是否使用偏置矩陣 偏置權(quán)值為 `b_ih` and `b_hh`. Default: ``True``(默認(rèn)是使用的) batch_first: 如果設(shè)置 ``True``, then the input and output tensors are provided as (batch, seq, feature). Default: ``False``,(seq,batch,features) dropout: 是否使用dropout機(jī)制,默認(rèn)是0,表示不使用dropout,如果提供一個非0的數(shù)字,則表示在每一個LSTM層之后默認(rèn)使用dropout,但是最后一個層的LSTM層不使用dropout。 bidirectional: 是否是雙向RNN,默認(rèn)是否,If ``True``, becomes a bidirectional LSTM. Default: ``False`` #--------------------------------------------------------------------------------------- 類的構(gòu)造函數(shù)的輸入為Inputs: input, (h_0, c_0) - **input** of shape `(seq_len, batch, input_size)`: tensor containing the features of the input sequence. - **h_0** of shape `(num_layers * num_directions, batch, hidden_size)`: tensor containing the initial hidden state for each element in the batch. If the LSTM is bidirectional, num_directions should be 2, else it should be 1. - **c_0** of shape `(num_layers * num_directions, batch, hidden_size)`: tensor containing the initial cell state for each element in the batch. If `(h_0, c_0)` is not provided, both **h_0** and **c_0** default to zero. #---------------------------------------------------------------------------------- 輸出是什么:Outputs: output, (h_n, c_n) - **output** of shape `(seq_len, batch, num_directions * hidden_size)`: tensor containing the output features `(h_t)` from the last layer of the LSTM, for each `t`. If a :class:`torch.nn.utils.rnn.PackedSequence` has been given as the input, the output will also be a packed sequence. For the unpacked case, the directions can be separated using ``output.view(seq_len, batch, num_directions, hidden_size)``, with forward and backward being direction `0` and `1` respectively. Similarly, the directions can be separated in the packed case. - **h_n** of shape `(num_layers * num_directions, batch, hidden_size)`: tensor containing the hidden state for `t = seq_len`. Like *output*, the layers can be separated using ``h_n.view(num_layers, num_directions, batch, hidden_size)`` and similarly for *c_n*. - **c_n** of shape `(num_layers * num_directions, batch, hidden_size)`: tensor containing the cell state for `t = seq_len`. #------------------------------------------------------------------------------------------ 類的屬性有Attributes: weight_ih_l[k] : the learnable input-hidden weights of the :math:`\text{k}^{th}` layer `(W_ii|W_if|W_ig|W_io)`, of shape `(4*hidden_size, input_size)` for `k = 0`. Otherwise, the shape is `(4*hidden_size, num_directions * hidden_size)` weight_hh_l[k] : the learnable hidden-hidden weights of the :math:`\text{k}^{th}` layer `(W_hi|W_hf|W_hg|W_ho)`, of shape `(4*hidden_size, hidden_size)` bias_ih_l[k] : the learnable input-hidden bias of the :math:`\text{k}^{th}` layer `(b_ii|b_if|b_ig|b_io)`, of shape `(4*hidden_size)` bias_hh_l[k] : the learnable hidden-hidden bias of the :math:`\text{k}^{th}` layer `(b_hi|b_hf|b_hg|b_ho)`, of shape `(4*hidden_size)` '''
上面的參數(shù)有點(diǎn)多,我就不一個一個翻譯了,其實(shí)很好理解,每一個都比較清晰。
三、 必需參數(shù)的深入理解
1、RNN、GRU、LSTM的構(gòu)造函數(shù)的三個必須參數(shù)理解——第一步:構(gòu)造循環(huán)層對象
在創(chuàng)建循環(huán)層的時候,第一步是構(gòu)造循環(huán)層,如下操作:
lstm = nn.LSTM(10, 20, 2)
構(gòu)造函數(shù)的參數(shù)列表為如下:
class LSTM(RNNBase): '''參數(shù)Args: input_size: hidden_size: num_layers: bias: batch_first: dropout: bidirectional: '''
(1)input_size:指的是每一個單詞的特征維度,比如我有一個句子,句子中的每一個單詞都用10維向量表示,則input_size就是10;
(2)hidden_size:指的是循環(huán)層中每一個LSTM內(nèi)部單元的隱藏節(jié)點(diǎn)數(shù)目,這個是自己定義的,隨意怎么設(shè)置都可以;
(3)num_layers:循環(huán)層的層數(shù),默認(rèn)是一層,這個根據(jù)自己的情況來定。
比如下面:
左邊的只有一層循環(huán)層,右邊的有兩層循環(huán)層。
2、通過第一步構(gòu)造的對象構(gòu)造前向傳播的過程——第二步:調(diào)用循環(huán)層對象,傳入?yún)?shù),并得到返回值
一般如下操作:
output, (hn, cn) = lstm(input, (h0, c0))
這里是以LSTM為例子來說的,
(1)輸入?yún)?shù)
input:必須是這樣的格式(seq,batch,feature)。第一個seq指的是序列的長度,這是根據(jù)自己的數(shù)據(jù)來定的,比如我的一個句子最大的長度是20個單詞組成,那這里就是20,上面的例子是假設(shè)句子長度為5;第二個是batch,這個好理解,就是一次使用幾條樣本,比如3組樣本;第三個features指的是每一個單詞的向量維度,需要注意的是,這個必須要和構(gòu)造函數(shù)的第一個參數(shù)input_size保持一樣的,上面的例子中是10.
(h0,c0):指的是每一個循環(huán)層的初始狀態(tài),可以不指定,不指定的情況下全部初始化為0,這里因?yàn)槭荓STM有兩個狀態(tài)需要傳遞,所以有兩個,像普通的RNN和GRU只有一個狀態(tài)需要傳遞,則只需要傳遞一個h狀態(tài)即可,如下:
output, hn = rnn(input, h0) # 普通rnn output, hn = gru(input, h0) # gru
這里需要注意的是傳入的狀態(tài)參數(shù)的維度,依然以LSTM來說:
h0和c0的數(shù)據(jù)維度均是(num_layers * num_directions, batch, hidden_size),這是什么意思呢?
第一個num_layer指的是到底有基層循環(huán)層,這好理解,幾層就應(yīng)該有幾個初始狀態(tài);
第二個num_directions指的是這個循環(huán)層是否是雙向的(在構(gòu)造函數(shù)中通過bidirectional參數(shù)指定哦),如果不是雙向的,則取值為1,如果是雙向的則取值為2;
第三個batch指的是每次數(shù)據(jù)的batch,和前面的batch保持一致即可;
最后一個hidden_size指的是循環(huán)層每一個節(jié)點(diǎn)內(nèi)部的隱藏節(jié)點(diǎn)數(shù),這個需要很好地理解循環(huán)神經(jīng)網(wǎng)絡(luò)的整個運(yùn)算流程才行哦!
(2)輸出結(jié)果
其實(shí)輸出的結(jié)果和輸入的是相匹配的,分別如下:
output, hn = rnn(input, h0) # 普通rnn output, hn = gru(input, h0) # gru output, (hn, cn) = lstm(input, (h0, c0)) # lstm
這里依然以lstm而言:
output的輸出維度:(seq_len, batch, num_directions * hidden_size),在上面的例子中,應(yīng)該為(5,3,20),我們通過驗(yàn)證的確如此,需要注意的是,第一個維度是seq_len,也就是說每一個時間點(diǎn)的輸出都是作為輸出結(jié)果的,這和隱藏層是不一樣的;
hn、cn的輸出維度:為(num_layers * num_directions, batch, hidden_size),在上面的例子中為(2,3,20),也得到了驗(yàn)證,我們發(fā)現(xiàn)這個跟序列長度seq_len是沒有關(guān)系的,為什么呢,輸出的狀態(tài)僅僅是指的是最后一個循環(huán)層節(jié)點(diǎn)輸出的狀態(tài)。
如下圖所示:
下面的例子是以普通的RNN來畫的,所以只有一個狀態(tài)h,沒有狀態(tài)c。
3、幾個重要的屬性理解
不管是RNN,GRU還是lstm,內(nèi)部可學(xué)習(xí)的參數(shù)其實(shí)就是幾個權(quán)值矩陣,包括了偏置矩陣,那怎么查看這些學(xué)習(xí)到的參數(shù)呢?就是通過這幾個矩陣來實(shí)現(xiàn)的
(1)weight_ih_l[k]:這表示的是輸入到隱藏層之間的權(quán)值矩陣,其中K表示的第幾層循環(huán)層,
若K=0,表示的是最下面的輸入層到第一個循環(huán)層之間的矩陣,維度為(hidden_size, input_size),如果k>0則表示第一循環(huán)層到第二循環(huán)層、第二循環(huán)層到第三循環(huán)層,以此類推,之間的權(quán)值矩陣,形狀為(hidden_size, num_directions * hidden_size)。
(2)weight_hh_l[k]: 表示的是循環(huán)層內(nèi)部之間的權(quán)值矩陣,這里的K表示的第幾層循環(huán)層,取值為0,1,2,3,4... ...。形狀為(hidden_size, hidden_size)
注意:循環(huán)層的層數(shù)取值是從0開始,0代表第一個循環(huán)層,1代表第二個循環(huán)層,以此類推。
(3)bias_ih_l[k]: 第K個循環(huán)層的偏置項(xiàng),表示的是輸入到循環(huán)層之間的偏置,維度為 (hidden_size)
(4)bias_hh_l[k]:第K個循環(huán)層的偏置項(xiàng),表示的是循環(huán)層到循環(huán)層內(nèi)部之間的偏置,維度為 (hidden_size)。
# 首先導(dǎo)入RNN需要的相關(guān)模塊 import torch import torch.nn as nn # 數(shù)據(jù)向量維數(shù)10, 隱藏元維度20, 2個RNN層串聯(lián)(如果是1,可以省略,默認(rèn)為1) rnn = nn.RNN(10, 20, 2) # 序列長度seq_len=5, batch_size=3, 數(shù)據(jù)向量維數(shù)=10 input = torch.randn(5, 3, 10) # 初始化的隱藏元和記憶元,通常它們的維度是一樣的 # 2個RNN層,batch_size=3,隱藏元維度20 h0 = torch.randn(2, 3, 20) # 這里有2層RNN,output是最后一層RNN的每個詞向量對應(yīng)隱藏層的輸出,其與層數(shù)無關(guān),只與序列長度相關(guān) # hn,cn是所有層最后一個隱藏元和記憶元的輸出 output, hn = rnn(input, h0) print(output.size(),hn.size()) # 分別是:torch.Size([5, 3, 20]) torch.Size([2, 3, 20]) # 查看一下那幾個重要的屬性: print("------------輸入--》隱藏------------------------------") print(rnn.weight_ih_l0.size()) print(rnn.weight_ih_l1.size()) print(rnn.bias_ih_l0.size()) print(rnn.bias_ih_l1.size()) print("------------隱藏--》隱藏------------------------------") print(rnn.weight_hh_l0.size()) print(rnn.weight_hh_l1.size()) print(rnn.bias_hh_l0.size()) print(rnn.bias_hh_l1.size()) '''輸出結(jié)果為: ------------輸入--》隱藏------------------------------ torch.Size([20, 10]) torch.Size([20, 20]) torch.Size([20]) torch.Size([20]) ------------隱藏--》隱藏------------------------------ torch.Size([20, 20]) torch.Size([20, 20]) torch.Size([20]) torch.Size([20]) '''
通過上面的運(yùn)算,發(fā)現(xiàn)結(jié)果和描述的是一模一樣的。
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
python多進(jìn)程并發(fā)的實(shí)現(xiàn)示例
python中的多線程無法利用多核優(yōu)勢,如果想要充分地使用多核CPU的資源,在python中大部分情況需要使用多進(jìn)程,本文主要介紹了python多進(jìn)程并發(fā)的實(shí)現(xiàn)示例,感興趣的可以了解一下2024-02-02詳解Python 多線程 Timer定時器/延遲執(zhí)行、Event事件
這篇文章主要介紹了Python 多線程 Timer定時器/延遲執(zhí)行、Event事件的相關(guān)知識,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-06-06手把手教你jupyter?notebook更換環(huán)境的方法
在日常使用jupyter-notebook時,可能會碰到需要切換不同虛擬環(huán)境的場景,下面這篇文章主要給大家介紹了關(guān)于jupyter?notebook更換環(huán)境的方法,需要的朋友可以參考下2023-05-05python leetcode 字符串相乘實(shí)例詳解
這篇文章主要介紹了python leetcode 字符串相乘的示例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-09-09python/golang實(shí)現(xiàn)循環(huán)鏈表的示例代碼
這篇文章主要介紹了python/golang如何實(shí)現(xiàn)循環(huán)鏈表,幫助大家更好的理解和學(xué)習(xí)循環(huán)鏈表的實(shí)現(xiàn)方法,感興趣的朋友可以了解下2020-09-09