赞
踩
目录
我们可以注意到这里的input是(T, N, E)而非和embedding的输出一样是(N, T, E)。这是因为rnn的自身结构:
为什么最后一个是hidden_size而不是神经网络的output_size呢?
不知道大家有没有发现:input、output的格式相同,都是[T,N,E]的形式,但为什么hidden_size如此不同变为了(num_layers, N, E)的形式呢?
根据PyTorch文档,nn.RNN
的输入输出如下:
1.input
nn.RNN输入要求:
(seq_len, batch_size, input_size)(T, N, E):
其中:
seq_len
是序列长度- batch_size是批大小,
input_size
是输入的特征维度
我们可以注意到这里的input是(T, N, E)而非和embedding的输出一样是(N, T, E)。这是因为rnn的自身结构:
图片来自b站耿直哥、
我们可以明显看到rnn网络在每个时间步中完成一次神经网络的功能。而embedding则是在每个时间步中向量化一个单词。
所以在处理数据时一定要记得进行矩阵变化!!!
例:
x = self.embedding_layer(x) # [N,T] -> [N,T,E] ho, hn = self.rnn(x) # ho [N,T,hidden_size] hn [?,N,E] hz = torch.permute(hn, dims=[1, 0, 2]) # [?,N,E] -> [N,?,E]在seq2seq中因为要将信息压缩在一个矩阵中通常还会执行以下步骤:
hz = torch.reshape(hz, shape=(hz.shape[0], self.output_dim)) # [N,?,E] -> [N,?*E]
.output
nn.RNN会有两个输出,分别是ho(output)和hn(hidden)。
2.1 h_o(output)
h_o会输出RNN在所有时间步上的隐藏状态输出。它包含了整个序列在每个时间步的隐藏状态。
ho的输出如下:
(seq_len, batch_size, num_directions * hidden_size) (T, N, E*(1or2)):
其中:
seq_len
是输入序列的长度- batch_size是批大小
num_directions
是方向数,单向为1,双向为2hidden_size
是隐藏状态的维度为什么最后一个是hidden_size而不是神经网络的output_size呢?
原因是
h_n
只保留了最后一步的 hidden_state,但中间的 hidden_state 也有可能会参与计算,所以 pytorch 把中间每一步输出的 hidden_state 都放到output
中(当然,只保留了 hidden_state 最后一层的输出),因此,你可以发现这个output
的维度是(seq_len, batch, num_directions * hidden_size)
。
接下来我们介绍h_n(hidden
)。我想你一定好奇为什么是h_n而不叫h_h?说实话我也很好奇,但大家约定俗成的名称就是h_n。有哪位大神知道可以留言感激不尽。
2.2 h_n(
hidden
)
:(h_n代表隐藏层的输入输出,在rnn网络中输入输出是格式是相同的)
(num_layers * num_directions, batch_size, hidden_size)
(num_layers*(1or2), N, E):
如果没有提供,默认为全0
其中:
num_layers
是RNN的层数。(不明白可以看下面的rnn结构)num_directions
是方向数,如果是单向RNN则为1,如果是双向RNN则为2。hidden_size
是隐藏状态的维度。不知道大家有没有发现:input、output的格式相同,都是[T,N,E]的形式,但为什么hidden_size如此不同变为了(num_layers, N, E)的形式呢?
简单来说就是因为隐藏状态不是一个时间序列,而是在每一层中都持有一个向量。而输出中间状态就是为了得到每个时刻的隐层输出。所以num_layers * num_directions 这个维度代替了seq_len。
初始化rnn:
rnn = nn.RNN(input_size, hidden_size, num_layers)
无需多言看图即懂:
- 其中Xn是input_size,
- A(第一层), A'(第二层), A''(第三层) 则是num_layers,
- 在每个A中都是一个RNN_cell,每个都是一个全连接网络,而hidden_size类似于全连接网络中的隐藏层。
多层rnn不懂看这里:循环神经网络的改进:多层RNN、双向RNN与预训练-CSDN博客
RNN_cell:
其内部结构如下:
没想到吧依旧是这张图。其实所谓的RNN_cell就是一个全连接神经网络。
而内部的计算过程:
输入:
input
: 当前时间步的输入,形状为(batch_size, input_size) (T, E)
hidden
: 前一时间步的隐藏状态,形状为(batch_size, hidden_size)
前向计算:
- 将输入
input
和前一隐藏状态hidden
进行线性变换:
gate = F.linear(input, self.weight_ih, self.bias_ih) + \ F.linear(hidden, self.weight_hh, self.bias_hh)- 将线性变换的结果
gate
应用激活函数(如tanh)得到新的隐藏状态new_hidden
:
new_hidden = F.tanh(gate)
输出:
new_hidden
: 当前时间步的新隐藏状态,形状为(batch_size, hidden_size)(N, E)
这个
new_hidden里的hidden_size就是前面input、output、h_0的hidden_size啦。对于RNN整个网络来说,这个new_hidden是RNN_cell的输出,就是隐层的输出。但是对于RNN_cell来说,则是经过完整的全连接网络并且激活过的output!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。