深度学习-一篇入门

【代码】RNN案例-1vN模型-预测未来多个时刻的输出

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



在需要预测未来多个时刻的输出时,可以使用1VN结构的RNN循环神经网络

本文展示一个使用1VN结构的RNN来预测未来多个时刻的输出的代码案例,并讲解相关思路

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




     01. RNN-1vN案例(预测多时刻)    





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





      RNN案例-1vN解决序列预测      


我们以sin函数序列数据的预测为例,讲述如何使用RNN-1vN模型解决序列预测问题
以下是一个sin函数的曲线与序列数据,我们希望通过前5个数据预测之后10个时刻数据
 RNN案例的数据 
这是一种常见的场景,利用前部分的数据,预测后续的数据,本文讲述如何使用RNN-1vN来解决此类问题





      RNN案例-1vN模型结构设计     


我们将数据处理为以下的形式:
 RNN案例处理后的数据
x1-x5是t时刻之前的5个数据,y1-y10是之后10个时刻的数据,我们使用x1-x5来预测y1-y10
我们设计一个结构为1VN的RNN模型如下:
 RNN案例的1VN模型结构 
 由于x只有一个变量,所以我们将x1-x5合并(5个变量),作为RNN初始时刻的输入X
然后通过RNN的循环迭代,连续输出每个时刻的y,直到输出所有时刻的y为止








     02. RNN-1vN案例(多时刻预测)-代码实现    





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





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


我们使用pytorch来实现上述所设计的RNN-1vN模型,以及训练模型
 具体实现代码如下:
import torch
import random
import torch.nn as nn

# ----------------------数据生成---------------------------------
data = torch.sin(torch.arange(-10, 10,0.1))                                     # 生成sin序列数据
xLen   = 5                                                                      # 利用前xLen个时刻的数据作为输入
yLen   = 10                                                                     # 预测之后yLen个时刻的数据
sample_n = len(data)-1-xLen-yLen-1                                              # 样本个数
x = torch.zeros(1,sample_n,xLen)                                                # 初始化x
y = torch.zeros(yLen,sample_n,1)                                                # 初始化y
for i in range(sample_n):                                                       # 从序列数据中获取x与y
    x[:,i,:]  = data[i:i+xLen].unsqueeze(0)                                     # 将前xLen个数据作为x
    y[:,i,:]  = data[i+xLen:i+xLen+yLen].unsqueeze(1)                           # 将后yLen个数据作为y
x=torch.cat([x,torch.zeros(yLen-1,sample_n,xLen)],dim=0)                        # 补充其余时刻的输入为0
                                                                                
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

#--------------------模型结构--------------------------------------------
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)                       
        self.hiden_size = hiden_size
    def forward(self, x,h0=None):
        if(h0==None):
            h0 = torch.zeros(1,x.shape[1],self.hiden_size)
        h,_ = self.rnn(x,h0)
        y   = self.fc(h)
        return y,h

#--------------------模型训练--------------------------------------------
# 模型设置
goal      = 0.00001                                                              # 训练目标                 
epochs    = 100000                                                               # 训练频数
model     = RnnNet(xLen,1,10)                                                    # 初始化模型,模型为1输入,1输出,10个隐节点
lossFun   = torch.nn.MSELoss()                                                   # 定义损失函数为MSE损失函数
optimizer = torch.optim.SGD(model.parameters(), lr=0.01,weight_decay=0.00001)    # 初始化优化器
# 模型训练
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,h = model(x)                                                                  # 模型预测
print('loss:',lossFun(py, y).data)                                               # 打印损失值
idx = 0                                                                          # 抽取一条样本
print('---smaple'+str(idx)+':trueValue and PredictValue:---')                    # 打印样本真实与预测结果
print(torch.cat([y[:,idx,:],py[:,idx,:]],dim=1).data)                            # 打印真实值与预测值进行对比
运行结果如下:
 ------当前epoch: 0 ----------         
train_loss: tensor(0.4789)           
valid_loss: tensor(0.4549)           
------当前epoch: 1000 ----------     
train_loss: tensor(0.0783)           
valid_loss: tensor(0.0602)           
------当前epoch: 2000 ----------     
....
------当前epoch: 98000 ----------    
train_loss: tensor(3.6951e-05)       
valid_loss: tensor(3.8498e-05)       
------当前epoch: 99000 ----------    
train_loss: tensor(3.6888e-05)       
valid_loss: tensor(3.8441e-05)       
-------------------------------------
loss: tensor(3.7481e-05)              
    ---smaple0:trueValue and PredictValue:---
tensor([[ 0.0752,  0.0758],
        [-0.0248, -0.0267],
        [-0.1245, -0.1266],
        [-0.2229, -0.2271],
        [-0.3191, -0.3268],
        [-0.4121, -0.4192],
        [-0.5010, -0.5064],
        [-0.5849, -0.5887],
        [-0.6630, -0.6653],
           [-0.7344, -0.7362]])  
 
可以看到,模型整体的损失值(MSE)已经极小,
从第0条样本的真实值与预测可以看到,真实值与预测值已经比较接近
说明模型已经能较好地预测未来10个时刻的数据





好了,以上就是如何使用一个1VN结构RNN来预测未来多个时刻的输出了~








 End 






联系老饼