1 什么是RNN
RNN又称循环神经网络,是一种在序列数据处理中广泛使用的神经网络模型。具有循环连接,允许信息在网络中持续传递。能够处理任意长度的输入序列,并且在处理序列时共享参数,这也是该模型在自然语言处理、语音识别、时间序列预测等任务中取得出色表现的主要原因。
2 RNN原理
RNN的目的就是用来处理序列数据的。在传统的神经网络模型中,是从输入层到隐含层再到输出层,层与层之间是全连接的,每层之间的节点是无连接的。但是这种普通的神经网络对于很多问题都无能无力。比如你要预测句子的下一个单词是什么,一般需要用到前面的单词,因为一个句子中前后单词并不是独立的。
RNN可以考虑到词的先后顺序对预测的影响,RNN包括三个部分:输入层、隐藏层和输出层。相对于前馈神经网络,RNN可以接收上一个时间点的隐藏状态。
3 RNN网络结构
单向RNN的基本结构包括一个主要的隐藏状态(hidden state)和一个可选的输出。在每个时间步骤,RNN接受输入和前一时刻的隐藏状态,并产生新的隐藏状态作为输出。这种隐藏状态的更新方式允许模型记忆先前的信息,并在后续时间步骤中使用。
在单向RNN的基础上,双向RNN接收后一时刻的隐藏层值的影响
简单说明单向RNN网络计算流程:
使用图形式进一步说明,单向和双向RNN网络计算过程
4 如何处理梯度爆炸/消失的问题
- 梯度剪裁: 梯度爆炸往往是由于梯度值变得非常大而导致的。为了防止梯度爆炸,可以对梯度进行剪裁,将其限制在一个固定的范围内。例如,可以设置一个阈值,如果梯度的范数超过了该阈值,就将梯度进行缩放,使其范数不超过阈值。
- 权重正则化: 可以通过正则化方法如L1正则化或L2正则化来约束网络的权重。这些正则化项会向损失函数中添加一个惩罚项,使得网络在学习过程中更加趋向于较小的权重值。较小的权重值可以帮助缓解梯度爆炸问题。
- 改变网络结构: 一些改进的RNN结构如长短期记忆网络(LSTM)和门控循环单元(GRU)被设计来解决梯度消失和梯度爆炸问题。这些网络结构引入了门控机制,能够更好地控制信息的流动,从而减少梯度的衰减或增长。LSTM和GRU已经成为处理序列数据的首选模型之一。
5 使用pytorch实现RNN,可以通过调用torch.nn.RNN类来构建
nn.RNN参数介绍
- input_size:输入的特征维度大小。它表示每个时间步输入的特征向量的大小。
- hidden_size:隐藏状态的维度大小。它定义了RNN模型中隐藏状态的大小。
- num_layers:RNN模型的层数。它指定在堆叠多个RNN层以增加模型容量和表征能力时要使用的层数。
- nonlinearity:非线性激活函数,默认为"Tanh"。可以选择使用其他激活函数,如"ReLU"。
- bias:是否使用偏置项,默认为True。如果设置为False,则RNN层将不具有偏置项。
- batch_first:是否将输入数据的维度设置为(batch_size, seq_length, input_size)。默认为False,表示输入数据的维度为(seq_length, batch_size, input_size)。
- dropout:应用于非最后一层的丢弃率。默认值为0,表示不应用丢弃。非零值将在每个RNN层的输出上应用丢弃。
- bidirectional:是否使用双向RNN,默认为False。如果设置为True,则会创建一个双向RNN,其包含正向和反向两个方向的隐藏状态。
在这些参数中最为重要的是input_size,hidden_size。其余参数通常不用设置,使用默认值即可。此外,nn.RNN还有其他方法和属性,如forward方法用于执行前向传播,parameters属性用于获取模型的参数等。你可以根据需要进一步探索和使用这些方法和属性来扩展和优化你的RNN模型。
单向RNN
#导入库
import torch
import torch.nn as nn
#定义网络
class rnn(nn.Module):
def __init__(self, input_size, hidden_size):
super(rnn, self).__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.rnn = nn.RNN(self.input_size, self.hidden_size)
def forward(self, input_data):
# 在 forward 函数中定义数据的计算和传递逻辑
output, hn = self.rnn(input_data)
return output, hn
#使用网络
input_size = 10
hidden_size = 20
# 创建 rnn 模型对象
rnn_model = rnn(input_size, hidden_size)
# 定义输入数据
input_data = torch.randn(5, 3, input_size)
# 使用 rnn 模型进行前向计算
output, hn = rnn_model(input_data) # 输出和隐藏状态
print(output.size(),hn.size())
#torch.Size([5, 3, 20]) torch.Size([1, 3, 20])
双向RNN
class BiRNN(nn.Module):
def __init__(self, input_size, hidden_size):
super(BiRNN, self).__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.num_directions = 2 # 双向RNN,有两个方向
self.rnn = nn.RNN(input_size, hidden_size, bidirectional=True)
def forward(self, input_data):
output, hn = self.rnn(input_data)
# 将前向和后向的输出拼接起来
output = torch.cat((output[:, :, :self.hidden_size], output[:, :, self.hidden_size:]), dim=2)
return output, hn