深度学习5 -- 循环神经网络(代码实现篇+付详细流程文件)

news/2024/11/25 2:46:02/

引言

  • 本文是使用pytorch对循环神经网络RNN(Recurrent Neural Network)的代码实现,作为之前介绍RNN原理的一个代码补充。

  • RNN原理介绍

  • 本文代码相关介绍相对较为详细,也为自己的一个学习过程,对RNN的理解还是比较浅显,有错误的地方欢迎指正。

简述RNN结构

  • 详细原理介绍可以参考上述链接,此处简述RNN结构实为方便理解后面代码分析部分。
  • 单向循环神经网络
    • RNN的应用场景一般是当前输入与前一个输入是有联系的,所以下图x部分的参数会与X_t-1有关
      • x:数据输入
      • u:输入层到隐藏层的权重
      • s:隐藏层的输出结果
      • v:隐藏层到输出层的权重
      • w:上一次的值S_t-1作为这一次输入的权重矩阵
      • 关于数学计算公式
  • 双向循环神经网络
    • 单项循环神经网络只能作为与前一个数据建立连接,双向循环神经网络则可以同后一个数据建立连接
    • 当然这个隐藏层只有一层,也可以多加几层构成深度循环神经网络

RNN实例

  • 关于实现RNN的实例,我觉得有一个比较简单但是又比较符合RNN使用场景的序列数据例子,那就是正弦和余弦函数。
    • 该例子来自参考资料1
    • 以sin函数值作为输入,其对应的cos函数值作为输出,在相同sin值的情况下会对应不同的cos值的情况,这就是因为输出结果不仅要看输入数据,还要依赖前后值的信息,且FC,CNN就不适合该例子了。

Pytorch中RNN函数torch.nn.RNN()参数介绍

  • 参数其实主要写input_size和hidden_size,其他的参数使用默认的即可,当然有特殊需要再设置

  • 其重要参数解析如下

    参数含义
    input_size输入RNN的维度/输入x的特征数量
    hidden_size隐藏层节点数量/隐藏层的特征数量
    num_layersRNN的层数
    nonlinearity指定激活函数使用tanh还是relu。默认是tanh
    bias如果是 False , 那么 RNN 层就不会使用偏置权重 b_ih 和 b_hh, 默认: True
    batch_first如果 True, 那么输入 Tensor 的 shape 应该是 (batch, seq, feature),并且输出也是一样(详见参3)
    dropout如果值非零, 那么除了最后一层外, 其它层的输出都会套上一个 dropout 层
    bidirectional如果 True , 将会变成一个双向 RNN, 默认为 False
  • 主要是介绍了节点数的一些细节 参考资料2

  • 主要介绍了数据维度的一些细节,介绍的挺详细的,可惜我还是没看懂,以后看懂了补上参考资料3

  • 贴两个询问ChatGPT的截图,作为比对
    ChatGPT3.5
    在这里ChatGPT4插入图片描述

RNN代码分析

  • 具体print输出结果以及打印出来的结果见文章末尾的测试文件资源)
  • 测试文件中还包含几个函数测试的结果,用来辅助分析代码
  • 注:个人分析的注释可能也有错误,仅供参考,且数据维度的变换那里目前理解能力有限,思考了很久还是一知半解,待后续有能力完全解析再做补充。
  • 该代码是他人写好的代码,并不是本人的实现代码,主要是确实个人能力不足目前难以自己写出来…
# encoding:utf-8
import torch
import numpy as np
import matplotlib.pyplot as plt
from torch import nn# 定义RNN模型(可以类别下方RNN简单测试代码理解)
class Rnn(nn.Module):def __init__(self, input_size):super(Rnn, self).__init__()# 定义RNN网络## hidden_size是自己设置的,貌似取值都是32,64,128这样来取值## num_layers是隐藏层数量,超过2层那就是深度循环神经网络了self.rnn = nn.RNN(input_size=input_size,hidden_size=32,num_layers=1,batch_first=True  # 输入形状为[批量大小, 数据序列长度, 特征维度])# 定义全连接层self.out = nn.Linear(32, 1)# 定义前向传播函数def forward(self, x, h_0):r_out, h_n = self.rnn(x, h_0)# print("数据输出结果;隐藏层数据结果", r_out, h_n)# print("r_out.size(), h_n.size()", r_out.size(), h_n.size())outs = []# r_out.size=[1,10,32]即将一个长度为10的序列的每个元素都映射到隐藏层上for time in range(r_out.size(1)):  # print("映射", r_out[:, time, :])# 依次抽取序列中每个单词,将之通过全连接层并输出.r_out[:, 0, :].size()=[1,32] -> [1,1]outs.append(self.out(r_out[:, time, :])) # print("outs", outs)# stack函数在dim=1上叠加:10*[1,1] -> [1,10,1] 同时h_n已经被更新return torch.stack(outs, dim=1), h_n TIME_STEP = 10
INPUT_SIZE = 1
LR = 0.02
model = Rnn(INPUT_SIZE)
print(model)# 此处使用的是均方误差损失
loss_func = nn.MSELoss()  
optimizer = torch.optim.Adam(model.parameters(), lr=LR)h_state = None  # 初始化h_state为Nonefor step in range(300):# 人工生成输入和输出,输入x.size=[1,10,1],输出y.size=[1,10,1]start, end = step * np.pi, (step + 1)*np.pi# np.linspace生成一个指定大小,指定数据区间的均匀分布序列,TIME_STEP是生成数量steps = np.linspace(start, end, TIME_STEP, dtype=np.float32) # print("steps", steps)x_np = np.sin(steps)y_np = np.cos(steps)# print("x_np,y_np", x_np, y_np)# 从numpy.ndarray创建一个张量 np.newaxis增加新的维度x = torch.from_numpy(x_np[np.newaxis, :, np.newaxis])y = torch.from_numpy(y_np[np.newaxis, :, np.newaxis])# print("x,y", x,y)# 将x通过网络,长度为10的序列通过网络得到最终隐藏层状态h_state和长度为10的输出prediction:[1,10,1]prediction, h_state = model(x, h_state)h_state = h_state.data  # 这一步只取了h_state.data.因为h_state包含.data和.grad 舍弃了梯度# print("precision, h_state.data", prediction, h_state)# print("prediction.size(), h_state.size()", prediction.size(), h_state.size())# 反向传播loss = loss_func(prediction, y)optimizer.zero_grad()loss.backward()# 更新优化器参数optimizer.step()# 对最后一次的结果作图查看网络的预测效果
plt.plot(steps, y_np.flatten(), 'r-')
plt.plot(steps, prediction.data.numpy().flatten(), 'b-')
plt.show()

另外一种构建RNN的方法

  • 除了上面介绍的torch.nn.RNN()外,还有RNNCell方法,使用方法如下:
  • cell = torch.nn.RNNCell(input_size=input_size, hidden_size=hidden_size)
  • hidden = cell(input, hidden)
    • input_size与hidden_size与上面的参数介绍的含义是一致的,但是输入类型不一样。
    • 和RNN不同的是RNN cell要自己写处理序列的循环,个人通俗理解就是,比如要处理3个句子,每个句子10个单词,每个单词用20长度的向量表示,如果使用nn.RNN(),那输出的tensor的shape应该是[10,3,20],而使用nn.RNNCell()需要将序列上的每个时刻分开处理,即送入的tensor的shape是[3,100],然后将该单元运行10次,灵活的代价当然就是比较麻烦。
    • 关于hidden_size输入shape与input_size同样有变化,概括来说就是(可以看上面代码的具体解析那有关于维度的详细分析)
    • input:batch_size*input_size
    • 输入的hidden: batch_size*hidden_size
    • 输出的hidden: batch_size*hidden_size

其他参考资料

  • 数据集为MNIST使用RNN实现(未测试,找资料时候看到了仅供参考)

M1

M2

  • RNN两种实现方式的区别以及代码实现比较

RR1

RR2

  • 本文代码详细测试过程文件(待上传)

http://www.ppmy.cn/news/383993.html

相关文章

总结的太到位:python 多线程系列详解

前言: 上vip课的时候每次讲到框架的执行,就会有好学的同学问用多线程怎么执行,然后我每次都会说在测开课程会详细讲解,这并不是套路,因为如果你不理解多线程,不清楚什么时候该用什么时候不该用,…

List容器(Java)

文章目录 1.容器介绍1.1 容器接口结构1.2 简单解析 2. List容器创建3. 访问操作(get, iterator, for)4. 修改操作(add, remove, set)5. 容量操作(clear, contains, isEmpty, size)6. 其他操作(toArray, )7. 泛型操作 1.容器介绍 1.1 容器接口结构 a. Java存储结构划分   Java…

联想杀毒显示 你的计算机有风险,都在说联想电脑管家,那我们也来看看这联想杀毒是怎么一回事-电脑管家怎么样...

说到杀毒软件,大家第一反应应该是两大阵营,一大阵营是国外那些牛逼的kaba、nod32、avest等等,另一大阵营肯定是国内以360为代表的免费杀毒阵营,提到国内的这些,大家肯定也都是从国内业界老大360到不入流的管家&#xf…

计算机病毒有存在的方式是,计算机病毒防治体系存在的问题有什么

主动防御,是未来发展的趋势。主要有两个方法,一是静态防御,就是我们常说的启发式,杰出代表杀软有:NOD32(48次通过VB100),德国小红伞(单引擎扫描07年第一);第二方式是动态防御(行为分析技术)&…

linux系列---常见命令

文章目录 1. 目录结构2. 命令总述2.1. 文件管理2.2. 磁盘管理2.3. 文档处理2.4. 用户及组2.5. 文件传输2.6. 网络通信2.7. 备份压缩2.8. 系统管理2.9. 系统设置2.10. 其他 3. 命令详解3.1. cURL3.2. rz与sz3.3. wget3.4. rpm3.5. yum3.6. cat 其实每个命名都是有由来的&#xf…

Linux下wget命令详解

Linux wget是一个下载文件的工具,它用在命令行下。对于Linux用户是必不可少的工具,尤其对于网络管理员,经常要下载一些软件或从远程服务器恢复备份到本地服务器。如果我们使用虚拟主机,处理这样的事务我们只能先从远程服务器下载到…

functions.php隐藏恶意代码,wordpress程序网站又一次的被挂恶意代码以及简单的清除网站木马与恶意软件的方法...

现在已经去除了恶意木马代码了可以放心浏览本站! 这次的恶意码我都不知道怎么出来的,而且同时感染了我两个wordpress网站,其中一个就是ps笔刷吧! 是昨晚感染的,eset检测到 http://brushes8.com/ JS/Redirector.NIL 特洛…

解决Windows 10 CPU占用高风扇吵问题

很多笔记本用户在升级到Windows 10后,都遇到了这样一个问题,那就是Windows 10的CPU占用明显高于Windows 7。这个问题对于台式机可能还算不了什么,顶多就是偶尔卡一下罢了。可由于笔记本大多采用变速风扇,CPU温度飙高时&#xff0c…