有参考,有参考。自存学习
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE'
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import torch
from torch import nn
import time
DAYS_FOR_TRAIN = 10
class LSTM_Regression(nn.Module):#调用nn.Module的初始化函数,初始化LSTMRegression类
"""
使用LSTM进行回归
参数:
- input_size: feature size
- hidden_size: number of hidden units
- output_size: number of output
- num_layers: layers of LSTM to stack
"""
def __init__(self, input_size, hidden_size, output_size=1, num_layers=2):
super().__init__()
self.lstm = nn.LSTM(input_size, hidden_size, num_layers)#定义一个LSTM层
# 其中输入的大小为inputsize,输出的大小为hiddensize,LSTM的层数为numlayers。
self.fc = nn.Linear(hidden_size, output_size)
#定义全连接层
def forward(self, _x):
x, _ = self.lstm(_x) # _x is input, size (seq_len, batch, input_size)
#这行代码是在LSTMRegression类的forward函数中,将输入_x送入LSTM层中进行计算,并将输出赋值给变量x
s, b, h = x.shape # x is output, size (seq_len, batch, hidden_size)
x = x.view(s * b, h)
x = self.fc(x)#把x送入全连接层
x = x.view(s, b, -1) # 把形状改回来
return x
def create_dataset(data, days_for_train=5) -> (np.array, np.array):
"""
根据给定的序列data,生成数据集
数据集分为输入和输出,每一个输入的长度为days_for_train,每一个输出的长度为1。
也就是说用days_for_train天的数据,对应下一天的数据。
若给定序列的长度为d,将输出长度为(d-days_for_train+1)个输入/输出对
"""
dataset_x, dataset_y = [], []
for i in range(len(data) - days_for_train):
_x = data[i:(i + days_for_train)]
dataset_x.append(_x)
dataset_y.append(data[i + days_for_train])
return (np.array(dataset_x), np.array(dataset_y))
## 数据类型变换:dataset_x和data_set_y数据类型(type)由列表(list)->数组(numpy.nparray
#由序列变为数组
#模型训练
if __name__ == '__main__':
t0 = time.time()
#记录当前时间,将其赋值给变量t0。
#通常情况下,可以通过将代码结束时的当前时间减去t0的值来测量代码的执行时间
data_close = pd.read_csv('000001.csv') # 读取文件
#data_close = ts.get_k_data('000001', start='2019-01-01', index=True)['close']"""
# 取上证指数的收盘价 ,'index=True'表示获取的是指数数据,而不是股票数据。['close']表示只获取收盘价数据。
#data_close.to_csv('000001.csv', index=False) # 将下载的数据转存为.csv格式保存
#data_close = pd.read_csv('000001.csv') # 读取.csv文件'''
# df_sh = ts.get_k_data('sh', start='2019-01-01', end=datetime.datetime.now().strftime('%Y-%m-%d'))
# print(df_sh.shape)'''
'绘制原始数据折线图aa'
data_close = data_close.astype('float32').values
#转换数据type,数据类型转换为float32,values将其转换为numpy数组
plt.plot(data_close)#将数据绘制折线图
plt.savefig('data.png', format='png', dpi=200)#保存图像,名字,格式,分辨率
plt.close()#关闭
'数据预处理,将价格标准化到0~1'
max_value = np.max(data_close)
min_value = np.min(data_close)
data_close = (data_close - min_value) / (max_value - min_value)
'制作数据集'
dataset_x, dataset_y = create_dataset(data_close, DAYS_FOR_TRAIN)
'划分训练集和测试集,70%作为训练集'
train_size = int(len(dataset_x) * 0.7)
train_x = dataset_x[:train_size]
train_y = dataset_y[:train_size]
# 将数据改变形状,RNN 读入的数据维度是 (seq_size, batch_size, feature_size)
train_x = train_x.reshape(-1, 1, DAYS_FOR_TRAIN)
#-1表示该维度的大小由程序自动计算得出,1表示batchsize为1,
# DAYSFORTRAIN表示featuresize为DAYSFORTRAIN。这是为了将数据转换为RNN读入的格式。
train_y = train_y.reshape(-1, 1, 1)
# 转为pytorch的tensor对象
'将numpy数组trainx转换为PyTorch的tensor对象。'
'这是因为在PyTorch中,神经网络的输入和输出必须是tensor对象。'
'通过将trainx转换为tensor对象,可以将其作为神经网络的输入'
train_x = torch.from_numpy(train_x)
train_y = torch.from_numpy(train_y)
model = LSTM_Regression(DAYS_FOR_TRAIN, 8, output_size=1, num_layers=2)
# 导入模型并设置模型的参数输入输出层、隐藏层等
model_total = sum([param.nelement() for param in model.parameters()])
# 计算模型参数
print("Number of model_total parameter: %.8fM" % (model_total / 1e6))
#这行代码的作用是打印模型的总参数数量。我们使用了Python的百分号格式化字符串,
# 其中%.8f表示将一个浮点数格式化为8位小数的字符串。我们将模型的总参数数量除以1e6,以将其从字节转换为兆字节。
# 最后,我们将结果插入到字符串中,使用%f占位符。
train_loss = []
loss_function = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-2, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)
for i in range(200):#迭代200次
out = model(train_x)
loss = loss_function(out, train_y)
loss.backward()
optimizer.step()
optimizer.zero_grad()
train_loss.append(loss.item())
'访问损失函数的值,您可以使用loss.item()方法。'
'该方法将损失函数的标量值作为Python浮点数返回'
'您可以使用loss.item()方法。该方法将损失函数的标量值作为Python浮点数返回'
# 将训练过程的迭代次数和损失值写入文档保存,并在终端打印出来
with open('log.txt', 'a+') as f:
f.write('{} - {}\n'.format(i + 1, loss.item()))
if (i + 1) % 1 == 0:
print('Epoch: {}, Loss:{:.5f}'.format(i + 1, loss.item()))
torch.save(model,"model.pt")
# 画loss曲线 matplotlib
plt.figure()#创建一个图形,空白画布
plt.plot(train_loss, c='b', label='loss')#plt.plot(x可省略, y, format_string, 样式**kwargs)
plt.title("Train_Loss_Curve")
plt.ylabel('train_loss')
plt.xlabel('epoch_num')
plt.savefig('loss.png', format='png', dpi=200)
plt.close()
# torch.save(model.state_dict(), 'model_params.pkl') # 可以保存模型的参数供未来使用
t1 = time.time()
T = t1 - t0
print('The training time took %.2f' % (T / 60) + ' mins.')
tt0 = time.asctime(time.localtime(t0))
tt1 = time.asctime(time.localtime(t1))
print('The starting time was ', tt0)
print('The finishing time was ', tt1)
# for test
model = model.eval() # 转换成测试模式
# model.load_state_dict(torch.load('model_params.pkl')) # 读取参数
# 注意这里用的是全集 模型的输出长度会比原数据少DAYS_FOR_TRAIN 填充使长度相等再作图
dataset_x = dataset_x.reshape(-1, 1, DAYS_FOR_TRAIN) # (seq_size, batch_size, feature_size)
dataset_x = torch.from_numpy(dataset_x)
pred_test = model(dataset_x) # 全量训练集
# 的模型输出 (seq_size, batch_size, output_size)
pred_test = pred_test.view(-1).data.numpy()
pred_test = np.concatenate((np.zeros(DAYS_FOR_TRAIN), pred_test)) # 填充0 使长度相同
assert len(pred_test) == len(data_close)
plt.plot(pred_test, 'r', label='prediction')
plt.plot(data_close, 'b', label='real')
plt.plot((train_size, train_size), (0, 1), 'g--')#g-- 绿色虚线
# 分割线 左边是训练数据 右边是测试数据的输出
plt.legend(loc='best')#添加图例 loc='best'位置默认,自动选择最佳位置
plt.savefig('result.png', format='png', dpi=200)
plt.close()