使用PyTorch实现简单的RNN

使用PyTorch实现简单的RNN

假设 X t ∈ R n × d X_t \in R^{n \times d} XtRn×d 是序列中时间步 t t t 的小批量输入, H t ∈ R n × h H_t \in R^{n \times h} HtRn×h 是该时间步输入的隐藏变量。计算过程如下:
H t = ϕ ( X t W d h + H t − 1 W h h + b h ) H_{t}=\phi(X_tW_{dh}+H_{t-1}W_{hh}+b_h) Ht=ϕ(XtWdh+Ht1Whh+bh)
其中,隐藏层的权重 W d h ∈ R d × h W_{dh} \in R^{d \times h} WdhRd×h W h h ∈ R h × h W_{hh} \in R^{h \times h} WhhRh×h 和偏置项系数 b h ∈ R 1 × h b_h \in R^{1 \times h} bhR1×h d d d 表示输入特征向量的维度, h h h 表示隐藏层单元的个数。
O t = H t W h q + b q O_{t}=H_{t}W_{hq}+b_{q} Ot=HtWhq+bq
其中,输出变量 O t ∈ R n × q O_t \in R^{n \times q} OtRn×q,输出层权重参数 W h q ∈ R h × q W_{hq} \in R^{h \times q} WhqRh×q,输出层的偏置项 b q ∈ R 1 × q b_q \in R^{1 \times q} bqR1×q q q q 表示输出层的个数。

一个基本的 RNN Cell 如下图所示:

将多个 RNN Cell 依次串联起来就可以得到最传统的循环神经网络的结构;

2.1 torch.nn.RNNCell

下面我们通过 PyTorch 内置的 RNNCell 方法实现一个简单的单隐藏循环神经网课。

"""
input_size:输入层输入的特征维度
hidden_size:隐藏层输出的特征维度
bias:bool类型,如果是False,那么不提供偏置,默认为True
nonlinearity:字符串类型,进行激活函数选择,可以是 "tanh" 或 "relu",默认为 "tanh"
"""
cell = torch.nn.RNNCell(input_size, hidden_size, bias, nonlinearity)
hidden = cell(input, hidden)

其中,input 是一个二维张量,维度是 (batch, input_size)input_size 表示的是当前特征的维度;而 hidden 也是一个维度为 (batch, hidden_size) 的二维张量,第一维表示的是批量大小,第二维则表示隐藏层的维度。

# 初始化模型参数
batchSize = 5     # 批量大小
seqLen = 3        # 序列长度
inputSize = 4     # 特征维度
hiddenSize = 2    # 隐藏层大小

由于我们使用的是一个 RNNCell,所以需要通过循环或迭代的方式将多个 RNNCell 连结起来,构成一个含有 3 个时间步或者序列长度为 3 的单隐藏循环神经网络。

import torch

# 初始化模型参数
batch_size = 5    # 批量大小
seq_len = 3       # 序列长度
input_size = 4    # 特征维度
hidden_size = 2   # 隐藏层大小

cell = torch.nn.RNNCell(input_size=input_size, hidden_size=hidden_size)
# 输入张量是三维的,维度为(seq, batch, features)
dataset = torch.randn(seq_len, batch_size, input_size)
hidden = torch.zeros(batch_size, hidden_size)  # 因为是单隐藏,所以没有layer_size
# 由于没有先验,所以初始化第一个隐藏层单元设置为全零
for idx, input in enumerate(dataset):
    # 每次取出一个seq:(batch, features)
    print("=" * 30, idx, "=" * 30)
    print("Input Size:", input.shape)
    
    # 迭代隐藏状态
    hidden = cell(input, hidden)
    print("outputs size:", hidden.shape)
    print(hidden)

输入结果如下所示:

============================== 0 ==============================
Input Size: torch.Size([5, 4])
outputs size: torch.Size([5, 2])
tensor([[-0.4303, -0.7020],
        [ 0.8070, -0.8489],
        [ 0.9530, -0.2026],
        [ 0.4949,  0.6330],
        [ 0.4102, -0.7713]], grad_fn=<TanhBackward>)
============================== 1 ==============================
Input Size: torch.Size([5, 4])
outputs size: torch.Size([5, 2])
tensor([[-0.7902,  0.0440],
        [-0.4864, -0.3627],
        [ 0.2286, -0.8892],
        [-0.9849, -0.9189],
        [-0.6484,  0.2796]], grad_fn=<TanhBackward>)
============================== 2 ==============================
Input Size: torch.Size([5, 4])
outputs size: torch.Size([5, 2])
tensor([[-0.8761, -0.8581],
        [-0.3768, -0.5525],
        [-0.9380, -0.8973],
        [-0.2933, -0.6940],
        [ 0.0205, -0.7125]], grad_fn=<TanhBackward>)

2.2 torch.nn.RNN

用于定义多层循环神经网络,函数原型如下:

"""
input_size:输入特征的维度
hidden_size:隐藏层神经元个数
num_layers:网络的层数,或者说是隐藏层的层数
nonlinearity:激活函数,默认为 tanh
bias:是否使用偏置,默认为True
"""
cell = torch.nn.RNN(input_size, hidden_size, num_layers=1, nonlinearity=tanh, bias=True)
out, hn = cell(inputs, h0)

其中, i n p u t input input 的维度为 (seqLen, batchSize, inputSize),初始化隐藏变量 h 0 h_0 h0 的维度是 (numLayers, batchSize, hiddenSize)

o u t out out 的维度为 (seqlen, batch, hidden_size) h n h_n hn 的维度是 (numlayers, batch, hidden)

初始化模型参数:

batchSize = 5  # 批量大小
seqLen = 6   # 序列长度或时间步个数
inputSize = 4, hiddenSize = 2  # 输入特征维度,隐藏神经元个数
numLayers = 3  # 隐藏层的数目

通过一个案例来理解多层循环神经网络的工作原理:

import torch

batch_size = 5     # 批量大小
seq_len = 6        # 序列长度或时间步
input_size = 4     # 输入特征维度
hidden_size = 2    # 隐藏层神经元个数
num_layers = 3      # 隐藏层的层数

cell = torch.nn.RNN(input_size=input_size, hidden_size=hidden_size, num_layers=num_layers)
# 输入数据的维度:(seqLen, batchSize, inputSize)
inputs = torch.randn(seq_len, batch_size, input_size)
h0 = torch.zeros(num_layers, batch_size, hidden_size)
out, hidden = cell(inputs, h0)
print("Output size:", out.shape)
print("Output:", out)
print("Hidden size:",hidden.shape)
print("Hidden:",hidden)

输入结果如下所示:

Output size: torch.Size([6, 5, 2])
Output: tensor([[[-0.7661, -0.1398],
         [-0.8071, -0.2583],
         [-0.7350, -0.2608],
         [-0.7267, -0.0988],
         [-0.8062, -0.4056]],...
         
Hidden size: torch.Size([3, 5, 2])
Hidden: tensor([[[ 0.4582,  0.1637],
         [ 0.0329,  0.2484],
         [ 0.6672,  0.2769],
         [ 0.2256,  0.8171],
         [ 0.9833, -0.3417]],...
cell = torch.nn.RNN(input_size=input_size, hidden_size=hidden_size,num_layers=num_layers, batch_first=True)

其中,如果参数 batch_first 设置为 True,则输入张量的维度为 (batchSize, seqLen, input_size) ,即序列长度与批量交换。一般地,为了避免混淆,我们将输入张量的维度设置为 (seqLen, batchSize, input_size) 是比较容易理解的

  • 12
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是使用PyTorch实现简易的RNN的步骤: 1.导入相关的库和数据 ``` import torch import numpy as np # 定义数据 data = "hello world" chars = list(set(data)) data_size, vocab_size = len(data), len(chars) char_to_idx = {ch:i for i, ch in enumerate(chars)} idx_to_char = {i:ch for i, ch in enumerate(chars)} ``` 2.定义超参数 ``` # 定义超参数 hidden_size = 100 # 隐藏层大小 seq_length = 5 # 序列长度 learning_rate = 1e-1 # 学习率 ``` 3.定义模型 ``` class RNN(torch.nn.Module): def __init__(self, input_size, hidden_size, output_size): super(RNN, self).__init__() self.hidden_size = hidden_size self.i2h = torch.nn.Linear(input_size + hidden_size, hidden_size) self.i2o = torch.nn.Linear(input_size + hidden_size, output_size) self.softmax = torch.nn.LogSoftmax(dim=1) def forward(self, input, hidden): combined = torch.cat((input, hidden), 1) hidden = self.i2h(combined) output = self.i2o(combined) output = self.softmax(output) return output, hidden def init_hidden(self): return torch.zeros(1, self.hidden_size) ``` 4.定义训练函数 ``` def train(input_tensor, target_tensor): hidden = rnn.init_hidden() rnn.zero_grad() loss = 0 for i in range(seq_length): output, hidden = rnn(input_tensor[i], hidden) loss += criterion(output, target_tensor[i].unsqueeze(0)) loss.backward() for p in rnn.parameters(): p.data.add_(-learning_rate, p.grad.data) return output, loss.item() / seq_length ``` 5.开始训练 ``` # 创建模型 rnn = RNN(vocab_size, hidden_size, vocab_size) # 定义损失函数和优化器 criterion = torch.nn.NLLLoss() optimizer = torch.optim.SGD(rnn.parameters(), lr=learning_rate) # 训练模型 for epoch in range(100): loss = 0 for i in range(0, data_size - seq_length, seq_length): input_tensor = torch.tensor([char_to_idx[ch] for ch in data[i:i+seq_length]]) target_tensor = torch.tensor([char_to_idx[ch] for ch in data[i+1:i+seq_length+1]]) output, loss_value = train(input_tensor, target_tensor) loss += loss_value if epoch % 10 == 0: print("Epoch:", epoch, " Loss:", loss / (data_size // seq_length)) ``` 这样就完成了简易的RNN模型的实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值