本站原创文章,转载请说明来自《老饼讲解-深度学习》www.bbbdata.com
在需要预测未来多个时刻的输出时,可以使用1VN结构的RNN循环神经网络
本文展示一个使用1VN结构的RNN来预测未来多个时刻的输出的代码案例,并讲解相关思路
通过本文可以了解,如何应用RNN-1VN结构来解决序列预测问题,以及如何实现代码
本节描述本案例所需要解决的问题,以及RNN模型的设计
RNN案例-1vN解决序列预测
我们以sin函数序列数据的预测为例,讲述如何使用RNN-1vN模型解决序列预测问题
以下是一个sin函数的曲线与序列数据,我们希望通过前5个数据预测之后10个时刻数据
这是一种常见的场景,利用前部分的数据,预测后续的数据,本文讲述如何使用RNN-1vN来解决此类问题
RNN案例-1vN模型结构设计
我们将数据处理为以下的形式:
x1-x5是t时刻之前的5个数据,y1-y10是之后10个时刻的数据,我们使用x1-x5来预测y1-y10
我们设计一个结构为1VN的RNN模型如下:
由于x只有一个变量,所以我们将x1-x5合并(5个变量),作为RNN初始时刻的输入X
然后通过RNN的循环迭代,连续输出每个时刻的y,直到输出所有时刻的y为止
本节使用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