赞
踩
1.python 3.8
2.torch 1.9.1+cu102
3.visdom (画图工具)
(目标任务:根据现有数据,预测未来数据)
生成y=i*2+b的数据(i的取值范围0-499,b的取值范围randint(1,10))。
- # -*- coding: UTF-8 -*-
- # 请看下面代码
- # y=x*2+b
- import random
-
- with open('data\\data.txt', 'w', encoding='utf-8') as fp:
- for i in range(500):
- b = random.randint(1, 10)
- fp.write(f'{i},{b},{i * 2 + b}\n')
生成的data.txt:
这里将data.txt中的x,b,y值分别存入列表之中。这里虽然继承了Dataset,但是后面训练代码中的数据加载部分我没有使用Dataloader,其中batch_size设为1,所以这里继承Dataset与否都行,我只是打个版。
- # -*- coding: UTF-8 -*-
- # 请看下面代码
- from torch.utils.data import Dataset
-
- class MyDataset(Dataset):
- def __init__(self):
- super(MyDataset, self).__init__()
- self.x = []
- self.b = []
- self.y = []
- with open('data\\data.txt', 'r', encoding='utf-8') as fp:
- for i in fp.readlines():
- temp = i.split(',') # ['x','b','y\n']
- self.x.append(float(temp[0])/10)
- self.b.append(float(temp[1])/10)
- self.y.append(float(temp[2].rsplit()[0])/10)
-
- def __getitem__(self, item):
- return [self.x[item], self.b[item]], self.y[item]
-
- def __len__(self):
- return len(self.x)
-
-
- # if __name__ == '__main__':
- # a = MyDataset()
- # # 点位分布图
- # from visdom import Visdom
- #
- # vis = Visdom()
- # vis.line([0], [0], win='win', opts=dict(title='title'))
- # for i in range(len(a.x)):
- # vis.line([a.x[i] * 2 + a.b[i]], [i], win='win', update='append')
加载x,b,y除以10主要是缩小数的大小,也类似于归一化了吧(主要这里我偷懒没做归一化了,可以自己实现归一化)。不归一化会减缓模型收敛,也会影响训练速度,所以能归一化还是归一化吧,不要像我一样。
模型采用LSTM网络,它也是属于RNN的一种。
- # -*- coding: UTF-8 -*-
- # 请看下面代码
- import torch
- from torch import nn
-
-
- class MyModel(nn.Module):
- def __init__(self):
- super(MyModel, self).__init__()
-
- self.lstm = nn.LSTM(2, 5, 2, batch_first=True, bidirectional=True)
- self.linear1 = nn.Linear(5 * 2, 1)
- self.linear2 = nn.Linear(30, 1)
-
- def forward(self, x):
- # x [b,seq,2]
- output, hidden = self.lstm(x)
- # output [b,seq,5]
- output = self.linear1(output)
- # output [b,seq,1]
- output = output.view(1, -1)
- # output [b,seq*1]
- output = self.linear2(output)
- # output [b,1]
- return output
-
- # if __name__ == '__main__':
- # model = MyModel()
- # x = torch.randn(1, 30, 2)
- # output = model(x)
- # print(output.shape)
本次任务中设置bidirectional=True定义双向LSTM貌似比单向的时候,收敛更快。
这里设置的时间步长为30,根据前三十个数据预测下一个数据,也就是说根据1-30个数据、预测第31个数据,根据2-31个数据预测第32个数据,以此类推。
- # -*- coding: UTF-8 -*-
- # 请看下面代码
- import torch
- import visdom
- from torch import optim, nn
- from model import MyModel
- from dataset import MyDataset
-
- device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
- lr = 1e-3
- seq = 30
-
- mydataset = MyDataset()
- x_all = mydataset.x
- b_all = mydataset.b
- y_all = mydataset.y
- max_len = len(y_all)
-
- data_x = [
- [x_all[i], b_all[i]] for i in range(len(x_all))
- ]
- data_y = y_all
-
- model = MyModel().to(device)
- opti = optim.AdamW(model.parameters(), lr=lr)
- lossfun = nn.MSELoss().to(device)
-
- vis = visdom.Visdom()
- vis.line([0], [0], win='loss', opts=dict(title='loss-win'))
- global_index = 1
-
- for i in range(70):
- for item in range(max_len - seq):
- x = data_x[item:item + seq]
- y = data_y[item + seq]
- x, y = torch.tensor(x, dtype=torch.float), torch.tensor(y, dtype=torch.float)
- x, y = x.view(1, seq, -1), y.view(1, 1)
- x, y = x.to(device), y.to(device)
- opti.zero_grad()
- pred = model(x)
- loss = lossfun(pred, y)
- loss.backward()
- opti.step()
-
- if item == max_len - seq - 1:
- print(f'预测值:{pred.item():.6f},真实值:{y.item():.6f},差值为:{pred.item() - y.item():.6f}')
- vis.line([loss.item()], [global_index], win='loss', update='append')
- global_index += 1
-
- torch.save(model.state_dict(), 'best.pt')
- # -*- coding: UTF-8 -*-
- # 请看下面代码
- import random
-
- import torch
- from visdom import Visdom
- from model import MyModel
-
- if __name__ == '__main__':
- model = MyModel()
- model.load_state_dict(torch.load('best.pt'))
- vis = Visdom()
-
- # 预测值和真实值分开画图
- # vis.line([0], [0], win='pred', opts=dict(title='预测'))
- # vis.line([0], [0], win='real', opts=dict(title='真实'))
- # for e in range(31, 501):
- # sss = e / 10
- # l = [[sss - float(i) / 10, random.randint(1, 10) / 10] for i in range(1, 31)]
- # l.sort(reverse=False)
- # print(l)
- # x = torch.tensor(l, dtype=torch.float)
- # x = x.view(1, 30, 2)
- # out = model(x)
- # print(out.item() * 10)
- # vis.line([out.item() * 10], [e], win='pred', update='append')
- # with open('data\\data.txt', 'r', encoding='utf-8') as fp:
- # for i in fp.readlines():
- # temp = i.split(',')
- # x = float(temp[0])
- # y = float(temp[2].strip())
- # vis.line([y], [x], win='real', update='append')
-
- # 预测值和真实值画在一个图
- vis.line([[0, 0]], [0], win='pred', opts=dict(title='预测-真实', legend=['pred', 'real']))
- with open('data\\data.txt', 'r', encoding='utf-8') as fp:
- for step, i in enumerate(fp.readlines()):
- temp = i.split(',')
- y = float(temp[2].strip())
- l = [[(step - float(j)) / 10, random.randint(1, 10) / 10] for j in range(1, 31)]
- l.sort(reverse=False)
- print(l)
- x = torch.tensor(l, dtype=torch.float)
- x = x.view(1, 30, 2)
- out = model(x)
- print(out.item() * 10)
- 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、如果此次任务算是实现拟合函数功能,那过程有什么不标准或可改进的吗?如果此次任务不算是预测,那么该如何使用已知数据实现未来数据的预测呢?
欢迎大家讨论,也希望大佬答疑,谢谢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。