LSTM模型变种

news2024/11/24 19:13:57

LSTM模型变种

一、GRU

1.什么是GRU

GRU(Gated Recurrent Unit)是一种循环神经网络(RNN)的变体,它被设计用来解决传统RNN在处理长序列时可能遇到的梯度消失或梯度爆炸问题。GRU通过引入门控机制来控制信息的流动,使得模型能够更好地捕捉长时间依赖关系。

GRU的主要特点在于它的结构比LSTM(Long Short-Term Memory)更简单,因为它只有一个隐藏状态,而没有像LSTM那样的细胞状态。尽管如此,GRU仍然能够有效地学习长期依赖,并且通常计算效率更高

2.GRU的基本结构

一个GRU单元包含两个主要的门:重置门(Reset Gate)和更新门(Update Gate)。这些门的作用是决定如何将新输入的信息与先前的记忆相结合。

  • 重置门 r t r_t rt)决定了前一时刻的状态 h t − 1 h_{t−1} ht1 有多少信息会被用于当前时刻的候选激活 $\tilde{h}_t $的计算。
  • 更新门 z t z_t zt)决定了前一时刻的状态 h t − 1 h_{t−1} ht1 和当前时刻的候选激活 h ~ t \tilde{h}_t h~t 如何结合以产生当前时刻的状态 h t h_t ht

3.模型结构

模型图:

在这里插入图片描述

内部结构:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.代码实现

原理实现

import numpy as np


class GRU:
    def __init__(self, input_size, hidden_size):
        self.input_size = input_size
        self.hidden_size = hidden_size

        # 初始化参数和偏置
        # 更新门
        self.W_z = np.random.randn(hidden_size, hidden_size+input_size)
        self.b_z = np.zeros(hidden_size)

        # 重置门
        self.W_r = np.random.randn(hidden_size, hidden_size + input_size)
        self.b_r = np.zeros(hidden_size)

        # 候选隐藏状态
        self.W_h = np.random.randn(hidden_size, hidden_size + input_size)
        self.b_h = np.zeros(hidden_size)

    def tanh(self, x):
        return np.tanh(x)

    def sigmoid(self, x):
        return 1 / (1 + np.exp(-x))

    def forward(self, x):
        # 初始化隐藏状态
        h_prev = np.zeros((self.hidden_size, ))
        concat_input = np.concatenate([x, h_prev], axis=0)

        z_t = self.sigmoid(np.dot(self.W_z, concat_input) + self.b_z)
        r_t = self.sigmoid(np.dot(self.W_r, concat_input) + self.b_r)

        concat_reset_input = np.concatenate([x, r_t*h_prev], axis=0)
        h_hat_t = self.tanh(np.dot(self.W_h, concat_reset_input) + self.b_h)

        h_t = (1 - z_t) * h_prev + z_t * h_hat_t

        return h_t


# 测试数据
input_size = 3
hidden_size = 2
seq_len = 4

x = np.random.randn(seq_len, input_size)
gru = GRU(input_size, hidden_size)

all_h = []
for t in range(seq_len):
    h_t = gru.forward(x[t, :])
    all_h.append(h_t)

print(np.array(all_h).shape)

nn.GRUCell

import torch.nn as nn
import torch


class GRUCell(nn.Module):
    def __init__(self, input_size, hidden_size):
        super(GRUCell, self).__init__()
        self.input_size = input_size
        self.hidden_size = hidden_size

        self.gru_cell = nn.GRUCell(input_size, hidden_size)

    def forward(self, x):
        h_t = self.gru_cell(x)
        return h_t


# 测试数据
input_size = 3
hidden_size = 2
seq_len = 4

gru_model = GRUCell(input_size, hidden_size)

x = torch.randn(seq_len, input_size)

all_h = []
for t in range(seq_len):
    h_t = gru_model(x[t])
    all_h.append(h_t)

print(all_h)

nn.GRU

import torch.nn as nn
import torch


class GRU(nn.Module):
    def __init__(self, input_size, hidden_size):
        super(GRU, self).__init__()
        self.input_size = input_size
        self.hidden_size = hidden_size

        self.gru = nn.GRU(input_size, hidden_size)

    def forward(self, x):
        out = self.gru(x)
        return out


# 测试数据
input_size = 3
hidden_size = 2
seq_len = 4
batch_size = 5

x = torch.randn(seq_len, batch_size, input_size)

gru_model = GRU(input_size, hidden_size)

out = gru_model(x)

print(out)

二、BiLSTM

1.什么是BiLSTM

BiLSTM(Bidirectional Long Short-Term Memory)是LSTM的一种扩展,它通过同时考虑序列的前向和后向信息来增强模型对序列数据的理解。传统的LSTM只能从过去到未来单方向处理序列,而BiLSTM则能够同时捕捉到序列中每个时间点上的前后文信息,从而提高模型在许多任务中的表现。

2.BiLSTM的工作原理

在BiLSTM中,对于每个时间步t,模型包含两个独立的LSTM层:

  • 前向LSTM:按照正常的时间顺序处理输入序列,即从第一个时间步到最后一个时间步。
  • 后向LSTM:以相反的时间顺序处理输入序列,即从最后一个时间步到第一个时间步。

这两个LSTM层分别输出一个隐藏状态,然后将这两个隐藏状态拼接起来形成最终的隐藏状态。这个拼接后的隐藏状态可以用来做进一步的预测或计算。

在这里插入图片描述

优点:

  • 上下文感知:BiLSTM可以利用整个序列的信息,因此对于需要理解上下文的任务特别有效。
  • 更好的性能:由于它可以捕捉更丰富的序列信息,通常在诸如命名实体识别、情感分析等自然语言处理任务上表现出色。

3.标注集

BMES标注:汉字作为词语开始Begin,结束End,中间Middle,单字Single,这四种情况就可以囊括所有的分词情况。比如“参观了北京天安门”这句话的标注结果就是BESBEBME

词性标注

4.代码实现

原理实现

import numpy as np
import torch


class BILSTM:
    def __init__(self, input_size, hidden_size, output_size):
        # 参数:词向量大小,隐藏层大小, 输出类别
        self.input_size = input_size
        self.hidden_size = hidden_size
        self.output_size = output_size

        # 正向
        self.lstm_forward = LSTM(input_size, hidden_size, output_size)

        # 反向
        self.lstm_backward = LSTM(input_size, hidden_size, output_size)

    def forward(self, x):
        # 正向LSTM
        output, _, _ = self.lstm_forward.forward(x)
        # 反向LSTM,np.flip是将数组进行翻转
        output_backward, _, _ = self.lstm_backward.forward(np.flip(x))
        # 合并两层的隐藏状态
        combine_output = [np.concatenate((x, y), axis=0) for x, y in zip(output, output_backward)]

        return combine_output


class LSTM:
    def __init__(self, input_size, hidden_size, output_size):
        # 参数:词向量大小,隐藏层大小, 输出类别
        self.input_size = input_size
        self.hidden_size = hidden_size
        self.output_size = output_size

        # 初始化权重,偏置,把结构的W,U拼接在一起
        self.W_f = np.random.rand(hidden_size, input_size+hidden_size)
        self.b_f = np.random.rand(hidden_size)

        self.W_i = np.random.rand(hidden_size, input_size + hidden_size)
        self.b_i = np.random.rand(hidden_size)

        self.W_c = np.random.rand(hidden_size, input_size + hidden_size)
        self.b_c = np.random.rand(hidden_size)

        self.W_o = np.random.rand(hidden_size, input_size + hidden_size)
        self.b_o = np.random.rand(hidden_size)

        # 输出层
        self.W_y = np.random.rand(output_size, hidden_size)
        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):
        # 初始化隐藏状态
        h_t = np.zeros((self.hidden_size,))
        # 初始化细胞状态
        c_t = np.zeros((self.hidden_size,))

        h_states = []  # 存储每一个时间步的隐藏状态
        c_states = []  # 存储每一个时间步的细胞状态

        for t in range(x.shape[0]):
            x_t = x[t]  # 获取当前时间步的输入(一个词向量)
            # 将x_t和h_t进行垂直方向拼接
            x_t = np.concatenate([x_t, h_t])

            # 遗忘门 "dot"迷茫中,这里是点积的效果,(5,7)点积(7,)得到的是(5,)
            f_t = self.sigmoid(np.dot(self.W_f, x_t) + self.b_f)

            # 输出门
            i_t = self.sigmoid(np.dot(self.W_i, x_t) + self.b_i)

            # 候选细胞状态
            c_hat_t = self.tanh(np.dot(self.W_c, x_t) + self.b_c)
            # 更新细胞状态, "*"对应位置直接相乘
            c_t = f_t * c_t + i_t * c_hat_t

            # 输出门
            o_t = self.sigmoid(np.dot(self.W_o, x_t) + self.b_o)
            # 更新隐藏状态
            h_t = o_t * self.tanh(c_t)

            # 保存时间步的隐藏状态和细胞状态
            h_states.append(h_t)
            c_states.append(c_t)

        # 输出层,分类类别
        y_t = np.dot(self.W_y, h_t) + self.b_y
        output = torch.softmax(torch.tensor(y_t), dim=0)

        return np.array(h_states), np.array(c_states), output


# 测试数据
input_size = 3
hidden_size = 2
seq_len = 4

x = np.random.randn(seq_len, input_size)
bilstm = BILSTM(input_size, hidden_size, 5)
out = bilstm.forward(x)

print(out)
print(np.array(out).shape)

API的使用

import torch
import torch.nn as nn
import numpy as np


class BiLstm(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(BiLstm, self).__init__()
        # 定义双向LSTM
        self.lstm = nn.LSTM(input_size, hidden_size, bidirectional=True)
        # 因为双向的,所以第一个参数是隐藏层的的二倍
        self.linear = nn.Linear(hidden_size*2, output_size)

    def forward(self, x):
        out, _ = self.lstm(x)
        out = self.linear(out)
        return out


# 测试数据
input_size = 3
hidden_size = 8
seq_len = 4
output_size = 5
batch_size = 6

x = torch.randn(seq_len, batch_size, input_size)

bilstm = BiLstm(input_size, hidden_size, output_size)

output = bilstm(x)

print(output.shape)

def forward(self, x):
out, _ = self.lstm(x)
out = self.linear(out)
return out

测试数据

input_size = 3
hidden_size = 8
seq_len = 4
output_size = 5
batch_size = 6

x = torch.randn(seq_len, batch_size, input_size)

bilstm = BiLstm(input_size, hidden_size, output_size)

output = bilstm(x)

print(output.shape)


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

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

相关文章

PCL 计算点云的高斯曲率

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 法向量计算 2.1.2 主曲率和高斯曲率计算 2.1.3 可视化函数 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接: PCL点云算法与项目实战案例汇总&a…

1000万元试水,看完AI约稿平台上赚钱的故事,真的心动了……

在生成对抗网络(GAN)、扩散模型(Diffusion Models)、视觉语言预训练模型(CLIP)等技术的发展下,AI 绘画可做的内容越来越多。 建筑设计、服装设计、室内设计、插画设计等垂类模型的出现也让更多…

从理论到实践:AI智能分析网关V4烟火检测算法的应用场景探索

在信息化和智能化的今天,AI智能分析网关V4作为一款集成了先进技术的硬件设备,在烟火检测领域展现出了强大的应用价值。本文将详细阐述AI智能分析网关V4烟火检测算法的原理及其在各种场景中的应用。 一、AI智能分析网关V4烟火检测算法原理 深度学习基础…

激光测距用高精度时间测量(TDC)电路MS1003,比 MS1002 具有更高的精度和更小的封装,适合于高精度小封装的应用领域

MS1003 是一款高精度时间测量 (TDC) 电路,对比 MS1002 具 有更高的精度和更小的封装,适合于高精度小封装的应用领域。 MS1003 具有双通道、多脉冲的采样能力、高速 SPI 通讯、 多种测量模式,适合于激光雷达和激光测距。 主要特点 …

word 无法进入修订模式

word 无法进入修订模式,原来是被保护了,取消保护却没有密码 方法: 1、新建-空白文档 2、插入-对象-文件中的文字...,然后选择受保护的文档。这样即可把受保护的文档克隆一份到新文档。新文档当然就可以进入修订模式了。

Mac上最好用的快捷回复工具-快捷短语

网络上打字回复已经成为我们日常生活中不可缺少的一件事了,当有的时候需要一遍又一遍的回复重复的内容的时候,难免会感到疲惫,每次复制粘贴重复的内容,时间一长真的会很让人抓狂。 这里给大家推荐一款很好用的快捷回复工具&#…

全局变量的重复定义会怎样?

有些人的第一反应是编译不过吧? //fun.c void func() {printf("测试1"); }//main.c void func() {printf("测试2"); } void main() {func(); } 编译: 这里可以看到保存错了,因为func重复定义了。 但是重复定义就会全部…

DNSlog注入原理

DNSlog注入 dnslog注入也相当于盲注的一种,但是比盲注效率高一点。 在一定的情况下,如果我们想对一个网站使用布尔或时间盲注,手动注入会对WAF的绕过会非常有帮助,但是效率不高,因此我们往往会使用SQLmap等工具注入&a…

十款主流图纸加密软件推荐|有效防止图纸泄密

在设计和工程行业,保护设计图纸的安全性至关重要。随着信息技术的发展,数据泄密事件频发,选择合适的图纸加密软件成为了企业和个人保护知识产权的重要手段。本文将推荐十款主流的图纸加密软件。 1. Ping32 Ping32是一款专注于图纸和设计文件…

「完美收官」科东软件2024上海国际工博会精彩回顾:鸿道操作系统赋能新型工业化

第24届中国国际工业博览会已经落下帷幕。历经24届,工博会已成为全球工业发展的“风向标”。今年的中国工博会以“工业聚能 新质领航”为主题,工业自动化、数控机床与金属加工、新能源与智能网联汽车、机器人等领域重磅展品悉数亮相,展示了中国…

STM32-TIM输入捕获

一、概述 IC(Input Capture)输入捕获 输入捕获模式下,当通道输入引脚出现指定电平跳变(上升沿或下降沿)时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续…

Label Studio 半自动化标注

引言 Label Studio ML 后端是一个 SDK,用于包装您的机器学习代码并将其转换为 Web 服务器。Web 服务器可以连接到正在运行的 Label Studio 实例,以自动执行标记任务。我们提供了一个示例模型库,您可以在自己的工作流程中使用这些模型,也可以根据需要进行扩展和自定义。 1…

厨房用品分割系统源码&数据集分享

厨房用品分割系统源码&数据集分享 [yolov8-seg-C2f-DCNV3&yolov8-seg-AFPN-P345等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI Global Al ln…

C++欧拉函数

题目一 求欧拉函数 解题思路 分解质因数&#xff1b;代入公式计算即可&#xff08;注意要防止计算出小数是结果不准&#xff09;&#xff1b; 代码实现 #include<iostream> #include<algorithm> #include<cmath>using namespace std;void Euler(int n) {i…

注册安全分析报告:惠农网

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

丝杆支撑座预压标准解析

丝杆支撑座预压的主要目的是提高轴的旋转精度、刚性和运行性能&#xff0c;同时防止轴在运转过程中产生震动和异响&#xff0c;从而提高系统的整体精度和稳定性。那么&#xff0c;丝杆支撑座的预压标准是什么呢&#xff1f; 丝杆支撑座的预压可以分为标准型轻预压和标准型重预压…

atcoder-374(a-e)

atcoder-374 文章目录 atcoder-374ABC简洁的写法正解 D正解 E A #include<bits/stdc.h>using namespace std;signed main() {string s;cin>>s;string strs.substr(s.size()-3);if(str "san") puts("Yes");else puts("No");return 0…

SpringBoot Jar 包加密防止反编译

今天看到了一个说明jar包加密的实现方式&#xff0c;特意试了下效果&#xff0c;并下载了插件源码及实现源码查看了下子&#xff0c;感兴趣的可以在最后得到gitee地址。 SpringBoot 程序 Jar 包加密的方式&#xff0c;通过代码加密可以实现无法反编译。应用场景就是当需要把公司…

谈谈电路板中高速电路设计和低速电路设计的区别

谈谈电路板中高速电路设计和低速电路设计的区别 1.高速电路和低速电路的应用场景&#xff1a;1.1.低速电路应用场景1.2.高速电路的应用场景1.3.高速电路设计比低速电路设计强吗 2.高速电路和低速电路的如何区分2.1.Fknee有效频率是什么2.2.区分高速和低速的步骤&#xff1a; 3.…

OpenFeign 工作原理源码记录

文章目录 EnableFeignClientsregisterDefaultConfigurationregisterFeignClients类路径扫描注册 FeignClientregisterFeignClient 总结 FeignClient 接口实例化FeignContextcreateContextthis.configurationsClient FeignBuilderloadBalance 负载均衡实现Targeter 创建接口代理…