循环神经网络RNN原理精讲,详细举例!

第一部分:为什么需要RNN?


在了解RNN是什么之前,我们先要明白它解决了什么问题。

传统的神经网络,比如我们常见的前馈神经网络(Feedforward Neural Network)或者卷积神经网络(CNN),它们有一个共同的特点:输入之间是相互独立的。

你给它一张猫的图片,它判断是猫。再给它一张狗的图片,它判断是狗。

这两个判断过程互不影响。前一次的输入和输出,对后一次的判断没有任何帮助。这在很多场景下是没问题的。

但是,请思考以下任务:

阅读理解: "今天天气很好,我心情也很___。" 空格里很可能填“好”或“不错”。这个推断依赖于前面的“天气很好”。

语音识别: 当你听到一句话的开头,它会帮助你预测后面可能出现的音节。

股票预测: 今天的股价,很大程度上取决于昨天、前天乃至过去一段时间的走势。

这些任务的共同点是,它们处理的都是序列数据(Sequential Data)。序列中的数据不是独立的,前一个数据点包含了对理解后一个数据点至关重要的信息。

传统的神经网络缺乏记忆能力,无法处理这种时间上的依赖关系。而RNN,就是为了解决这个问题而生的。

结论:RNN是一种专门用于处理序列数据的神经网络,其设计的核心就是赋予网络一种“记忆”能力,让它能够捕捉序列中的时间依赖关系。

第二部分:RNN的核心结构

1. 折叠形式 (Folded):

              ,-----,|     |  <-- (代表信息的循环)'-----'^|x_t   --->   [  A  ]   --->   o_t(输入)       (RNN单元)      (输出)
  • [ A ]: 代表RNN的处理单元。

  • x_t: 代表在时间点 t 的输入。

  • o_t: 代表在时间点 t 的输出。

  • 最重要的部分是那个指向自身的循环箭头: 它表示 A 单元的输出结果(具体来说是隐藏状态 h_t,我们稍后会讲)会作为下一次计算的输入,再次进入 A 单元。这就是“循环”或“记忆”的来源。

2. 展开形式 (Unfolded):

         (初始记忆)h_(-1)|v... --> [  A  ] --(传递记忆 h_0)--> [  A  ] --(传递记忆 h_1)--> [  A  ] --(传递记忆 h_2)--> ...|                        |                        |^                        ^                        ^|                        |                        |x_0                      x_1                      x_2        (序列输入)|                        |                        |v                        v                        vo_0                      o_1                      o_2        (序列输出)(t=0 时刻)               (t=1 时刻)               (t=2 时刻)

让我们来详细解读一下这个结构:

  • x_t:这是在时间步(time step)t 的输入。比如,在处理一句话 "I am a student" 时,x_0 就是 "I",x_1 就是 "am",以此类推。

  • h_t:这是在时间步 t 的隐藏状态(Hidden State)。可以把它理解为RNN在时间点 t 的记忆。它不仅包含了当前输入x_t的信息,还包含了上一个时间步的隐藏状态h_t−1(也就是过去的记忆)的信息。

  • o_t:这是在时间步 t 的输出。比如,在做下一个词预测时,o_t 就是基于到x_t为止的所有信息,预测出的下一个最可能的词。

  • A:代表RNN的计算单元。重要的是,在所有时间步中,这个A是完全相同的。它包含的参数(权重矩阵)在整个序列处理过程中是共享的。这大大减少了模型的参数量,也让模型学会一种通用的处理规则,而不是为每个时间点都学一套新规则。

  • 图中虽然画了多个 [ A ],但请记住,它们是同一个单元,拥有完全相同的参数(权重)。我们只是为了说明流程,把它在时间维度上复制了多份。

工作流程(前向传播)

  1. 初始状态:在 t=0 时,我们需要一个初始的隐藏状态 h_−1(通常初始化为全零向量)。

  2. t=0 时刻:RNN单元接收初始隐藏状态 h_−1 和第一个输入 x_0。通过内部计算,它会生成新的隐藏状态(新的记忆)h_0,并可能产生一个输出 o_0。

  3. t=1 时刻:RNN单元接收上一时刻的记忆 h_0 和当前输入 x_1。它将这两者结合,更新自己的记忆,生成新的隐藏状态 h_1,并输出 o_1。

  4. 循环往复:这个过程一直持续下去,直到序列的所有输入都被处理完毕。在每一步,h_t 都像一个“记忆胶囊”,携带着从序列开始到当前位置的所有重要信息,向下传递。

结论:RNN通过一个循环的隐藏状态(Hidden State),将过去的信息编码并传递到当前步骤,从而实现了对序列数据的记忆。

第三部分:深入RNN的数学原理

现在我们把那个黑盒子 "A" 打开,看看里面到底发生了什么计算。

在任意一个时间步 t,计算主要分为两步:

1. 更新隐藏状态 h_t:

拆解这个公式:

  • h_t−1:上一时刻的隐藏状态(向量)。

  • x_t:当前时刻的输入(向量)。

  • W_hh:隐藏状态到隐藏状态的权重矩阵。它决定了“应该保留多少上一时刻的记忆”。

  • W_xh:输入到隐藏状态的权重矩阵。它决定了“应该从当前输入中吸收多少新信息”。

  • b_h:隐藏状态的偏置项(bias)

  • f:激活函数。在RNN中,通常使用 tanh(双曲正切函数)。为什么用tanh?因为它能将输出值压缩到-1到1之间,这有助于控制信息流,防止梯度在网络中传播时变得过大或过小(尽管不能完全解决,后面会讲)。

2. 计算输出 o_t:

  • h_t:当前时刻刚刚计算出来的隐藏状态。

  • W_hy:隐藏状态到输出的权重矩阵。它决定了“如何利用当前的记忆来生成输出”。

  • b_y:输出的偏置项

  • g:输出层的激活函数。这个根据具体任务决定。

    • 如果是分类任务(比如情感分析),通常用 Softmax

    • 如果是回归任务(比如预测股价),可能就不用激活函数或用线性激活函数。

关键点:在整个训练过程中,模型要学习的就是这几个共享的权重矩阵(W_hh,W_xh,W_hy)和偏置项。无论序列有多长,它们都是同一套参数。

第四部分:RNN的训练与挑战

训练:BPTT算法

RNN的训练算法叫做通过时间的反向传播(Backpropagation Through Time, BPTT)

还记得那个展开的RNN图吗?BPTT的原理其实很简单:

  • 前向传播:按照我们上面讲的流程,从头到尾计算出所有时间步的隐藏状态和输出。

  • 计算总损失:将每个时间步的输出 o_t 与真实标签 y_t 进行比较,计算损失(例如使用交叉熵损失),然后将所有时间步的损失相加,得到总损失。

  • 反向传播:将总损失从最后一个时间步开始,沿着展开的图反向传播,计算每个权重矩阵的梯度。因为权重是共享的,所以每个时间步计算出的梯度会累加到对应的共享权重上。

  • 更新权重:使用梯度下降法(如Adam, SGD等)根据累加后的总梯度来更新权重矩阵 W_hh,W_xh,W_hy。

长期依赖问题(Long-Term Dependencies)

这是简单RNN最致命的弱点。

想象这个句子:"I grew up in France... (此处省略很多文字)... therefore, I speak fluent French."

为了正确预测出 "French",模型需要记住很久以前的信息 "France"。

在BPTT过程中,梯度需要从序列末端一直传播回序列的开端。根据链式法则,这个梯度会不断地乘以权重矩阵 W_hh。

  • 梯度消失(Vanishing Gradients):如果 W_hh 中的值(更准确地说是它的雅可比矩阵的范数)小于1,那么在多次连乘后,梯度会变得极其微小,趋近于0。这导致模型无法从遥远的过去学习到信息,长期记忆丢失。这是最常见也最棘手的问题。

  • 梯度爆炸(Exploding Gradients):反之,如果 W_hh 中的值大于1,多次连乘后梯度会变得非常大,导致模型训练不稳定,参数更新幅度过大,甚至变成NaN。这个问题相对容易发现和解决(例如通过梯度裁剪 (Gradient Clipping) 来限制梯度的大小)。

由于梯度消失问题的存在,标准的RNN很难学习到超过5-10个时间步的依赖关系,这极大地限制了它的应用。

第五部分:解决方案与演进——LSTM与GRU

为了解决长期依赖问题,研究人员设计了更复杂的RNN变体,其中最成功、最流行的就是长短期记忆网络(Long Short-Term Memory, LSTM)和门控循环单元(Gated Recurrent Unit, GRU)

它们的核心思想是引入门(Gate)的结构。

你可以把门想象成一个信息过滤器,它由一个Sigmoid激活函数和一个逐元素相乘操作组成。Sigmoid的输出在0到1之间,可以看作是一个开关:

  • 输出为0,表示“完全关闭”,不允许任何信息通过。

  • 输出为1,表示“完全打开”,让所有信息通过。

  • 输出在0和1之间,表示“部分打开”,按比例让信息通过。

LSTM: 它引入了一个独立的细胞状态(Cell State),专门负责长距离传递信息。然后,它设计了三个精巧的门来控制细胞状态:

  1. 遗忘门(Forget Gate):决定应该从细胞状态中丢弃哪些旧信息。

  2. 输入门(Input Gate):决定哪些新信息应该被存入细胞状态。

  3. 输出门(Output Gate):决定细胞状态中的哪些信息应该被用作当前的输出。

通过这三个门的协同工作,LSTM可以明确地学习到何时遗忘、何时记忆、何时输出,从而有效地解决了梯度消失问题,能够捕捉非常长的序列依赖。

GRU: 这是LSTM的一个简化版,它将遗忘门和输入门合并为了一个更新门(Update Gate),并且没有独立的细胞状态。GRU的结构更简单,参数更少,计算效率更高,在许多任务上能达到和LSTM相近的效果。

明天我们讲解RNN的pytorch逐行实现以及LSTM与GRU的深入原理讲解

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

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

相关文章

如何用USRP捕获手机信号波形(中)手机/基站通信

目录&#xff1a; 如何用USRP捕获手机信号波形&#xff08;上&#xff09;系统及知识准备 如何用USRP捕获手机信号波形&#xff08;中&#xff09;手机/基站通信 如何用USRP捕获手机信号波形&#xff08;下&#xff09;协议分析 四、信号捕获结果 4.1 时域波形 我怀疑下面…

(LeetCode 面试经典 150 题 ) 155. 最小栈 (栈)

题目&#xff1a;155. 最小栈 思路&#xff1a;栈&#xff0c;时间复杂度0(n)。 在插入栈元素val时&#xff0c;同时加入一个字段&#xff0c;维护插入当前元素val时的最小值即可。 C版本&#xff1a; class MinStack { public:stack<pair<int,int>> st;MinStac…

算法:动态规划 洛谷 线性状态动态规划 P1439【模板】最长公共子序列

思路&#xff1a;因为n<1e5,所以不能O&#xff08;n方&#xff09;的复杂度&#xff0c;所以常规的计算最长公共子序列的方法就不行&#xff0c;不过这题有个特点&#xff0c;就是a&#xff0c;b都是排列&#xff0c;那么a有的数b也有&#xff0c;并且数量还一样&#xff0c…

Linux跑后台服务

vi /usr/lib/systemd/system/my_service.service文件配置内容&#xff1a;[Unit] Descriptionmyprogram Afternetwork.target[Service] Userroot Typesimple ExecStart/home/userabc/programs/myprogram/myprogram.out Restarton-failure WorkingDirectory/home/userabc/progra…

Linux基础练习题1

1、配置网络地址 请为此虚拟机配置以下网络参数&#xff1a; 1&#xff09;主机名&#xff1a;chenyu.example.com &#xff08;将chenyu改成自己名字的全拼&#xff09; 2&#xff09;IP 地址&#xff1a;192.168.100.100/24 3&#xff09;默认网关&#xff1a;192.168.100.25…

# 前端开发规范基础汇总

前端开发规范基础汇总 命名规范 常用的命名规范 camelCase&#xff08;小驼峰式命名法 —— 首字小写&#xff09;PascalCase&#xff08;大驼峰式命名法 —— 首字大写&#xff09;snake_case&#xff08;下划线命名法&#xff09;kebab-case&#xff08;短横线命名法&…

jQuery UI Tabs切换功能实例

jQuery UI Tabs切换功能使用jQuery UI实现Tabs切换功能的方法。代码示例创建了一个包含四个标签页&#xff08;按钮A-D&#xff09;的界面&#xff0c;每个标签对应不同的内容区域。通过引入jQuery UI库并调用tabs()方法实现基本切换功能。文章还提到可以通过配置选项修改默认行…

关于为什么stm32的开漏输出可以读取引脚的数值

在使用软件模拟iic通信时&#xff0c;要将SDA线配置为开漏输出&#xff0c;既然配置为开漏输出&#xff0c;为什么程序还可以通过SDA线读取数据&#xff1f;查阅手册&#xff1a;只说了结论&#xff1a;在开楼模式下&#xff0c;对输入数据寄存器的读访问可以得到IO状态来看输出…

墨者:SQL手工注入漏洞测试(SQLite数据库)

1. 墨者学院&#xff1a;SQL手工注入漏洞测试(SQLite数据库)&#x1f680; 2. SQLite数据库注入特点&#x1f50d; SQLite数据库和MySQL数据库语法不同&#xff0c;不能直接套用MySQL的注入方式。但SQLite有个特殊的数据库sqlite_master&#xff0c;它存储了所有表结构信息&…

【Apache Tomcat】

目录Tomcat 基本简介Tomcat 架构组成Tomcat 的目录结构Tomcat 的工作原理Tomcat 的配置文件Tomcat 与其他服务器对比Tomcat 使用场景Tomcat 与 Spring Boot常见问题与优化Tomcat&#xff08;全称 Apache Tomcat&#xff09;是由 Apache 软件基金会开发和维护的一款 开源的 Web …

Nginx参数proxy_set_header 与 add_header 核心区别

proxy_set_header 与 add_header 是 Nginx 中两个用于操作 HTTP 头部信息的指令&#xff0c;但作用方向和使用场景完全不同。以下是两者的核心区别&#xff1a;核心区别概述特性proxy_set_headeradd_header作用方向✅ 请求头&#xff08;Request Headers&#xff09; → 后端服…

若依框架-前端二次开发快速入门简述

1.目录如左图所示&#xff0c;主要分为bin,build,node_modules,public,src几个部分&#xff0c;我们从gitee上使用bash将项目克隆到本地后&#xff0c;进入项目目录&#xff0c;并安装好依赖后可以直接使用命令启动服务&#xff0c;具体命令见README.md&#xff0c;安装好依赖后…

day 41 类和方法

day 28 类是对属性和方法的封装&#xff0c;可以理解为模版&#xff0c;通过对模型实例化可以实现调用这个类的属性和方法。比如创建一个随机森林类&#xff0c;然后就可以调用它的训练和预测方法。 一个常见的类的定义包括了&#xff1a; 1、关键字class 2、类名 3、语法固定…

Docker学习日志-Docker容器配置、Nginx 配置与文件映射

Docker学习日志-Docker容器配置、Nginx 配置与文件映射 docker run 之后能否再次修改卷映射或端口映射&#xff1f; 不能直接修改已创建容器的卷映射或端口映射。 Docker 的设计原则是 **容器是不可变的 **&#xff0c;也就是说&#xff1a; 一旦容器通过 docker run 创建完成&…

cpp实现音频重采样8k->16k及16k->8k

static int convert_8khz_to_16khz(void* dst_buf, void* src_buf, int src_size) {short* in static_cast<short*>(src_buf);short* out static_cast<short*>(dst_buf);int in_samples src_size / sizeof(short);// 边界处理&#xff1a;前两个样本out[0] in[…

【机器学习】机器学习新手入门概述

目录 一、机器学习概念 1.1基本概念 1.2 主要类型 1.2.1 监督学习&#xff08;Supervised Learning&#xff09; &#xff08;1&#xff09;基本介绍 &#xff08;2&#xff09;任务目标 &#xff08;3&#xff09;常见算法 &#xff08;4&#xff09;应用场景 1.2.2 无…

嵌入式硬件篇---ESP32稳压板

制作 ESP32 稳压板的核心目标是&#xff1a;给 ESP32 提供稳定的 3.3V 电源&#xff08;ESP32 的工作电压必须是 3.3V&#xff09;&#xff0c;同时支持多种供电方式&#xff08;比如锂电池、USB、外接电源&#xff09;&#xff0c;并具备保护功能&#xff08;防止过流、接反电…

sql server 删除用户时提示:数据库主体在该数据库中拥有 架构,无法删除

sql server 删除用户时提示&#xff1a;数据库主体在该数据库中拥有 架构&#xff0c;无法删除&#xff0c;怎么办&#xff1f; 1、删除用户ncdb2、 数据库主体在该数据库中拥有 架构&#xff0c;无法删除。3、查看该用户拥有的架构4、找到该用户拥有的这个架构&#xff0c;右键…

分类-鸢尾花分类

目录 基本步骤 决策树&#xff08;分类&#xff09; 导入鸢尾花数据集 赋值给x与y 划分数据集 导入决策树模型 实例化 训练 ​编辑 导入计算准确率的库 计算准确率 随机森林&#xff08;分类&#xff09; 导入鸢尾花的数据集&#xff0c; 赋值x&#xff0c;y 取后一…

单元测试、系统测试、集成测试知识详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、单元测试的概念单元测试是对软件基本组成单元进行的测试&#xff0c;如函数或一个类的方法。当然这里的基本单元不仅仅指的是一个函数或者方法&#xff0c;有可…