【NLP笔记】RNN总结

文章目录

  • 经典RNN
    • 单向RNN
    • 双向RNN
    • Deep RNN
    • RNN特性总结
  • 变体RNN
    • LSTM
    • GRU

参考及转载内容:

  • 循环神经网络(RNN)
  • 深度学习05-RNN循环神经网络
  • 完全理解RNN(循环神经网络)

传统的CNN(Covolutional Neural Network,卷积神经网络)通常是给定输入预测对应的输出,是一对一的关系(输入层->隐藏层->输出层,隐藏层之间无关联,为顺序传播的关系),没有涉及输入信息间的关联关系。而在实际应用中,如自然语言处理、语音处理、时序数据处理等任务都依赖于上下文的输入才能够确定输出,因此CNN就无法很好地解决此类任务所需的关联关系提取。

CNN

RNN(Recurrent Neural Network,循环神经网络)就是针对这一类需要考虑上下文信息的数据分析与处理提出来的网络架构,循环神经网络的隐藏层会对之前的信息进行记忆存储,隐藏层之间的信息可以进行交互,当前隐藏层的输入可以包含上一个隐藏层的输出、上一个隐藏层存储的信息状态、输入层的输出。

未展开的RNN

经典RNN

单向RNN

在这里插入图片描述

假设 x t x_{t} xt表示第 t t t步的输入, s t s_{t} st表示第 t t t步的隐藏层的状态,该状态是根据上一个隐藏层状态 s t − 1 s_{t-1} st1计算得出,假设 U U U表示输入层的链接矩阵, W W W表示上一个隐藏时刻到下一个隐藏时刻的权重矩阵, f ( x ) f(x) f(x)为非线性层的激活函数,一般为 t a n h tanh tanh R e L U ReLU ReLU,则时刻 t t t的隐藏层计算为: s t = f ( U x t + W s t − 1 ) s_{t}=f(Ux_{t}+Ws_{t-1}) st=f(Uxt+Wst1)则时刻t的输出计算为: o t = g ( V ∗ s t ) o_{t}=g(V*s_{t}) ot=g(Vst)其中 V V V表示输出层的权重矩阵, g ( x ) g(x) g(x)为激活函数。可以看到当前时刻的输出与多个历史时刻的数据相关,因为每个当前时刻的输出都受到上个时刻的影响。但是单向RNN仅考虑了历史信息,很多时候需要共同结合上下文信息才能够得到更好的预测结果。

# pytorch中的单向RNN
import torch
import torch.nn as nn# 定义输入数据
input_size = 10   # 输入特征的维度
sequence_length = 5   # 时间步个数
batch_size = 3   # 批次大小# 创建随机输入数据
#输入数据的维度为(sequence_length, batch_size, input_size),表示有sequence_length个时间步,
#每个时间步有batch_size个样本,每个样本的特征维度为input_size。
input_data = torch.randn(sequence_length, batch_size, input_size)
print("输入数据",input_data)
# 定义RNN模型
# 定义RNN模型时,我们指定了输入特征的维度input_size、隐藏层的维度hidden_size、隐藏层的层数num_layers等参数。
# batch_first=False表示输入数据的维度中批次大小是否在第一个维度,我们在第二个维度上。
rnn = nn.RNN(input_size, hidden_size=20, num_layers=1, batch_first=False)
"""
在前向传播过程中,我们将输入数据传递给RNN模型,并得到输出张量output和最后一个时间步的隐藏状态hidden。
输出张量的大小为(sequence_length, batch_size, hidden_size),表示每个时间步的隐藏层输出。
最后一个时间步的隐藏状态的大小为(num_layers, batch_size, hidden_size)。
"""
# 前向传播,第二个参数h0未传递,默认为0
output, hidden = rnn(input_data)
print("最后一个隐藏层",hidden.shape)
print("输出所有隐藏层",output.shape)# 打印每个隐藏层的权重和偏置项
# weight_ih表示输入到隐藏层的权重,weight_hh表示隐藏层到隐藏层的权重,注意这里使出是转置的结果。
# bias_ih表示输入到隐藏层的偏置,bias_hh表示隐藏层到隐藏层的偏置。
for name, param in rnn.named_parameters():if 'weight' in name or 'bias' in name:print(name, param.data)

单向RNN的参数是共享的,RNN参数共享指的是:在每一个时间步上,所对应的参数是共享的。参数共享的目的有两个:一、用这些参数来捕获序列上的特征;二、共享参数减少模型的复杂度。

对于RNN的参数共享,我们可以理解为对于一个句子或者文本,参数U可以看成是语法结构、参数W是一般规律,而下一个单词的预测必须是上一个单词和一般规律W与语法结构U共同作用的结果。我们知道,语法结构和一般规律在语言当中是共享的。所以,参数自然就是共享的!

我们需要记住的是,深度学习是怎么减少参数的,很大原因就是参数共享,而CNN是在空间上共享参数,RNN是在时间序列上共享参数。

双向RNN

在这里插入图片描述

这种可以结合上下文信息的RNN结构即双向RNN,双向RNN的隐藏层需要保存两个状态值,一个是正向计算,一个是反向计算,基于上述单向计算的过程,双向计算可表示如下: o t = g ( V ∗ s t + V ′ ∗ s t ′ ) o_{t}=g(V*s_{t}+V'*s'_{t}) ot=g(Vst+Vst)
正向计算: s t = f ( U x t + W s t − 1 ) s_{t}=f(Ux_{t}+Ws_{t-1}) st=f(Uxt+Wst1)
反向计算: s t ′ = f ( U ′ x t + W s t + 1 ) s'_{t}=f(U'x_{t}+Ws_{t+1}) st=f(Uxt+Wst+1)
在正向计算和反向计算过程中,权重不共享。其中网络参数的更新是通过前向传播和反向传播过程完成的,其中反向传播的过程采用的是BPTT(BackPropagation Through Time)算法进行的,其实基本原理也是基于常规的BP算法,只是BPTT需要考虑不同时刻的梯度计算结果之和,具体计算可参考:BPTT算法推导 。

# pytorch定义双向RNN
import torch
import torch.nn as nn# 定义输入数据
input_size = 10   # 输入特征的维度
sequence_length = 5   # 时间步个数
batch_size = 3   # 批次大小# 创建随机输入数据
input_data = torch.randn(sequence_length, batch_size, input_size)# 定义双向RNN模型
rnn = nn.RNN(input_size, hidden_size=20, num_layers=1, batch_first=False, bidirectional=True)# 前向传播
output, hidden = rnn(input_data)# 输出结果
print("输出张量大小:", output.size())
print("最后一个时间步的隐藏状态大小:", hidden.size())

Deep RNN

在这里插入图片描述

基本循环神经网络和双向循环神经网络只有单个隐藏层,有时不能很好的学习数据内部关系,可以通过叠加多个隐藏层,形成深度循环神经网络结构。单层的隐藏层RNN的参数是共享的,深层的RNN会有 L L L层的参数,其每一层都可以是一个双向RNN结构。

# pytorch实现双向RNN
import torch
import torch.nn as nn# 定义输入数据和参数
input_size = 5
hidden_size = 10
num_layers = 2
batch_size = 3
sequence_length = 4# 创建输入张量
input_tensor = torch.randn(sequence_length, batch_size, input_size)# 创建多层RNN模型
rnn = nn.RNN(input_size, hidden_size, num_layers)# 前向传播
output, hidden = rnn(input_tensor)# 打印输出张量和隐藏状态的大小
print("Output shape:", output.shape)
print("Hidden state shape:", hidden.shape)

RNN特性总结

  • 单向单隐藏层传播参数共享;

  • 参数更新采用BPTT的算法实现;
    在这里插入图片描述

  • 存在梯度消失和梯度爆炸的问题;

    • 梯度消失:传统的RNN不能捕获长距离词之间的关系。从图中可以看到tanh函数在x趋近于无穷大和无穷小时梯度值都为0,当邻近神经元梯度接近0时,因为前面层的梯度是由后面层的梯度连乘得到的,多个梯度相乘会使梯度值以指数级速度下降,最终在反向传播几步后就完全消失,比较远的时刻的梯度值为0。
    • 梯度爆炸:RNN的学习依赖于我们的激活函数和网络初始参数,如果Jacobian矩阵中的值太大,会产生梯度爆炸而不是梯度消失问题。梯度消失比梯度爆炸受到了更多的关注有两方面的原因。其一,梯度爆炸容易发现,梯度值会变成NaN,导致程序崩溃。其二,用预定义的阈值裁剪梯度可以简单有效的解决梯度爆炸问题。梯度消失问题就不容易发现并且也不好处理,这也是梯度消失比梯度爆炸受到学术界更多关注的原因。
  • RNN的几种架构:

    • 单输入单输出(Single Input Single Output,SISO): 给定一段文本,预测下一个词语;
      在这里插入图片描述
      在这里插入图片描述

    • 单输入多输出(Single Input Multiple Output,SIMO):如上图有两种实现形式。这种1 to N的结构可以处理的问题有很多,比如图像标注,输入的X是图像的特征,而输出的y序列是一段句子。

    • 多输入单输出(Multiple Input Single Output,MISO):输入是一个序列,输出是一个单独的值而不是序列。这种结构通常用来处理序列分类问题。如输入一段文字判别它所属的类别,输入一个句子判断其情感倾向,输入一段文档并判断它的类别等等。

    • 多输入多输出(Multiple Input Multiple Output,MIMO):一种是NtoN,输入和输出序列是等长的。这种可以作为简单的Char RNN可以用来生成文章,诗歌,甚至是代码,非常有意思。另一种是这种结构又叫Encoder-Decoder模型,也称之为Seq2Seq模型。在现实问题中,我们遇到的大部分序列都是不等长的。如机器翻译中,源语言和目标语言的句子往往并没有相同的长度。而Encoder-Decoder结构先将输入数据编码成一个上下文向量c,之后在通过这个上下文向量输出预测序列。

变体RNN

参考链接:【译】理解LSTM(通俗易懂版)

LSTM

RNN的结构的隐藏层只有一个状态,对邻近的输入会非常敏感,如果我们再增加一个门(gate)来控制特征的流通和损失,即c,让它来保存长期的状态,这就是长短时记忆网络(Long Short Term Memory,LSTM)。
在这里插入图片描述
新增加的状态c,称为单元状态。我们把LSTM按照时间维度展开:
其中图像上的标识 σ \sigma σ标识使用sigmod激活到[0-1],tanh激活到[-1,1],⨀ 是一个数学符号,表示逐元素乘积(element-wise product)或哈达玛积(Hadamard product)。当两个相同维度的矩阵、向量或张量进行逐元素相乘时,可以使用 ⨀ 符号来表示。
在这里插入图片描述
LSTM的输入有三个:当前时刻网络的输出值 x t x_{t} xt、上一时刻LSTM的输出值 h t − 1 h_{t-1} ht1 、以及上一时刻的记忆单元向量 c t − 1 c_{t−1} ct1

LSTM的输出有两个:当前时刻LSTM输出值 h t h_{t} ht、当前时刻的隐藏状态向量 h t h_{t} ht、和当前时刻的记忆单元状态向量 c t c_{t} ct

注意:记忆单元c在LSTM 层内部结束工作,不向其他层输出。LSTM的输出仅有隐藏状态向量h。

LSTM 的关键是单元状态,即贯穿图表顶部的水平线,有点像传送带。这一部分一般叫做单元状态(cell state)它自始至终存在于LSTM的整个链式系统中。

在这里插入图片描述

f t f_{t} ft叫做遗忘门,表示 C t − 1 C_{t−1} Ct1 的哪些特征被用于计算 C t C_{t} Ct f t f_{t} ft是一个向量,向量的每个元素均位于(0~1)范围内。通常我们使用 sigmoid 作为激活函数,sigmoid 的输出是一个介于于(0~1)区间内的值,但是当你观察一个训练好的LSTM时,你会发现门的值绝大多数都非常接近0或者1,其余的值少之又少。
在这里插入图片描述

C t C_{t} Ct表示单元状态更新值,由输入数据 x t x_{t} xt和隐节点 h t − 1 h_{t-1} ht1经由一个神经网络层得到,单元状态更新值的激活函数通常使用tanh。 i t i_{t} it叫做输入门,同 f t f_{t} ft一样也是一个元素介于(0~1)区间内的向量,同样由 x t x_{t} xt h t − 1 h_{t-1} ht1经由sigmoid激活函数计算而成。
在这里插入图片描述

在这里插入图片描述

最后,为了计算预测值 y t y^{t} yt和生成下个时间片完整的输入,我们需要计算隐节点的输出 h t h_{t} ht
在这里插入图片描述

GRU

Gated Recurrent Unit – GRU 是 LSTM 的一个变体。他保留了 LSTM 划重点,遗忘不重要信息的特点,在long-term 传播的时候也不会被丢失。

LSTM 的参数太多,计算需要很长时间。因此,最近业界又提出了 GRU(Gated RecurrentUnit,门控循环单元)。GRU 保留了 LSTM使用门的理念,但是减少了参数,缩短了计算时间。

相对于 LSTM 使用隐藏状态和记忆单元两条线,GRU只使用隐藏状态。异同点如下:
在这里插入图片描述
GRU的计算过程如下:
在这里插入图片描述
如图所示,GRU 没有记忆单元,只有一个隐藏状态h在时间方向上传播。这里使用r和z共两个门(LSTM 使用 3 个门),r称为 reset 门,z称为 update 门。r(reset门)决定在多大程度上“忽略”过去的隐藏状态,定义了前面记忆保存到当前时间步的量。

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

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

相关文章

【异或】Leetcode 136. 只出现一次的数字

【异或】Leetcode 136. 只出现一次的数字 解法1 只需要全部异或一下,剩下的就是剩下的元素 ---------------🎈🎈题目链接 136. 只出现一次的数字🎈🎈------------------- 解法1 只需要全部异或一下,剩下的…

【GitHub】2FA(双重身份验证)

无需额外设备完美插件处理:Authenticator Crx搜搜:https://www.crxsoso.com/ 或者google查询:Authenticator

BRAM底层原理详细解释(1)

目录 一、原语 二、端口简述 2.1 端口简介 2.2 SDP端口映射 三、端口信号含义补充说明 3.1 字节写使能(Byte-Write Enable)- WEA and WEBWE: 3.2 地址总线—ADDRARDADDR and ADDRBWRADDR 3.3 数据总线—DIADI, DIPADIP, DIBDI, and D…

(一)、Doris安装使用(基于Doris 2.0.6)

第 1 章Doris简介 1.1、 Doris 概述 ​ Apache Doris由百度大数据部研发(之前叫百度 Palo,2018年贡献到 Apache 社区后,更名为 Doris),在百度内部,有超过200个产品线在使用,部署机器超过1000台…

RHEL9部署Docker环境

华子目录 Docker引擎架构docker引擎架构示意图执行过程示例 RHEL9上安装Docker1.系统要求2.安装yum-utils工具包3.yum安装docker-ce4.配置docker镜像加速docker拉取镜像的过程配置阿里云镜像仓库重新加载守护进程重启Docker服务 5.拉取并运行hello-world镜像6.测试是否安装成功…

四、HarmonyOS应用开发-ArkTS开发语言介绍

目录 1、TypeScript快速入门 1.1、编程语言介绍 1.2、基础类型 1.3、条件语句 1.4、函数 1.5、类 1.6、模块 1.7、迭代器 2、ArkTs 基础(浅析ArkTS的起源和演进) 2.1、引言 2.2、JS 2.3、TS 2.4、ArkTS 2.5、下一步演进 3、ArkTs 开发实践…

HTTP(2)

HTTP 通信过程包括从客户端发往服务器端的请求及从服务器端返回客户端的响应。 那么请求和响应是怎样运作的呢 HTTP 报文 用于 HTTP 协议交互的信息被称为 HTTP 报文。 请求端(客户端)的HTTP 报文叫做请求报文,响应端(服务器…

Vscode按键占用问题解决

Vscode按键占用 在使用vscode的过程中,官方按键 Ctrl . 按键可以提示修复代码中的问题,但是发现按了没有反应。 解决问题 首先确认vscode中是否设置了这个按键,默认设置了的系统输入法中是否有按键冲突了,打开输入法设置检查 …

【保姆级讲解Redis基础命令】

🌈🌈🌈个人主页:程序员不想敲代码啊🌈🌈🌈 💫CSDN优质创作者,CSDN实力新星 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处&#xff0c…

【PostGresql】------ pg多表数据多个条件汇总 使用 union 方法示例代码

1. 示例代码如下: SELECT"ID","DT_DATE","CNAME","RMAN_NAME","DEP_NAME","DEP_ID","INVEST_MAN_NAME","TYPE_NAME","INVEST_LEVEL_NAME","POSITION_NAME",…

【Springboot3+Mybatis】文件上传阿里云OSS 基础管理系统CRUD

文章目录 一、需求&开发流程二、环境搭建&数据库准备三、部门管理四、员工管理4.1 分页(条件)查询4.2 批量删除员工 五、文件上传5.1 介绍5.2 本地存储5.3 阿里云OSS1. 开通OSS2. 创建存储空间Bucket 5.4 OSS快速入门5.5 OSS上传显示文件 六、配置文件6.1 yml配置6.2 C…

RocketMq 顺序消费、分区消息、延迟发送消息、Topic、tag分类 实战 (消费者) (三)

消费端配置 如下所示:是消费者的配置类,有以下几点需要注意的地方 1、是TargetMessageListener这个监听类(下文会把这个监听类的具体代码贴出来),需要把这个监听类订阅。 2、rocketMqDcProperties.getTargetProperties…

0基础 三个月掌握C语言(13)-下

数据在内存中的存储 浮点数在内存中的存储 常见的浮点数:3.141592、1E10等 浮点数家族包括:float、double、long double类型 浮点数表示的范围:在float.h中定义 练习 关于(float*)&n: &n:这是一…

字符串哈希(c++)

1、定义 字符串哈希把不同的字符串映射成不同的整数 1.1、规则 1、把字符串映射成一个P进制数字 对于一个长度为n的字符串s 这样定义Hash函数: 例如:字符串abc,其哈希函数值为ap^2 bp^1 c; 即97 * 131^2 98 * 131^1 99; 2、两个字符串不一…

【计算机网络篇】数据链路层(3)差错检测

文章目录 🥚误码🍔两种常见的检错技术⭐奇偶校验⭐循环冗余校验🎈例子 🥚误码 误码首先介绍误码的相关概念 🍔两种常见的检错技术 ⭐奇偶校验 奇校验是在待发送的数据后面添加1个校验位,使得添加该校验…

C++|类封装、类的分文件编写练习:设计立方体类、点和圆的关系

文章目录 练习案例1:设计立方体类CPP代码 练习案例2:点和圆的关系CPP代码 代码总结类的分文件编写 练习案例1:设计立方体类 设计立方体类(Cube) 求出立方体的面积和体积 分别用全局函数和成员函数判断两个立方体是否相等。 CPP代码 class Cube { pub…

GPT4.0

GPT4.0 支持官网所有功能以及所有第三方GPTS,完全同步官网。无需魔法,填写授权码直达官网。全天超18小时维护,无需担心不稳定。没有永久卡,3.5免费提供,4.0可以按需下单即可,不存在跑路。 需要的联系

详细安装步骤:vue.js 三种方式安装(vue-cli)

Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据驱动的 web 界面的渐进式框架。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。它不仅易于上手,还便于与第三方库或既有项目整合。 三种 Vue.js 的安装方法&…

unity 多屏幕操作

想了解基础操作请移步:(重点是大佬写的好,这里就不再赘述) Unity 基础 之 使用 Display 简单的实现 多屏幕显示的效果_unity display-CSDN博客 在panel上也可以通过获取 Canvas,来达到切换多屏幕的操作, …

Flutter-仿携程首页类型切换

效果 唠叨 闲来无事,不小心下载了携程app,还幻想可以去旅游一番,奈何自己运气不好,自从高考时第一次吹空调导致自己拉肚子考试,物理,数学考了一半就交卷,英语2B铅笔除了问题,导致原…