Day60:循环神经网络详解与案例
上一节中我们介绍了卷积神经网络,这是一种处理二维图像数据非常友好的网络模型,但是如果是序列数据,我们可能就需要记忆前面遇到过的序列,比如我“小明非常喜欢上学”,处理到“上学”的时候,需要知道主语是“小明”,这时候就需要用到循环神经网络(RNN)了。
RNN的基本原理
循环神经网络(Recurrent Neural Network,RNN)是一种适用于处理序列数据的神经网络模型。它具有记忆功能,能够捕捉序列数据中的时序信息。RNN通过在不同时间步共享权重参数,将先前的信息传递到后续的时间步中,实现对序列数据的处理和学习。
一个简单的RNN单元包含一个循环神经元(Recurrent Neuron)和一个非线性激活函数。在每个时间步,循环神经元接收当前的输入和前一时间步的隐藏状态,计算出一个新的隐藏状态作为输出。RNN的训练过程中,通过反向传播算法来更新权重参数,使网络能够适应序列数据的特征。
然而,传统的RNN在处理长序列时容易遇到梯度消失和梯度爆炸的问题,导致难以有效学习长期依赖关系。为了解决这个问题,出现了一些改进的循环神经网络模型,如长短期记忆网络(LSTM)和门控循环单元(GRU),它们引入了门控机制来控制信息的传递和遗忘,从而更好地处理长序列数据。
其模型定义代码为:
class RNNModel(nn.Module):
def __init__(self, input_dim, embedding_dim, hidden_dim, output_dim):
super(RNNModel, self).__init__()
self.embedding = nn.Embedding(input_dim, embedding_dim)
self.rnn = nn.RNN(embedding_dim, hidden_dim)
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, text, text_lengths):
embedded = self.embedding(text)
packed_embedded = nn.utils.rnn.pack_padded_sequence(embedded, text_lengths.cpu(), enforce_sorted=False)
packed_output, hidden = self.rnn(packed_embedded)
output, _ = nn.utils.rnn.pad_packed_sequence(packed_output)
hidden = torch.squeeze(hidden, 0)
return self.fc(hidden)
2. LSTM和GRU
LSTM引入了三个关键的门控机制:输入门(input gate)、遗忘门(forget gate)和输出门(output gate)。
- 输入门:决定哪些信息将被更新到记忆单元中。它由一个sigmoid函数和一个tanh函数组成。sigmoid函数输出的是0到1之间的值,表示每个输入元素的重要程度;tanh函数产生一个新的候选值向量,表示要更新到记忆单元的信息。输入门通过将这两个结果相乘,决定了最终更新到记忆单元的信息。
- 遗忘门:决定从记忆单元中遗忘哪些信息。它由一个sigmoid函数决定,输出的是0到1之间的值,表示每个记忆单元元素的保留程度。0表示完全遗忘,1表示完全保留。
- 输出门:决定从记忆单元中输出哪些信息。它由一个sigmoid函数和一个tanh函数组成。sigmoid函数决定哪些记忆单元元素将被输出,tanh函数将这些元素转化为一个新的向量。输出门通过将这两个结果相乘,得到最终的输出。
这些门控机制使得LSTM能够选择性地更新和输出信息,从而更好地处理长期依赖关系。
其模型定义代码为:
class LSTMModel(nn.Module):
def __init__(self, input_dim, embedding_dim, hidden_dim, output_dim):
super(LSTMModel, self).__init__()
self.embedding = nn.Embedding(input_dim, embedding_dim)
self.lstm = nn.LSTM(embedding_dim, hidden_dim)
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, text, text_lengths):
embedded = self.embedding(text)
packed_embedded = nn.utils.rnn.pack_padded_sequence(embedded, text_lengths.cpu(), enforce_sorted=False)
packed_output, (hidden, _) = self.lstm(packed_embedded)
output, _ = nn.utils.rnn.pad_packed_sequence(packed_output)
hidden = torch.squeeze(hidden, 0)
return self.fc(hidden)
GRU(Gated Recurrent Unit)是对LSTM的简化版本,它引入了两个关键的门控机制:更新门(update gate)和重置门(reset gate)。
- 更新门:决定要从前一个状态中保留多少信息并更新到当前状态中。它由一个sigmoid函数决定,输出的是0到1之间的值,表示前一个状态的保留程度。
- 重置门:决定要忽略前一个状态中多少信息。它也由一个sigmoid函数决定,输出的是0到1之间的值,表示前一个状态的遗忘程度。
GRU通过这两个门控机制来控制信息的流动,使得模型能够选择性地更新和忽略信息,从而处理长期依赖关系。
其模型定义代码为:
class GRUModel(nn.Module):
def __init__(self, input_dim, embedding_dim, hidden_dim, output_dim):
super(GRUModel, self).__init__()
self.embedding = nn.Embedding(input_dim, embedding_dim)
self.gru = nn.GRU(embedding_dim, hidden_dim)
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, text, text_lengths):
embedded = self.embedding(text)
packed_embedded = nn.utils.rnn.pack_padded_sequence(embedded, text_lengths.cpu(), enforce_sorted=False)
packed_output, hidden = self.gru(packed_embedded)
output, _ = nn.utils.rnn.pad_packed_sequence(packed_output)
hidden = torch.squeeze(hidden, 0)
return sel
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
1. AI爱好者,爱搞事的 2. 想要掌握第二门语言的Javaer或者golanger 3. 决定考计算机领域研究生,给实验室搬砖的uu,强烈建议你花时间学完这个,后续搬砖比较猛 4. 任何对编程感兴趣的,且愿意掌握一门技能的人