pytorch 最简单的单向RNN应用

news2024/11/24 2:32:48

单向RNN

这几天一直在看RNN方面的知识,其中最感到疑惑的是下面的两张图。下面两张图说出了单向循环神经网络的所有原理,但是这里面其实是有一点问题的。比如下面第一张图,整个RNN的构成其实是有三个矩阵的。首先输入向量通过输入矩阵U,与上一个的隐藏层状态乘以权重矩阵W后相乘得到了这一层的隐藏状态ht,ht通过权重矩阵V得到最后的输出。

下面这一张图更加简单,整个RNN共用一个矩阵。下图的第二张图讲的非常清楚。将上一层的隐藏层状态和当前的输入拼接送入权重矩阵A中得到本层的隐藏层的状态。

 

 pytorch中 RNN的实现

RNN — PyTorch 1.13 documentation

 上面是隐藏层的的计算公式。这也说明了RNN为什么叫做循环神经网络,因为它是不同时序的数据共用一个权重矩阵。

 结合一下下面这张图解释一些RNN中参数的含义。

 

 input_size:表示 输入特征的维度。也就是x0的维度

hidden_size:表示隐藏层的输出维度。也就是h1的维度

num_layers: 表示中间隐藏层的个数。上图表示只有一个隐藏层,也就是只有一个权重矩阵A

seq_lenth :  表示词向量的个数。就是上图中x0,x1,x2这些向量的个数。这里解释一下计算的过程,首先x0输入RNN网络中,得到隐藏层的状态,隐藏层的状态被保留了下来,然后输入下一个向量,这时添加上一个时刻的隐藏层的状态,可以得到之前的信息。下面的代码可以看出有个for循环,就是遍历每一个词向量。最后的输出包含两个变量,一个是所有时刻输出组成的向量,一个是最后一个时刻的输出。一般使用最后一个时刻的向量就可以,因为这个向量就已经包含了前面所有的信息。

 bidirectional:表示的是是否使用双向的RNN。

import torch
import torch.nn as nn

batchsize=2
seq_lenth=3   ##时间长度
input_size=10
hidden_size=5

#随机初始化一个随机序列
input=torch.randn(batchsize,seq_lenth,input_size)
#随机一个初始状态
h0=torch.zeros(batchsize,hidden_size)

#setp1 调用pytorch中API
signal_rnn=nn.RNN(input_size=input_size,hidden_size=hidden_size,batch_first=True)
rnn_output,hn=signal_rnn(input,h0.unsqueeze(0))

# print('所有的隐藏层输出',rnn_output.shape)
# print('最后一个隐藏层的输出',hn.shape)
print('RNN的输出')
# print('所有的隐藏层输出',rnn_output)
print('最后一个隐藏层的输出',hn)
print('最后一个时刻RNN的输出',rnn_output[:,-1,])

#step2 自己手写实现简单的API
def rnn_forward(input,weight_ih,bias_ih,weight_hh,bias_hh,h0=None):
    batchsize,seq_lenth,input_size=input.shape
    hidden_size=weight_ih.shape[0]

    #初始化一个输出矩阵
    h_out=torch.zeros(batchsize,seq_lenth,hidden_size)

    #计算最后的输出
    for t in range(seq_lenth):
        x=input[:,t,:].unsqueeze(2)  #获取当前时刻的输入特征  batch_size*input_size*1
        weight_ih_batch=weight_ih.unsqueeze(0).tile(batchsize,1,1)
        weight_hh_batch=weight_hh.unsqueeze(0).tile(batchsize,1,1)

        w_times_x=torch.bmm(weight_ih_batch,x).squeeze(-1)
        w_times_h=torch.bmm(weight_hh_batch,h0.unsqueeze(2)).squeeze(-1) #batch_size*hidden_size
        h0=torch.tanh(w_times_h+bias_ih+w_times_x+bias_hh)
        h_out[:,t,:]=h0
    return h_out,h0.unsqueeze(0)

#验证一下rnn_forward的正确性
# for pram,name in signal_rnn.named_parameters():
#     print('参数',pram,'值',name)

custom_rnn_output,custom_state_final=rnn_forward(input,signal_rnn.weight_ih_l0,signal_rnn.bias_ih_l0,signal_rnn.weight_hh_l0,signal_rnn.bias_hh_l0,h0=h0)

print('单向RNN')
# print(custom_rnn_output)
print('单向RNN的最后输出',custom_state_final)

 讲到这里差不多就明白了RNN的基本知识了。

RNN实战

import numpy as np
import matplotlib.pyplot as plt

# 生成一些数据,并且可视化
steps = np.linspace(0, np.pi*4, 100, dtype=np.float)
x_np = np.sin(steps)
y_np = np.cos(steps)
plt.plot(steps, y_np, 'r-', label='target(cos)')
plt.plot(steps, x_np, 'b-', label='input(sin)')
plt.legend(loc='best')
plt.show()

 这里做一个预测问题,输入为sin值,输出对应的cos值。从上图中,可以看到x1和x2具有相同的cos值,但是对应的输入不一样,也就是说如果使用传统直连模型,这种预测问题是很不好做的。

import torch
from torch import nn

class Rnn(nn.Module):
    def __init__(self, input_size):
        super(Rnn, self).__init__()

        self.rnn = nn.RNN(
            input_size=input_size, ##输入特征的维度
            hidden_size=16,  ##隐藏层输出的维度
            num_layers=1,  ##隐藏层的个数
            batch_first=True
        )

        self.out = nn.Sequential(
            # nn.Linear(16,16),
            # nn.ReLU(),
            nn.Linear(160,1),
            # nn.Sigmoid()
        )

    def forward(self, x, h_state=None):
        r_out, h_state = self.rnn(x, h_state)
        out=self.out(r_out.flatten())

        return out, h_state

if __name__=='__main__':
    from torchinfo import summary
    model=Rnn(1)
    #输入  batchsize,seq_lenth,input_size
    input=torch.rand(1,10,1)
    summary(model)
    out,ht=model(input)
    print('预测的输出',out.shape)
    print('RNN最后一个时刻的输出',ht.shape)

模型的训练

import numpy as np
import torch
from torch import nn
from models import Rnn

seq_lenth = 10  # 词向量的维度
input_size=1   #输入的维度

# 模型的模型的创建
model = Rnn(input_size)

# 定义优化器和损失函数
loss_func = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.02)

h_state = None  # 第一次的时候,暂存为0

for epoch in range(10):
    epoch_loss=0
    for step in range(300):  ###生成3000个随机序列
        # 生成训练数据
        start, end = step , (step + 1)
        steps = np.linspace(start, end, seq_lenth, dtype=np.float32)
        x = torch.tensor(np.sin(steps))
        x = x.view(1, seq_lenth, 1)
        y = torch.tensor((np.cos(end)),dtype=torch.float32)
        y = y.view(1,1,1)

        prediction, h_state = model(x, h_state)
        # h_state = h_state.data
        h_state = h_state.detach()  # 隐藏层的状态不参与梯度传播

        loss = loss_func(prediction, y)
        epoch_loss=epoch_loss+loss.data
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    print('第{}个epoch损失值'.format(epoch),epoch_loss/300)

    torch.save(model,'./model{}.pth'.format(epoch))

 

模型的测试

import numpy as np
import torch

import matplotlib.pyplot as plt
model=torch.load('model5.pth')
seg_lenth=10
h_state = None
x_true=[]
y_true=[]
y_predicted=[]
for step in range(300,350):  ###生成300个随机序列
    # 生成训练数据
    start, end = step , (step + 1)
    steps = np.linspace(start, end, seg_lenth, dtype=np.float32)
    x = torch.tensor(np.sin(steps))
    x_true.append((x[-1]))
    x = x.view(1, seg_lenth, 1)
    y = torch.tensor((np.cos(end)), dtype=torch.float32)
    y = y.view(1, 1, 1)
    y_true.append((y.data.numpy().flatten()))
    prediction, h_state = model(x, h_state)
    h_state = h_state.detach()
    y_predicted.append(prediction.data.numpy().flatten())

print('预测值',y_predicted)
print('真实值',y_true)
plt.plot(np.array(x_true),np.array(y_predicted), 'r-',label='predict')
plt.plot(np.array(x_true),np.array(y_true), 'b-',label='true')
# plt.plot(np.array(y_predicted),'r-',label='predict')
# plt.plot(np.array(y_true),'b-',label='true')
plt.legend(loc='best')
plt.show()

 

 由上面的效果图,可以看到模型拟合的很好。但是最开始的值差别非常大。

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

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

相关文章

实验8 数据库完整性、安全设计

第1关 执行 CREATE USER 创建以2022100904为用户名的用户,同时设置其密码为root1234 任务描述 执行 CREATE USER 创建以2022100904为用户名的用户,同时设置其密码为root1234 相关知识 创建用户的语法为如下: CREATE USER 用户名localhost IDE…

记一次 .NET 某安全生产信息系统 CPU爆高分析

一:背景 1.讲故事 今天是🐏的第四天,头终于不巨疼了,写文章已经没什么问题,赶紧爬起来写。 这个月初有位朋友找到我,说他的程序出现了CPU爆高,让我帮忙看下怎么回事,简单分析了下…

JaveWeb框架(三):JavaWeb项目实战 基于Servlet 实现系统登录注册功能

MVC实战项目 仓储管理系统需求:实现基本的登录和注册功能MVC实战项目:登录和注册登录功能实现注册功能实现总结Redis章节复习已经过去,新的章节JavaWeb开始了,这个章节中将会回顾JavaWeb实战项目 公司管理系统部分功能 代码会同步…

软件测试线上故障规范及模板,希望能帮到大家

目录 前言 线上故障规范及模板 [NOF-32] 全平台所有业务下单后支付异常,无法调起支付 创建: XX年/XX月/XX日 更新: XX年/XX月/XX日 解决: XX年/XX月/XX日 总结 前言 对于每一个测试人员来说,软件测试过程中有一个四字成语,真的是如噩梦一…

通用springboot框架

前言 到现在已经学习并工作了许久,于是打算弄一个通用的springboot框架。 这个框架,哪怕是你到正式工作的时候,也是能用上的,也不会给人感觉特别的low 那么,本项目的git我会放在结尾 接下来我来具体说一下该通用的spr…

谷粒商城技术栈总结

文章目录谷粒商城ElasticSearch一、基本概念1、Index(索引)2、Type(类型)3、Document(文档)4、倒排索引机制二、Docker 安装 Es1、下载镜像文件2、创建实例三、初步检索1、_cat2、索引一个文档(…

vue - vue中的process.env.NODE_ENV讲解

vue中process.env讲解: 1,什么是process.env process.env 是 Node.js 中的一个环境对象。其中保存着系统的环境的变量信息。可使用 Node.js 命令行工具直接进行查看。如下: 而 NODE_ENV 就是其中的一个环境变量。这个变量主要用于标识当前的环…

【微服务】Nacos 如何做到⼀致性协议下沉的与自研 Distro 协议

目录 一、⼀致性协议下沉 1、⼀致性协议抽象 2、数据存储抽象 二、Nacos 自研 Distro 协议 1、背景 2、设计思想 2.1、数据初始化 2.2、数据校验 2.3、写操作 2.4、读操作 3、小结 一、⼀致性协议下沉 既然 Nacos 已经做到了将 AP、CP 协议下沉到了内核模块&#xff…

Hasoop实训2:实现课件分发

目录 1、准备工作 2、创建工作目录 3、上传课件压缩包 4、创建IP地址列表文件 5、创建脚本完成课件分发任务 6、总结 1、准备工作 在实训1:Hadoop实训1:Linux基本搭建和操作_open_test01的博客-CSDN博客​​​​​​ 中已经配置好了三台虚拟主机…

架构师必读 —— 逻辑模型(6)

横向思考与纵向思考 为了不陷入歪理之中,养成从宏观到微观的思考习惯极其重要。换句话说,就是“先横向思考,再纵向思考”。 横向思考是指,“广而浅地把握整体”。纵向思考是指, “针对某部分深入分析“。有了广泛而基本…

微服务框架 SpringCloud微服务架构 服务异步通讯 51 死信交换机 51.2 TTL

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式,系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 服务异步通讯 文章目录微服务框架服务异步通讯51 死信交换机51.2 TTL51.2.1 TTL51.2.2 总结51 死信交换机 51.2 TTL 51.2.1 TTL TTL&…

如何使用vs code远程连接服务器?如何免密登录?VSCode SSH

依旧是写在前面的废话环节 背景: 计算机专业。实验室电脑情况:两台服务器,一台配置3029ti,一台配置2080ti。深度学习训练跑代码用自己的电脑远程连接服务器,进行代码运行。 用到的软件: visual studio c…

vue3+vite+ts项目集成科大讯飞语音识别(项目搭建过程以及踩坑记录)

🐱个人主页:不叫猫先生 🙋‍♂️作者简介:前端领域新星创作者、华为云享专家、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀! 💫系列专栏&#xff…

Web前端105天-day48-jQuery

jQuery01 目录 前言 一、复习 二、jQuery 三、css操作 四、点击事件 五、class 六、show_hide 七、标签栏切换 八、自定有动画 九、属性操作 十、大小图切换 总结 前言 jQuery01学习开始 一、复习 DOM: 文档 对象 模型 HTML代码 转换成 document 对象, 然后再渲染…

ospf,三层交换机,热备,以太网通道练习实验(含命令)

♥️作者:小刘在这里 ♥️每天分享云计算网络运维课堂笔记,疫情之下,你我素未谋面,但你一定要平平安安,一 起努力,共赴美好人生! ♥️夕阳下,是最美的,绽放,…

Sikuli循环执行点击图标的脚本

首先需要sikulix jar包 新建java项目 导入sikulix jar包 编写代码如下 这样电脑每隔一段时间就会去点击一下c.png这个图标 package one; import org.sikuli.script.Screen; public class clickMouse { public static void main(String[] args) throws Exception { …

人力资本管理(HCM)软件的主要好处是什么?

人力资本管理(HCM)包括企业在招聘、雇用和培训期间为优化生产力采取的所有流程。为了最大限度地发挥团队的作用,留住顶尖人才,管理者和领导者需要投资于适当的实践和资源。实现这一目标的方法之一是通过人力资本管理。 作为一套…

js中数组是如何在内存中存储的?

数组不是以一组连续的区域存储在内存中,而是一种哈希映射的形式。它可以通过多种数据结构来实现,其中一种是链表。 js分为基本类型和引用类型: 基本类型是保存在栈内存中的简单数据段,它们的值都有固定的大小,保存在…

【FFmpeg+Qt】视频进度条控制——点击跳转和拖动跳转

首先进度条采用Qslider,设置进度条主要有两点,一是当前视频总时长,二是当前播放时长,需要通过FFmpeg转码成mp4文件才能获取相应的时长数据; 往期回顾: 【QtFFmpeg】视频转码详细流程_logani的博客-CSDN博…

从用户测试中学到的知识

从客户那里获得良好的反馈是个挑战。用户测试有的时候看起来是一个艰巨而且昂贵的任务。但是用户测试可以带来良好的经验,从而帮助设计更好的产品。 那么,从哪里开始呢?我测试了几种方法,有些失败,有些成功。下面我将讲述我所学到…