这是我参与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