nn.RNN的输入输出及其内部结构说明

目录

1.input 

       我们可以注意到这里的input是(T, N, E)而非和embedding的输出一样是(N, T, E)。这是因为rnn的自身结构:

  2.output 

2.1 h_o(output)

为什么最后一个是hidden_size而不是神经网络的output_size呢?

2.2 h_n(hidden):

        不知道大家有没有发现:input、output的格式相同,都是[T,N,E]的形式,但为什么hidden_size如此不同变为了(num_layers, N, E)的形式呢?

初始化rnn:

RNN_cell:

根据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]

  2.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,双向为2
  • hidden_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就是一个全连接神经网络。

而内部的计算过程:

  1. 输入:

    • input: 当前时间步的输入,形状为(batch_size, input_size) (T, E)
    • hidden: 前一时间步的隐藏状态,形状为(batch_size, hidden_size)
  2. 前向计算:

    • 将输入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)
      
  3. 输出:

      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!

  • 36
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在TensorFlow中,可以使用`tf.nn.bidirectional_dynamic_rnn()`函数实现双向RNN。该函数的返回值是一个元组,包含两个元素,分别是前向和后向RNN的输出。每个输出都是一个张量,形状为`[batch_size, max_time, num_units]`,其中`batch_size`是输入的批量大小,`max_time`是输入序列的最大时间步数,`num_units`是RNN单元的数量。需要注意的是,如果在调用`tf.nn.bidirectional_dynamic_rnn()`函数时没有提供`sequence_length`参数,则`max_time`将等于输入序列的最大时间步数,否则将等于`sequence_length`中的最大值。 以下是一个使用`tf.nn.bidirectional_dynamic_rnn()`函数实现双向RNN的例子: ```python import tensorflow as tf # 定义输入数据 batch_size = 32 max_time = 10 input_size = 20 inputs = tf.placeholder(tf.float32, [batch_size, max_time, input_size]) # 定义前向和后向RNN的单元数量 num_units = 64 # 定义前向和后向RNN的单元 cell_fw = tf.nn.rnn_cell.BasicLSTMCell(num_units) cell_bw = tf.nn.rnn_cell.BasicLSTMCell(num_units) # 定义双向RNN outputs, states = tf.nn.bidirectional_dynamic_rnn(cell_fw, cell_bw, inputs, dtype=tf.float32) # 输出前向和后向RNN的输出 output_fw, output_bw = outputs # 输出前向和后向RNN的状态 state_fw, state_bw = states # 输出前向和后向RNN的最后一个时间步的输出 output_fw_last = output_fw[:, -1, :] output_bw_last = output_bw[:, -1, :] # 输出前向和后向RNN的最后一个时间步的状态 state_fw_last = state_fw[1] state_bw_last = state_bw[1] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值