LSTM(长短期记忆网络)详解

1️⃣ LSTM介绍

标准的RNN存在梯度消失梯度爆炸问题,无法捕捉长期依赖关系。那么如何理解这个长期依赖关系呢?

例如,有一个语言模型基于先前的词来预测下一个词,我们有一句话 “the clouds are in the sky”,基于"the clouds are in the",预测"sky",在这样的场景中,预测的词和提供的信息之间位置间隔是非常小的,如下图所示,RNN可以捕捉到先前的信息。
在这里插入图片描述
然而,针对复杂场景,我们有一句话"I grew up in France… I speak fluent French","French"基于"France"推断,但是它们之间的间隔很远很远,RNN 会丧失学习到连接如此远信息的能力。这就是长期依赖关系。

为了解决该问题,LSTM通过引入三种门遗忘门输入门输出门控制信息的流入和流出,有助于保留长期依赖关系,并缓解梯度消失【注意:没有梯度爆炸昂】。LSTM在1997年被提出


2️⃣ 原理

下面这张图是标准的RNN结构:

  • x t x_t xt是t时刻的输入
  • s t s_t st是t时刻的隐层输出, s t = f ( U ⋅ x t + W ⋅ s t − 1 ) s_t=f(U\cdot x_t+W\cdot s_{t-1}) st=f(Uxt+Wst1),f表示激活函数, s t − 1 s_{t-1} st1表示t-1时刻的隐层输出
  • h t h_t ht是t时刻的输出, h t = s o f t m a x ( V ⋅ s t ) h_t=softmax(V\cdot s_t) ht=softmax(Vst)
    在这里插入图片描述

LSTM的整体结构如下图所示,第一眼看到,反正我是看不懂。前面讲到LSTM引入三种门遗忘门输入门输出门,现在我们逐一击破,一个个分析一下它们到底是什么。
在这里插入图片描述
这是3D视角的LSTM:
在这里插入图片描述
首先来看遗忘门,也就是下面这张图:

在这里插入图片描述

遗忘门输入包含两部分

  • s t − 1 s_{t-1} st1:表示t-1时刻的短期记忆(即隐层输出),在LSTM中当前时间步的输出 h t − 1 h_{t-1} ht1就是隐层输出 s t − 1 s_{t-1} st1
  • x t x_t xt:表示t时刻的输入

遗忘门输出为 f t f_t ft,公式表示为:
f t = σ ( W f ⋅ [ h t − 1 , x t ] + b f ) f_t=\sigma\left(W_f\cdot[h_{t-1},x_t] + b_f\right) ft=σ(Wf[ht1,xt]+bf)
其中, W f W_f Wf b f b_f bf是遗忘门的参数, [ s t − 1 , x t ] [s_{t-1},x_t] [st1,xt]表示concat操作。 σ ( ) \sigma() σ()表示sigmoid函数。

遗忘门定我们会从长期记忆中丢弃什么信息【理解为:删除什么日记】,输出一个在 0 到 1 之间的数值,1 表示“完全保留”,0 表示“完全舍弃”。

然后来看输入门
在这里插入图片描述

输入门的输入包含两部分:

  • s t − 1 s_{t-1} st1:表示t-1时刻的短期记忆
  • x t x_t xt:表示t时刻的输入

输入门的输出为新添加的内容 i t ∗ C ~ t i_t * \tilde{C}_t itC~t,其具体操作为:
i t = σ ( W i ⋅ [ s t − 1 , x t ] + b i ) C ~ t = tanh ⁡ ( W C ⋅ [ s t − 1 , x t ] + b C ) \begin{aligned}i_{t}&=\sigma\left(W_i\cdot[s_{t-1},x_t] + b_i\right)\\\tilde{C}_{t}&=\tanh(W_C\cdot[s_{t-1},x_t] + b_C)\end{aligned} itC~t=σ(Wi[st1,xt]+bi)=tanh(WC[st1,xt]+bC)

输入门决定什么样的新信息被加入到长期记忆(即细胞状态)中【理解为:添加什么日记】。

然后,我们来更新长期记忆,将 C t − 1 C_{t-1} Ct1更新为 C t C_t Ct。我们把旧状态 C t − 1 C_{t-1} Ct1与遗忘门的输出 f t f_t ft相乘,忘记一些东西。接着加上输入门的输出 i t ∗ C ~ t i_t * \tilde{C}_t itC~t,新加一些东西,最终得到新的长期记忆 C t C_t Ct。具体操作为:
在这里插入图片描述

C t = f t ∗ C t − 1 + i t ∗ C ~ t C_t=f_t*C_{t-1}+i_t*\tilde{C}_t Ct=ftCt1+itC~t

最后来看输出门
在这里插入图片描述

输出门的输入包含:

  • s t − 1 s_{t-1} st1:表示t-1时刻的短期记忆
  • x t x_t xt:表示t时刻的输入
  • c t c_t ct:更新后的长期记忆

输出门的输出为 h t h_{t} ht s t s_{t} st h t h_t ht作为当前时间步的输出, s t s_{t} st当做短期记忆输入到t+1,其具体操作为:
o t = σ ( W o [ s t − 1 , x t ] + b o ) s t = h t = o t ∗ t a n h ( C t ) \begin{aligned}&o_{t}=\sigma\left(W_{o} \left[ s_{t-1},x_{t}\right] + b_{o}\right)\\&s_{t}=h_{t}=o_{t}*\mathrm{tanh}\left(C_{t}\right)\end{aligned} ot=σ(Wo[st1,xt]+bo)st=ht=ottanh(Ct)

首先,我们运行一个 sigmoid 层来确定长期记忆的哪个部分将输出出去。接着,我们把长期记忆通过 tanh 进行处理(得到一个在-1到1之间的值)并将它和 o t o_{t} ot相乘,最终将输出copy成两份 h t h_t ht s t s_{t} st h t h_t ht作为当前时间步的输出, s t s_{t} st当做短期记忆输入到t+1。

LSTM的结构分析完了,那为什么LSTM能够缓解梯度消失呢?

我前面写的这篇文章中介绍了为什么RNN会有梯度消失和爆炸:点这里查看

主要原因是反向传播时,梯度中有这一部分:
∏ j = k + 1 3 ∂ s j ∂ s j − 1 = ∏ j = k + 1 3 t a n h ′ W \prod_{j=k+1}^3\frac{\partial s_j}{\partial s_{j-1}}=\prod_{j=k+1}^3tanh^{'}W j=k+13sj1sj=j=k+13tanhW
LSTM的作用就是让 ∂ s j ∂ s j − 1 \frac{\partial s_j}{\partial s_{j-1}} sj1sj≈1

在LSTM里,隐藏层的输出换了个符号,从 s s s变成 C C C了,即 C t = f t ∗ C t − 1 + i t ∗ C ~ t C_t=f_t*C_{t-1}+i_t*\tilde{C}_t Ct=ftCt1+itC~t。注意, f t f_t ft , i t 和 C ~ t i_{t\text{ 和}}\tilde{C}_t it C~t 都是 C t − 1 C_{t-1} Ct1的复合函数(因为它们都和 h t − 1 h_{t-1} ht1有关,而 h t − 1 h_{t-1} ht1又和 C t − 1 C_{t-1} Ct1有关)。因此我们来求一下 ∂ C t ∂ C t − 1 \frac{\partial C_t}{\partial C_{t-1}} Ct1Ct
∂ C t ∂ C t − 1 = f t + ∂ f t ∂ C t − 1 ⋅ C t − 1 + … \frac{\partial C_t}{\partial C_{t-1}}=f_t+\frac{\partial f_t}{\partial C_{t-1}}\cdot C_{t-1}+\ldots Ct1Ct=ft+Ct1ftCt1+

后面的我们就不管了,展开求导太麻烦了。这里面 f t f_t ft是遗忘门的输出,1表示完全保留旧状态,0表示完全舍弃旧状态,如果我们把 f t f_t ft设置成1或者是接近于1,那 ∂ C t ∂ C t − 1 \frac{\partial C_t}{\partial C_{t-1}} Ct1Ct就有梯度了。因此LSTM可以一定程度上缓解梯度消失,然而如果时间步很长的话,依然会存在梯度消失问题,所以只是缓解

注意:LSTM可以缓解梯度消失,但是梯度爆炸并不能解决,因为LSTM不影响参数W


3️⃣ 代码

# 创建一个LSTM模型
import torch
import torch.nn as nn
import torch.nn.functional as Fclass LSTM(nn.Module):def __init__(self,input_size,hidden_size,num_layers,output_size):super().__init__()self.num_layers=num_layersself.hidden_size=hidden_size# 定义LSTM层# batch_first=True则输入形状为(batch, seq_len, input_size)self.lstm=nn.LSTM(input_size,hidden_size,num_layers,batch_first=True)# 定义全连接层,用于输出self.fc=nn.Linear(hidden_size,output_size)def forward(self, x):# self.lstm(x)会返回两个值# out:形状为 (batch,seq_len,hidden_size)# 隐层状态和细胞状态:形状为 (batch, num_layers, hidden_size);在这里,我们忽略隐层状态和细胞状态的输出,因此使用了占位符out, _ = self.lstm(x)out = self.fc(out)return outif __name__=='__main__':input_size=10hidden_size=64num_layers=1output_size=1net=LSTM(input_size,hidden_size,num_layers,output_size)# x的形状为(batch_size, seq_len, input_size)x=torch.randn(16,8,input_size)out=net(x)print(out.shape)

输出结果为:

torch.Size([16, 8, 1]),表示有16个batch,对于每个batch,有8个时间步,每个时间步的output大小为1

4️⃣ 总结

  • 思考一个问题,对于多层LSTM,如何理解呢?
    在这里插入图片描述
    注意:图中颜色相同的其实表达的值一样, h = s h=s h=s

    1. 第一层 LSTM 首先初始隐层状态 s 0 l a y e r 1 s^{layer1}_0 s0layer1和细胞状态 c 0 l a y e r 1 c^{layer1}_0 c0layer1,然后输入 x t − 1 x_{t-1} xt1 生成隐层状态和输出 s t − 1 l a y e r 1 = h t − 1 l a r y e r 1 s^{layer1}_{t-1}=h_{t-1}^{laryer1} st1layer1=ht1laryer1和细胞状态 c t − 1 l a y e r 1 c^{layer1}_{t-1} ct1layer1
    2. 第二层 LSTM首先初始隐层状态 s 0 l a y e r 2 s^{layer2}_0 s0layer2和细胞状态 c 0 l a y e r 2 c^{layer2}_0 c0layer2,然后接收第一层的输出 h t − 1 l a r y e r 1 h_{t-1}^{laryer1} ht1laryer1作为输入,生成 s t − 1 l a y e r 2 = h t − 1 l a r y e r 2 s^{layer2}_{t-1}=h_{t-1}^{laryer2} st1layer2=ht1laryer2 c t − 1 l a y e r 2 c^{layer2}_{t-1} ct1layer2
    3. 第N层 LSTM首先初始隐层状态 s 0 l a y e r N s^{layerN}_0 s0layerN和细胞状态 c 0 l a y e r N c^{layerN}_0 c0layerN,然后接收第N-1层的输出 h t − 1 l a r y e r N − 1 h_{t-1}^{laryer N-1} ht1laryerN1作为输入,生成最终的 s t − 1 l a y e r N = h t − 1 l a r y e r 2 s^{layerN}_{t-1}=h_{t-1}^{laryer2} st1layerN=ht1laryer2 c t − 1 l a y e r N c^{layerN}_{t-1} ct1layerN
  • 为什么需要多层LSTM?
    多层 LSTM 通过增加深度来增强模型的表示能力和复杂度,能够学习到更高阶、更抽象的特征

  • 通过控制遗忘门的输出 f t f_t ft来控制梯度,以缓解梯度消失问题,但不能缓解梯度爆炸

5️⃣ 参考

  • 理解 LSTM 网络

  • 【LSTM长短期记忆网络】3D模型一目了然,带你领略算法背后的逻辑

  • 关于RNN的梯度消失&爆炸问题

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

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

相关文章

Servlet⽣生命周期超级细(笔记)

简介: 讲解Servlet的⽣生命周期 Servlet 接⼝口⾥里里⾯面有5个⽅方法,其中三个⽣生命周期⽅方法和两个普通⽅方法 1. 加载和初始化阶段 过程: 当一个 Servlet 第一次被客户端请求时或者服务器启动时,Servlet 容器会加载该 Servlet 类&…

HBuilder(uniapp) 配置android模拟器

HBuilder(uniapp) 配置android模拟器 选择完成之后,点击ok,再次点击Configure—》AVD Manager

基于麒麟服务器操作系统V10版本,部署Nginx服务、MySql服务搭建PHP环境,实现静态网站平台的搭建。

一、环境准备 关闭防火墙。 查看当前防火墙的状态 systemctl status firewalld Copy 如果防火墙的状态参数是inactive,则防火墙为关闭状态。 如果防火墙的状态参数是active,则防火墙为开启状态。 关闭防火墙。 如果您想临时关闭防火墙,需要运行以下命令: systemctl…

用OMS进行 OceanBase 租户间数据迁移的测评

基本概念 OceanBase迁移服务(,简称OMS),可以让用户在同构或异构 RDBMS 与OceanBase 数据库之间进行数据交互,支持数据的在线迁移,以及实时增量同步的复制功能。 OMS 提供了可视化的集中管控平台&#xff…

Hadoop生态圈框架部署(六)- HBase完全分布式部署

文章目录 前言一、Hbase完全分布式部署(手动部署)1. 下载Hbase2. 上传安装包3. 解压HBase安装包4. 配置HBase配置文件4.1 修改hbase-env.sh配置文件4.2 修改hbase-site.xml配置文件4.3 修改regionservers配置文件4.4 删除hbase中slf4j-reload4j-1.7.33.j…

108. UE5 GAS RPG 实现地图名称更新和加载关卡

在这一篇里,我们将实现对存档的删除功能,在删除时会有弹框确认。接着实现获取玩家的等级和地图名称和存档位置,我们可以通过存档进入游戏,玩家在游戏中可以在存档点存储存档。 实现删除存档 删除存档需要一个弹框确认&#xff0…

移除元素(leetcode 27)

给定一个数组,在数组中删除等于这个目标值的元素,然后返回新数组的大小 数组理论: 数组是一个连续的类型相近的元素的一个集合,数组上的删除是覆盖,只能由后面的元素进行覆盖,而不能进行真正意义上的地理位…

【征稿倒计时!华南理工大学主办 | IEEE出版 | EI检索稳定】2024智能机器人与自动控制国际学术会议 (IRAC 2024)

#华南理工大学主办!#IEEE出版!EI稳定检索!#组委阵容强大!IEEE Fellow、国家杰青等学术大咖领衔出席!#会议设置“优秀论文”“优秀青年学者报告”“优秀海报”等评优奖项 2024智能机器人与自动控制国际学术会议 &#…

【React】状态管理之Zustand

🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 ​💫个人格言: "如无必要,勿增实体" 文章目录 状态管理之Zustand引言1. Zustand 的核心特点1.1 简单直观的 API1.2 无需 Provi…

【ict基础软件赛道】真题-50%openGauss

题目取自赛前测试链接 OpenGauss安装前使用哪个工具检查环境是否符合安装哪个功能不是gs_guc工具提供的opengauss数据库逻辑复制的特点描述正确的是opengauss的全密态数据库等值查询能力描述正确的是哪个不属于ssh客户端工具opengauss三权分立说法正确的是opengauss wdr snapsh…

Python酷库之旅-第三方库Pandas(218)

目录 一、用法精讲 1021、pandas.DatetimeIndex.inferred_freq属性 1021-1、语法 1021-2、参数 1021-3、功能 1021-4、返回值 1021-5、说明 1021-6、用法 1021-6-1、数据准备 1021-6-2、代码示例 1021-6-3、结果输出 1022、pandas.DatetimeIndex.indexer_at_time方…

【miniMax开放平台-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被机器执行自动化程序攻击,存在如下风险: 暴力破解密码,造成用户信息泄露,不符合国家等级保护的要求。短信盗刷带来的拒绝服务风险 ,造成用户无法登陆、注册,大量收到垃圾短信的…

树状数组+概率论,ABC380G - Another Shuffle Window

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 G - Another Shuffle Window 二、解题报告 1、思路分析 不难用树状数组计…

MySQL:表设计

表的设计 从需求中获得类,类对应到数据库中的实体,实体在数据库中表现为一张一张的表,类中的属性就对应着表中的字段(也就是表中的列) 表设计的三大范式: 在数据库设计中,三大范式&#xff0…

网盘聚合搜索项目Aipan(爱盼)

本文软件由网友 刘源 推荐; 简介 什么是 Aipan(爱盼) ? Aipan(爱盼)是一个基于 Vue 和 Nuxt.js 技术构建的开源网盘搜索项目。其主要目标是为用户提供一个能够自主拥有和管理的网盘搜索网站。该项目持续维护和更新&a…

当微软windows的记事本被AI加持

1985年,微软发布了Windows 1.0,推出了一款革命性的产品:记事本(Notepad)。这款软件旨在鼓励使用一种未来主义的新设备——鼠标,并让人们可以不依赖VI等键盘工具就能书写文本和编写代码。记事本因其简洁和高…

Dubbo 3.x源码(25)—Dubbo服务引用源码(8)notify订阅服务通知更新

基于Dubbo 3.1,详细介绍了Dubbo服务的发布与引用的源码。 此前我们学习了接口级的服务引入订阅的refreshInterfaceInvoker方法,当时还有最为关键的notify服务通知更新的部分源码没有学习,本次我们来学习notify通知本地服务更新的源码。 Dubb…

自存 关于RestController请求传参数 前端和后端相关

1.Get请求 Get请求传递参数一般是 1.通过PathVariable来映射 URL 绑定的占位符 后端 GetMapping("test/{id}")public R test(PathVariable Integer id){System.out.println(id);return R.success(id);}前端 export function test(id:any){return request({url:&q…

Python练习27

Python日常练习 题目: 编写函数,接收一个正偶数a,任何一个都可以分解成两个 素数之和,如果存在多组符合条件的素数,则全部输出。 例如: 【请输入一个正偶数】50 50 3 47 50 7 43 50 13 37 5…

查询DBA_FREE_SPACE缓慢问题

这个是一个常见的问题,理论上应该也算是一个bug,在oracle10g,到19c,我都曾经遇到过;今天在给两套新建的19C RAC添加监控脚本时,又发现了这个问题,在这里记录一下。 Symptoms 环境:…