PyTorch:从零实现一个双向循环神经网络
从零实现一个双向循环神经网络(Bi-directional Recurrent Neural Network, Bi-RNN)从零开始,可以帮助我们深入理解 RNN 的机制。以下是实现步骤:
- 定义 RNN 单元:实现一个简单的 RNN 单元,能够处理单个时间步长的数据。
- 定义双向 RNN:实现前向和后向的 RNN,组合它们的输出。
- 定义损失函数和优化器:使用 PyTorch 提供的工具来定义损失函数和优化器。
以下是实现一个简单的双向 RNN 的完整代码:
import torch
import torch.nn as nn
import torch.optim as optim# 定义一个简单的 RNN 单元
class SimpleRNNCell(nn.Module):def __init__(self, input_size, hidden_size):super(SimpleRNNCell, self).__init__()self.input_size = input_sizeself.hidden_size = hidden_sizeself.W_ih = nn.Parameter(torch.Tensor(input_size, hidden_size))self.W_hh = nn.Parameter(torch.Tensor(hidden_size, hidden_size))self.b_ih = nn.Parameter(torch.Tensor(hidden_size))self.b_hh = nn.Parameter(torch.Tensor(hidden_size))self.reset_parameters()def reset_parameters(self):nn.init.kaiming_uniform_(self.W_ih, a=math.sqrt(5))nn.init.kaiming_uniform_(self.W_hh, a=math.sqrt(5))nn.init.zeros_(self.b_ih)nn.init.zeros_(self.b_hh)def forward(self, input, hidden):hy = torch.tanh(torch.mm(input, self.W_ih) + self.b_ih + torch.mm(hidden, self.W_hh) + self.b_hh)return hy# 定义双向 RNN
class BiRNN(nn.Module):def __init__(self, input_size, hidden_size, output_size):super(BiRNN, self).__init__()self.hidden_size = hidden_sizeself.rnn_fw = SimpleRNNCell(input_size, hidden_size)self.rnn_bw = SimpleRNNCell(input_size, hidden_size)self.fc = nn.Linear(2 * hidden_size, output_size)def forward(self, input):seq_len, batch_size, _ = input.size()h_fw = torch.zeros(batch_size, self.hidden_size)h_bw = torch.zeros(batch_size, self.hidden_size)output_fw = []output_bw = []for t in range(seq_len):h_fw = self.rnn_fw(input[t], h_fw)output_fw.append(h_fw)for t in range(seq_len-1, -1, -1):h_bw = self.rnn_bw(input[t], h_bw)output_bw.append(h_bw)output_fw = torch.stack(output_fw, dim=0)output_bw = torch.stack(output_bw[::-1], dim=0)output = torch.cat((output_fw, output_bw), dim=2)output = self.fc(output)return output# 定义模型参数
input_size = 10
hidden_size = 20
output_size = 5
seq_len = 7
batch_size = 3# 创建模型
model = BiRNN(input_size, hidden_size, output_size)# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)# 生成一些随机输入和目标输出
input = torch.randn(seq_len, batch_size, input_size)
target = torch.randn(seq_len, batch_size, output_size)# 训练步骤
output = model(input)
loss = criterion(output, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()print(f'Loss: {loss.item()}')
代码解释
- SimpleRNNCell:实现一个简单的 RNN 单元,包括输入到隐藏层和隐藏层到隐藏层的线性变换,并使用
torch.tanh
作为激活函数。 - BiRNN:实现一个双向 RNN,包含前向和后向的 RNN 单元。它处理输入序列,分别计算前向和后向的隐藏状态,并将它们连接起来,通过一个全连接层生成最终输出。
- 训练步骤:生成一些随机数据,定义损失函数和优化器,执行前向传播、计算损失、反向传播和参数更新。
通过上述步骤,可以实现一个简单的双向 RNN。