PyTorch学习系列教程:循环神经网络【RNN】

简介: 前两篇推文分别介绍了DNN和CNN,今天本文来介绍深度学习的另一大基石:循环神经网络,即RNN。RNN应该算是与CNN齐名的一类神经网络,在深度学习发展史上具有奠基性地位。注:RNN既用于表达循环神经网络这一类网络,也用于表达标准RNN模块。正常情况下不存在理解歧义,因此本文不加以明确区分。

640.png标准的RNN模块结构


如果说从DNN到CNN的技术演进是为了面向图像数据解决提取空间依赖特征的问题,那么RNN的出现则是为了应对序列数据建模,提取时间依赖特征(这里的"时间"不一定要求具有确切的时间信息,仅用于强调数据的先后性)。


延续前文的行文思路,本文仍然从以下四个方面加以介绍:

  • 什么是RNN
  • RNN为何有效
  • RNN的适用场景
  • 在PyTorch中的使用


01 什么是RNN


循环神经网络,英文Recurrent Neural Network,简写RNN。显然,这里的"循环"是最具特色的关键词。那么,如何理解"循环"二字呢?这首先要从RNN适用的任务——序列数据建模说起。


RNN适用于序列数据建模,典型的序列数据可以是时间序列数据,例如股票价格、天气预报等;也可以是文本序列数据,比如文本情感分析,语言翻译等。这些数据都有一个共同的特点,那就是输入数据除了具有特征维度外,还有一个先后顺序的维度。以股票数据为例,假设一支股票包含[open, high, low, close]四个维度特征,那么其数据结构的示意图为:


640.png


实际上,这就是一个二维的数据矩阵[T, 4],其中T为时序长度,4为特征个数。在机器学习中,单支股票数据只能算作一个样本,进一步考虑多支股票则可构成标准的序列数据集[N, T, 4],其中N为股票数量。


进一步地,针对这样的序列数据集,RNN是怎样进行特征提取的呢?这里,我们有必要先追溯RNN之前的模型——DNN,并给出一个简单的DNN网络架构如下:


640.png


一个具有4个输入特征、单隐藏层的DNN架构


如果我们不考虑股票的时间特性(消除前述数据集的时间维度),则每支股票特征仅有4个,便可以直接利用上述的3层DNN架构完成特征处理,并得到最终的预测结果。上述这一过程可以抽象为:


微信截图_20220528093747.png


这其实恰好就是前文提到的内容:神经网络本质上是在拟合一个复杂的复合函数,其中这个复合函数的输入是X,网络参数是W和b。


那么,当引入了时间维度,输入数据不再是4个特征,而是T×4个特征,且这T组特征具有确切的先后顺序,那么RNN要如何处理呢?一个简单的思路是将上述DNN结构堆叠起来,并循环执行,例如网络结构可能长这样


640.png


RNN处理序列数据示意图


如上述示意图所示,纵向上仍然是一个单纯的DNN网络进行数据处理的流程,而横向上则代表了新增的时间维度也正因为这个时间维度的出现,所以时刻t对应DNN输入数据将来源于两部分:当前时刻t对应的4个输入特征,以及t-1时刻的输出信息,即图中粉色横向宽箭头表示的部分


是否好奇:为啥要将t-1时刻的的输出作为t时刻的输入呢?当然是因为要序列建模!如果不把相邻时刻的输入输出联系起来,那序列先后顺序又该如何体现?


用数学公式加以抽象表示,就是:


微信截图_20220528093934.png


上式中,Wi表达当前输入信息的权重矩阵,Wh表达对前一时刻输入的权重矩阵,且二者在各个时刻是相同的,可理解为面向时间维度的权值共享。


对比该公式和前面DNN中的公式,主要有两点区别:

  • 映射函数的输入数据部分不止是X,还有前一时刻提供的信息ht-1;
  • 模型的直接输出变为中间状态ht,而ht与最终输出y的区别在于:y可以是直接给出最终需要的信息,例如股票预测中的收盘价,但ht为了兼顾相邻时刻之间的信息交互,往往不一定符合最终的输出结果,所以可能需要对ht进一步使用一个DNN网络进行映射得到想要的输出


至此,我们再来看一下开篇中给出的标准RNN模块结构:


640.png


上图中的右侧(unfold部分),横向代表了沿时间维度传播的流程,纵向代表了单个时刻的信息处理流程(各时刻都是一个DNN),其中X代表各时刻的输入特征,ht代表各时刻对应的状态信息,U和V分别为当前输入和前一时刻状态的网络权重,W为由当前状态ht拟合最终需要结果的网络权重。而左侧呢,其实就是把这个循环处理的流程抽象为一个循环结构,也就是那个指向自己的箭头。


这个用指向自己的箭头来表示神经网络的循环,乍一看还挺唬人的!


至此,其实就已经完成了标准RNN的结构介绍。用一个更为广泛使用且抽象的RNN单元结构示意图,表达如下:


640.jpg


标准RNN模块的内部结构


标准RNN结构非常简单,通常来说,在神经网络中过于简单的结构也意味着其表达能力有限。比如说,由于每经过一个时间节点的信息传递,都会将之前的历史信息和当前信息进行线性组合,并通过一个tanh激活函数。tanh激活函数的输出值在(-1,1)之间,这也就意味着,如果时间链路较长时历史信息很可能会被淹没!这也是标准RNN结构最大的问题——不容易表达长期记忆——换句话说,就是时间链路较长的历史信息会变得很小。


于是,一个相对更为复杂、可以提供相对长期记忆的循环神经网络——LSTM应运而生。LSTM:Long-Shot Term Memory network,中文即为长短时记忆网络。顾名思义,这是一个能够兼顾长期和短期记忆的网络。内部是如何实现的呢?LSTM单元结构如下


640.jpg


当然,除了上述这一单元结构示意图,LSTM还往往需要这样一组标准计算公式(
这个等到后续择机再讲吧。。):


640.png


宏观对照标准RNN和LSTM单元结构,可以概括二者间的主要异同点如下:

  • 相同点:各单元结构的输入信息均包含两部分,即当前时刻的输入和前一时刻的输入;输出均为ht
  • 不同点:
  • RNN中接收前一时刻的输入信息只有一种(这部分叫做ht),体现为相邻单元间的单箭头;而在LSTM中接收前一时刻的输入则包含两部分(两部分分别是ht和ct,ct是新引入的部分),体现为相邻单元间的双箭头
  • RNN中的内部结构非常简单,就是两部分向量相加的结果;而LSTM的内部结构相对非常复杂


深入理解LSTM单元的内部结构,建议参考某国外作者的博客:https://colah.github.io/posts/2015-08-Understanding-LSTMs/。本文中的部分网络模块示意图素材也摘自于此(想必也是国内各种介绍循环神经网络时广泛传播的一组内容)。


这里不再班门弄斧,仅简单补充个人理解:

  • 与标准RNN中简单地将前一状态信息与当前信息线性相加不同,LSTM中设计了三个门结构(所谓的门结构就是经过sigmoid处理后的权重矩阵,这个矩阵的取值在(0, 1)之间,越接近于1表示通过的信息越大,越接近于0表示对信息的消减越严重),即遗忘门、输入门和输出门,其中:


  • 遗忘门作用于历史数据输入上,用于控制历史信息对当前输出影响的大小;
  • 输入门作用于当前输入上,用于控制当前输入信息对当前输出影响的大小;
  • 输出门则进一步控制当前输出的大小;


  • LSTM中之所以相较于标准RNN能提供更为长期的记忆,根本原因在于引入了从历史信息直接到达输出的通路(LSTM结构中的上侧贯通线),由于该通路可以不与当前时刻输入同步接受相同的门控作用,所以允许网络学习更为久远的记忆(只需将遗忘门的结果学习得大一些);
  • LSTM除了可以提供长期记忆,还可以提供短期记忆,原因在于专门提供了对当前输入信息的通路(LSTM结构中的下侧通路),但同时该信息又与部分历史信息会和,一并经过输入门的控制,这一部分子结构大体定位相当于标准RNN中的简单处理流程


进一步复盘由RNN到LSTM的改进:虽然LSTM设计的非常精妙,通过三个门结构很好的权衡了历史信息和当前信息对输出结果的影响,但也有一个细节问题——为了控制两部分信息的相对大小,我们是不是只需要1个参数就可以了呢?比如,计算x和y的加权平均时,我们无需为其分别提供两个系数α和β,计算z=αx+βy,而只需z=αx+y就可以,或者写成其归一化形式z=αx+(1-α)y。正是基于这一朴素思想,LSTM的精简版——GRU单元结构顺利诞生!


具体来说,GRU就是将遗忘门和输入门整合为一个更新门,其单元结构如下:


640.jpg

对比下LSTM与GRU的异同点


所以概括一下:从RNN到LSTM的改进是为了增加网络容量,权衡长短期记忆;而从LSTM到GRU的演进则是为了精简模型,去除冗余结构。


上述大体介绍了循环神经网络的起源,并简要介绍了三种最常用的循环神经网络单元结构:RNN、LSTM和GRU。如果说卷积和池化是卷积神经网络中的标志性模块,那么这三个模块无疑就是循环神经网络中的典型代表。


02 RNN为何有效


DNN可以用通用近似定理论证其有效性(更准确地说,通用近似定理适用于所有神经网络,而不止是DNN),CNN也可以抽取若干个特征图直观的表达其卷积的操作结果,但RNN似乎并不容易直接说明其为何会有效。


总体而言,我个人从以下几个方面加以感性理解:

  • 循环神经网络适用于序列数据建模场景,而相较于普通的DNN(包括CNN,其实也是不带有时间依赖信息的单时刻输入特征)而言,其最大的特点在于如何按顺序提取各时刻的新增信息,所以形式上必然是要将当前信息与历史信息做融合
  • 为了保持对所有时刻信息处理流程的一致性,RNN中也有权值共享机制,即网络参数在随时间维度的传播过程中使用同一套网络权重(Wi和Wh),这保证了处理时序信息的公平性
  • 适当的门机制。实际上,标准的RNN单元其记忆能力是有限的,所以谈不上有效;但为何LSTM却非常有效?其核心就在于门的设计上,即允许神经网络通过反向传播算法去自主学习:什么情况下应给历史信息较大的权重——记忆历史;什么情况下又该给当前输入信息较大的权重——更新现在,而这一切都交由网络通过训练集自己去训练


循环神经网络是一个精妙的设计,对于序列建模而言是非常有效的,其历史地位不亚于卷积神经网络。但也值得指出,目前循环神经网络似乎已经有了替代结构——注意力机制——这也是对序列建模非常有效的网络结构,而且无需按时间顺序执行,可以方便的实现并行化,从而提高执行效率——当然,这是后来的故事!


03 RNN适用的场景


论及循环神经网络适用的场景,其实答案是相对明确的,即序列数据建模。进一步地,这里的序列数据既可以是带有时间属性的时序数据,也可以是仅含有先后顺序关系的其他序列数据,例如文本序列等。


与此同时,根据输入数据和预测结果各自序列长度的不同,又衍生了几种不同的任务场景,包括:


  • N to 1:前述的例子都是N个时刻的输入对应1个时刻的输出,例如股票预测,天气预报、文本情感分类等


640.png


  • 1 to N:典型应用是NLP中的作诗、写文章等,即仅提供标题或起始单词,交由模型输出一篇文章


640.png


  • N to N:即给定N个历史时刻的输入数据,同步给出相应的N个输出(注意,这里的输入和输出是同步的),典型的应用场景是词性分析,即逐一输入一段文本中的各个单词,要求输出各单词的词性判断结果


640.png


  • N to M:也就是给定N个历史的输入数据,完全处理后得到M个输出,其中M个输出与N个输入具有先后顺序,输入和输出是异步的(也叫Seq2Seq)。典型的场景是机器翻译:给定N个英文单词,翻译结果是M个中文词语,多步的股票预测也符合这种场景


640.png


04 在PyTorch中的使用


对于标准RNN、LSTM和GRU三种典型的循环神经网络单元,PyTorch中均有相应的实现。对使用者来说,无需过度关心各单元内在的结构,因为三者几乎是具有相近的封装形式,无论是类的初始化参数,还是对输入和输出数据的形式上。


所以,这里以LSTM为例加以阐述。首先来看其类的签名文档:


640.png


上述文档仅给出了LSTM的理论介绍,主要是陈列了其内部结构的几个相关理论计算公式。而对于类的初始化参数方面,LSTM并未直接给出形参列表,而是使用*arg和**kwargs来接受自定义的传入参数,其中,常用的参数包括


640.png


具体来说:

  • input_size:输入数据的特征维度,例如在前面举的股票例子中包括open、high、low和close共4个特征,即input_size=4
  • hidden_size:前面提到,在每个时间截面循环神经单元其实都是一个DNN结构,默认情况下该DNN只有单个隐藏层,hidden_size即为该隐藏层神经元的个数,在前述的股票例子中隐藏层神经元数量为3,即hidden_size=3
  • num_layers:虽然RNN、LSTM和GRU这些循环单元的的重点是构建时间维度的序列依赖信息,但在单个事件截面的特征处理也可以支持含有更多隐藏层的DNN结构,默认状态下为1
  • bias:类似于nn.Linear中的bias参数,用于控制是否拟合偏置项,默认为bias=True,即拟合偏置项
  • batch_first:用于控制输入数据各维度所对应的含义,前面举例中一直用的示例维度是(N, T, 4),即分别对应样本数量、时序长度和特征数量,这种可能比较符合部分人的思维习惯(包括我自己也是如此),但实际上LSTM更喜欢的方式是将序列维度放于第一个维度,此时即为(T, N, 4)。batch_first默认为False,即样本数量为第二个维度,序列长度为第一个维度,(seq_len, batch, input_size)
  • dropout:用于控制全连接层后面是否设置dropout单元,增加dropout有时是为了增强模型的泛化能力
  • bidirectional:上述所介绍LSTM等都是沿着序列的正向进行处理和传播,正向传播更容易记住靠后的序列信息,而忘记前面的信息;所以LSTM的一种改进就是双向循环单元结构,即首先沿正向处理一遍,再逆向处理一遍。bidirectional参数即用于控制是单向还是双向,默认为bidirectional=False,即仅正向处理


接下来是输入和输出信息:


640.png640.png


大体来看,输入和输出具有相近的形式(这也是为啥可以循环处理的原因),对于LSTM来说包含三部分,即:


  • input/output:(L, N, H_in/H_out),其中L为序列长度,N为样本数量,H_in和H_out分别为输入数据和输出结果的特征维度,即前面初始化中用到的input_size和hidden_size


  • h_n和c_n,分别对应最后时刻循环单元对应的隐藏状态和细胞状态(LSTM的相邻单元之间有两条连接线,上面的代表细胞状态c_n,下面代表隐藏状态h_n),如果是RNN或者GRU则只有隐藏状态h_n


  • 进一步地,output与h_n的联系和区别是什么呢?output是区分时间维度的输出序列,记录了各时刻所对应DNN的最终输出结果,L个序列长度对应了L个时刻的输出;而h_n则只记录最后一个序列所对应的隐藏层输出,所以只有一个时刻的结果,但如果num_layers>1或者bidirectional设置为True时,则也会有多个输出结果。当在默认情况下,即num_layers=1,bidirectional=False时,output[-1]=h_n


关于循环神经网络的介绍就到这里,后续将基于股票数据集提供一个实际案例。


640.png





目录
相关文章
|
1月前
|
存储 物联网 PyTorch
基于PyTorch的大语言模型微调指南:Torchtune完整教程与代码示例
**Torchtune**是由PyTorch团队开发的一个专门用于LLM微调的库。它旨在简化LLM的微调流程,提供了一系列高级API和预置的最佳实践
158 59
基于PyTorch的大语言模型微调指南:Torchtune完整教程与代码示例
|
2月前
|
PyTorch Linux 算法框架/工具
pytorch学习一:Anaconda下载、安装、配置环境变量。anaconda创建多版本python环境。安装 pytorch。
这篇文章是关于如何使用Anaconda进行Python环境管理,包括下载、安装、配置环境变量、创建多版本Python环境、安装PyTorch以及使用Jupyter Notebook的详细指南。
314 1
pytorch学习一:Anaconda下载、安装、配置环境变量。anaconda创建多版本python环境。安装 pytorch。
|
2月前
|
机器学习/深度学习 数据采集 存储
时间序列预测新突破:深入解析循环神经网络(RNN)在金融数据分析中的应用
【10月更文挑战第7天】时间序列预测是数据科学领域的一个重要课题,特别是在金融行业中。准确的时间序列预测能够帮助投资者做出更明智的决策,比如股票价格预测、汇率变动预测等。近年来,随着深度学习技术的发展,尤其是循环神经网络(Recurrent Neural Networks, RNNs)及其变体如长短期记忆网络(LSTM)和门控循环单元(GRU),在处理时间序列数据方面展现出了巨大的潜力。本文将探讨RNN的基本概念,并通过具体的代码示例展示如何使用这些模型来进行金融数据分析。
346 2
|
1月前
|
并行计算 监控 搜索推荐
使用 PyTorch-BigGraph 构建和部署大规模图嵌入的完整教程
当处理大规模图数据时,复杂性难以避免。PyTorch-BigGraph (PBG) 是一款专为此设计的工具,能够高效处理数十亿节点和边的图数据。PBG通过多GPU或节点无缝扩展,利用高效的分区技术,生成准确的嵌入表示,适用于社交网络、推荐系统和知识图谱等领域。本文详细介绍PBG的设置、训练和优化方法,涵盖环境配置、数据准备、模型训练、性能优化和实际应用案例,帮助读者高效处理大规模图数据。
48 5
|
1月前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
|
2月前
|
机器学习/深度学习 缓存 PyTorch
pytorch学习一(扩展篇):miniconda下载、安装、配置环境变量。miniconda创建多版本python环境。整理常用命令(亲测ok)
这篇文章是关于如何下载、安装和配置Miniconda,以及如何使用Miniconda创建和管理Python环境的详细指南。
477 0
pytorch学习一(扩展篇):miniconda下载、安装、配置环境变量。miniconda创建多版本python环境。整理常用命令(亲测ok)
|
3月前
|
机器学习/深度学习
小土堆-pytorch-神经网络-损失函数与反向传播_笔记
在使用损失函数时,关键在于匹配输入和输出形状。例如,在L1Loss中,输入形状中的N代表批量大小。以下是具体示例:对于相同形状的输入和目标张量,L1Loss默认计算差值并求平均;此外,均方误差(MSE)也是常用损失函数。实战中,损失函数用于计算模型输出与真实标签间的差距,并通过反向传播更新模型参数。
|
2月前
|
机器学习/深度学习 数据采集 自然语言处理
【NLP自然语言处理】基于PyTorch深度学习框架构建RNN经典案例:构建人名分类器
【NLP自然语言处理】基于PyTorch深度学习框架构建RNN经典案例:构建人名分类器
|
2月前
|
机器学习/深度学习 存储 自然语言处理
深度学习入门:循环神经网络------RNN概述,词嵌入层,循环网络层及案例实践!(万字详解!)
深度学习入门:循环神经网络------RNN概述,词嵌入层,循环网络层及案例实践!(万字详解!)
|
4月前
|
自然语言处理 C# 开发者
Uno Platform多语言开发秘籍大公开:轻松驾驭全球用户,一键切换语言,让你的应用成为跨文化交流的桥梁!
【8月更文挑战第31天】Uno Platform 是一个强大的开源框架,允许使用 C# 和 XAML 构建跨平台的原生移动、Web 和桌面应用程序。本文详细介绍如何通过 Uno Platform 创建多语言应用,包括准备工作、设置多语言资源、XAML 中引用资源、C# 中加载资源以及处理语言更改。通过简单的步骤和示例代码,帮助开发者轻松实现应用的国际化。
44 1