简单易懂深入PyTorch中RNN、LSTM和GRU使用和理解

目录

torch.nn子模块Recurrent Layers

nn.RNNBase

RNNBase 类描述

RNNBase 类的功能和作用

flatten_parameters() 方法

示例代码

nn.RNN

RNN 类描述

RNN 类的功能和作用

RNN 类的参数

输入和输出

注意事项

示例代码

nn.LSTM

LSTM 类描述

LSTM 类的功能和作用

LSTM 类的参数

输入和输出

注意事项

示例代码

nn.GRU

GRU 类描述

GRU 类的功能和作用

GRU 类的参数

输入和输出

注意事项

示例代码

nn.RNNCell

RNNCell 类描述

RNNCell 类的功能和作用

RNNCell 类的参数

输入和输出

形状

变量

注意事项

示例代码

nn.LSTMCell

LSTMCell 类描述

LSTMCell 类的功能和作用

LSTMCell 类的参数

输入和输出

变量

注意事项

示例代码

nn.GRUCell

GRUCell 类描述

GRUCell 类的功能和作用

GRUCell 类的参数

输入和输出

形状

变量

注意事项

示例代码

总结


torch.nn子模块Recurrent Layers

nn.RNNBase

RNNBase 类描述

torch.nn.RNNBase 是 PyTorch 中用于构建循环神经网络的基类。它是 RNN、LSTM 和 GRU 等更具体的循环神经网络类的基础。下面将详细描述这个类和它的一个主要方法 flatten_parameters

RNNBase 类的功能和作用
  • 初始化: RNNBase 类提供了 RNN, LSTM, 和 GRU 这些子类的基本初始化参数。这包括输入大小(input_size)、隐藏层大小(hidden_size)、层数(num_layers)、使用偏置(bias)、是否以批处理为主(batch_first)、dropout 比例(dropout)、是否双向(bidirectional)等。

  • 参数管理: RNNBase 还提供了一些用于参数管理的实用方法,如参数的存储和重置。

  • 注意: RNNBase 类本身并不实现 forward 方法。这意味着你不能直接使用 RNNBase 来创建一个模型实例;它只是提供了一个共同的基础结构,用于构建各种类型的循环神经网络。

flatten_parameters() 方法
  • 作用: flatten_parameters 方法用于优化 RNN 的内部参数存储结构,从而使得 RNN 可以使用更快的代码路径进行计算。

  • 技巧: 这个方法尤其在使用 GPU 和启用 cuDNN 时非常有效。在这些条件下,它会重新设置参数数据指针,以优化内存访问模式和提高效率。

  • 注意事项: 当模块不在 GPU 上或者没有启用 cuDNN 时,flatten_parameters 将不起作用,也就是说,它在这种情况下是一个无操作(no-op)。

示例代码

下面是一个示例代码,展示了如何使用 LSTM (继承自 RNNBase)并在其中调用 flatten_parameters 方法。

import torch
import torch.nn as nn

# 定义一个简单的 LSTM 网络
class SimpleLSTM(nn.Module):
    def __init__(self, input_size, hidden_size, num_layers):
        super(SimpleLSTM, self).__init__()
        self.lstm = nn.LSTM(input_size, hidden_size, num_layers)

    def forward(self, x):
        self.lstm.flatten_parameters()
        output, (hn, cn) = self.lstm(x)
        return output, hn, cn

# 参数
input_size = 10
hidden_size = 20
num_layers = 2

# 创建模型实例
model = SimpleLSTM(input_size, hidden_size, num_layers)

# 示例输入
x = torch.randn(5, 3, input_size)  # (seq_length, batch, input_size)

# 前向传播
output, hn, cn = model(x)

这段代码展示了如何创建一个简单的 LSTM 网络,它在每次前向传播前调用 flatten_parameters 方法以优化性能。在这里,x 是一个随机生成的输入张量,其维度是序列长度、批大小和输入大小。

nn.RNN

RNN 类描述

torch.nn.RNN 是 PyTorch 中用于构建一个简单的 Elman 循环神经网络(RNN)的类。它可以应用于输入序列,使用 tanhReLU 作为激活函数。下面将详细描述这个类的功能、参数和注意事项。

RNN 类的功能和作用
  • Elman RNN: 这个类实现了基本的 Elman RNN 架构。对于输入序列中的每个元素,每层 RNN 都会计算一个新的隐藏状态,该状态取决于当前输入和前一时间点的隐藏状态。

  • 激活函数: 可以选择使用 tanhReLU 作为非线性激活函数。

RNN 类的参数
  1. input_size: 输入特征的数量。
  2. hidden_size: 隐藏状态的特征数量。
  3. num_layers: RNN层的数量。例如,num_layers=2 表示两个 RNN 层堆叠在一起。
  4. nonlinearity: 使用的非线性激活函数,可以是 'tanh''relu'
  5. bias: 如果为 False,则层不使用偏置权重 b_ihb_hh
  6. batch_first: 如果为 True,则输入和输出张量的格式为 (batch, seq, feature);否则为 (seq, batch, feature)
  7. dropout: 如果非零,将在每个 RNN 层的输出上引入一个 Dropout 层,除了最后一层。
  8. bidirectional: 如果为 True,则变为双向 RNN。
输入和输出
  • 输入: input, h_0

    • input: 形状为 (seq_len, batch, input_size)(batch, seq_len, input_size)(如果 batch_first=True)的张量,包含输入序列的特征。
    • h_0: 形状为 (num_layers * num_directions, batch, hidden_size) 的张量,包含初始隐藏状态。如果未提供,默认为零。
  • 输出: output, h_n

    • output: 包含最后一层 RNN 的输出特征(h_t)的张量。
    • h_n: 形状为 (num_layers * num_directions, batch, hidden_size) 的张量,包含批次中每个元素的最终隐藏状态。
注意事项
  1. 权重和偏置的初始化: 所有权重和偏置都从均匀分布 U(-k, k) 初始化,其中 k = 1 / hidden_size
  2. 双向 RNN: 对于双向 RNN,前向和后向分别为方向 0 和 1。
  3. 非确定性问题: 在某些版本的 cuDNN 和 CUDA 上,RNN 函数可能存在非确定性问题。可以通过设置特定的环境变量来强制确定性行为。
  4. 特定条件下的性能优化: 在特定条件下(如使用 V100 GPU,数据在 GPU 上,数据类型为 torch.float16 等),cudnn 可以选择持久算法来提升性能。

示例代码

import torch
import torch.nn as nn

# 创建 RNN 实例
rnn = nn.RNN(input_size=10, hidden_size=20, num_layers=2, nonlinearity='tanh')

# 输入数据
input = torch.randn(5, 3, 10)  # (seq_len, batch, input_size)
h0 = torch.randn(2, 3, 20)     # (num_layers, batch, hidden_size)

# 前向传播
output, hn = rnn(input, h0)

这段代码展示了如何创建一个简单的 RNN 网络并进行前向传播。在这个例子中,input 是一个随机生成的输入张量,其维度是序列长度、批大小和输入大小。h0 是初始隐藏状态。输出 output 包含了每个时间步的隐藏状态,而 hn 是最终的隐藏状态。

nn.LSTM

LSTM 类描述

torch.nn.LSTM 是 PyTorch 中用于构建长短期记忆(LSTM)网络的类。LSTM 是一种特殊类型的循环神经网络(RNN),特别适合处理和预测时间序列数据中的长期依赖关系。

LSTM 类的功能和作用
  • 长短期记忆: LSTM 通过引入“门”机制(包括输入门、遗忘门、输出门)来控制信息的保留和遗忘,这有助于解决传统 RNN 在长序列上训练时的梯度消失问题。
LSTM 类的参数
  1. input_size: 输入特征的数量。
  2. hidden_size: 隐藏状态的特征数量。
  3. num_layers: RNN层的数量。例如,num_layers=2 表示两个 LSTM 层堆叠在一起。
  4. bias: 如果为 False,则层不使用偏置权重 b_ihb_hh
  5. batch_first: 如果为 True,则输入和输出张量的格式为 (batch, seq, feature);否则为 (seq, batch, feature)
  6. dropout: 如果非零,将在每个 LSTM 层的输出上引入一个 Dropout 层,除了最后一层。
  7. bidirectional: 如果为 True,则变为双向 LSTM。
  8. proj_size: 如果大于 0,则使用带有投影的 LSTM。这将改变 LSTM 单元的输出维度和某些权重矩阵的形状。
输入和输出
  • 输入: input, (h_0, c_0)

    • input: 形状为 (seq_len, batch, input_size)(batch, seq_len, input_size)(如果 batch_first=True)的张量,包含输入序列的特征。
    • h_0: 形状为 (num_layers * num_directions, batch, hidden_size) 的张量,包含初始隐藏状态。
    • c_0: 形状为 (num_layers * num_directions, batch, hidden_size) 的张量,包含初始细胞状态。
  • 输出: output, (h_n, c_n)

    • output: 包含最后一层 LSTM 的输出特征(h_t)的张量。
    • h_n: 形状为 (num_layers * num_directions, batch, hidden_size) 的张量,包含序列中每个元素的最终隐藏状态。
    • c_n: 形状为 (num_layers * num_directions, batch, hidden_size) 的张量,包含序列中每个元素的最终细胞状态。
注意事项
  1. 权重和偏置的初始化: 所有权重和偏置都从均匀分布 U(-k, k) 初始化,其中 k = 1 / hidden_size
  2. 双向 LSTM: 对于双向 LSTM,h_noutput 的含义有所不同。h_n 包含最终的前向和后向隐藏状态,而 output 包含每个时间步的隐藏状态。
  3. 投影大小: proj_size 应小于 hidden_size
  4. 非确定性问题: 在某些版本的 cuDNN 和 CUDA 上,LSTM 函数可能存在非确定性问题。可以通过设置特定的环境变量来强制确定性行为。

示例代码

import torch
import torch.nn as nn

# 创建 LSTM 实例
lstm = nn.LSTM(input_size=10, hidden_size=20, num_layers=2)

# 输入数据
input = torch.randn(5, 3, 10)  # (seq_len, batch, input_size)
h0 = torch.randn(2, 3, 20)     # (num_layers, batch, hidden_size)
c0 = torch.randn(2, 3, 20)     # (num_layers, batch, hidden_size)

# 前向传播
output, (hn, cn) = lstm(input, (h0, c0))

这段代码展示了如何创建一个 LSTM 网络并进行前向传播。在这个例子中,input 是一个随机生成的输入张量,其维度是序列长度、批大小和输入大小。h0c0 分别是初始隐藏状态和细胞状态。输出 output 包含了每个时间步的隐藏状态,而 (hn, cn) 是最终的隐藏状态和细胞状态。

nn.GRU

GRU 类描述

torch.nn.GRU 是 PyTorch 中用于构建门控循环单元(GRU)网络的类。GRU 是一种循环神经网络,类似于 LSTM,但结构更为简单,用于处理序列数据。

GRU 类的功能和作用
  • 门控机制: GRU 通过引入重置门(reset gate)和更新门(update gate)来控制信息的流动,这有助于捕捉序列数据中的长期依赖关系,并解决传统 RNN 的梯度消失问题。
GRU 类的参数
  1. input_size: 输入特征的数量。
  2. hidden_size: 隐藏状态的特征数量。
  3. num_layers: RNN层的数量。例如,num_layers=2 表示两个 GRU 层堆叠在一起。
  4. bias: 如果为 False,则层不使用偏置权重 b_ihb_hh
  5. batch_first: 如果为 True,则输入和输出张量的格式为 (batch, seq, feature);否则为 (seq, batch, feature)
  6. dropout: 如果非零,将在每个 GRU 层的输出上引入一个 Dropout 层,除了最后一层。
  7. bidirectional: 如果为 True,则变为双向 GRU。
输入和输出
  • 输入: input, h_0

    • input: 形状为 (seq_len, batch, input_size)(batch, seq_len, input_size)(如果 batch_first=True)的张量,包含输入序列的特征。
    • h_0: 形状为 (num_layers * num_directions, batch, hidden_size) 的张量,包含初始隐藏状态。
  • 输出: output, h_n

    • output: 包含最后一层 GRU 的输出特征(h_t)的张量。
    • h_n: 形状为 (num_layers * num_directions, batch, hidden_size) 的张量,包含序列中每个元素的最终隐藏状态。
注意事项
  1. 权重和偏置的初始化: 所有权重和偏置都从均匀分布 U(-k, k) 初始化,其中 k = 1 / hidden_size
  2. 双向 GRU: 对于双向 GRU,h_noutput 的含义有所不同。h_n 包含最终的前向和后向隐藏状态,而 output 包含每个时间步的隐藏状态。
  3. PyTorch中的GRU与原始论文的差异: PyTorch 中 GRU 的实现与原始论文在计算新门(new gate)时略有不同,这种差异是为了提高效率。
  4. 非确定性问题: 在某些版本的 cuDNN 和 CUDA 上,GRU 函数可能存在非确定性问题。可以通过设置特定的环境变量来强制确定性行为。

示例代码

import torch
import torch.nn as nn

# 创建 GRU 实例
gru = nn.GRU(input_size=10, hidden_size=20, num_layers=2)

# 输入数据
input = torch.randn(5, 3, 10)  # (seq_len, batch, input_size)
h0 = torch.randn(2, 3, 20)     # (num_layers, batch, hidden_size)

# 前向传播
output, hn = gru(input, h0)

 这段代码展示了如何创建一个 GRU 网络并进行前向传播。在这个例子中,input 是一个随机生成的输入张量,其维度是序列长度、批大小和输入大小。h0 是初始隐藏状态。输出 output 包含了每个时间步的隐藏状态,而 hn 是最终的隐藏状态。

nn.RNNCell

RNNCell 类描述

torch.nn.RNNCell 是 PyTorch 中的一个模块,用于实现单个 Elman RNN 单元。这个类比完整的 RNN 类更为基础,它处理的是序列中的单个时间步,而不是整个序列。

RNNCell 类的功能和作用
  • 单时间步处理: RNNCell 适用于在自定义循环中一次处理一个时间步,这提供了对序列处理过程的更细粒度控制。
RNNCell 类的参数
  1. input_size (int): 输入特征的数量。
  2. hidden_size (int): 隐藏状态的特征数量。
  3. bias (bool): 如果为 False,则单元不使用偏置权重 b_ihb_hh。默认为 True
  4. nonlinearity (str): 使用的非线性激活函数,可以是 'tanh''relu'。默认为 'tanh'
输入和输出
  • 输入: input, hidden

    • input: 包含输入特征的张量。
    • hidden: 包含初始隐藏状态的张量。如果未提供,默认为零。
  • 输出: h'

    • h': 形状为 (batch, hidden_size) 的张量,包含批次中每个元素的下一个隐藏状态。
形状
  • input: 形状为 (N, H_in)(H_in) 的张量,其中 H_in = input_size
  • hidden: 形状为 (N, H_out)(H_out) 的张量,其中 H_out = hidden_size。如果未提供,默认为零。
  • output: 形状为 (N, H_out)(H_out) 的张量,包含下一个隐藏状态。
变量
  • weight_ih (torch.Tensor): 学习得到的输入-隐藏权重,形状为 (hidden_size, input_size)
  • weight_hh (torch.Tensor): 学习得到的隐藏-隐藏权重,形状为 (hidden_size, hidden_size)
  • bias_ih: 学习得到的输入-隐藏偏置,形状为 (hidden_size)
  • bias_hh: 学习得到的隐藏-隐藏偏置,形状为 (hidden_size)
注意事项
  • 权重和偏置的初始化: 所有权重和偏置都从均匀分布 U(-k, k) 初始化,其中 k = 1 / hidden_size

示例代码

import torch
import torch.nn as nn

# 创建 RNNCell 实例
rnn = nn.RNNCell(10, 20)

# 输入数据
input = torch.randn(6, 3, 10)  # (time_steps, batch, input_size)
hx = torch.randn(3, 20)        # (batch, hidden_size)

# 模拟时间步循环
output = []
for i in range(6):
    hx = rnn(input[i], hx)
    output.append(hx)

这段代码展示了如何使用 RNNCell 来处理一个序列。在这个例子中,input 是一个随机生成的输入张量,其维度是时间步、批大小和输入大小。hx 是初始隐藏状态。循环通过逐个时间步调用 RNNCell 来更新 hx,并将每个时间步的输出收集到 output 列表中。

nn.LSTMCell

LSTMCell 类描述

torch.nn.LSTMCell 是 PyTorch 中用于构建单个长短期记忆(LSTM)单元的类。与 LSTM 类处理整个序列不同,LSTMCell 只处理序列中的单个时间步。

LSTMCell 类的功能和作用
  • 单时间步处理: LSTMCell 适用于在自定义循环中逐个时间步处理数据,这提供了对序列处理过程的更细粒度控制。
  • LSTM机制: 同 LSTM 类似,LSTMCell 使用输入门、遗忘门、输出门和细胞状态来控制和维持长期依赖关系。
LSTMCell 类的参数
  1. input_size (int): 输入特征的数量。
  2. hidden_size (int): 隐藏状态的特征数量。
  3. bias (bool): 如果为 False,则单元不使用偏置权重 b_ihb_hh。默认为 True
输入和输出
  • 输入: input, (h_0, c_0)

    • input: 形状为 (batch, input_size)(input_size) 的张量,包含输入特征。
    • h_0: 形状为 (batch, hidden_size)(hidden_size) 的张量,包含初始隐藏状态。
    • c_0: 形状为 (batch, hidden_size)(hidden_size) 的张量,包含初始细胞状态。
  • 输出: (h_1, c_1)

    • h_1: 形状为 (batch, hidden_size)(hidden_size) 的张量,包含下一个隐藏状态。
    • c_1: 形状为 (batch, hidden_size)(hidden_size) 的张量,包含下一个细胞状态。
变量
  • weight_ih (torch.Tensor): 学习得到的输入-隐藏权重,形状为 (4*hidden_size, input_size)
  • weight_hh (torch.Tensor): 学习得到的隐藏-隐藏权重,形状为 (4*hidden_size, hidden_size)
  • bias_ih: 学习得到的输入-隐藏偏置,形状为 (4*hidden_size)
  • bias_hh: 学习得到的隐藏-隐藏偏置,形状为 (4*hidden_size)
注意事项
  • 权重和偏置的初始化: 所有权重和偏置都从均匀分布 U(-k, k) 初始化,其中 k = 1 / hidden_size
  • 不同的设备精度: 在某些 ROCm 设备上,使用 float16 输入时,此模块的反向传播可能使用不同的精度。

示例代码

import torch
import torch.nn as nn

# 创建 LSTMCell 实例
lstm_cell = nn.LSTMCell(10, 20)  # (input_size, hidden_size)

# 输入数据
input = torch.randn(2, 3, 10)  # (time_steps, batch, input_size)
hx = torch.randn(3, 20)        # (batch, hidden_size)
cx = torch.randn(3, 20)        # (batch, hidden_size)

# 模拟时间步循环
output = []
for i in range(input.size()[0]):
    hx, cx = lstm_cell(input[i], (hx, cx))
    output.append(hx)

# 将输出堆叠起来
output = torch.stack(output, dim=0)

 这段代码展示了如何使用 LSTMCell 来处理一个序列。在这个例子中,input 是一个随机生成的输入张量,其维度是时间步、批大小和输入大小。hxcx 分别是初始隐藏状态和细胞状态。循环通过逐个时间步调用 LSTMCell 来更新 hxcx,并将每个时间步的隐藏状态收集到 output 列表中,最后将这些输出堆叠起来。

nn.GRUCell

GRUCell 类描述

torch.nn.GRUCell 是 PyTorch 中用于构建单个门控循环单元(GRU)的类。与完整的 GRU 类不同,GRUCell 专门处理序列中的单个时间步。

GRUCell 类的功能和作用
  • 单时间步处理: GRUCell 用于在自定义循环中逐步处理数据,允许在每个时间步进行更精细的控制。
  • GRU机制: 与 GRU 类似,GRUCell 使用更新门(update gate)和重置门(reset gate)来控制信息的流动,有效地捕捉序列数据中的长期依赖关系。
GRUCell 类的参数
  1. input_size (int): 输入特征的数量。
  2. hidden_size (int): 隐藏状态的特征数量。
  3. bias (bool): 如果为 False,则单元不使用偏置权重 b_ihb_hh。默认为 True
输入和输出
  • 输入: input, hidden

    • input: 包含输入特征的张量。
    • hidden: 包含初始隐藏状态的张量。如果未提供,默认为零。
  • 输出: h'

    • h': 包含批次中每个元素的下一个隐藏状态的张量。
形状
  • input: 形状为 (N, H_in)(H_in) 的张量,其中 H_in = input_size
  • hidden: 形状为 (N, H_out)(H_out) 的张量,其中 H_out = hidden_size。如果未提供,默认为零。
  • output: 形状为 (N, H_out)(H_out) 的张量,包含下一个隐藏状态。
变量
  • weight_ih (torch.Tensor): 学习得到的输入-隐藏权重,形状为 (3*hidden_size, input_size)
  • weight_hh (torch.Tensor): 学习得到的隐藏-隐藏权重,形状为 (3*hidden_size, hidden_size)
  • bias_ih: 学习得到的输入-隐藏偏置,形状为 (3*hidden_size)
  • bias_hh: 学习得到的隐藏-隐藏偏置,形状为 (3*hidden_size)
注意事项
  • 权重和偏置的初始化: 所有权重和偏置都从均匀分布 U(-k, k) 初始化,其中 k = 1 / hidden_size
  • 不同的设备精度: 在某些 ROCm 设备上,使用 float16 输入时,此模块的反向传播可能使用不同的精度。

示例代码

import torch
import torch.nn as nn

# 创建 GRUCell 实例
gru_cell = nn.GRUCell(10, 20)  # (input_size, hidden_size)

# 输入数据
input = torch.randn(6, 3, 10)  # (time_steps, batch, input_size)
hx = torch.randn(3, 20)        # (batch, hidden_size)

# 模拟时间步循环
output = []
for i in range(6):
    hx = gru_cell(input[i], hx)
    output.append(hx)

这段代码展示了如何使用 GRUCell 来处理一个序列。在这个例子中,input 是一个随机生成的输入张量,其维度是时间步、批大小和输入大小。hx 是初始隐藏状态。循环通过逐个时间步调用 GRUCell 来更新 hx,并将每个时间步的输出收集到 output 列表中。

总结

         在这篇博客中,我们深入探索了 PyTorch 中的循环神经网络(RNN)相关的几个关键类:RNNBase, RNN, LSTM, GRU 及其对应的单元格版本 RNNCell, LSTMCell, GRUCell。每个类的功能、作用、参数和使用方法都得到了详细的解释和示例代码的支持。从基础的 RNN 架构到更复杂的 LSTM 和 GRU 结构,本文提供了深入了解这些强大的序列模型工具的机会,同时也展示了如何在实际场景中应用这些模型。这些类不仅对于理解序列数据的基本动态至关重要,而且在许多先进的深度学习应用中发挥着核心作用。

猜你喜欢

转载自blog.csdn.net/qq_42452134/article/details/135402306