序列决策

RNN、GRU、LSTM细节

RNN网络

0. 网络框架

Long Short - Term Memory
Long Short - Term Memory

1. RNN 的核心公式

在 RNN 中,每个时间步的隐藏状态 \(h_t\) 是通过以下公式计算的: \[ h_t = \text{tanh}(W_{hh} \cdot h_{t-1} + W_{ih} \cdot x_t + b_h) \] 其中:

  • \(h_t\):当前时间步的隐藏状态,形状为 (hidden_size,)
  • \(h_{t-1}\):上一时间步的隐藏状态,形状同样为 (hidden_size,)
  • \(x_t\):当前时间步的输入,形状为 (input_size,)
  • \(W_{hh}\):隐藏状态到隐藏状态的权重矩阵,形状为 (hidden_size, hidden_size)
  • \(W_{ih}\):输入到隐藏状态的权重矩阵,形状为 (hidden_size, input_size)
  • \(b_h\):偏置项,形状为 (hidden_size,)
  • \(\text{tanh}\):激活函数,用于引入非线性。

2. 部分超参数的解释

"天气真好,心情愉快。"

  1. batch_size(批量大小)
    • 定义:表示一次处理多少个样本(句子)。
    • 映射:如果我们有 5 句类似的话(比如 "天气真好,心情愉快。"、"今天下雨了,有点烦。" 等),并选择一次处理其中的 3 句,那么 batch_size=3
    • 代码维度batch_size 是输入张量的第一个维度,形状为 (batch_size, ...)。例如,(3, sequence_length, input_size) 表示一次处理 3 个句子。
  2. sequence_length(序列长度)
    • 定义:表示每个样本(句子)的时间步数,即句子中有多少个时间步(词或字符)。
    • 映射:如果我们将句子拆分为词,则 "天气真好,心情愉快。" 包含 6 个词("天气"、"真"、"好"、"心情"、"愉快"、"。"),因此 sequence_length=6
    • 代码维度sequence_length 是输入张量的第二个维度,形状为 (..., sequence_length, ...)。例如,(batch_size, 6, input_size) 表示每个句子有 6 个时间步。
  3. input_size(输入特征维度)
    • 定义:表示每个时间步的输入向量的维度。
    • 映射:假设我们使用词嵌入(word embedding)将每个词映射为一个 10 维的向量,则 input_size=10。例如,"天气" 被表示为 [0.1, -0.2, ..., 0.8](长度为 10 的向量)。
    • 代码维度input_size 是输入张量的最后一个维度,形状为 (..., input_size)。例如,(batch_size, sequence_length, 10) 表示每个时间步的输入是一个 10 维向量。

3. Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class SimpleRNN(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(SimpleRNN, self).__init__()
self.rnn = nn.RNN(input_size, hidden_size, batch_first=True)
self.fc = nn.Linear(hidden_size, output_size)

def forward(self, x):
"""
前向传播逻辑:
- x: 输入序列 (batch_size, sequence_length, input_size)
"""
# RNN 输出:h_n 是最后一个时间步的隐藏状态
rnn_out, h_n = self.rnn(x)
# 使用最后一个时间步的隐藏状态作为分类依据
out = self.fc(h_n.squeeze(0))
return out
  1. rnn_out 的维度:32×10×10
    1. 第一维(32):表示批量大小(batch size)。也就是说,当前批次中有 32 个样本。
    2. 第二维(10):表示序列长度(sequence length,句子长度(“句子词语个数”))。每个样本包含 10 个时间步的数据。
    3. 第三维(10):表示最后一个隐藏层的维度(hidden_size,设置的数字)。每个时间步的输出是一个 10 维的向量。
    4. 含义
      • rnn_out 表示 RNN 在每个时间步的输出。对于每个样本,在每个时间步都会生成一个隐藏状态向量(维度为 hidden_size)。
      • 因此,rnn_out[0, :, :] 表示第一个样本在整个时间序列上的所有隐藏状态输出(形状为 10×10)。
      • 如果你需要某个特定时间步的输出,可以通过索引提取,例如 rnn_out[:, t, :] 表示所有样本在第 t 个时间步的隐藏状态。
  2. h_n 的维度:1×32×10(没有sequence length的信息,只表示当前h_n的信息)
    1. 第一维(1):表示 RNN 的层数(num_layers)。如果你只定义了一层 RNN,那么这一维就是 1。
    2. 第二维(32):表示批量大小(batch size),与 rnn_out 的第一维一致。
    3. 第三维(10):表示隐藏层的维度(hidden_size),与 rnn_out 的第三维一致。
    4. 含义
      • h_n 表示 RNN 在最后一个时间步的隐藏状态(或每一层的最终隐藏状态)。
      • 如果是单层 RNN,h_n 就是最后一个时间步的隐藏状态;如果是多层 RNN,h_n 包含每一层的最终隐藏状态。
      • 对于单层 RNN,h_n[0, :, :] 表示所有样本在最后一个时间步的隐藏状态(形状为 32×10)。
  3. 为什么rnn_outh_n的维度在sequence length表现不一样?
  • 因为rnn_out输出的是一个句子,句子对应得就是(batch_size,sequence_length,hidden_size),对于batch_size来说,两者是并行计算的,但是对于rnn来说,他输出的是整个批次的对话信息,而对于h_n来说,他只是保存了所有batch当前时刻的隐藏层算出的结果,这个结果是针对当前输入的单词而言得,所以在一个batch中,同时输入32个量化得单词,得到相应维度的h_n