【NLP】循环神经网络--RNN学习.day3

news2024/9/27 21:23:12

一.初步认识RNN

循环神经网络(Recurrent Neural Network, RNN)是一种用于处理序列数据的深度学习模型。与传统的静态神经网络相比,RNN 可以有效处理输入数据的时间序列特性。这使得 RNN 在处理自然语言处理(NLP)、时间序列预测、音频处理等任务时非常有效。以下是对 RNN 的详细解释。

1. 基本结构

1.1. 结构图示:

在传统的神经网络中,信息是单向流动的,而 RNN 具有一个循环结构,允许信息在时间步骤之间进行传递。下面是 RNN 的基本结构:

  x1 → [ H1 ] 
         ↑
  x2 → [ H2 ]
         ↑
  x3 → [ H3 ]
          ...
  • 输入 ( x t ) (x_t) (xt): 输入序列的第 (t) 个元素,如文本中的每个单词或时间序列数据中的每个点。
  • 隐藏状态 ( H t ) (H_t) (Ht): RNN 的隐藏状态,存储之前时间步的信息用于当前时间步的计算。

常见的RNN架构如下图两种:
在这里插入图片描述

1.2. 计算步骤:

对于 RNN,每个时间步的隐藏状态计算如下:

H t = tanh ( W h h H t − 1 + W h x x t + b ) H_t = \text{tanh}(W_{hh}H_{t-1} + W_{hx}x_t + b) Ht=tanh(WhhHt1+Whxxt+b)

  • ( W h h ) : 隐藏层到隐藏层的权重矩阵。 (W_{hh}): 隐藏层到隐藏层的权重矩阵。 (Whh):隐藏层到隐藏层的权重矩阵。
  • ( W h x ) : 输入层到隐藏层的权重矩阵。 (W_{hx}): 输入层到隐藏层的权重矩阵。 (Whx):输入层到隐藏层的权重矩阵。
  • ( b ) : 偏置向量。 (b): 偏置向量。 (b):偏置向量。

2. RNN 的前向传播

在前向传播中,RNN 根据输入序列逐步计算隐藏状态和输出。可以表示为:

  1. 初始隐藏状态 ( H 0 ) (H_0) (H0)通常为零。
  2. 对于每个时间步骤 ( t ) (t) (t):
    • 计算新的隐藏状态 ( H t ) (H_t) (Ht)
    • 可选地计算输出 ( y t ) (y_t) (yt)
      y t = W h y H t + b y y_t = W_{hy}H_t + b_y yt=WhyHt+by
    • 其中 ( W h y ) (W_{hy}) (Why) 是隐藏状态到输出的权重矩阵, ( b y ) (b_y) (by) 是输出的偏置。

3. RNN 的应用

RNN 和其变种广泛应用于以下领域:

在这里插入图片描述

  • 自然语言处理:

    • 语言模型
    • 机器翻译
    • 文本生成
  • 时间序列预测:

    • 股票价格预测
    • 气象数据分析
  • 语音和音频处理:

    • 语音识别
    • 音频生成

**

4.代码实现

**
下面的代码实现提供了一个使用 PyTorch 构建的基本 RNN 模型,包括对输入、隐藏状态的初始化、和前向传播的实现。以下是经过改进并注释齐全的完整代码:

import torch
import torch.nn as nn

# 创建一个随机输入张量:10个批次,6个时间步,5维特征(词向量大小)
x = torch.randn(10, 6, 5)  # batch_size=10, seq_len=6, input_size=5

# 定义 RNN 类
class RNN(nn.Module):
    def __init__(self, input_size, hidden_size, batch_first=True): 
        super(RNN, self).__init__()

        # 使用 RNNCell 创建 RNN 单元
        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 中需要数据维度是 (seq_len, batch_size, input_size)
            x = x.permute(1, 0, 2)  # 转换为 (seq_len, batch_size, input_size)
        else:
            seq_len, batch_size, input_size = x.size()

        hiddens = []  # 存储每个时间步的隐藏状态

        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 个时间步更新隐藏层状态
            hidden_t = self.rnn_cell(x[t], hidden_t)
            # 将每个时间步的隐藏状态添加到列表中
            hiddens.append(hidden_t)

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

        if self.batch_first:
            hiddens = hiddens.permute(1, 0, 2)  # 如果 batch_first 为 True,转换为 (batch_size, seq_len, hidden_size)

        return hiddens  # 返回所有时间步的隐藏状态


# 实例化 RNN 模型
model = RNN(input_size=5, hidden_size=8, batch_first=True)
outputs = model(x)  # 前向传播
print(outputs.shape)  # 打印输出形状

代码解析

  1. 输入张量:

    • 创建一个随机输入张量 x,其形状为 (10, 6, 5),即有 10 个批次,每个批次有 6 个时间步,每个时间步的输入为 5 维特征。
  2. RNN 类:

    • __init__: 定义 RNN 的构造函数,初始化 RNNCell 和隐藏状态的维数。
    • _initialize_hidden: 创建一个零张量作为初始化的隐藏状态。
    • forward: 定义前向传播,提取输入张量的形状并转换为适合 RNN 输入的格式。使用循环遍历每个时间步,更新隐藏状态,并将其保存到列表中。
  3. 模型实例化和前向传播:

    • 创建 RNN 类的实例 model,并用随机的输入 x 进行前向传播,最终打印输出的形状。

输出形状的解释

  • 输出的形状为 (batch_size, seq_len, hidden_size),即 (10, 6, 8),表示每个批次有 6 个时间步的隐藏状态,每个隐藏状态的维度是 8。

注意事项

  • 使用 RNNCell 可以进行较低级的操作,灵活度较高,如果需要处理复杂的 RNN 结构或多层 RNN,可以考虑使用 nn.RNNnn.LSTMnn.GRU

二.单向 RNN 和双向 RNN

  • 单向 RNN 和双向 RNN 是递归神经网络(RNN)的两种主要变体。它们的主要区别在于信息的流动方向,以及如何利用输入序列的信息。下面我们将详细解释这两种类型的 RNN,并提供相应的代码示例。

单向 RNN

  • 单向 RNN 是最基本的 RNN 形式。它从序列的开始(时间步 0)处理到序列的结束(时间步 T),在每个时间步 t,它仅依赖于时间步 t 及之前的输入。这种类型的 RNN 适合处理单向的序列数据,例如时间序列预测。

双向 RNN

双向 RNN 在模型的设计中同时引入两个 RNN,一个从前向后处理输入序列,另一个从后向前处理。每个 RNN 的输出可以联合使用,以捕捉前后文信息。这使得双向 RNN 能够在第二个时间步的输出中利用前面的数据,同时也能够利用后面的数据。这种结构在语言建模、语音识别等任务中非常有用。

代码示例

下面是使用 PyTorch 实现单向和双向 RNN 的代码示例。

单向 RNN
import torch
import torch.nn as nn

# 定义单向 RNN 类
class SimpleRNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(SimpleRNN, self).__init__()
        self.rnn = nn.RNN(input_size, hidden_size, batch_first=True)  # 单向 RNN
        self.fc = nn.Linear(hidden_size, output_size)  # 输出层

    def forward(self, x):
        # RNN 返回的输出和隐藏状态
        out, _ = self.rnn(x)  # out 的形状为 (batch_size, seq_len, hidden_size)
        out = self.fc(out[:, -1, :])  # 取序列最后一个时间步的输出
        return out

# 示例输入
input_size = 5
hidden_size = 8
output_size = 3
batch_size = 10
seq_len = 6

x = torch.randn(batch_size, seq_len, input_size)  # 输入张量

# 实例化单向 RNN 模型
model = SimpleRNN(input_size, hidden_size, output_size)
output = model(x)  # 前向传播
print("单向 RNN 输出形状:", output.shape)  # 输出形状应该是 (batch_size, output_size)
双向 RNN
import torch
import torch.nn as nn

# 定义双向 RNN 类
class BiDirectionalRNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(BiDirectionalRNN, self).__init__()
        self.rnn = nn.RNN(input_size, hidden_size, batch_first=True, bidirectional=True)  # 双向 RNN
        self.fc = nn.Linear(hidden_size * 2, output_size)  # 输出层,hidden_size * 2 是因为是双向的

    def forward(self, x):
        out, _ = self.rnn(x)  # out 的形状为 (batch_size, seq_len, hidden_size * 2)
        out = self.fc(out[:, -1, :])  # 取序列最后一个时间步的输出
        return out

# 示例输入
input_size = 5
hidden_size = 8
output_size = 3
batch_size = 10
seq_len = 6

x = torch.randn(batch_size, seq_len, input_size)  # 输入张量

# 实例化双向 RNN 模型
model = BiDirectionalRNN(input_size, hidden_size, output_size)
output = model(x)  # 前向传播
print("双向 RNN 输出形状:", output.shape)  # 输出形状应该是 (batch_size, output_size)

代码解析

  1. 单向 RNN 示例:

    • SimpleRNN 类定义了一个单向 RNN,使用 nn.RNN 创建 RNN 层。在 forward 方法中,RNN 的输出 out 取值序列中最后一个时间步的输出,并通过线性层 fc 转换到所需的输出维度。
  2. 双向 RNN 示例:

    • BiDirectionalRNN 类与单向 RNN 相似,但通过设定 bidirectional=True 创建了一个双向 RNN。因为 RNN 是双向的,所以输出的隐藏状态维度将是 hidden_size * 2。在 forward 方法中,同样取最后一个时间步的输出进行处理。

输出形状

  • 单向 RNN 的输出形状是 (batch_size, output_size)。双向 RNN 的输出形状也是 (batch_size, output_size),但使用的隐藏层大小是原来的两倍。

PyTorch 的 官方文档。

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

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

相关文章

【Python报错已解决】TypeError: forward() got an unexpected keyword argument ‘labels‘

🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 专栏介绍 在软件开发和日常使用中,BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

使用API有效率地管理Dynadot域名,注册域名服务器(NS)信息

前言 Dynadot是通过ICANN认证的域名注册商,自2002年成立以来,服务于全球108个国家和地区的客户,为数以万计的客户提供简洁,优惠,安全的域名注册以及管理服务。 Dynadot平台操作教程索引(包括域名邮箱&…

【9.模块化开发和代码重用之——头文件、动静态库】

目录 前言软件工程的基本原则程序的模块化开发和代码重用技术开发自己的头文件定义实现自己的头文件编写实现文件(源文件)编译代码链接目标文件到可执行文件 实现类似标准库效果的几种方法实际使用的开发方法头文件库 尝试自动链接静态库(好像…

替换jar包中class文件

虽然.jar文件是一种Java归档文件,可以使用压缩软件打开,但是并不能通过压缩软件来修改其内容,只能通过jar命令来更新文件。 一、背景 在使用血氧仪SDK时出现了问题,经过分析是在申请权限时版本不兼容导致的闪退异常,…

大数据新视界 --大数据大厂之 Kylin 多维分析引擎实战:构建数据立方体

💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

全国信息学奥赛泄题事件:一场对公平与公正的严峻考验

在科技与教育日益融合的今天,信息学奥林匹克竞赛作为选拔计算机科学领域未来人才的重要平台,始终承载着培养青少年逻辑思维、编程能力和创新潜力的重任。然而,2024年9月发生的一起全国CSP-J/S认证考试泄题事件,却如同一枚重磅炸弹…

SpringBoot教程(三十) | SpringBoot集成Shiro权限框架

SpringBoot教程(三十) | SpringBoot集成Shiro权限框架 一、 什么是Shiro二、Shiro 组件核心组件其他组件 三、流程说明shiro的运行流程 四、SpringBoot 集成 Shiro (shiro-spring-boot-web-starter方式)1. 添加 Shiro 相关 maven2…

领导让部署一个系统服务,我该怎么弄?

文章目录 Dockerdocker基础通过Dockerfile构建镜像打包镜像,离线使用docker修改代理内容 Nginxubuntu安装nginxnginx基本操作 问题Sqlalchemy可以反射一些表,另外一些反射为None查看服务器的架构和版本,查看本机外网IPPG数据库创建角色创建库…

CentOS7 离线部署docker和docker-compose环境

一、Docker 离线安装 1. 下载docker tar.gz包 下载地址: Index of linux/static/stable/x86_64/ 本文选择版本:23.0.6 2.创建docker.service文件 vi docker.service文件内容如下: [Unit] DescriptionDocker Application Container Engi…

SpringBoot中XXL-JOB实现灵活控制的分片处理方案

❃博主首页 &#xff1a; 「码到三十五」 &#xff0c;同名公众号 :「码到三十五」&#xff0c;wx号 : 「liwu0213」 ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a…

9.25盒马鲜生一面

1.自我介绍 2.css两种盒子模型 ​3.rem和em 4.px概念 5.transition和animation的区别 6.移动端适配方案 7.vh、vw、% 8.js基本数据类型 9.call、apply、bind的区别 10.js实现继承的方法 11.get和post的区别 12.web安全&#xff08;XSS&#xff0c;CSRF&#xff09; …

甩锅笔记:好好的服务端应用突然起不来,经定位是无法访问外网了?测试又说没改网络配置,该如何定位?

在工作中、团队协作时&#xff0c;可能遇到的问题&#xff0c;如集成测试等场景。但是作为偏前端的全栈&#xff0c;锅从天上来&#xff0c;不是你想甩就能甩&#xff0c;尤其面对测试等比较强势的团体&#xff08;bug创造者&#xff09;&#xff0c;你必须有强大的心理承受能力…

Vscode Run Code Py中文乱码问题

F1打开命令行界面&#xff0c;找到settings.json文件&#xff1b;选Workspace这个 找/直接输"code-runner.executorMap" python值改为"$pythonPath $fullFileName"

进程和线程的区别;线程的多种创建方式;Thread 类及常见方法;线程的状态

文章目录 进程和线程的区别线程的创建方式继承Thread&#xff0c;重写run&#xff08;创建单独的类/匿名内部类&#xff09;实现Runnable&#xff0c;重写run&#xff08;创建单独的类/匿名内部类&#xff09;实现Callable&#xff0c;重写call&#xff08;创建单独的类/匿名内…

828华为云征文 | 云服务器Flexus X实例,Docker集成搭建 Jupyter Notebook

828华为云征文 | 云服务器Flexus X实例&#xff0c;Docker集成搭建 Jupyter Notebook Docker 部署 Jupyter Notebook 是一个方便且快速的方式&#xff0c;可以帮助你搭建一个用于数据分析、机器学习和科学计算的环境 华为云端口放行 服务器放行对应端口9955 Docker安装并配置镜…

计算物理精解【1】-C++计算(1)

文章目录 基础hello,worldgetlinestd::cin引用与指针函数数据类型基本数据类型更多类型sizeof 正则表达式单次匹配多次匹配组匹配字符串的匹配 splitmap基础实战整型变量符号表简单分析生成整型变量表 正则表达式基础regex_matchregex_replaceswap Eigen概述简单例子Matrix基础…

DNS协议解析

DNS协议解析 什么是DNS协议 IP地址&#xff1a;一长串唯一标识网络上的计算机的数字 域名&#xff1a;一串由点分割的字符串名字 网址包含了域名 DNS&#xff1a;域名解析协议 IP>域名 --反向解析 域名>IP --正向解析 域名 由ICANN管理&#xff0c;有级别&#xf…

2.1 HuggingFists系统架构(二)

部署架构 上图为HuggingFists的部署架构。从架构图可知&#xff0c;HuggingFists主要分为服务器(Server)、计算节点(Node)以及数据库(Storage)三部分。这三部分可以分别部署在不同的机器上&#xff0c;以满足系统的性能需求。为部署方便&#xff0c;HuggingFists社区版将这三部…

Python | Leetcode Python题解之第419题棋盘上的战舰

题目&#xff1a; 题解&#xff1a; class Solution:def countBattleships(self, board: List[List[str]]) -> int:return sum(ch X and not (i > 0 and board[i - 1][j] X or j > 0 and board[i][j - 1] X)for i, row in enumerate(board) for j, ch in enumerat…

vue全局注册和局部注册的区别

1.全局注册&#xff1a; a、b为注册的组件 2.局部注册 3.有图可以看出&#xff0c;全局注册会影响白屏时间