Day60:循环神经网络详解与案例

alt

上一节中我们介绍了卷积神经网络,这是一种处理二维图像数据非常友好的网络模型,但是如果是序列数据,我们可能就需要记忆前面遇到过的序列,比如我“小明非常喜欢上学”,处理到“上学”的时候,需要知道主语是“小明”,这时候就需要用到循环神经网络(RNN)了。

RNN的基本原理

循环神经网络(Recurrent Neural Network,RNN)是一种适用于处理序列数据的神经网络模型。它具有记忆功能,能够捕捉序列数据中的时序信息。RNN通过在不同时间步共享权重参数,将先前的信息传递到后续的时间步中,实现对序列数据的处理和学习。

一个简单的RNN单元包含一个循环神经元(Recurrent Neuron)和一个非线性激活函数。在每个时间步,循环神经元接收当前的输入和前一时间步的隐藏状态,计算出一个新的隐藏状态作为输出。RNN的训练过程中,通过反向传播算法来更新权重参数,使网络能够适应序列数据的特征。

1alt

然而,传统的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)。

2alt

  • 输入门:决定哪些信息将被更新到记忆单元中。它由一个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)。

3alt

  • 更新门:决定要从前一个状态中保留多少信息并更新到当前状态中。它由一个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%内容,订阅专栏后可继续查看/也可单篇购买

大模型-AI小册 文章被收录于专栏

1. AI爱好者,爱搞事的 2. 想要掌握第二门语言的Javaer或者golanger 3. 决定考计算机领域研究生,给实验室搬砖的uu,强烈建议你花时间学完这个,后续搬砖比较猛 4. 任何对编程感兴趣的,且愿意掌握一门技能的人

全部评论

相关推荐

投递华为等公司10个岗位
点赞 评论 收藏
转发
1 收藏 评论
分享
牛客网
牛客企业服务