当前位置:   article > 正文

pytorch框架LSTM(RNN)实现预测_rnn pytorch csdn

rnn pytorch csdn

一、环境配置

        1.python 3.8

        2.torch 1.9.1+cu102

        3.visdom (画图工具)

二、数据准备(模拟数据)

        (目标任务:根据现有数据,预测未来数据)

        生成y=i*2+b的数据(i的取值范围0-499,b的取值范围randint(1,10))。

  1. # -*- coding: UTF-8 -*-
  2. # 请看下面代码
  3. # y=x*2+b
  4. import random
  5. with open('data\\data.txt', 'w', encoding='utf-8') as fp:
  6. for i in range(500):
  7. b = random.randint(1, 10)
  8. fp.write(f'{i},{b},{i * 2 + b}\n')

        生成的data.txt:

三、数据加载

        这里将data.txt中的x,b,y值分别存入列表之中。这里虽然继承了Dataset,但是后面训练代码中的数据加载部分我没有使用Dataloader,其中batch_size设为1,所以这里继承Dataset与否都行,我只是打个版。

  1. # -*- coding: UTF-8 -*-
  2. # 请看下面代码
  3. from torch.utils.data import Dataset
  4. class MyDataset(Dataset):
  5. def __init__(self):
  6. super(MyDataset, self).__init__()
  7. self.x = []
  8. self.b = []
  9. self.y = []
  10. with open('data\\data.txt', 'r', encoding='utf-8') as fp:
  11. for i in fp.readlines():
  12. temp = i.split(',') # ['x','b','y\n']
  13. self.x.append(float(temp[0])/10)
  14. self.b.append(float(temp[1])/10)
  15. self.y.append(float(temp[2].rsplit()[0])/10)
  16. def __getitem__(self, item):
  17. return [self.x[item], self.b[item]], self.y[item]
  18. def __len__(self):
  19. return len(self.x)
  20. # if __name__ == '__main__':
  21. # a = MyDataset()
  22. # # 点位分布图
  23. # from visdom import Visdom
  24. #
  25. # vis = Visdom()
  26. # vis.line([0], [0], win='win', opts=dict(title='title'))
  27. # for i in range(len(a.x)):
  28. # vis.line([a.x[i] * 2 + a.b[i]], [i], win='win', update='append')

        加载x,b,y除以10主要是缩小数的大小,也类似于归一化了吧(主要这里我偷懒没做归一化了,可以自己实现归一化)。不归一化会减缓模型收敛,也会影响训练速度,所以能归一化还是归一化吧,不要像我一样。

四、模型搭建

        模型采用LSTM网络,它也是属于RNN的一种。

  1. # -*- coding: UTF-8 -*-
  2. # 请看下面代码
  3. import torch
  4. from torch import nn
  5. class MyModel(nn.Module):
  6. def __init__(self):
  7. super(MyModel, self).__init__()
  8. self.lstm = nn.LSTM(2, 5, 2, batch_first=True, bidirectional=True)
  9. self.linear1 = nn.Linear(5 * 2, 1)
  10. self.linear2 = nn.Linear(30, 1)
  11. def forward(self, x):
  12. # x [b,seq,2]
  13. output, hidden = self.lstm(x)
  14. # output [b,seq,5]
  15. output = self.linear1(output)
  16. # output [b,seq,1]
  17. output = output.view(1, -1)
  18. # output [b,seq*1]
  19. output = self.linear2(output)
  20. # output [b,1]
  21. return output
  22. # if __name__ == '__main__':
  23. # model = MyModel()
  24. # x = torch.randn(1, 30, 2)
  25. # output = model(x)
  26. # print(output.shape)

        本次任务中设置bidirectional=True定义双向LSTM貌似比单向的时候,收敛更快。

五、训练代码

        这里设置的时间步长为30,根据前三十个数据预测下一个数据,也就是说根据1-30个数据、预测第31个数据,根据2-31个数据预测第32个数据,以此类推。

  1. # -*- coding: UTF-8 -*-
  2. # 请看下面代码
  3. import torch
  4. import visdom
  5. from torch import optim, nn
  6. from model import MyModel
  7. from dataset import MyDataset
  8. device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
  9. lr = 1e-3
  10. seq = 30
  11. mydataset = MyDataset()
  12. x_all = mydataset.x
  13. b_all = mydataset.b
  14. y_all = mydataset.y
  15. max_len = len(y_all)
  16. data_x = [
  17. [x_all[i], b_all[i]] for i in range(len(x_all))
  18. ]
  19. data_y = y_all
  20. model = MyModel().to(device)
  21. opti = optim.AdamW(model.parameters(), lr=lr)
  22. lossfun = nn.MSELoss().to(device)
  23. vis = visdom.Visdom()
  24. vis.line([0], [0], win='loss', opts=dict(title='loss-win'))
  25. global_index = 1
  26. for i in range(70):
  27. for item in range(max_len - seq):
  28. x = data_x[item:item + seq]
  29. y = data_y[item + seq]
  30. x, y = torch.tensor(x, dtype=torch.float), torch.tensor(y, dtype=torch.float)
  31. x, y = x.view(1, seq, -1), y.view(1, 1)
  32. x, y = x.to(device), y.to(device)
  33. opti.zero_grad()
  34. pred = model(x)
  35. loss = lossfun(pred, y)
  36. loss.backward()
  37. opti.step()
  38. if item == max_len - seq - 1:
  39. print(f'预测值:{pred.item():.6f},真实值:{y.item():.6f},差值为:{pred.item() - y.item():.6f}')
  40. vis.line([loss.item()], [global_index], win='loss', update='append')
  41. global_index += 1
  42. torch.save(model.state_dict(), 'best.pt')

六、测试代码

  1. # -*- coding: UTF-8 -*-
  2. # 请看下面代码
  3. import random
  4. import torch
  5. from visdom import Visdom
  6. from model import MyModel
  7. if __name__ == '__main__':
  8. model = MyModel()
  9. model.load_state_dict(torch.load('best.pt'))
  10. vis = Visdom()
  11. # 预测值和真实值分开画图
  12. # vis.line([0], [0], win='pred', opts=dict(title='预测'))
  13. # vis.line([0], [0], win='real', opts=dict(title='真实'))
  14. # for e in range(31, 501):
  15. # sss = e / 10
  16. # l = [[sss - float(i) / 10, random.randint(1, 10) / 10] for i in range(1, 31)]
  17. # l.sort(reverse=False)
  18. # print(l)
  19. # x = torch.tensor(l, dtype=torch.float)
  20. # x = x.view(1, 30, 2)
  21. # out = model(x)
  22. # print(out.item() * 10)
  23. # vis.line([out.item() * 10], [e], win='pred', update='append')
  24. # with open('data\\data.txt', 'r', encoding='utf-8') as fp:
  25. # for i in fp.readlines():
  26. # temp = i.split(',')
  27. # x = float(temp[0])
  28. # y = float(temp[2].strip())
  29. # vis.line([y], [x], win='real', update='append')
  30. # 预测值和真实值画在一个图
  31. vis.line([[0, 0]], [0], win='pred', opts=dict(title='预测-真实', legend=['pred', 'real']))
  32. with open('data\\data.txt', 'r', encoding='utf-8') as fp:
  33. for step, i in enumerate(fp.readlines()):
  34. temp = i.split(',')
  35. y = float(temp[2].strip())
  36. l = [[(step - float(j)) / 10, random.randint(1, 10) / 10] for j in range(1, 31)]
  37. l.sort(reverse=False)
  38. print(l)
  39. x = torch.tensor(l, dtype=torch.float)
  40. x = x.view(1, 30, 2)
  41. out = model(x)
  42. print(out.item() * 10)
  43. vis.line([[out.item() * 10, y]], [step], win='pred', update='append')

        预测-真实值图示:

        项目文档结构:

 

 七、疑问

        本人新手,在实验的过程中有些许疑问,想和大家一块讨论,也请大佬答疑。

        1、此次任务目标说是预测,但与其说是预测,本人觉得更像是拟合函数,所以这次的任务能叫做是预测吗?使用训练好的模型进行test测试,因为数据只用了x~[0-499]来作为训练集,如果使用x范围之外的数据进行test的输入,那就会表现的很不准确,所以这到底算是有预测功能呢(只是不能预测较远的数据),还是仅仅只是实现拟合函数功能罢了。(如果有预测功能,可以通过加大时间步来提升预测精确度吗?)

        2、把数据输入进网络,通过RNN\LSTM和线性层后得到[bacth,seq,1]格式的数据,之后我应该是取[:,-1,:],也就是最后一个时间步作为最终预测结果呢,还是将通过RNN\LSTM和线性层后得到[bacth,seq,1]格式的数据变成[batch,seq*1]然后放入线性层将得到的[batch,1]格式的数据作为最后的预测结果呢?

        3、如果此次任务算是实现拟合函数功能,那过程有什么不标准或可改进的吗?如果此次任务不算是预测,那么该如何使用已知数据实现未来数据的预测呢?

        欢迎大家讨论,也希望大佬答疑,谢谢!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/112527
推荐阅读
相关标签
  

闽ICP备14008679号