神经网络之RNN和LSTM(基于pytorch-api)

1.RNN

1.1简介

RNN用于处理序列数据。在传统的神经网络模型中,是从输入层到隐含层再到输出层,层与层之间是全连接的,每层之间的节点是无连接的。但是这种普通的神经网络对于很多问题却无能无力。例如,你要预测句子的下一个单词是什么,一般需要用到前面的单词,因为一个句子中前后单词并不是独立的。RNN之所以称为循环神经网路,即一个序列当前的输出与前面的输出也有关。具体的表现形式为网络会对前面的信息进行记忆并应用于当前输出的计算中,即隐藏层之间的节点不再无连接而是有连接的,并且隐藏层的输入不仅包括输入层的输出还包括上一时刻隐藏层的输出。理论上,RNN能够对任何长度的序列数据进行处理。但是在实践中,为了降低复杂性往往假设当前的状态只与前面的几个状态相关。

1.2RNN结构

1.2.1一对多

这种结构 无疑是"看图说话","看视频"

1.2.2经典结构n to n

step1 :解析数据

涉及到词向量的解析模型:一个字或者词把他分为300维向量!!!

而x1,x2,x3,x4....x300就是这些输入的特征

step2:建立一层

为了建模序列问题,RNN引入了隐状态h(hidden state)的概念,h可以对序列形的数据提取特征,接着再转换为输出。先从h1的计算开始看:

step3

2的计算和h1类似。要注意的是,在计算时,每一步使用的参数U、W、b都是一样的,也就是说每个步骤的参数都是共享的,这是RNN的重要特点,一定要牢记。

依次计算剩下来的(使用相同的参数U,W,b):

这里为了方便起见,只画出序列长度为4的情况,实际上,这个计算过程可以到300()下去。得到输出值的方法就是直接通过h进行计算:

正如之前所说,一个箭头就表示对对应的向量做一次类似于f(Wx+b)的变换,这里的这个箭头就表示对h1进行一次变换,得到输出y1。的变换,这里的这个箭头就表示对h1进行一次变换,得到输出y1。

1.3RNN缺点

  1. 梯度消失与梯度爆炸问题
  • 原理

    • 在 RNN 中,梯度在反向传播过程中会经过多次矩阵乘法运算。对于传统的激活函数(如 Sigmoid 或 Tanh),其导数范围通常在 0 到 1 之间。当进行多次乘法时,梯度会变得越来越小,最终趋近于 0,这就是梯度消失问题。相反,如果权重矩阵的值较大,梯度在反向传播过程中会不断增大,导致梯度爆炸。
  • 影响

    • 梯度消失会使 RNN 难以学习到序列中的长期依赖关系。因为当梯度趋近于 0 时,网络参数几乎不会更新,早期时间步的信息无法有效地传递到后面的时间步,导致模型无法捕捉到序列中远距离元素之间的关联。

    • 梯度爆炸则会使参数更新幅度过大,导致模型不稳定,无法收敛到最优解,甚至可能使参数值变为 NaN(非数字),导致训练失败。

  1. 难以处理长序列
  • 信息丢失

    • 由于 RNN 是按时间步依次处理序列数据的,随着序列长度的增加,早期时间步的信息在传递到后面的时间步时会逐渐被稀释或遗忘。这使得 RNN 在处理长序列时,难以保留和利用序列开头的重要信息,从而影响模型对整个序列的理解和处理能力。
  • 训练效率低

    • 处理长序列时,RNN 需要进行大量的时间步计算,这会导致训练时间显著增加。同时,由于梯度消失和梯度爆炸问题的存在,训练过程可能会变得不稳定,需要更多的技巧和时间来调整参数,进一步降低了训练效率。
  1. 并行计算困难
  • 计算方式限制

    • RNN 的结构决定了它在处理序列数据时是按时间步顺序进行的,每个时间步的输出依赖于前一个时间步的隐藏状态。这意味着在计算当前时间步的输出时,必须等待前一个时间步的计算完成,无法像前馈神经网络那样进行大规模的并行计算。
  • 影响训练和推理速度

    • 并行计算能力的缺乏限制了 RNN 在处理大规模数据时的效率。在训练过程中,无法充分利用现代 GPU 的并行计算能力,导致训练时间变长;在推理阶段,也会影响模型的响应速度,降低系统的实时性

2.LSTM

解决梯度消失问题

长短时记忆网络的思路比较简单。原始RNN的隐藏层只有一个状态,即h,它对于短期的输入非常敏感。那么,假如我们再增加一个状态,即c,让它来保存长期的状态,那

新增加的状态c,称为单元状态(cell state)。我们把上图按照时间维度展开

LSTM的关键,就是怎样控制长期状态c。在这里,LSTM的思路是使用三个控制开关。第一个开关,负责控制继续保存长期状态c;第二个开关,负责控制把即时状态输入到长期状态c;第三个开关,负责控制是否把长期状态c作为当前的LSTM的输出。三个开关的作用如下图所示:

长短时记忆网络的前向计算

前面描述的开关是怎样在算法中实现的呢?这就用到了门(gate) 的概念。门实际上就是一层全连接层,它的输入是一个向量,输出是一个0到1之间的实数向量。假设W是门的权重向量,b是偏置项,那么门可以表示为:

就是用门的输出向量按元素乘以我们需要控制的那个向量。因为门的输出是0到1之间的实数向量,那么,当门输出为0时,任何向量与之相乘都会得到0向量,这就相当于啥都不能通过;输出为1时,任何向量与之相乘都不会有任何改变,这就相当于啥都可以通过。因为δ(也就是sigmoid函数)的值域是(0,1)

LSTM用两个门来控制单元状态c的内容,一个是遗忘门(forget gate),它决定了上一时刻的单元状态有多少保留到当前时刻ct;另一个是输入门(input gate),它决定了当前时刻网络的输入xt有多少保存到单元状态ct。LSTM用输出门(output gate)来控制单元状态ct有多少输出到LSTM的当前输出值ht。

1.遗忘门

2.输入门

下图是的~ct计算

我们就把LSTM关于当前的记忆~ct和长期的记忆ct-1组合在一起,形成了新的单元状态ct。由于遗忘门的控制,它可以保存很久很久之前的信息,由于输入门的控制,它又可以避免当前无关紧要的内容进入记忆。下面,我们要看看输出门,它控制了长期记忆对当前输出的影响

输出门:

LSTM最终的输出,是由输出门和单元下图表示LSTM最终输出的计算:

下图表示LSTM最终输出的计算:

总结:

1.就是三个门就是通过全连接层来控制权重,再来控制再当前输入,你一般只需记得这一点就行。(lstm不行了)

2.集成函数:

cpp 复制代码
torch.nn.LSTM(input_size, hidden_size, num_layers=1,
 bias=True, batch_first=False, dropout=0, bidirectional=False, proj_size=0)
  1. input_size 根据词嵌入模型来
  • 类型int

  • 含义 :输入特征的维度,也就是每个时间步输入向量的大小。例如,在处理词嵌入时,input_size 就是词向量的维度。

  • 设置原则:你自己的词向量转化模型

  1. hidden_size
  • 类型int

  • 含义:隐藏状态的维度,即 LSTM 单元中隐藏层的神经元数量。这个参数决定了 LSTM 能够学习和表示的信息复杂度。

  • 设置原则:应远小于词嵌入的维度,否则可能会丢失输入特征中的重要信息;但也不需要过大,以免增加模型的复杂度和计算成本。

  1. num_layers
  • 类型int,默认值为 1

  • 含义 :堆叠的 LSTM 层数。当 num_layers > 1 时,会构建一个多层的 LSTM 网络,上层 LSTM 的输入是下层 LSTM 的输出。

  1. bias
  • 类型bool,默认值为 True

  • 含义 :是否使用偏置项。如果设置为 True,LSTM 层会在计算过程中添加偏置项。

  1. batch_first
  • 类型bool,默认值为 False

  • 含义 :指定输入和输出张量的维度顺序。如果设置为 True,输入和输出张量的形状为 (batch_size, seq_len, input_size);如果设置为 False,形状为 (seq_len, batch_size, input_size)

  • 要用seq_len是序列长度

  1. dropout
  • 类型float,默认值为 0

  • 含义 :在除最后一层外的每层 LSTM 输出上应用的 Dropout 概率。Dropout 是一种正则化技术,用于防止过拟合。取值范围为 [0, 1],当设置为 0 时,不应用 Dropout。

  • 0.5

  1. bidirectional
  • 类型bool,默认值为 False

  • 含义 :是否使用双向 LSTM。如果设置为 True,LSTM 会同时从序列的正向和反向进行处理,然后将两个方向的输出拼接起来,这有助于模型捕捉序列中的前后文信

  1. proj_size
  • 类型int,默认值为 0

  • 含义 :如果设置为非零值,会在 LSTM 单元中添加投影层,将隐藏状态投影到指定的维度 proj_size。这可以减少模型的参数数量。

3.torchAPI

利用torch库搭建一个网络

python 复制代码
class Model(nn.Module):
    def __init__(self, config):
        super(Model, self).__init__()
        if config.embedding_pretrained is not None:
            self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)
        else:
            self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)
        self.lstm = nn.LSTM(config.embed, config.hidden_size, config.num_layers,
                            bidirectional=True, batch_first=True, dropout=config.dropout)
        #三百维
        self.fc = nn.Linear(config.hidden_size * 2, config.num_classes)
 
    def forward(self, x):
        x, _ = x #j
        out = self.embedding(x)  # [batch_size, seq_len, embeding]=[128, 32, 300]
        out, _ = self.lstm(out)  # (output, (h_n, c_n))
        #out #(batch_size, seq_len, hidden_size)(当 batch_first=True 时
        out = self.fc(out[:, -1, :])  # 句子最后时刻的 hidden state
        return out
相关推荐
AuGuSt_813 小时前
【深度学习】Hopfield网络:模拟联想记忆
人工智能·深度学习
HXQ_晴天6 小时前
深度学习中卷积层(Conv)、BN层(Batch Normalization)和 ReLU层(Rectified Linear Unit)的详细介绍
人工智能·深度学习·batch
邪恶的贝利亚7 小时前
神经网络架构之transformer
人工智能·神经网络·transformer
AI浩7 小时前
【Block总结】SAFMN,空间自适应调制与局部特征增强的协同设计|即插即用
人工智能·深度学习·计算机视觉
@Dai7 小时前
【AI】DeepSeek本地部署,Ollama + vscode + Continue,实现本地运行LLM大模型,以及代码自动补全
人工智能·vscode·深度学习·学习·编辑器
明明真系叻8 小时前
2025.3.2机器学习笔记:PINN文献阅读
人工智能·笔记·深度学习·机器学习·1024程序员节·pinn
Donvink8 小时前
【AIGC系列】4:Stable Diffusion应用实践和代码分析
人工智能·深度学习·机器学习·stable diffusion·aigc·transformer
从入门-到精通9 小时前
通过统计学视角解读机器学习:从贝叶斯到正则化
人工智能·深度学习·神经网络·机器学习
KingDol_MIni10 小时前
一个使用ALIGNN神经网络对材料性能预测的深度学习案例解读
人工智能·pytorch·深度学习
Loving_enjoy14 小时前
深度学习五大模型:CNN、Transformer、BERT、RNN、GAN详细解析
深度学习