RNN模型学习

news2024/9/27 5:45:06

RNN模型

循环神经网络(Recurrent Neural Network, RNN)是一种用于处理序列数据的神经网络。**RNN具有内部状态(或称为记忆),这允许它在处理序列中的每个元素时考虑之前的信息。**这种特性使得RNN非常适合于自然语言处理、语音识别、时间序列预测等任务,因为这些任务都涉及到对序列信息的理解。

时间序列

时间序列是指按照时间顺序排列的一系列数据点,这些数据点通常是在连续相等的时间间隔内收集的。时间序列分析是统计学的一个分支,专注于通过观察过去的数据来理解和预测未来的发展趋势。它被广泛应用于经济学、金融学、气象学、医学等多个领域。

传统RNN存在的问题:难以处理长期依赖关系、梯度消失或梯度爆炸等。

RNN的变种:

  • 长短期记忆网络(LSTM)
  • 门控循环单元(GRU)

RNN模型框架

在这里插入图片描述

在RNN的经典架构中,网络通过一个特殊的循环结构将信息从一个处理步骤传递到下一个。这个循环结构通常被称为“隐藏层状态”或简单地称为“隐藏状态”。隐藏状态是RNN的记忆部分,它能够捕获并存储关于已处理序列元素的信息。

在这里插入图片描述

RNN的基本工作原理是通过一个循环结构来维持一种“记忆”,这个结构可以将信息从序列的一个步骤传递到下一个步骤,相当于递归的操作。具体来说,在每一个时间步t,RNN接收当前的输入xt和前一时间步的状态ht-1,并基于这两个信息计算出新的输出yt和更新后的状态ht。这一过程可以用以下公式简单表示:
h t = f ( W h x x t + W h h h t − 1 + b h ) y t = g ( W h y h t + b y ) h_t=f(W_{hx}x_t+W_{hh}h_{t−1}+b_h) \\y_t=g(W_{hy}h_t+b_y) ht=f(Whxxt+Whhht1+bh)yt=g(Whyht+by)
f 和 g 分别是激活函数,比如tanh或ReLU;Whx, Whh, Why 是权重矩阵;bh, by,是偏置向量。

RNN的内部结构

在这里插入图片描述

采用tanh激活函数

RNN模型输入输出关系对应模式

在这里插入图片描述

在循环神经网络(RNN)中,根据输入和输出序列的长度关系,可以将模型分为三种主要架构:一对多、多对一以及多对多。这些不同的架构适用于不同类型的任务。

一对多 (One-to-Many)

这种结构通常用于生成任务,比如基于一个初始状态或条件生成一系列输出。例如:

  • 音乐生成:给定一个起始音符,生成一段旋律。
  • 文本生成:给定一个单词或短语作为种子,生成一段连续的文字。

在这个架构中,只有一个输入提供给RNN,然后它会生成多个时间步上的输出。这可以通过让RNN进入自反馈模式来实现,即每个时间步的输出被用作下一个时间步的输入。

多对一 (Many-to-One)

这种结构适用于需要从整个序列中提取信息并做出单一决策的情况。常见的应用场景包括:

  • 情感分析:基于整篇文章的内容判断其情绪倾向。
  • 图像描述:给定一张图片(可以视为像素序列),生成一句话来描述图片内容。
  • 序列分类:识别一段信号是否属于某个类别。

在这种情况下,RNN接收一系列输入,并在最后一个时间步产生单个输出。这个输出通常是整个序列特征的一个总结或摘要。

多对多 (Many-to-Many)

这是最灵活的一种架构,允许处理任意长度的输入序列并生成相应长度的输出序列。多对多RNN有几种变体:

  • 同步序列到序列

    :输入和输出序列具有相同的长度。这种情况常见于:

    • 语音识别:将音频信号转换为文字。
    • 机器翻译:将一种语言的句子翻译成另一种语言的句子。
  • 非同步序列到序列

    :输入和输出序列长度不同。例如:

    • 视频标注:给定一个视频流,生成较短的标签或描述。
    • 摘要生成:从较长的文章中生成较短的摘要。

在同步的多对多情况下,每个时间步都有对应的输入和输出。而在非同步的情况下,可能需要使用编码器-解码器架构,其中编码器将输入序列编码为固定大小的向量,然后解码器基于这个向量生成输出序列。

RNN代码实现

RNN原理

import numpy as np


# 假设输入数据有3个时间步,每个时间步两个特征
x = np.random.rand(3, 2)
# print(x)

# 定义RNN的参数
input_size = 2
hidden_size = 3
output_size = 1

# 初始化权重和偏置
w_xh = np.random.rand(input_size, hidden_size)  # 输入到隐藏
w_hh = np.random.rand(hidden_size, hidden_size)  # 隐藏到隐藏
w_hy = np.random.rand(hidden_size, output_size)  # 隐藏到输出层

bh = np.zeros((hidden_size,))  # 隐藏层的偏置,以元组的形式传入
by = np.zeros((output_size,))  # 输出层的偏置


# 激活函数
def tanh(x):
    return np.tanh(x)


# 初始化隐藏状态
H_prev = np.zeros((hidden_size,))

# 前向传播
# 时间步1
x1 = x[0]
# 时间步1的隐藏状态, 没有上个时刻的隐藏状态,所以直接使用初始值
# H1 = tanh(np.dot(x1, w_xh) + np.dot(H0, H_prev) + bh)
# 因为没有上个时刻,所以没有H0,np.dot(H0, H_prev)就等于全0, bh初始也为0
H1 = tanh(np.dot(x1, w_xh) + H_prev)
o1 = np.dot(H1, w_hy) + by  # 计算输出

# 时间步2
x2 = x[1]
H2 = tanh(np.dot(x2, w_xh) + np.dot(H1, w_hh) + bh)
o2 = np.dot(H2, w_hy) + by

# 时间步3
x3 = x[2]
H3 = tanh(np.dot(x3, w_xh) + np.dot(H2, w_hh) + bh)
o3 = np.dot(H3, w_hy) + by

print("H1:", H1)
print("o1:", o1)
print("H2:", H2)
print("o2:", o2)
print("H3:", H3)
print("o3:", o3)

RNNCell的API调用

import torch
import torch.nn as nn


# 创建数据
x = torch.randn(10, 6, 5)  # 批次,词数,每个词的向量维度


# 定义一个rnn类
class RNN(nn.Module):
    def __init__(self, input_size, hidden_size, batch_first=True):
        super(RNN, self).__init__()
        # 参数为输入维度和隐藏层维度
        self.rnn_cell = nn.RNNCell(input_size, hidden_size)
        self.hidden_size = hidden_size
        # 判断输入的张量的第一个维度是否为批次大小
        self.batch_first = batch_first

    def _initialize_hidden(self, batch_size):
        # 初始化隐藏状态,形状为(batch_size, hidden_size)
        return torch.zeros(batch_size, self.hidden_size)

    def forward(self, x, init_hidden=None):
        # 如果batch_first为True,那么x的形状为(batch_size, seq_len(词数), input_size)
        if self.batch_first:
            batch_size, seq_len, input_size = x.size()  # 获取输入数据的尺寸

            # rnn需要的数据维数是(batch_size, seq_len, input_size)
            x = x.permute(1, 0, 2)
        else:
            seq_len, batch_size, input_size = x.size()
        hiddens = []  # 用于储存每一个时间步的隐藏状态信息

        # 提供初始化为全0的隐藏状态
        if init_hidden is None:
            # 初始化隐藏状态
            init_hidden = self._initialize_hidden(batch_size)
            # 将初始隐藏状态移动到输入张量相同的设备上
            init_hidden = init_hidden.to(x.device)

        hidden_t = init_hidden  # 统一变量名

        # 循环遍历每一个时间步
        for t in range(seq_len):
            # 在第t个时间步更新隐藏状态
            # x[t]取出来的值是(batch_size, 词向量)
            # 比如取出来的是三句话的第一个词的向量,每一个词向量是(4,)的话,取出来就是(3,4)的形状
            hidden_t = self.rnn_cell(x[t], hidden_t)
            # 保存该时间步的隐藏状态到列表当中
            hiddens.append(hidden_t)

        # 将所有时间步的隐藏状态堆叠成为一个新的张量,增加一个维度
        hiddens = torch.stack(hiddens)

        # 如果batch_first为True,需要重新排维度,将维度转回去(seq_len, batch_size, input_size)转回(batch_size, seq_len, hidden_size)
        if self.batch_first:
            hiddens = hiddens.permute(1, 0, 2)

        print(hiddens)
        return hiddens  # 返回隐藏状态列表


model = RNN(5, 8, batch_first=True)
output = model(x)
print(output.shape)

RNN的API调用

import torch
import torch.nn as nn


# 设置超参数
batch_size, seq_len, input_size = 10, 6, 5  # input_size词向量大小
hidden_size = 3  # 隐藏层大小

# 数据输入
x = torch.randn(batch_size, seq_len, input_size)
# print(x.shape)

# 初始化隐藏状态,全零向量
h_prev = torch.zeros(batch_size, hidden_size)
# print(h_prev.shape)
# print(h_prev)

# 创建一个RNN实例
# 参数:input_size输入向量维度,hidden_size:隐藏层维度,batch_first是否使用batch_size作为第一维度
rnn = nn.RNN(input_size, hidden_size, batch_first=True)

# 我的版本的RNN不用传入初始化的隐藏状态
# 返回值:output,每个时间步输出的隐藏状态, state_final,最后一个时间步的隐藏状态
# output, state_final = rnn(x, h_prev.unsqueeze(0))
output, state_final = rnn(x)

print(output)
print(output.shape)
print(state_final)
print(state_final.shape)

irst=True)

我的版本的RNN不用传入初始化的隐藏状态

返回值:output,每个时间步输出的隐藏状态, state_final,最后一个时间步的隐藏状态

output, state_final = rnn(x, h_prev.unsqueeze(0))

output, state_final = rnn(x)

print(output)
print(output.shape)
print(state_final)
print(state_final.shape)


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

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

相关文章

【CSS】鼠标 、轮廓线 、 滤镜 、 堆叠层级

cursor 鼠标outline 轮廓线filter 滤镜z-index 堆叠层级 cursor 鼠标 值说明值说明crosshair十字准线s-resize向下改变大小pointer \ hand手形e-resize向右改变大小wait表或沙漏w-resize向左改变大小help问号或气球ne-resize向上右改变大小no-drop无法释放nw-resize向上左改变…

ISA Server配置https踩坑全过程

首先普通的http配置请参考 【ISA Server 2006发布Web网站】 https://www.bilibili.com/video/BV1qc411v75w/?share_sourcecopy_web&vd_sourcef35b2f2d0d34140bcba81b8b6f8c1b69 本文只一笔带过,讲一下https部分。 正解 由于我维护的是windows server 2003的…

付费进群V5版本首发源码

付费进群V5版本首发 最新分站大屏 更新三个模板 仿官方模板等等 最新防注入技术 源码下载:https://download.csdn.net/download/m0_66047725/89797314 更多资源下载:关注我。

Postgresql怎么查询数据库中所有的表,odoo17数据库最依赖表整理

今天遇到了一个需求,需要梳理odoo中数据库表的分类,所以想要知道怎么查询当前数据库中所有的表,特此记录. 一个简单的SQL语句: select * from pg_tables;得到的结果如下: 显然这个有点杂乱,我们换一个SQL语句: select tablename from pg_tables where schemanamepublic不过…

LiveQing视频点播流媒体RTMP推流服务功能-支持电子放大拉框放大直播视频拉框放大录像视频流拉框放大电子放大

LiveQing视频点播流媒体RTMP推流服务功能-支持电子放大拉框放大直播视频拉框放大录像视频流拉框放大电子放大 1、鉴权直播2、视频点播3、RTMP推流视频直播和点播流媒体服务 1、鉴权直播 鉴权直播-》播放 ,左键单击可以拉取矩形框,放大选中的范围&#x…

(四)悟说几个特殊矩阵及矩阵函数

上一期介绍了矩阵的出现源于解线性方程组。但是,矩阵出现之后,就犹如打开了潘多拉的盒子,会产生许多魔法。 1 旋转矩阵 我们知道用矩阵左乘某个向量,相当于对该向量做线性变换。那么是否有一种矩阵,能让向量旋转&…

前端项目代理到本地调试

我们在项目开发中,有时mock数据不能满足我们的需求,可以考虑把线上地址运行在本地代码上进行开发调试,也就是所谓的代理 这里推荐使用的工具是 whistle SwitchyOmega 1. 首先在chrome浏览器中安装插件SwitchyOmega 下载地址 CrxDL - 下载…

Git - 初识版本库

版本库也叫仓库,英文名 repository。 ‍ 创建版本库 之前我们说了版本库的概念: 存储版本的地方(存放各个版本之间差异的地方),通常称为版本库。通常版本库是以文件(夹)的形式存放在磁盘上&a…

【数据结构初阶】排序算法(上)插入排序与选择排序

文章目录 1.排序概念及运用1. 1 概念1. 2 运用1.3 常见排序算法 2. 插入排序2. 1 直接插入排序2. 2 希尔排序2. 2. 1 希尔排序的时间复杂度 3. 选择排序3. 1 直接选择排序3. 2 堆排序3. 3 Top-K问题 1.排序概念及运用 1. 1 概念 排序:所谓排序,就是使一…

小米2025届软件开发工程师(C/C++/Java)(编程题AK)

选择题好像也是25来个 编程题 T1 题目描述 小明喜欢解决各种数学难题。一天,他遇到了一道有趣的题目:他需要帮助他的朋友们完成一个排序任务。小明得到两个长度为 n 的数组a[]和b[]。他可以在两个数组对应位置进行交换,即选定一个位置 i &#xff0c…

PCL 求八叉树的体素中心

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 八叉树构建 2.1.2 获取体素中心 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接: PCL点云算法与项目实战案例汇总(长期更新&#xf…

注意力机制篇 | YOLOv8改进之在C2f模块引入EffectiveSE注意力模块 | 基于SE注意力

前言:Hello大家好,我是小哥谈。EffectiveSE(Effective Squeeze-Excitation) 是一种改进的通道注意力模块,其目的是在保持模型性能的同时减少计算复杂性和信息丢失。它基于原始的 Squeeze-Excitation (SE) 模块,但通过一些关键的改进来提高效率。🌈 目录 🚀1.基…

前端——flex布局

flex布局——弹性布局 传统布局: 浮动 定位 行内块等 1. flex布局 方法简单 不需要计算 能自动分配父级里面的子元素排版 对齐方式等等 >flex布局 可以适应不同屏幕布局 2. flex布局使用 - 给父级盒子 display: flex 开启弹性盒模型 - 子元素就会默…

栈的基本概念和及具体实现

今天给大家介绍一下栈的基本概念及实现!话不多说,立即开始! 1.栈的概念: 一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈 顶,另一端称为栈底。栈中的…

计算机网络--TCP、UDP抓包分析实验

计算机网络实验 目录 实验目的 实验环境 实验原理 1、UDP协议 2、TCP协议 实验具体步骤 实验目的 1、掌握使用wireshark工具对UDP协议进行抓包分析的方法,掌握UDP协议的报文格式,掌握UDP协议校验和的计算方法,理解UDP协议的优缺点&am…

vant van-pull-refresh + van-list实现list列表支持搜索和下拉刷新

1 介绍 在使用 van-pull-refresh van-list实现list列表下拉刷新时遇到几个问题在这里进行一个总结。 2 出现的问题 问题一:当van-pull-refresh van-list组合使用时,下拉刷新会调用两个加载图标。 解答:去除van-pull-refresh加载图标&…

leetcode-189:轮转数组

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5,6,7,1,2,3,4…

快讯:腾讯轻量服务器四周年,最低一折续费,还有免费升配

最近腾讯云轻量服务器四周年庆开始了,免费升级配置,续费服务器最低一折。 最低一折续费: 持有多久的轻量服务器决定续费几折,已经持有四年就是一折,三年1.5折以此类推。 免费升级配置: 2-4-5免费升级到…

String类常用的方法

源代码: 输出结果:

Linux 之 logrotate 【日志分割】

简介 logrotate 是一个用于管理日志文件的工具。它可以自动对日志文件进行轮转、压缩、删除等操作,以防止日志文件无限增长占用过多磁盘空间。logrotate 通常作为一个守护进程定期运行,也可以通过 cron 任务来调度执行 工作原理 按照配置文件中的规则…