神经网络预测 神经网络预测模型
前言
在上一篇文章《如何创建神经网络模型?几行代码搞定!》中,我们介绍了创建神经网络模型的方法。那么,接下来我们就使用自己创建的神经网络模型对股票涨跌进行预测,其预测效果如何呢?且看下文精彩内容。
定义模型网络结构
要使用神经网络模型对股票涨跌进行预测,首先我们需要定义模型的网络结构。这里我们定义的是一个全连接神经网络,有 2 个输入:分别是收益率序列和换手率序列,有 1 个输出:未来10个交易日涨幅是否超过5%。理论依据是,我假设股票后续的涨跌受前面30天收益率和换手率的影响。也就是说,我们这个模型要做的事情是,根据前30个交易日的收益率和换手率数据,来预测将来10个交易日之内涨幅是否超过5% 。
下面是模型定义的代码:
Classification Model
class ClsModel(nn.Module):
def __init__(self):
super().__init__()
self.linear1 = nn.Linear(30, 30)
self.linear2 = nn.Linear(30, 30)
self.linear3 = nn.Linear(30, 2)
def forward(self, x1, x2):
x1 = torch.sigmoid(self.linear1(x1))
x2 = torch.sigmoid(self.linear2(x2))
x = x1 + x2
x = torch.sigmoid(self.linear3(x))
return x
print(&34;----- Finished -----&34;)
模型可视化后,我们可以非常直观地看到它的网络结构:
自定义数据集类
这里自定义数据集类的目的是,方便在训练时调用训练框架现成的 DataLoader 接口来对数据进行加载。
from torch.utils.data import Dataset, DataLoader
import os
from torchvision import transforms
import pickle
from sklearn import preprocessing
import pandas as pd
class PickleDataset(Dataset):
def __init__(self, dataset_dir, transform=None):
self.dataset_dir = dataset_dir
self.transform = transform
x_data = []
y_label = []
读取 bin 文件
for filename in os.listdir(dataset_dir):
file_path = os.path.join(dataset_dir, filename)
GrowthRate005 = filename.split(&34;_&34;)[3]
GrowthRate005 = int(GrowthRate005)
y_label.append(GrowthRate005)
try:
f = open(file_path, &39;rb&39;)
pickle_data = pickle.load(f)
f.close
except EOFError:
print(file_path)
ChangePercent_list = pickle_data[&34;ChangePercent&34;]
TurnoverRatio_list = pickle_data[&34;TurnoverRatio&34;]
temp_data = []
for data in ChangePercent_list:
temp_data.append(data)
for data in TurnoverRatio_list:
temp_data.append(data)
x_data.append(temp_data)
self.data_list = x_data
self.label_list = y_label
def __len__(self):
return len(self.data_list)
def __getitem__(self, idx):
x_data = self.data_list[idx]
y_label = self.label_list[idx]
x_data, y_label = map(torch.tensor, (x_data, y_label))
x_data = x_data.to(torch.float32)
return (x_data, y_label)
print(&34;----- Finished -----&34;)
数据集加载测试
上面我们自定义了数据集类,那么,在正式开始模型训练之前,我们需要进行数据集加载测试,检查数据集加载是否正确,是否是我们所期望的数据格式。
train_dataset = PickleDataset(dataset_dir=&34;./dataset/classification/train/&34;)
valid_dataset = PickleDataset(dataset_dir=&34;./dataset/classification/val/&34;)
print(&34;length of train_dataset: {}&34;.format(len(train_dataset)))
print(&34;length of valid_dataset: {}&34;.format(len(valid_dataset)))
print(valid_dataset[0])
train_loader = DataLoader(train_dataset, batch_size=4, shuffle=True)
valid_loader = DataLoader(valid_dataset, batch_size=4, shuffle=True)
for idx, data in enumerate(train_loader):
print(&34;length of data: {}&34;.format(len(data)))
print(&34;length of data[0][0]: {}&34;.format(len(data[0][0])))
print(data[1]) x 对应的 y 数据
print(data[0]) x 数据
break
print(&34;----- Finished -----&34;)
从下图的运行结果中,我们可以看到,我这一批用来测试的数据,训练集总共有 36193 个样本,验证集有 2000 个样本。
编写模型训练策略
模型训练策略,主要是创建模型实例、加载数据、设置优化器、设置损失函数、梯度更新、模型保存之类的,具体情况如下面的代码所示:
from torch import optim
import torch.nn.functional as F
def loss_batch(model, loss_func, xb, yb, opt=None):
input_x1 = xb[:,11:41]
input_x2 = xb[:,52:82]
output = model(input_x1, input_x2)
loss = loss_func(model(input_x1, input_x2), yb)
if opt is not None:
loss.backward()
opt.step()
opt.zero_grad()
return loss.item(), len(xb)
def get_data(train_ds, valid_ds, bs):
return (
DataLoader(train_ds, batch_size=bs, shuffle=True),
DataLoader(valid_ds, batch_size=bs),
)
def get_model():
model = ClsModel()
return model, optim.SGD(model.parameters(), lr=0.001)
def train(model, loss_func, opt, train_dl, valid_dl, epochs):
best_acc = 0
for epoch in range(epochs):
model.train()
for x, y in train_dl:
x = x.to(torch.float32)
loss_batch(model, loss_func, x, y, opt)
model.eval()
计算验证集的损失值
with torch.no_grad():
losses, nums = zip(
*[loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl]
)
train_losses, train_nums = zip(
*[loss_batch(model, loss_func, xb, yb) for xb, yb in train_dl]
)
val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)
train_loss = np.sum(np.multiply(train_losses, train_nums)) / np.sum(train_nums)
计算当前模型在验证集上的预测精度
correct_num = 0
total_num = 0
for xb, yb in valid_dl:
xb = xb.to(torch.float32)
input_x1 = xb[:,11:41]
input_x2 = xb[:,52:82]
outputs = model(input_x1, input_x2)
value, predict = torch.max(outputs, 1)
correct_num += (predict == yb).sum()
total_num += len(yb)
accuracy = correct_num/total_num
if accuracy > best_acc:
best_acc = accuracy
保存模型
str_best_acc = &34;{:.4f}&34;.format(float(best_acc))
best_model_save_path = &34;./output30/best_model_&34; + str_best_acc + &34;.pth&34;
torch.save(model, best_model_save_path)
print(&34;[Info] save {} success .&34;.format(best_model_save_path))
now_time = datetime.datetime.now().strftime(&34;%Y-%m-%d %H:%M:%S&34;)
print(&34;[{}] epoch: {}, train_loss: {}, val_loss: {}, accuracy = {}&34;.format(now_time, epoch, train_loss, val_loss, accuracy))
print(&34;nums: {}, losses: {}&34;.format(nums, losses))
return
print(&34;----- Finished -----&34;)
开始训练模型
上面我们已经写好了模型训练的策略,现在,可以开始调用那些函数对模型进行训练了。
from torch import optim
import torch.nn.functional as F
获取数据
bs = 256
train_dl, valid_dl = get_data(train_dataset, valid_dataset, bs)
获取模型和优化器
model, optimizer = get_model()
更换优化器
optimizer = optim.Adam(model.parameters(), lr=0.0001)
开始训练
loss_func = F.cross_entropy
epochs = 5000
train(model, loss_func, optimizer, train_dl, valid_dl, epochs)
print(&34;----- Finished -----&34;)
训练详情如下图所示:
从上图的模型训练过程图中,我们可以看到,随着训练迭代轮次的增加,其预测的准确率逐渐上升,截至我写到这里,预测的准确率为:59.90% !说明我们的前面的理论假设有一定的道理,前30天的收益率和换手率确实对未来十天的涨幅有影响,至于影响的程度有多少,还需进一步探究。
使用训练好的模型对股票涨跌进行预测
通过前面我们介绍的方法训练好模型后,我们就可以使用保存下来的准确率最高的模型对股票将来的涨幅进行预测了。要特别指出是,这里我们模型的预测任务是:判断未来十个交易日内,股票涨幅是否超过5% 。如果模型输出是 0,则表示未来十个交易日内,该股票的涨幅不会超过 5%;如果模型输出是 1,则表示未来十个交易日内,该股票涨幅将会超过 5% 。
加载模型文件
MODEL_PATH = &34;./output30/best_model_0.5990.pth&34;
model = torch.load(MODEL_PATH)
model.eval()
获取数据
bs = 1
train_dataset = PickleDataset(dataset_dir=&34;./dataset/classification/train/&34;)
valid_dataset = PickleDataset(dataset_dir=&34;./dataset/classification/val/&34;)
train_dl, valid_dl = get_data(train_dataset, valid_dataset, bs)
print(&34;length of train_dataset: {}&34;.format(len(train_dataset)))
print(&34;length of valid_dataset: {}&34;.format(len(valid_dataset)))
soft_max = nn.Softmax(dim=1)
test_num = 0
true_num = 0
false_num = 0
with torch.no_grad():
for xb, yb in valid_dl:
input_x1 = xb[:,11:41]
input_x2 = xb[:,52:82]
output = model(input_x1, input_x2)
output_soft_max = soft_max(output)
value, predict = torch.max(output_soft_max, 1)
yb_np = yb.cpu().numpy()
predict = predict.cpu().numpy()
score = value.cpu().numpy()
test
if score < 0.7:
continue
test_num += 1
if yb_np == predict:
true_num += 1
else:
false_num += 1
success_rate = round((true_num/test_num)*100, 2)
print(&34;test_num: {}, yb: {}, predict: {}, score: {}, true_num: {}, false_num: {}, 准确率: {}&34;.format(test_num, yb_np, predict, score, true_num, false_num, success_rate))
break
print(&34;----- Finished -----&34;)
程序运行结果如下图所示:
从模型预测结果图中,我们可以看到,置信度大于0.7时,模型预测的准确率为 80% 。看到此处,可能会有朋友感到困惑,我们明明加载的是 best_model_0.5990.pth 模型文件,其在验证集中评估的准确率为 59.90%,为啥到了这里,准确率却变成了 80%?
实际上,答案就在模型预测的代码中了,可以看到,我们把置信度低于 0.7 的预测结果都筛除出去了,所以最终的准确率提高了,原因就是这么简单。
结语
以上就是我们使用自定义的神经网络模型对股票涨跌进行预测的案例了,感觉不错的话,可以帮忙点个赞哦,大家的支持是我继续更新下去的动力。
最后,需要提醒大家的是,模型预测的准确性不仅和模型的网络结构设计有关,还和数据的内容有关。数据的内容和我们要预测的事物之间,一定要有内在的关联才行,否则,再好的网络模型也无法预测哦。大家可以尝试自己搭建模型,使用自己的数据进行训练,相信你们能得到比我更好的结果。