Pytorch中循环神经网络的输入/输出维度探究

由于循环神经网络的种类繁多,可以叠加多层,并且还可以设置双向RNN网络;同时,Pytorch Docs在这一块又写的很简略,因此循环神经网络的输入输出维度一直犹如一团乱麻。今天做实验彻底弄明白。

这里以RNN为例,官方文档中的介绍如下:

Figure 1

Figure 2

现在开始做实验,设置2个 batch的数据, seq_len = 10,Dimention = 1:

1
2
3
4
5
6
7
#为方便,把batch_size设置在第一个维度
inputs_1 = torch.Tensor(list(range(1, 11))).reshape(10, 1).unsqueeze(0)
inputs_2 = torch.Tensor(list(range(11, 21))).reshape(10, 1).unsqueeze(0)
inputs = torch.cat((inputs_1, inputs_2), dim=0)
print(inputs.shape)

>>> torch.Size([2, 10, 1])

创建RNN模型, 设置hidden_size=15,layer=1,单向RNN, 运行得到结果:

1
2
3
4
5
6
7
model = nn.RNN(1, 15, 1, batch_first=True, bidirectional=False)
output, hidden = model(inputs)
print('output_size : ', output.shape)
print('hidden_size : ', hidden.shape)

>>> output_size : torch.Size([2, 10, 15])
>>> hidden_size : torch.Size([1, 2, 15])

显然,output的维度含义为[Batch_size, seq_len, hidden_size]。等等,Docs里面不是说output的维度是[seq_len, Batch_size, num_directions × hidden_size]吗?这里疑问留待解答。

hidden的维度按照Docs的定义显然是[num_layers × num_directions, batch_size, hidden_size]。这个例子中num_layer=1,num_directions=1,batch_size=2,hidden_size=15。

现在,我们为解答output的疑问,关闭batch_first, 这里实验数据也要做一定修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
inputs_1 = torch.Tensor(list(range(1, 11))).reshape(10, 1).unsqueeze(1)
inputs_2 = torch.Tensor(list(range(11, 21))).reshape(10, 1).unsqueeze(1)
inputs = torch.cat((inputs_1, inputs_2), dim=1)
print(inputs.shape)

>>> torch.Size([10, 2, 1])

model = nn.RNN(1, 15, 1, batch_first=False, bidirectional=False)
output, hidden = model(inputs)
print('output_size : ', output.shape)
print('hidden_size : ', hidden.shape)

>>> output_size : torch.Size([10, 2, 15])
>>> hidden_size : torch.Size([1, 2, 15])

可以发现,这时候hidden的维度并没有改变,而output的维度显然变成了[seq_len, Batch_size, num_directions × hidden_size]。WTF???意思就是说,batch_first并不会影响到hidden的维度顺序,但会影响到output的维度顺序。(搞不懂官方怎么想的)

好了,为了方便起见,我们还是将batch_first开启,此时设置num_layers=3,启用双向RNN:

1
2
3
4
5
6
7
model = nn.RNN(1, 15, 3, batch_first=True, bidirectional=True)
output, hidden = model(inputs)
print('output_size : ', output.shape)
print('hidden_size : ', hidden.shape)

>>> output_size : torch.Size([2, 10, 30])
>>> hidden_size : torch.Size([6, 2, 15])

output的最后一个维度从15变成了30,原因是开启了双向RNN,最后一个维度等于 num_directions × hidden_size。经过查询得知:正向传播的hidden为[2, 10, 0:15];反向传播的hidden为[2, 10, 15:30]。可见,对于双向循环网络,python并没有处理两个方向的output,而是分别输出,要求程序员自己处理。

显然,pytorch的维度提示中的表达式并不是随便写的,而是有分先后顺序。比如某一个维度为L×D,则该维度可以看做一个(L, D)的Tensor经过Flatten操作。L=1的D位于0 ~ D-1,L=2的D位于D ~ 2D-1……

hidden的第一个维度从1变成了6,原因是开启了双向RNN,同时叠加了3层网络,最后一个维度等于num_layers × num_directions。根据pytorch维度提示的思路,6=num_layers × num_directions=2×3,即第一个维度是num_layers, 第二个维度是num_directions。因此可以知:

[0, :, :]和[1, :, :]分别是是第一层RNN正反传播的hidden

[2, :, :]和[3, :, :]分别是是第二层RNN正反传播的hidden

[4, :, :]和[5, :, :]分别是是第三层RNN正反传播的hidden

最后再看一下输入中有一个初始hidden,显然这个tensor也应该按照num_layers × num_directions的顺序进行初始化。

文章作者: 地瓜
文章链接: https://www.l-zhe.com/2019/08/08/Pytorch中循环神经网络的输入,输出维度探究/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 人参地里的地瓜
打赏
  • 微信
  • 支付宝

评论
目录