LSTM变种模型

GRU

GRU简介

门控循环神经网络 (Gated Recurrent Neural NetworkGRNN) 的提出,旨在更好地捕捉时间序列中时间步距离较大的依赖关系。它通过可学习的门来控制信息的流动。其中,门控循环单元 (Gated Recurrent Unit GRU) 是一种常用的 GRNN GRU LSTM 做了很多简化,同时却保持着和 LSTM 相同的效果。

GRU的原理

GRU 的两个重大改进

  • 将三个门:输入门、遗忘门、输出门变为两个门:更新门 (Update Gate) 和 重置门 (Reset Gate)
  • (候选) 单元状态隐藏状态 (输出) 合并,即只有 当前时刻候选隐藏状态 当前时刻隐藏状

模型结构

简化图

内部结构图

  •  x_{t}:当前时刻输入信息
  • h_{t-1}:上一时刻的隐藏状态。隐藏状态充当了神经网络记忆,它包含了之前节点所见过的数据的信息
  • h_{t}:传递下一时刻的隐藏状态
  • \tilde{h}_{t}:候选隐藏状态
  • r_{t}:重置门
  • z_{t}:更新门
  • \sigma:sigmoid函数,通过这个函数可以将数据变为0-1范围内的数值
  • tanh:tanh函数,通过这个函数可以将数据变为[-1,1]范围内的数值
  • W_{z}W_{r}和w是W是模型参数(权重矩阵),需要通过训练数据来学习
  • GRU通过其他门控制机制能够有效的捕捉到序列数据中的时间动态,同时相较于LSTM来说,由于起结构更加简洁,通常参数更少,计算效率更高
重置门

重置门决定在计算当前候选隐藏状态时,忽略多少过去的信息

更新门

更新门决定了多少过去的信息将被保留,它使用前一时间步的隐藏状态(h_{t-1})和当前输入(x_{t})来计算得出

候选隐藏状态

候选隐藏状态是当前时间步的建议更新,它包含了当前输入和过去的隐藏状态的信息,重置门的作用体现在它可以允许模型抛弃或保留之前的隐藏状态。

 最终隐藏状态

最终隐藏状态是通过融合过去的隐藏状态和当前大的隐藏状态来计算得出的,更新门Z_{t}控制了融合过去信息和当前信息的比列

代码实现
原生代码
import numpy as np
class GRU:
    def __init__(self, input_size, hidden_size):
        # # gru_model = GRU(10, 5)
        self.input_size = input_size # 10
        self.hidden_size = hidden_size # 5
        # hidden_size 是隐藏层的大小
        # input_size + hidden_size 当前时刻xt的维度+上一个时刻隐藏层的大小
        # (5, 15)
        self.W_z = np.random.randn(hidden_size, input_size + hidden_size)
        # (5)
        self.b_z = np.zeros((hidden_size, ))
        # (5, 15)
        self.W_r = np.random.randn(hidden_size, input_size + hidden_size)
        # (5)
        self.b_r = np.zeros((hidden_size, ))
        # (5, 15)
        self.W_h = np.random.randn(hidden_size, input_size + hidden_size)
        # (5)
        self.b_h = np.zeros((hidden_size, ))
    def sigmoid(self, x):
        return 1 / (1 + np.exp(-x))
    def tanh(self, x):
        return np.tanh(x)
    def forward(self, x):
        # print("Input shape:", x.shape)
        # Input shape: (10,)
        h_prev = np.zeros((hidden_size, )) #(5,)
        concat_input = np.concatenate((h_prev, x), axis=0) # (15,)
        z_t = self.sigmoid(np.dot(self.W_z, concat_input) + self.b_z) # (5,)
        r_t = self.sigmoid(np.dot(self.W_r, concat_input) + self.b_r) # (5,)
        # s = r_t * h_prev
        # print(r_t.shape) # (5,)
        # print(s.shape) # (5,)
        concat_reset_input = np.concatenate((r_t * h_prev, x), axis=0) # (15,)
        h_candidate = self.tanh(np.dot(self.W_h, concat_reset_input) + self.b_h) # (5,)
        h_t = (1 - z_t) * h_prev + z_t * h_candidate # (5,)
        return h_t
# 测试原生代码实现的 GRU
input_size = 10
hidden_size = 5
seq_len = 8
# gru_model = GRU(10, 5)
gru_model = GRU(input_size, hidden_size)
x = np.random.randn(seq_len, input_size)
# print("Input shape:", x.shape) # (8, 10)
all_out = []
for t in range(seq_len): # 8
    x_t = x[t,:] # 确保 x_t 形状为 (input_size, 1) 
    # print("Input shape:", x_t.shape) # Input shape: (10,)
    h_t = gru_model.forward(x_t)
    all_out.append(h_t)
print("Output shape:", h_t.shape)
print("All output:", np.array(all_out).shape)
PyTorch

nn.GRUCell

import torch
import torch.nn as nn
class GRU(nn.Module):
    def __init__(self, input_size, hidden_size):
        super(GRU, self).__init__()
        self.hidden_size = hidden_size # 5
        # (10, 5)
        self.gru_cell = nn.GRUCell(input_size, hidden_size)
    def forward(self, x, h_prev):
        # h_t = self.gru_cell(x, h_prev) 返回的是当前时间步 t 的隐藏状态 h_t
        h_t = self.gru_cell(x, h_prev)
        return h_t
# 测试 PyTorch 实现的 GRU
input_size = 10
hidden_size = 5
timesteps = 8
# gru_model = GRU(10, 5)
gru_model = GRU(input_size, hidden_size)
x = torch.randn(timesteps, input_size) # (8, 10)
h_prev = torch.zeros(hidden_size) # (5,)
for t in range(timesteps):
    # (1,10) (5,1)
    h_t = gru_model(x[t], h_prev)
    print("Output shape:", h_t.shape)

nn.GRU

import torch
import torch.nn as nn
class GRUModel(nn.Module):
    def __init__(self, input_size, hidden_size):
        super(GRUModel, self).__init__()
        self.hidden_size = hidden_size # 5
        self.gru = nn.GRU(input_size, hidden_size, batch_first=True)
    def forward(self, x):
        # # (1, 8, 10) [batch_size, timesteps, input_size]
        # 前向传播
        output, h_n = self.gru(x)
        return output, h_n
# 测试 PyTorch 实现的 GRU
input_size = 10
hidden_size = 5
timesteps = 8 # seq_len
batch_size = 1 # 设置批次大小为 1
# gru_model = GRUModel(10, 5)
gru_model = GRUModel(input_size, hidden_size)
# (1, 8, 10) [batch_size, timesteps, input_size]
x = torch.randn(batch_size, timesteps, input_size) # 输入张量的形状为 (batch_size,seq_len, input_size)
output, h_n = gru_model(x)
#  Output shape: torch.Size([1, 8, 5])
print("Output shape:", output.shape) # 输出形状为 (batch_size, seq_len,hidden_size)
# Final hidden state shape: torch.Size([1, 1, 5])
print("Final hidden state shape:", h_n.shape) # 最终隐藏状态的形状为 (num_layers,batch_size, hidden_size)

(1)output(

  • 形状为 (batch_size, sequence_length, hidden_size)
  • 这是一个完整的模型中的一个循环网络层,所以最后的输出不涉及分类数,而是隐藏层
  • 这个张量包含了 GRU 对每个时间步的输出,也就是每个时间步的隐藏状态。对于每个时间步 t GRU 会输出一个对应的隐藏状态
  • 如果 batch_first=True (如在代码中设置的那样),则 output 的第一个维度是批次大小
    batch_size ,第二个维度是序列长度 sequence_length ,第三个维度是隐藏层的大小 hidden_size 。

(2)h_n

  • 形状为 (num_layers * num_directions, batch_size, hidden_size)
  • 这是 GRU 最后一个时间步的隐藏状态。它只保留每个样本在整个序列中最后一个时间步的隐藏状态。
  • 如果是单向 GRU num_directions=1 ;如果是双向 GRU (即 bidirectional=True ),
    num_directions=2

BiLSTM

概述

双向长短期记忆网络(Bi-directional Long Short-Term MemoryBiLSTM 是一种扩展自长短期记忆网络(LSTM )的结构,旨在解决传统 LSTM 模型只能考虑到过去信息的问题 BiLSTM 在每个时间步同时考虑了过去和未来的信息,从而更好地捕捉了序列数据中的双向上下文关系。
BiLSTM 的创新点在于引入了两个独立的 LSTM ,一个按正向顺序处理输入序列,另一个按逆向顺序 处理输入序列。这样,每个时间步的输出就包含了当前时间步之前和之后的信息,进而使得模型能够更好地理解序列数据中的语义和上下文关系
  • 正向传递: 输入序列按照时间顺序被输入到第一个LSTM。每个时间步的输出都会被计算并保留下来。
  • 反向传递 : 输入序列按照时间的逆序(即先输入最后一个元素)被输入到第二个 LSTM 。与正向传递类似,每个时间步的输出都会被计算并保留下来。
  • 合并输出 : 每个时间步,将两个 LSTM 层的输出通过某种方式合并(如拼接或加和)以得到最终的输出。

BILSTM模型应用背景

命名体识别

标注集

BMES标注集
分词的标注集并非只有一种,举例中文分词的情况,汉子作为词语开始 Begin,结束End,中间Middle, 单字Single ,这四种情况就可以囊括所有的分词情况。于是就有了 BMES 标注集,这样的标注集在命名实体识别任务中也非常常见。

词性标注
在序列标注问题中单词序列就是 x,词性序列就是y ,当前词词性的判定需要综合考虑前后单词的词性。 而标注集最著名的就是863 标注集和北大标注集

代码实现

原生代码

import numpy as np
import torch
class BiLSTM:
    # # bilstm = BiLSTM(2, 3, 4)
    def __init__(self, input_size, hidden_size, output_size):
        self.input_size = input_size # 2
        self.hidden_size = hidden_size #3
        self.output_size = output_size #4
        # 正向 LSTM 参数
        # self.forward_lstm = LSTM(2, 3, 4)
        self.forward_lstm = LSTM(input_size, hidden_size, output_size)
        # 反向 LSTM 参数
        self.backward_lstm = LSTM(input_size, hidden_size, output_size)
    def forward(self, inputs):
        # 正向 LSTM 传播
        forward_outputs, _, _ = self.forward_lstm.forward(inputs)
        # 反向 LSTM 传播
        # np.flip(inputs, axis=0) 是用来翻转 inputs 数组的第一维(即时间步维度)
        backward_outputs, _, _ = self.backward_lstm.forward(np.flip(inputs,
        axis=0))
        # 合并正向和反向的输出
        # x1 = [f1, f2, f3]
        # x2 = [b1, b2, b3]
        # zip() 的结果是 [(f1, b1), (f2, b2), (f3, b3)]
        combined_outputs = [np.concatenate((f, b), axis=0) for f, b in zip(forward_outputs, np.flip(backward_outputs, axis=0))]
        return combined_outputs
    
class LSTM:
    def __init__(self, input_size, hidden_size, output_size):
        """
        :param input_size: 词向量大小
        :param hidden_size: 隐藏层大小
        :param output_size: 输出类别
        """
        self.input_size = input_size #2
        self.hidden_size = hidden_size #3
        self.output_size = output_size #4
        # 初始化权重和偏置
        # (3, 5)
        self.w_f = np.random.rand(hidden_size, input_size + hidden_size)
        # (3,)
        self.b_f = np.random.rand(hidden_size)
        # (3, 5)
        self.w_i = np.random.rand(hidden_size, input_size + hidden_size)
        # (3,)
        self.b_i = np.random.rand(hidden_size)
        # (3, 5)
        self.w_c = np.random.rand(hidden_size, input_size + hidden_size)
        # (3,)
        self.b_c = np.random.rand(hidden_size)
        # (3, 5)
        self.w_o = np.random.rand(hidden_size, input_size + hidden_size)
        # (3,)
        self.b_o = np.random.rand(hidden_size)
        # (4, 3)
        # 输出层
        self.w_y = np.random.rand(output_size, hidden_size)
        # (4,)
        self.b_y = np.random.rand(output_size)
    def tanh(self, x):
        return np.tanh(x)
    def sigmoid(self, x):
        return 1 / (1 + np.exp(-x))
    def forward(self, x):
        # (5, 2)
        h_t = np.zeros((self.hidden_size,)) # 初始隐藏状态 (3,1)
        c_t = np.zeros((self.hidden_size,)) # 初始细胞状态 (3,1)
        h_states = [] # 存储每个时间步的隐藏状态
        c_states = [] # 存储每个时间步的细胞状态
        for t in range(x.shape[0]): # 5
            x_t = x[t] # 当前时间步的输入
            # concatenate 将x_t和h_t拼接 垂直方向
            x_t = np.concatenate([x_t, h_t]) # (5,)
            # 遗忘门
            f_t = self.sigmoid(np.dot(self.w_f, x_t) + self.b_f) # (3, 5)*(5,)=>(3,)+(3,)=>(3,)
            # 输入门
            i_t = self.sigmoid(np.dot(self.w_i, x_t) + self.b_i) # (3, 5)*(5,)=>(3,)+(3,)=>(3,)
            # 候选细胞状态
            c_hat_t = self.tanh(np.dot(self.w_c, x_t) + self.b_c) # (3, 5)*(5,)=>(3,)+(3,)=>(3,)
            # 更新细胞状态
            c_t = f_t * c_t + i_t * c_hat_t # (3,)*(3,)+(3,)*(3,)=>(3,)
            # 输出门
            o_t = self.sigmoid(np.dot(self.w_o, x_t) + self.b_o) # (3, 5)*(5,)=>(3,)+(3,)=>(3,)
            # 更新隐藏状态
            h_t = o_t * self.tanh(c_t) # (3,)*(3,)=>(3,)
            # 保存每个时间步的隐藏状态和细胞状态
            h_states.append(h_t) #(5,3)
            c_states.append(c_t) # (5,3)

        # 输出层 对最后一个时间步的隐藏状态进行预测,分类类别
        y_t = np.dot(self.w_y, h_t) + self.b_y # (4, 3)*(3,)=>(4,)+(4,)=>(4,)   
        # 转成张量形式 dim 0 表示行的维度
        output = torch.softmax(torch.tensor(y_t), dim=0) # (4,)
        # 转换为 NumPy 数组
        return np.array(h_states), np.array(c_states), output
    
# 测试用例
input_size = 2
hidden_size = 3
output_size = 4
# bilstm = BiLSTM(2, 3, 4)
bilstm = BiLSTM(input_size, hidden_size, output_size)
# 输入序列
inputs = np.random.rand(5, 2)
# 前向传播
outputs = bilstm.forward(inputs)
# Outputs after one forward pass: (5, 6)
print("Outputs after one forward pass:", np.array(outputs).shape)

Pytorch

import torch
import torch.nn as nn
# 定义BiLSTM类
class BiLSTM(nn.Module):
    # # bilstm = BiLSTM(10, 6, 5)
    def __init__(self, input_dim, hidden_dim, output_dim):
        super(BiLSTM, self).__init__()
        # 初始化双向LSTM层,输入维度input_dim,隐藏层维度hidden_dim,双向设为True
        self.lstm = nn.LSTM(input_size=input_dim, hidden_size=hidden_dim,bidirectional=True)
        # 初始化线性层,因为是双向的,所以输入维度是2倍的hidden_dim,输出维度是output_dim
        self.linear = nn.Linear(hidden_dim * 2, output_dim)
    def forward(self, input_seq):
        # 创建一个测试输入张量,形状为(seq_len, batch_size, input_dim)
        # test_input = torch.randn(3, 1, 10)
        # 通过双向LSTM层处理输入序列
        # lstm_out时间步的隐藏状态输出
        lstm_out, _ = self.lstm(input_seq)
        # torch.Size([3, 1, 12])
        # print(lstm_out.shape)
        # lstm_out[-1] 通常指的是从LSTM模型获取的输出序列中的最后一个元素。
        # torch.Size([1, 12])
        # print(lstm_out[-1].shape)
        # 将双向LSTM层的最后一步的输出通过线性层获得最终输出
        final_output = self.linear(lstm_out[-1])
        return final_output
# 测试案例
# 输入维度
input_dim = 10 # 输入向量的维度
hidden_dim = 6 # 隐藏层的维度
output_dim = 5 # 输出向量的维度
seq_len = 3 # 输入序列的长度
# 实例化BiLSTM
# bilstm = BiLSTM(10, 6, 5)
bilstm = BiLSTM(input_dim, hidden_dim, output_dim)
# 创建一个测试输入张量,形状为(seq_len, batch_size, input_dim)
# 这里假设batch_size为1
# test_input = torch.randn(3, 1, 10)
test_input = torch.randn(seq_len, 1, input_dim)
# 获得BiLSTM的输出
test_output = bilstm(test_input)
print(test_output)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/968681.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

业务开发 | 基础知识 | Maven 快速入门

Maven 快速入门 1.Maven 全面概述 Apache Maven 是一种软件项目管理和理解工具。基于项目对象模型的概念(POM),Maven 可以从中央信息中管理项目的构建,报告和文档。 2.Maven 基本功能 因此实际上 Maven 的基本功能就是作为 Ja…

新一代SCADA: 宏集Panorama Suite 2025 正式发布,提供更灵活、符合人体工学且安全的应用体验

宏集科技宣布正式推出全新Panorama Suite 2025 SCADA软件!全新版本标志着 Panorama Suite的一个重要里程碑,代表了从 Panorama Suite 2022 开始并跨越三个版本(2022、2023、2025)的开发过程的顶峰。 此次重大发布集中在六个核心主…

PAT乙级真题 — 1080 MOOC期终成绩(java)【测试点3超时】

对于在中国大学MOOC(http://www.icourse163.org/ )学习“数据结构”课程的学生,想要获得一张合格证书,必须首先获得不少于200分的在线编程作业分,然后总评获得不少于60分(满分100)。总评成绩的计…

【Oracle篇】浅谈执行计划中的多表连接(含内连接、外连接、半连接、反连接、笛卡尔连接五种连接方式和嵌套、哈希、排序合并三种连接算法)

💫《博主介绍》:✨又是一天没白过,我是奈斯,从事IT领域✨ 💫《擅长领域》:✌️擅长阿里云AnalyticDB for MySQL(分布式数据仓库)、Oracle、MySQL、Linux、prometheus监控;并对SQLserver、NoSQL(…

TCP 端口号为何位于首部前四个字节?协议设计的智慧与启示

知乎的一个问题很有意思:“为什么在TCP首部中要把TCP的端口号放入最开始的四个字节?” 这种问题很适合我这种搞历史的人,大年初一我给出了一个简短的解释,但仔细探究这个问题,我们将会获得 TCP/IP 被定义的过程。 文…

oracle表分区--范围分区

文章目录 oracle表分区分区的原因分区的优势oracle表分区的作用oracle表分区类型一、范围分区二、 创建分区表和使用:1、按照数值范围划分2、按照时间范围3、MAXVALUE2. 向现有表添加新的分区3、 分区维护和重新组织(合并/删除) oracle表分区…

蓝桥杯(B组)-每日一题(求最大公约数最小公倍数)

题目&#xff1a; 代码展现&#xff1a; #include<iostream> using namespace std; int main() {int m,n,x,y;cin>>m>>n;//输入两个整数int b;bm%n;//取余数xm;//赋值yn;while(b)//当余数不为0的时候{xy;//辗转相除求最小公约数yb;bx%y;}cout<<y<&…

基于STM32的学习环境控制系统设计

&#x1f91e;&#x1f91e;大家好&#xff0c;这里是5132单片机毕设设计项目分享&#xff0c;今天给大家分享的是学习环境控制。 设备的详细功能见网盘中的文章《21、基于STM32的学习环境控制系统设计》&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1uWSZX2zbZwy9sY…

WPS接入DeepSeek模型

1.wps 下载安装 WPS-支持多人在线协作编辑Word、Excel和PPT文档_WPS官方网站 &#xff08;最好是安装最新的wps&#xff09; 2.offieceAi工具下载安装 软件下载 | OfficeAI助手 下载后安装下载下来的两个工具。安装路径可以自行修改 3.打开WPS,点击文件-》 选项-》信任中心 勾…

4. React 中的 CSS

用例中的干净的脚手架的创建可以参考另一篇文章&#xff1a;3.React 组件化开发React官方并没有给出在React中统一的样式风格&#xff1a; 由此&#xff0c;从普通的css&#xff0c;到css modules&#xff0c;再到css in js&#xff0c;有几十种不同的解决方案&#xff0c;上百…

Unity进阶教程AOI算法原理详解

最新课程《全栈双客户端(Unity/Cocos) TurnKey方案》更新了AOI专题&#xff0c;今天分享一下AOI算法的实现原理。 AOI的功能和作用 在MMORPG网路游戏当中&#xff0c;单服同时在线一般都会有几千人。当有个玩家执行一个操作&#xff0c;理想情况下要把玩家的操作广播同步给单…

w~大模型~合集30

我自己的原文哦~ https://blog.51cto.com/whaosoft/13284996 #VideoMamba 视频理解因大量时空冗余和复杂时空依赖&#xff0c;同时克服两个问题难度巨大&#xff0c;CNN 和 Transformer 及 Uniformer 都难以胜任&#xff0c;Mamba 是个好思路&#xff0c;让我们看看本文是…

【ThreeJS Basics 1-3】Hello ThreeJS,实现第一个场景

文章目录 环境创建一个项目安装依赖基础 Web 页面概念解释编写代码运行项目 环境 我的环境是 node version 22 创建一个项目 首先&#xff0c;新建一个空的文件夹&#xff0c;然后 npm init -y , 此时会快速生成好默认的 package.json 安装依赖 在新建的项目下用 npm 安装依…

Python----PyQt开发(PyQt基础,环境搭建,Pycharm中PyQttools工具配置,第一个PyQt程序)

一、QT与PyQT的概念和特点 1.1、QT QT是一个1991年由The Qt Company开发的跨平台C图形用户界面应用程序开发 框架&#xff0c;可构建高性能的桌面、移动及Web应用程序。也可用于开发非GUI程序&#xff0c;比如 控制台工具和服务器。Qt是面向对象的框架&#xff0c;使用特殊的代…

PostgreSQL 开发利器:Navicat 核心功能与资源攻略

近几年&#xff0c;&#x1f418; PostgreSQL 在全球数据库排名中表现优异。在 2025 年 2 月 DB-Engines 排名中 (如图)&#xff0c;PostgreSQL 稳居第四名&#xff0c;并逐渐逼近第三名的 Microsoft SQL Server&#xff0c;其评分和受欢迎度持续增长&#xff0c;成为开源数据库…

大模型数据集全面整理:444个数据集下载地址

本文针对Datasets for Large Language Models: A Comprehensive Survey 中的 444 个数据集&#xff08;涵盖8种语言类别和32个领域&#xff09;进行完整下载地址整理收集。 2024-02-28&#xff0c;由杨刘、曹家欢、刘崇宇、丁凯、金连文等作者编写&#xff0c;深入探讨了大型语…

【AI大模型】Ollama部署本地大模型DeepSeek-R1,交互界面Open-WebUI,RagFlow构建私有知识库

文章目录 DeepSeek介绍公司背景核心技术产品与服务应用场景优势与特点访问与体验各个DeepSeek-R系列模型的硬件需求和适用场景 Ollama主要特点优势应用场景安装和使用配置环境变量总结 安装open-webui下载和安装docker desktop配置镜像源安装open-webui运行和使用 RagFlow介绍主…

修改docker内容器中的某配置文件的命令

先找到配置文件config.php find / -name "config.php" 2>/dev/null 然后用vi编辑器修改配置文件 vi /var/www/config.php 最后就是vi的基本操作&#xff0c;根据具体需求使用&#xff1a; vi 有两种主要模式&#xff1a; 命令模式&#xff1a;进入 vi 后的默认…

23.[前端开发]Day23-移动端适配方案-考拉海购移动端项目

01-05 移动端适配rem方案 适配方案 – rem动态html的font-size rem的font-size尺寸 方式一&#xff1a;动态font-size-媒体查询 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Com…

数据中心网络监控

数据中心是全球协作的特定设备网络&#xff0c;用来在internet网络基础设施上传递、加速、展示、计算、存储数据信息。 对于任何利用IT基础设施的企业来说&#xff0c;数据中心都是运营的核心&#xff0c;它本质上为整个业务网络托管业务应用程序和存储空间。数据中心可以是任…