PYTORCH实现LSTM的股票预测
- 概要
- 数据源
- TUSHARE 的安装
- LSTM
- LSTM 主要架构
- 关键代码
- LSTM网络的搭建
- 模型训练
- 模型测试:
- 结果展示
概要
本文将基于 LSTM 模型实现一个股票的预测
因为是神经网络的初学者,文章中有很多不足之处,欢迎指正
代码参考Pytorch 学习之LSTM预测航班的LSTM网络 进行搭建。
根据论文 Deep Learning for Stock Selection Based on High Frequency Price-Volume Data1 要求,通过修改了网络中的参数,增加了遗忘层,改了输入和输出的宽度,以及增加了图像的可视化,使得模型具有更好的,更直观的预测结果。
数据源
Tushare是一个免费、开源的python财经数据接口包。主要实现对股票等金融数据从数据采集、清洗加工 到 数据存储的过程,能够为金融分析人员提供快速、整洁、和多样的便于分析的数据,为他们在数据获取方面极大地减轻工作量,使他们更加专注于策略和模型的研究与实现上。
TUSHARE 的安装
pip install tushare 简单粗暴
如果你仍然不行,那么可以点击百度自行搜索tushare 怎么安装~~
安装好后我们就可以来看一下深证成指的最近一年的数据
code 里面放的是股票的编号,start 表示股票的开始时间, end 表示结束时间
ktype 表示的是数据的类型
ktype | 获取数据频率 |
---|---|
15 | 15分钟/次 |
30 | 30分钟/次 |
D | 每天 |
W | 每周 |
1 2 3 4 5 6 | import tushare as ts import matplotlib.pyplot as plt code='399001' a=ts.get_hist_data(code,start='2018-12-05',end='2019-12-05',ktype='D') print(a) |
运行下程序我们可以得到
得到的数据是类型是
但是我们在这里并不会用到pandas,所以我们直接使用values 将他转换为array 类型,然后我们选择每天的开盘价,并进行一个倒序,就得到了2018-12-05到 2019-12-05的每天的开盘价。
1 2 3 | b=a['open'].values b=b[::-1] plt.plot(b) |
LSTM
时间序列预测是回归神经网络的一种,在1997年提出,广泛的用于图像处理和时间序列的预测。LSTM网络能够很好地基于已处理过的和新接受到的信息来了解现在的信息。相比较于传统的人工神经网络,LSTM能够分类出有用的信息并保存,删除无用的信息。LSTM将输入单元分在了长期记忆层和短期记忆层,这样他就能将一些不那么重要的信息给遗忘,LSTM能够很好的解决长期时间序列问题,也很好的解决了梯度爆炸和梯度消失的问题。
LSTM 主要架构
LSTM 有非常重要的三个门 输入门(input gate),输出门(output gate),和遗忘门(forget gate),通过三门制来实现主要链路C_t的信息的添加和删除。
门是一种通过选择性让信息通过的方法,他们由一个Sigmoid 神经网络层和一个元素相乘的操作实现。Sigmoid层输出0~1之间的值,每个值表示对应的部分信息是否应该通过。0值表示不允许信息通过,1值表示让所有信息通过。
遗忘门:遗忘门主要是对上一个节点传进来的输入进行选择性忘记。简单来说就是会 “忘记不重要的,记住重要的”。具体来说是通过计算得到的值来作为忘记门控,来控制上一个状态的值哪些需要留哪些需要忘。
输入门: 选择记忆阶段。这个阶段将这个阶段的输入有选择性地进行“记忆”。主要是会对输入进行选择记忆。哪些重要则着重记录下来,哪些不重要,则少记一些。
输出门:O_(t)将决定C(t)中那些会进入短记忆层,那些将会作为t时间的输出。
关键代码
数据集选择
根据论文要求选择沪深300作为本次的数据,我将2019-01-05 到2019-08-01 每天的开盘价格作为我们的训练数据,将2019-01-05 到 2019-11-07 作为测试数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import tushare as ts import torch from pandas import Series, DataFrame import matplotlib.pyplot as plt import numpy as np from torch import nn from torch.autograd import Variable # need Variable to contain the training data code='399300' a=ts.get_hist_data(code, start='2019-01-05', end='2019-08-01',ktype='D') a=a['open'] a=a[::-1] b=a.values c=ts.get_hist_data(code, start='2019-01-05', end='2019-11-07',ktype='D') c=c['open'] c=c[::-1] c=c.values |
归一化处理
数据归一化的目的是提高网络的收敛速度和消除特征数据维度对网络的负面影响
归一化操作代码:
1 2 3 4 5 6 7 | def data_pre(data1): dataset = data1.astype('double') max_value = np.max(dataset) # 获得最大值 min_value = np.min(dataset) # 获得最小值 scalar = max_value - min_value dataset = list(map(lambda x: x / scalar, dataset)) # return dataset |
数据集的创建:
look_back 取得是2,那么在daraX中我们就可以添加由第一天和第二天的开盘价组成的列表a,通过二维的数据集来实现使用第一天的数据来预测第二天。dataY 里添加的是一维的第二天的标准。用于计算损失。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | def create_dataset(dataset, look_back=2): dataX, dataY = [], [] for i in range(len(dataset) - look_back ): a = dataset[i:(i + look_back)] dataX.append(a) dataY.append(dataset[i + look_back]) return np.array(dataX), np.array(dataY) dataset=data_pre(b) data_test=data_pre(c) data_X2, data_Y2 = create_dataset(data_test) #创建好输入输出 data_X, data_Y = create_dataset(dataset) train_X = data_X train_Y = data_Y train_X = train_X.reshape(-1,1,2) train_Y = train_Y.reshape(-1,1,1) #设置LSTM能够识别的数据类型,形成tran_X一维两个参数的数组, #将其转化为tensor类型 train_x = torch.from_numpy(train_X).double() train_y = torch.from_numpy(train_Y).double() |
LSTM网络的搭建
LSTM 网络调用了pytorch nn.module,网络内部的结构全都由 pytorch 这个包给实现了。他主要的构成有两块,一个是__init__模块中对函数的一个层的一个搭建,这里我们按论文的要求来,设立两层LSTM,每层LSTM后跟一个dropout ,最后再建立一层全连接层。 图中的Softmax 层有待商榷(PS:其实是我加上去后就预测不出来了~~~)
另一个就是一个网络的一个前向传递,再简单来说就是将我们的数据按图中箭头所示,流水线操作。将数据集输入到LSTM层中,再将输出输入到全连接层中,最后就能得到我们想要的预测值。
1 2 3 4 5 6 7 8 9 10 11 12 | class lstm(nn.Module): def __init__(self,input_size,hidden_size,output_size,num_layer): super(lstm,self).__init__() self.layer1= nn.LSTM(input_size,hidden_size,num_layer,bias=True,batch_first=False,dropout=0.1) self.layer2 = nn.Linear(hidden_size,output_size) def forward(self,x): x,_ =self.layer1(x) s,b1,n=x.size() x=x.view(s*b1,n) #view 的作用实现的是将我们的三维网络转化成二维 x=self.layer2(x) x=x.view(s,b1,-1)#view 中的-1的意思是由电脑来计算第三维的值是多少 return x |
优化器的选择
本次训练选择Adam优化器,损失函数选为MSELoss 学习速率定为0.01
1 2 3 | model=lstm(2,4,2,2) #模型搭建 criterion = nn.MSELoss() #损失函数 optimizer = torch.optim.Adam(model.parameters(), lr=0.01) #优化器 (论文已证明Adam相比之下较好)学习速率定为0.01 |
模型训练
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | for epoch in range(1500): # 步长为1500 #forward propagation 前向传播 out=model.forward(var_x) loss= criterion(out,var_y) 损失计算 #back propagation optimizer.zero_grad() #梯度清零 loss.backward() optimizer.step() if epoch%100==0: #画图 out1=out.view(-1).data.numpy() plt.plot(out1,'r') plt.plot(data_X.view(-1).data.numpy(), 'b') print(loss) plt.show() |
模型测试:
1 2 3 4 5 6 7 8 | var_data = Variable(data_X2).float() pred_test = model(var_data) # 测试集的预测结果 #改变输出的格式 pred_test = pred_test.view(-1).data.numpy() #画出实际结果和预测的结果 plt.plot(pred_test, 'r', label='prediction') plt.plot(data_X2.view(-1).data.numpy(), 'b', label='real') plt.legend(loc='best') |
结果展示
1300步时出的图
最后的预测结果,箭头会训练集和测试集的分隔点,可以看到在250步后依然能够较好的拟合出曲线的一个趋势。
-
https://gitee.com/likelihoodlab/HFStock-Public/blob/master/Deep_Learning_for_Stock_Selection.pdf ??