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 # 10self.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): # 8x_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_th_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 # 5self.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 # 2self.hidden_size = hidden_size #3self.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_outputsclass LSTM:def __init__(self, input_size, hidden_size, output_size):""":param input_size: 词向量大小:param hidden_size: 隐藏层大小:param output_size: 输出类别"""self.input_size = input_size #2self.hidden_size = hidden_size #3self.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]): # 5x_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,双向设为Trueself.lstm = nn.LSTM(input_size=input_dim, hidden_size=hidden_dim,bidirectional=True)# 初始化线性层,因为是双向的,所以输入维度是2倍的hidden_dim,输出维度是output_dimself.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)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微服务与网关

什么是网关 背景 单体项目中,前端只用访问指定的一个端口8080,就可以得到任何想要的数据 微服务项目中,ip是不断变化的,端口是多个的 解决方案:网关 网关:就是网络的关口,负责请求的路由、转发…

二分算法篇:二分答案法的巧妙应用

二分算法篇:二分答案法的巧妙应用 那么看到二分这两个字想必我们一定非常熟悉,那么在大学期间的c语言的教学中会专门讲解二分查找,那么我们来简单回顾一下二分查找算法,我们知道二分查找是在一个有序的序列中寻找一个数在这个序列…

C# OpenCV机器视觉:模仿Halcon各向异性扩散滤波

在一个充满创意与挑战的图像处理工作室里,阿强是一位热情的图像魔法师。他总是在追求更加出色的图像效果,然而,传统的图像处理方法有时候并不能满足他的需求。 有一天,阿强听说了 Halcon 中的各向异性扩散滤波功能,它…

实现:多活的基础中间件

APIRouter : 路由分发服务 API Router 是一个 HTTP 反向代理和负载均衡器,部署在公有云中作为 HTTP API 流量的入口,它能识别 出流量的归属 shard ,并根据 shard 将流量转发到对应的 ezone 。 API Router 支持多种路由键&am…

DeepSeek本地化部署

DeepSeek本地化部署 本教程为一键式部署,适合于mac、ubuntu、windows。【开源地址】 环境要求 nodejs > 18Python > 3.10.12 步骤一:安装ollama客户端 官网直接安装,ollama官网。安装完成后使用命令:ollama -h&#xf…

大数据与大模型:数字时代的共生力量

引言:大数据与大模型的崭新时代 在数字化浪潮汹涌澎湃的当下,大数据与大模型无疑是最为耀眼的两颗明星 ,深刻地改变着我们的生活、工作和思维方式。大数据,作为信息时代的宝藏,蕴含着无尽的价值。从电商平台的海量交易…

[2025年最新]2024.3版本idea无法安装插件问题解决

背景 随着大模型的持续发展,特别年前年后deepseek的优异表现,编程过程中,需要解决ai来辅助编程,因此需要安装一些大模型插件 问题描述 在线安装插件的时候会遇到以下问题: 1.数据一直在加载,加载的很满 2.点…

自动驾驶---如何打造一款属于自己的自动驾驶系统

在笔者的专栏《自动驾驶Planning决策规划》中,主要讲解了行车的相关知识,从Routing,到Behavior Planning,再到Motion Planning,以及最后的Control,笔者都做了相关介绍,其中主要包括算法在量产上…

三角拓扑聚合优化器TTAO-Transformer-BiLSTM多变量回归预测(Maltab)

三角拓扑聚合优化器TTAO-Transformer-BiLSTM多变量回归预测(Maltab) 完整代码私信回复三角拓扑聚合优化器TTAO-Transformer-BiLSTM多变量回归预测(Maltab) 一、引言 1、研究背景和意义 在现代数据科学领域,时间序列…

Jenkins+gitee 搭建自动化部署

Jenkinsgitee 搭建自动化部署 环境说明: 软件版本备注CentOS8.5.2111JDK1.8.0_211Maven3.8.8git2.27.0Jenkins2.319最好选稳定版本,不然安装插件有点麻烦 一、安装Jenkins程序 1、到官网下载相应的版本war或者直接使用yum安装 Jenkins官网下载 直接…

AI 编程开发插件codeium Windsurf(vscode、editor) 安装

1、vscode中安装: 2、vscode中使用 3、输入注册的账号密码,就可以使用。 4、或者直接下载editor 5、安装editor 下一步,下一步,直到安装成功,中间可以改下安装位置,如果C盘空间不够。 同样提示注册或者登录…

【Mac排错】ls: command not found 终端命令失效的解决办法

【TroubleShooting on Mac】ls: command not found 终端命令失效的解决办法 A Solution to Solve “Command not found” of Terminal on Mac 一直在使用心爱的MacBook Pro的Terminal,并且为她定制了不同的Profile。 这样,看起来她可以在不同季节&…

河北某石油管廊自动化监测

1. 项目简介 近年来,国家密集出台油气管道建设相关政策和规划引导中国油气管道加快建设,2017年,在《中长期油气管网规划》中对2025年和2030年油气管道发展目标均作出了相应的规划目标。另一方面,随着油气管道行业的发展&#xff…

问题:通过策略模式+工厂模式+模板方法模式实现ifelse优化

项目场景: 提示:这里简述项目相关背景: 示例:商城系统有会员系统,不同会员有不同优惠程度,普通会员不优惠;黄金会员打8折;白金会员优惠50元,再打7折; 问题描…

Android ndk兼容 64bit so报错

1、报错logcat如下 2025-01-13 11:34:41.963 4687-4687 DEBUG pid-4687 A #01 pc 00000000000063b8 /system/lib64/liblog.so (__android_log_default_aborter16) (BuildId: 467c2038cdfa767245f9280e657fdb85) 2025…

centos安装Nexus Repository OSS(Maven私服)

1. 下载链接:https://help.sonatype.com/en/download.html 2. 注意页面下载页面中的要求:JDK17(启动时提示最低JDK1.8最高JDK17,但是使用JDK1.8无法正常启动) 3. mkdir /opt/nexus 将压缩包上传到该目录并解压。 tar …

b站——《【强化学习】一小时完全入门》学习笔记及代码(1-3 多臂老虎机)

问题陈述 我们有两个多臂老虎机(Multi-Armed Bandit),分别称为左边的老虎机和右边的老虎机。每个老虎机的奖励服从不同的正态分布: 左边的老虎机:奖励服从均值为 500,标准差为 50 的正态分布,即…

Linux:安装 node 及 nvm node 版本管理工具(ubuntu )

目录 方法一:手动下载安装文件安装方法二:curl安装 方法一:手动下载安装文件安装 git clone 远程镜像 git clone https://gitee.com/mirrors/nvm安装 nvm bash install.sh刷新配置,使配置在终端生效 // 方法 1 source /root/.…

基于STM32的ADS1230驱动例程

自己在练手项目中用到了ADS1230,根据芯片手册自写的驱动代码,已测可用,希望对将要用到ADS1230芯片的人有所帮助。 芯片:STM32系列任意芯片、ADS1230 环境:使用STM32CubeMX配置引脚、KEIL 部分电路: 代码…

游戏引擎学习第98天

仓库:https://gitee.com/mrxiao_com/2d_game_2 开始进行一点回顾 今天的目标是继续实现正常贴图的操作,尽管目前我们还没有足够的光照信息来使其完全有用。昨日完成了正常贴图相关的基础工作,接下来将集中精力实现正常贴图的基本操作,并准备…