RNN神经网络和基于Pytorch的实践

   本文主要讲述了RNN循环神经网络的基本原理和利用pytorch进行序列生成的实践,原理的部分主要参考 https://blog.csdn.net/HappyRocking/article/details/83657993,实践的部分主要参考的是《深度学习原理和Pytorch实战》。在这里向作者表示感谢。

本文主要包含以下三个部分

  1. RNN问题引入
  2. RNN基本原理说明
  3. 基于pytorch实现RNN的序列生成任务

1、RNN问题引入

1.1 序列生成问题

对于一段给定的文本,一段给定的语音信号等等,我们都可以将其称为是一个序列。序列中的元素可以是一个符号,一个字符,一个单词等等。以文本序列为例,假设现在我们有一个句子是由W1W2…Wn个单词所构成。其中每一个Wi是一个单词。那么,我们如何根据给定的句子,构建出一个模型来实现自动生成新的序列的功能呢?这个问题就是序列生成问题。

1.2 序列生成问题的实际应用

在自然语言处理的相关任务中,通常可以通过序列生成来完成单词预测,句子生成等任务。
在语音信号处理中,可以通过已经有的声音信号来生成语音句子。
在股票金融中,可以通过将每天的股价构建出一个时间序列来预测未来新的股票价格。

2、RNN基本原理说明

2.1 基本神经网络的结构

基本的神经网络主要包含以下三个部分:
1、输入层:主要负责接收神经网络中的训练和测试数据。
2、隐藏层:主要负责整个神经网络的特征学习。
3、输出层:负责产生模型计算后的结果。
































隐藏层









输出层









输入层







在RNN中,其基本神经网络的结构也是由这三种结构所构成的。在本文所提出的问题中,输入层接收的数据是序列中的一个元素,我们通过RNN网络和当前输入的元素来一步一步生成新的元素。直到整个序列元素生成结束。将模型的产生的结果通过输出层进行输出。

2.2 基本的RNN网络的结构

与我们所熟知的基本的前馈神经网络相比,RNN网络最大的不同之处在于它的网络中,各个隐藏层的节点的之间是具有一定联系的。在一般的前馈神经网络中,其隐藏层的节点的输入数据全部都是来自输入层的。但是在RNN神经网络中,其隐藏层节点的数据来源不仅包含输入层输入的数据,还包含同层的前一个隐藏节点的输出。所以其隐藏层的节点以及对应的输出节点的结构如下。






















输入数据






上一个状态的信息






预测结果










xi









hi









hi-1









oi







其中xi表示当前的输入节点,hi表示当前的隐藏层节点,hi-1表示同层的上一个隐藏状态节点。对于我们的序列生成问题而言,序列中的每一个单词是xi,可以确定的是,每一个单词xi不可能是独立的,各个输入节点的之间是存在一定的关系的。那么就需要我们的网络结构能够捕捉和感知到这种联系信息。我们将其称为单词xi的上下文。根据RNN中隐藏层节点的输入来看,hi单元的输入包含了xi和hi-1这两个部分,xi提供了当前词汇的特征,而hi-1则提供的了上下文的信息。这恰好是我们要完成序列生成所需要的。

根据上面的分析,我们可以得出来基本的RNN神经网络的结构如下:

通过上述的结构,我们不难发现基本的RNN网络机构有这样几个特点:
1、输入层的每一个节点之和隐藏层中一个与其对应的节点相连接,不与其他隐藏层的节点相连接。
2、隐藏层的每一个节点hi的输出受到前一个状态节点和输入节点两个节点的影响。
3、输入节点的数量和输出节点数量相同。

2.3 RNN相关参数的计算

首先,在原来的基本结构图上加入参数:

由上面的图不难发现,RNN中的相关权重主要分为输入层到隐藏层的权重u,隐藏层到输出层的权重v,以及隐藏层节点之间的传播权重w。同时可以发现,输入层每个节点到隐藏层节点的输入权重u相同,同理v和w也相同。
首先的给出RNN前向传播的计算过程:
hi=f(whi−1+uxi+b)h^{i} = f(wh^{i-1} + ux_i + b) hi=f(whi1+uxi+b)
oi=f(vhi+b)o_i = f(vh_i + b) oi=f(vhi+b)
本文主要是面对初学者,所以尽量减少繁杂的数学公式,主要给出上面两个核心公式。hi表示当前的状态节点的信息。oi表示当前节点,b表示偏置,f表示激活函数。w,u,v表示权重参数,xi表示当前输入节点。

2.4 RNN的实际训练

RNN的训练的核心思想也是反向传播的方式,主要应用的是BPTT算法,这是一种对于随时间的反向传播算法,其主要的训练方式也是沿着需要优化的参数的负梯度不断寻找更优的点,直到收敛。BPTT的计算公式在这里就不列出来了,有兴趣的可以参考RNN 与 LSTM 的原理详解这篇文章。

下面介绍一下RNN在序列生成问题中的训练方式,RNN网络从左到右依次读入序列中的一个字符,并且输入一种可能的字符预测,这个预测马上匹配相应下一个字符并得到反馈误差ei。这个误差可以使用交叉熵的方式进行衡量。我们可以每个序列遍历完成之后,将累计的误差进行反向传播,更新所有的权重。进入到下一个序列进行训练。就这样,RNN周而复始的进行训练,直到所有的序列的训练都结束。

虽然RNN在每一个时刻仅仅读入一个元素,但是由于RNN的同层连接,因此多步之前输入的元素可能还会对当前的元素产生影响。所以输入给RNN的相当于是整个句子序列。

2.5 基于Pytorch的RNN的核心代码

import torch
import torch.nn
class RnnCore(nn.Module):def __init__(self,inputSize,hiddenSize,outputSize,layers=1):### inputSize:输入层的大小(一般就是输入节点的数量)# hiddenSize:RNN隐藏层节点的数量# outputSize:输出层元素的数量# layers:隐藏层的层数##super(RnnCore,self).__init__()self.hidden_size = hiddenSizeself.num_layers = layers#下面开始定义一个基本的网络结构#首先是定义输入层 nn.Embedding#通过embedding层的操作,将输入的序列的input_size个节点的序列编码成hidden_size个节点的序列#输入给隐藏层self.embedding = nn.Embedding(inputSize,hiddenSize)#然后定义RNN层### 第一个hidden_size:也就是input_size,指的是RNN网络的输入节点的数量,#经过embedding层之后变成了 hiddensize# hidden_size:RNN层网络的节点的数量#num_layers:rnn的层数#bartch_firts :将数据的第一个维度置位为batch的大小#输入数据x原来的size为 length_seq,bathc_size,input_size#转换之后变为 batch_size,length_seq,input_sizeself.rnn = nn.RNN(hiddenSize,hiddenSize,layers,batch_first=True)#定义全连接的输出层self.fc = nn.Linear(hiddenSize,outputSize)#最后定义softmax层,从outputSize数量的元素中找出最终的预测字符self.softmax = nn.LogSoftmax(dim=1)#下面定义前向传播的的过程### inputs:输入数据# hidden :隐藏层的初始化信息def forward(self,inputs,hidden):#inputs的尺寸为: (batch_size,num_step,data_dim)# num_step:一个序列的长度,扫描完一个序列需要若干个时间步# data_dim :序列中每一个元素的向量维度# x 的尺寸为:batch_size,num_step,hidden_sizex = self.embedding(inputs)output,hidden = self.rnn(x,hidden)#获取最后一个时间步的结果。# output的size (batch_size,hidden_size)output = output[:,-1,:]#将隐藏层的最后结果输入到输出层,获取最后的结果output = self.fc(output)return output,hidden#下面定义隐藏的初始化方式def initHidden(self):# 包括 层数,batch数 以及隐藏层的节点数return Variable(torch.zeros(self.num_layers,1,self,hidden_size))

3 基于Pytorch实现的序列生成实战

3.1 任务描述

观察以下序列:
01
0011
000111
00001111
…………
不难发下其规律:
1、它们都只包含0和1
2、它们的长度不相等
3、0和1的数量是相同的,出现是连续的
4、通用的表示为 ‘0’* n + ‘1’ *n,n表示0和1出现的数量
这个序列在计算机中,我们称其为上下文无关文法,简单的说,就是可以被一组替代规则所生成,而与所处的上下文本身是无关的。

我们举例来说明这种序列的应用
The evidence was convincing 这是一个名词[n] + 动词[v]的结构
继续拓展可以变成
The evidence the layer provided was convincing NNVV结构
…………

3.2任务分析

1、如果出现的序列是0000,那么下一位是0还是1显然不能确定
2、如果出现的序列是00001,那么下一位是1
3、如果序列是00001111,此时0和1的数量相同,显然这个序列下一步应该结束

下面我们使用RNN来完成这个序列生成的任务。主要可以分为训练学习和序列生成两个步骤,在训练阶段,RNN尝试用前面的字符来预测下一个,在生成阶段,RNN会根据给点的种子来生成一个完整的序列。

#encoding=utf-8
import torch
import torch.nn  as nn
import torch.optim
from torch.autograd import Variablefrom collections import Counterimport matplotlib
import matplotlib.pyplot as plt
from matplotlib import rc
import numpy as np#首先构建RNN网络
class SimpleRnn(nn.Module):def __init__(self,input_size,hidden_size,output_size,num_layers=1):super(SimpleRnn,self).__init__()self.hidden_size = hidden_sizeself.num_layers  = num_layers#一个embedding层self.embedding = nn.Embedding(input_size,hidden_size)###pytorch的RNN层,batch_first表示可以让输入的张量表示第一个维度batch的指标#在定义这个部件的时候,需要制定输入节点的数量input_size 隐藏层节点的数量hidden_size#和RNN层的数目#我们世界上使用nn.RNN 来构造多层RNN的,只不过每一层RNN的神经元的数量要相同self.rnn = nn.RNN(hidden_size,hidden_size,num_layers,batch_first= True)#输出全连接层self.fc = nn.Linear(hidden_size,output_size)#最后的logsoftmax层self.softmax = nn.LogSoftmax(dim=1)def forward(self,inputs,hidden):'''基本运算过程:先进行embedding层的计算在将这个向量转换为一个hidden_size维度的向量。input的尺寸为 batch_size,num_step,data_dim'''x = self.embedding(inputs)#此时x的size为batch_size,num_step.hidden_size#从输入层到隐藏层的计算output,hidden = self.rnn(x,hidden)#从输出中选择最后一个时间步的数值,output中包含了所有时间步的结果#output的输出size batch_size,num_step,hidden_sizeoutput = output[:,-1,:]#此时output的尺寸为[batch_szie,hidden_size]#最后输入全连接层output = self.fc(output)#此时output的尺寸为 batch_size,hidden_size#输入softmaxoutput = self.softmax(output)return output,hidden#对隐藏层进行初始化#注意尺寸的大小为layer_size,batch_size,hidden_sizedef initHidden(self):return Variable(torch.zeros(self.num_layers,1,self.hidden_size))#下面是训练以及校验的过程
#首先生成01字符串类的数据以及样本的数量
train_set = []
validset = []
sample = 2000#训练样本中最大的n值
sz = 10#定义n的不同权重,我们按照10:6:4:3:1:1....来配置n=1,2,3,4,5
probablity = 1.0 *np.array([10,6,4,3,1,1,1,1,1,1])#保证n的最大值是sz
probablity = probablity[:sz]#归一化,将权重变成概率
probablity = probablity / sum(probablity)#开始生成sample这么多个样本,
#每一个样本的长度是根据概率来定义的
for m in range(2000):#对于随机生成的字符串,随机选择一个n,n被选择的权重记录在probablity#n表示长度#range生成序列,p表示通过之前定义的probablity的概率分布进行抽样n = np.random.choice(range(1,sz+1),p=probablity)#生成程度为2n这个字符串,用list的形式完成记录inputs = [0]*n + [1]*n#在最前面插入3表示开始字符,在结尾插入2表示结束符inputs.insert(0,3)inputs.append(2)train_set.append(inputs)#在生成sample/10的校验样本
for m in range(sample // 10):n =np.random.choice(range(1,sz+1),p=probablity)inputs = [0] * n + [1] *ninputs.insert(0,3)inputs.append(2)validset.append(inputs)#再生成若干个n特别大的样本用于校验
for m in range(2):n = sz + minputs = [0] * n + [1] *ninputs.insert(0,3)inputs.append(2)validset.append(inputs)#下面是训练过程
#输入的size是4,可能的值为0,1,2,3
#输出size为3 可能为 0,1 2rnn = SimpleRnn(input_size=4, hidden_size=2, output_size=3)
criterion = torch.nn.NLLLoss() #定义交叉熵函数
optimizer = torch.optim.Adam(rnn.parameters(),lr=0.001) #采用Adam算法#重复进行50次试验
num_epoch = 50
results = []
for epoch in range(num_epoch):train_loss = 0np.random.shuffle(train_set)#对每一个序列进行训练for i,seq in enumerate(train_set):loss = 0hidden = rnn.initHidden() #初始化隐含层的神经元、#对于每一个序列的所有字符进行循环for t in range(len(seq)-1):#当前字符作为输入,下一个字符作为标签x = Variable(torch.LongTensor([seq[t]]).unsqueeze(0))# x的size为 batch_size=1。time_steps=1,data_dimension = 1y = Variable(torch.LongTensor([seq[t+1]]))#y的size batch_size =1 data_dimension =1output,hidden = rnn(x,hidden)#output 的size:batch_size,output_size=3#hidden尺寸 layer_size = 1,batch_size = 1,hidden_sizeloss += criterion(output,y)#计算每一个字符的损失数值loss = 1.0 * loss / len(seq)optimizer.zero_grad()loss.backward()optimizer.step()train_loss += loss#打印结果if i>0 and i % 500 ==0:print('第{}轮,第{}个,训练平均loss:{:.2f}'.format(epoch,i,train_loss.data.numpy()/i))#下面在校验集上进行测试valid_loss = 0errors = 0show_out_p =''show_out_t = ''for i,seq in enumerate(validset):loss = 0outstring = ''targets = ''diff = 0hidden = rnn.initHidden()for t in range(len(seq)-1):x = Variable(torch.LongTensor([seq[t]]).unsqueeze(0))y = Variable(torch.LongTensor([seq[t+1]]))output,hidden = rnn(x,hidden)data = output.data.numpy()print("the output is ",data)#获取最大概率输出mm = torch.max(output,1)[1][0]#以字符的形式添加到outputstring中outstring += str(mm.data.numpy())targets += str(y.data.numpy()[0])loss += criterion(output,y) #计算损失函数#输出模型预测字符串和目标字符串之间差异的字符数量diff += 1 - mm.eq(y).data.numpy()[0]loss = 1.0 * loss / len(seq)valid_loss += loss#计算累计的错误数errors += diffif np.random.rand() < 0.1:#以0,1的概率记录一个输出的字符串show_out_p += outstring show_out_t += targets#打印结果print(output[0][2].data.numpy())print('第{}轮,训练loss: {:.2f},校验loss:{:.2f},错误率:{:.2f}'.format(epoch,train_loss.data.numpy()/len(train_set),valid_loss.data.numpy()/len(validset),1.0*errors/len(validset)))print("the show output is: ",show_out_p)print("the show taget is: ",show_out_t)results.append([train_loss.data.numpy()/len(train_set),valid_loss/len(train_set),1.0*errors/len(validset)])

4 RNN网络结构扩展

本部分的内容主要参考参考RNN 与 LSTM 的原理详解这篇文章。根据我们上文所叙述的RNN网络的结构,我们直到RNN的基本网络结构是一个输入单元对应一个隐藏单元,一个隐藏单元对应一个输出单元。那么,我们可以对于这种基本结构进行扩展。

1、多输入,单输出的结构

2、单输入、多出结构

3、编码解码结构

RNN基本原理以及基于Pytorch实践相关推荐

  1. RNN知识+LSTM知识+encoder-decoder+ctc+基于pytorch的crnn网络结构

    一.基础知识: 下图是一个循环神经网络实现语言模型的示例,可以看出其是基于当前的输入与过去的输入序列,预测序列的下一个字符. 序列特点就是某一步的输出不仅依赖于这一步的输入,还依赖于其他步的输入或输出 ...

  2. 银行股价预测——基于pytorch框架RNN神经网络

    银行股价预测--基于pytorch框架RNN神经网络 任务目标 数据来源 完整代码 流程分析 1.导包 2.读入数据并做预处理 3.构建单隐藏层Rnn模型 4.设计超参数,训练模型 5.加载模型,绘图 ...

  3. 学习笔记:深度学习(8)——基于PyTorch的BERT应用实践

    学习时间:2022.04.26~2022.04.30 文章目录 7. 基于PyTorch的BERT应用实践 7.1 工具选取 7.2 文本预处理 7.3 使用BERT模型 7.3.1 数据输入及应用预 ...

  4. EasyBert,基于Pytorch的Bert应用

    向AI转型的程序员都关注了这个号???????????? 机器学习AI算法工程   公众号:datayx EasyBert 基于Pytorch的Bert应用,包括命名实体识别.情感分析.文本分类以及文 ...

  5. 基于PyTorch深度学习无人机遥感影像目标检测、地物分类及语义分割

    随着无人机自动化能力的逐步升级,它被广泛的应用于多种领域,如航拍.农业.植保.灾难评估.救援.测绘.电力巡检等.但同时由于无人机飞行高度低.获取目标类型多.以及环境复杂等因素使得对无人机获取的数据处理 ...

  6. 深度学习必备书籍——《Python深度学习 基于Pytorch》

    作为一名机器学习|深度学习的博主,想和大家分享几本深度学习的书籍,让大家更快的入手深度学习,成为AI达人!今天给大家介绍的是:<Python深度学习 基于Pytorch> 文章目录 一.背 ...

  7. 基于PyTorch的遥感影像、无人机影像的地物分类、目标检测、语义分割和点云分类

    我国高分辨率对地观测系统重大专项已全面启动,高空间.高光谱.高时间分辨率和宽地面覆盖于一体的全球天空地一体化立体对地观测网逐步形成,将成为保障国家安全的基础性和战略性资源.随着小卫星星座的普及,对地观 ...

  8. 从CNN到Transformer:基于PyTorch的遥感影像、无人机影像的地物分类、目标检测、语义分割和点云分类

    更多资讯,请关注:Ai尚研修科研技术动态 公众号 我国高分辨率对地观测系统重大专项已全面启动,高空间.高光谱.高时间分辨率和宽地面覆盖于一体的全球天空地一体化立体对地观测网逐步形成,将成为保障国家安全 ...

  9. 使用google的bert结合哈工大预训练模型进行中文/英文文本二分类,基于pytorch和transformer

    使用bert的哈工大预训练模型进行中文/英文文本二分类,基于pytorch和transformer 前提 简要介绍 开始 导入必要的包和环境 准备并读取数据 导入模型的tokenizer 对数据进行t ...

  10. 【项目实战课】基于Pytorch的SRGAN图像超分辨实战

    欢迎大家来到我们的项目实战课,本期内容是<基于Pytorch的SRGAN图像超分辨实战>.所谓项目实战课,就是以简单的原理回顾+详细的项目实战的模式,针对具体的某一个主题,进行代码级的实战 ...

最新文章

  1. 高并发架构系列:MQ消息队列的12点核心原理总结
  2. c语言编译时检查逻辑错误吗,C语言陷阱与技巧20节,自定义“编译时”assert方法,在代码编译阶段检查“逻辑”错误...
  3. C++将地址转换为字符串
  4. 大王——有趣干货集合
  5. Java中的synchronized
  6. SIMD与NEON概念理解
  7. 基于Simulink的机械式飞行操纵系统建模与仿真
  8. 【XML基础】XML语言简介及简单例子
  9. SU2021下载SketchUp2021最新下载安装教程SU草图大师2021下载安装
  10. 什么是智能家电?消费者不知判定标准
  11. 关于搭建k8s集群遇到的问题与解决方法
  12. 剪辑视频,垂直翻转如何实现
  13. 2022年,全网最真实的软件测试面试题
  14. vwf活性_血管性血友病因子(VWF)应该针对血型设置参考范围吗?
  15. 心率检测实现报告(三)
  16. pandas数据分析常用的一些方法
  17. 安卓、苹果怎么多开微信?微信多开软件
  18. (译)网站加速最佳实践——雅虎35条
  19. AcWing 844.走迷宫
  20. 2020秋招金九银十程序员离职跳槽指南,作为过来人想对你们说这几点

热门文章

  1. c语言写打开程序的脚本,详细解析C语言中的开方实现
  2. 在Linux系统中搭建web服务器
  3. java实现lbs_如何在 Java 中利用 redis 实现 LBS 服务
  4. PBOOT网站后太登录显示验证码错误的解决经验分享
  5. linux 组建raid0教程,用两块硬盘组建RAID0磁盘阵列简单教程(图文详解)
  6. t430服务器查看raid状态,dell t430 raid1教程
  7. 功能测试Ⅲ——缺陷及缺陷管理
  8. 三角形边长求高的c语言函数公式,三角形边长计算公式
  9. DevOps平台的“精益创业”之路
  10. tar命令打包并压缩指定的文件夹并且排除指定的文件