深度学习-一篇入门

【代码】RNN案例-Nv1模型-预测下一个时刻的输出

作者 : 老饼 发表日期 : 2023-04-07 17:24:03 更新日期 : 2024-11-28 11:14:21
本站原创文章,转载请说明来自《老饼讲解-深度学习》www.bbbdata.com



NV1结构是RNN循环神经网络中的一种经典结构,可用于解决序列预测问题

本文展示一个使用NV1结构的RNN来解决sin函数拟合问题的代码案例,并讲解思路

通过本文可以了解,如何应用RNN-NV1结构来解决序列预测问题,以及如何实现代码





      01. RNN案例-sin函数的拟合(预测下一时刻)     





本节描述本案例所需要解决的问题,以及RNN模型的设计





      RNN案例(Nv1)-sin函数拟合-问题描述      


作为简单的入门,我们以sin函数为例,因为sin函数就是一个时序性非常强的函数,极具代表性
因此,本文以sin函数为例,简单上手与了解如何使用RNN解决序列数据的预测

如图所示,以下是一个sin函数的曲线与序列数据,我们希望通过前5个数据预测下一个数据
 RNN案例-序列数据
在本问题中,属于单时刻输出的预测,因此,是一种最简单的场景,我们以此来作为初步上手RNN





     RNN模型设计    


我们将数据处理为以下的形式:
 数据预处理结果
x1-x5是t时刻之前的5个数据,y是本时刻的数据,我们使用x1-x5来预测y
我们设计一个Nv1的RNN模型如下:
 RNN的NV1模型结构 
它的意义就是,按顺序将前五个时刻的数据更新到隐节点中,
最后再使用承载了所有输入信息(x1-x5)的隐节点来拟合输出y








     02. RNN案例-sin函数的拟合-代码实现    





本节使用pytorch实现上节所设计的模型,用于拟合sin函数下一时刻的输出





      RNN案例(Nv1)-sin函数拟合代码实现     


我们使用pytorch来实现上述所设计的模型,以及训练模型
值得注意的是,在计算损失函数时,我们只需考虑最后一个时刻的预测值的损失
 具体实现代码如下:
import torch
import random
import torch.nn as nn
import matplotlib.pyplot as plt

# ----------------------数据生成--------------------------
data = torch.sin(torch.arange(-10, 10,0.1))                                 # 生成sin序列数据
plt.plot(data)                                                              
seqLen   = 5                                                                # 利用前5个时刻预测下一时刻
sample_n = len(data)-1-seqLen-1                                             # 样本个数
x = torch.zeros(seqLen,sample_n,1)                                          # 初始化x
y = torch.zeros(1,sample_n,1)                                               # 初始化y
for i in range(sample_n):                                                   # 从序列数据中获取x与y
    x[:,i,:]  = data[i:i+seqLen].unsqueeze(1)                               # 将前5个数据作为x
    y[:,i,:]  = data[i+seqLen]                                              # 将下一个数据作为y
                                                                            
valid_sample_n = round(sample_n*0.2)                                        # 抽取20%的样本作为验证样本
idx = range(sample_n)                                                       # 生成一个序列,用于抽样
valid_idx = random.sample(idx, valid_sample_n)                              # 验证数据的序号
train_idx = [i for i in idx if i not in valid_idx]                          # 训练数据的序号
train_x = x[:,train_idx,:]                                                  # 抽取训练数据的x
train_y = y[:,train_idx,:]                                                  # 抽取训练数据的y
valid_x = x[:,valid_idx,:]                                                  # 抽取验证数据的x
valid_y = y[:,valid_idx,:]                                                  # 抽取验证数据的y

#--------------------模型结构----------------------------------
# RNN神经网络的结构
class RnnNet(nn.Module):
    def __init__(self,input_size,out_size,hiden_size):
        super(RnnNet, self).__init__()
        self.rnn = nn.RNN(input_size, hiden_size)                       
        self.fc  = nn.Linear(hiden_size, out_size)                       
        
    def forward(self, x):
        h,_ = self.rnn(x)                                                   # 计算循环隐层
        h = h[-1,:,:].unsqueeze(0)                                          # 只需要最后一个时刻的隐节点
        y = self.fc(h)                                                      # 计算输出
        return y,h

#--------------------模型训练-----------------------------------
# 模型设置                                                                  
goal      = 0.0001                                                          # 训练目标                 
epochs    = 20000                                                           # 训练频数
model     = RnnNet(1,1,10)                                                  # 初始化模型,模型为1输入,1输出,10个隐节点
lossFun   = torch.nn.MSELoss()                                              # 定义损失函数为MSE损失函数
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)                    # 初始化优化器
# 模型训练                                                                  
for epoch in range(epochs):                                                                        
    optimizer.zero_grad()                                                   # 将优化器里的参数梯度清空
    train_py,_ = model(train_x)                                             # 计算模型的预测值   
    train_loss = lossFun(train_py, train_y)                                 # 计算损失函数值
    valid_py,_ = model(valid_x)                                             # 计算模型的预测值   
    valid_loss = lossFun(valid_py, valid_y)                                 # 计算损失函数值
    if(epoch%1000==0):                                                      
        print('------当前epoch:',str(epoch),'----------')                   # 打印当前步数
        print('train_loss:',train_loss.data)                                # 打印训练损失值
        print('valid_loss:',valid_loss.data)                                # 打印验证损失值
                                                                            
    if(train_loss<goal):                                                    # 如果训练已经达到目标
        break                                                               # 则退出训练
    train_loss.backward()                                                   # 更新参数的梯度
    optimizer.step()                                                        # 更新参数

# ------------------展示结果--------------------------------------          
py,_ = model(x)                                                             # 模型预测
loss= lossFun(py, y).data                                                   # 打印损失函数
print('整体损失值:',loss)
plt.figure()                                                                # 初始化画布
plt.plot( y[0,:,0], color='r', linestyle='-.',label='true_y')               # 绘制真实曲线
plt.plot( py[0,:,0].detach(), color='b', linestyle='-.',label='predict_y')  # 绘制预测曲线
plt.legend(loc=1,framealpha=1)                                              # 展示图例
plt.show()                                                                  # 展示图像
运行结果如下:
------当前epoch: 0 ----------            
train_loss: tensor(0.9424)              
valid_loss: tensor(0.8353)              
------当前epoch: 1000 ----------         
....
------当前epoch: 18000 ----------        
train_loss: tensor(0.0002)              
valid_loss: tensor(0.0003)              
------当前epoch: 19000 ----------        
train_loss: tensor(0.0002)              
valid_loss: tensor(0.0002)              
-----------------------------------------
整体损失值: tensor(0.0002)              

RNN-NV1模型-代码运行结果 
可以看到,模型整体的损失值(MSE)已经极小,所预测的y与真实y已经几乎完全一样







好了,以上就是如何使用一个NV1结构RNN循环神经网络来进行序列预测的案例与代码了~








 End 





联系老饼