尝试阶段,本科课设,简易实现,应付期末,还在探索,欢迎交流
来自老师给的CSV文件,共3000多行,每行包含字段如下:
avg_price | close | amp_rate | factor | high_limit | low_limit | open | quote_rate | turnover | turnover_rate | volume |
---|
本次预测是就是基于上述字段,预测之后某一天的股票平均价格。
https://zybuluo.com/hanbingtao/note/541458
https://tf.wiki/
http://www.tensorfly.cn/
output_rnn,final_states=tf.nn.dynamic_rnn(cell, input_rnn,initial_state=init_state, dtype=tf.float32)
#output_rnn是记录lstm每个输出节点的结果,final_states是最后一个cell的结果
#dynamic_rnn是一套循环操作,输入初始和值和状态,返回最终的值和状态
#输入初始的值的shape=(batch_size,time_step,rnn_unit),初始状态是h(batch_size,rnn_unit),c(batch_size,rnn_unit),每批的每组都有对应的状态
#输出值:shape=(batch_size,time_step,rnn_unit),因为每一组、每一个时间步、每一个细胞中都会有一个输出值
#输出状态:h(batch_size,rnn_unit),c(batch_size,rnn_unit) 每一组中的每一个细胞最后会得出一个状态值(h和c),
#output_rnn与final_states的关系:output_rnn是每个时间步的输出组成的矩阵,对于output_rnn中一个时间步内的数据h来说,经过一次y=wh+b变化得到这个时间步输出的结果y
#output_rnn中每个时间步的输出就是这个时间步的状态h,这个h还将用于下一个时间步的输出与状态的计算,也就是说每一个时间步的状态(c,h)都由上一个时间步的输出h和本次时间步的输入x计算得到
#output_rnn最后一个时间步的输出等于final_states中的h
#对于一批数据而言(一批有好多组),不同组数据的状态值是独立的,但是大家用的都是一套权重参数
#负向反馈的目标,是让loss尽可能低,这个loss是对一批数据(一批有很多组)的综合评价,修改后的权重参数并非让每一组的结果变的更好,而是让一批数据整体的结果变得更好
#如果不同批次内,同一组号的数据连接在一起结果是延时间的连续的,则final_states也应该feed进去,不考虑负向反馈的话,假如一共有n批数据,这样做等价于使用第一批数据并把时间步扩充了n倍的效果
#考虑负向反馈的话,这样做等价于,时间步扩充了n倍,但每次过固定数目的时间步就对之前一定数目的结果整体评估一下,然后更新权重参数
#相比于直接将时间步扩充了n倍,这样做准确度可能不如直接扩充,但是某一瞬间消耗的内存应该是小于直接扩充的,毕竟每次负向反馈的处理的权重参数少了很多
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
#训练和预测
only_prediction=0
#数据常量
colnums=21
output_size=10
rows=3000
#神经网络常量
rnn_unit=20 #hidden layer units
input_size=colnums-output_size
batch_size=5
time_step=10
epoch=2000
lr=0.0006 #学习率
#其他常数
# model_path='./model'
model_path='./model2'
data_path='./dataset.csv'
# 定义输入输出的w和b
wi = tf.Variable(tf.random_normal([input_size, rnn_unit]))
bi = tf.Variable(tf.random_normal(shape=[rnn_unit, ], mean=0.0, stddev=1.0))
wo = tf.Variable(tf.random_normal([rnn_unit, output_size]))
bo = tf.Variable(tf.random_normal(shape=[output_size, ], mean=0.0, stddev=1.0))
#导入数据
def import_data():
f=open(data_path)
df=pd.read_csv(f) #读入股票数据
data=df.iloc[:rows,:colnums].values
return data
#获取训练集
def get_train_data(data,train_begin=0,train_end=500):
batch_index=[]
data_train=data[train_begin:train_end]
train_x,train_y=[],[] #训练集
for i in range(int(len(data_train)/time_step)):
if i % batch_size==0:
batch_index.append(i)
data = data_train[i*time_step:(i+1)*time_step,:] # 对每批中每组数据进行标准化
x=data[:,:colnums-output_size]
mean_x=np.mean(x, axis=0)
std_x=np.std(x, axis=0) + 0.1
x = (x - mean_x) / std_x
y=data[:,colnums-output_size:colnums]
mean_y=np.mean(y, axis=0)
std_y=np.std(y, axis=0) + 0.1
y = (y - mean_y) / std_y
train_x.append(x.tolist())
train_y.append(y.tolist())
return batch_index,train_x,train_y
#获取测试集
def get_test_data(data,test_begin=0,test_end=20):
data_test=data[test_begin:test_end]
test_x,test_y,mean,std=[],[],[],[]
for i in range(int(len(data_test)/time_step)):
x=data_test[i*time_step:(i+1)*time_step,:colnums-output_size]
mean_x = np.mean(x, axis=0)
std_x = np.std(x, axis=0) + 0.1
x = (x - mean_x) / std_x
mean_y, std_y = [], []
for j in (range(output_size)):
mean_y.append(mean_x[0])
std_y.append(std_x[0])
mean.append(mean_y)
std.append(std_y)
test_x.append(x.tolist())
test_y=data_test[:,0]
return test_x,test_y,mean,std
#定义模型
def RNN(cell,X,init_state):
#定义隐藏层的运算
input=tf.reshape(X,[-1,input_size])
input_rnn=tf.matmul(input,wi)+bi
input_rnn=tf.reshape(input_rnn,[-1,time_step,rnn_unit])
output_rnn,final_states=tf.nn.dynamic_rnn(cell, input_rnn,initial_state=init_state, dtype=tf.float32) #output_rnn是记录lstm每个输出节点的结果,final_states是最后一个cell的结果
output=tf.reshape(output_rnn,[-1,rnn_unit]) #作为输出层的输入
pred=tf.matmul(output,wo)+bo
return pred,final_states
#开始训练
def train_data(train_begin=500,train_end=2500):
#读数据集,设置神经网络模型,准备X和Y,初始状态
batch_index, train_x, train_y = get_train_data(import_data(), train_begin, train_end)
cell = tf.nn.rnn_cell.BasicLSTMCell(rnn_unit)
X = tf.placeholder(tf.float32, shape=[None, time_step, input_size])
Y = tf.placeholder(tf.float32, shape=[None, time_step, output_size])
init_state = cell.zero_state(batch_size, dtype=tf.float32)
#构建计算图结点
pred, final_states=RNN(cell,X,init_state)
loss = tf.reduce_mean(tf.square(tf.reshape(pred,[-1,]) - tf.reshape(Y,[-1,])))
train_op = tf.train.AdamOptimizer(lr).minimize(loss)
#声明保存模型需要用的对象
saver = tf.train.Saver(tf.global_variables(), max_to_keep=15)
#开始训练
sess = tf.Session()
sess.run(tf.global_variables_initializer())
for i in range(epoch):
for step in range(len(batch_index) - 1):
feed_dict = {
X: train_x[batch_index[step]:batch_index[step + 1]],
Y: train_y[batch_index[step]:batch_index[step + 1]]}
_, loss_, states = sess.run([train_op, loss, final_states],
feed_dict=feed_dict)
print( i, loss_)
if i % 20 == 0:
print("保存模型:", saver.save(sess, model_path+'/stock.model', global_step=i))
print("保存模型:", saver.save(sess, model_path, global_step=i))
sess.close()
#预测
def prediction(test_begin=0,test_end=500):
#读数据集,配置X和初始状态
test_x, test_y,mean,std = get_test_data(import_data(), test_begin, test_end)
X=tf.placeholder(tf.float32, shape=[None,time_step,input_size])
cell = tf.nn.rnn_cell.BasicLSTMCell(rnn_unit)
init_state = cell.zero_state(1, dtype=tf.float32)
#构建计算图结点
pred, final_states=RNN(cell,X,init_state)
#配置读取模型需要用的对象
saver=tf.train.Saver(tf.global_variables())
#开始预测
sess=tf.Session()
module_file = tf.train.latest_checkpoint(model_path)
saver.restore(sess, module_file)
test_predict=[]
for step in range(len(test_x)):
prob=sess.run(pred,feed_dict={
X:[test_x[step]]})
test_predict.append(prob[len(prob)-1])
sess.close
# acc = np.average(np.abs(test_predict - test_y) / test_y) # 偏差
# print(acc)
#以折线图表示结果
real=[]
pred=(np.array(test_predict)*std)+mean
plt.figure()
plt.plot(list(range(len(test_y))), test_y, color='r')
for step in range(0,len(test_predict)-1):
real.append(test_y[(step+1) * time_step:(step+1) * time_step + output_size])
plt.plot(list(range((step+1) * time_step, (step+1) * time_step + output_size)), pred[step], color='b', marker="v")
acc = np.average(np.abs( pred[:len(real)]-np.array(real)) / np.array(real)) # 偏差
print("acc", acc)
plt.show()
if only_prediction==0:
with tf.variable_scope('train'):
train_data(500,2000)
with tf.variable_scope('train', reuse=True):
prediction(2500, 3000)
else:
with tf.variable_scope('train'):
prediction(2500, 3000)
大三下学期软件工程的课设就是要求尝试使用RNN进行股票预测,我之前从未接触过Python和神经网络的相关知识,这次课设算是给了我一个学习的动力。
我的学习路线是bp神经网络,RNN神经网络,Python,TensorFlow。bp神经网络是开启我神经网络大门的钥匙,我学习的过程中,我曾对神经网络持有一种怀疑的态度,原因是,我对神经网络的认知是采用了一种特殊的数据结构,运用逐步接近最优的算法,通过大量输入与输出样本,模拟输入与输出中的某种规律,这种数据结构就是神经元,所采用的算法就是构造误差函数,使用梯度下降令误差函数达到最小。
梯度下降是其实并不难理解,假设y=f(x)是一元连续函数,梯度下降就是不断令x=x+ny’,假如y是某定义域内的凹函数,我们知道,y’=0的点是,该函数的极小值点,极小值点的左侧y’<0,而右侧y’>0,所以如果x梯度下降的起点在极小值点的左边,那么可见x在逐步增加的,如果起点在在极小值点右边,则x会逐步减少,且这种变化的幅度会随函数导数大小而改变,导数大变化幅度也大,导数小,变化幅度也小,可以想象,对于凹函数给定任意起点,不断使用梯度下降,最终x会收敛在极小值点。
我们可以求出误差函数对某一参数的偏导数,然后不断用梯度下降修正这个参数,当这个误差函数收敛到一个值时,则说明误差函数的极小值点(并非严谨定义上的极小值)时,参数应该接近的当前值,此时输出结果与预期结果相差的最小。神经网络用它独有的数据结构定义了大量参数,对这些参数求偏导并梯度下降,使误差函数收敛到一个值。
RNN和LSTM也是用的这个道理,只不过RNN和LSTM把一组运算的输出也作为输入的一部分进行运算,通常这两组数据具有时间先后关系,RNN是将之前的数据全部作为参考,而LSTM又引入了一组参数,可以令之前部分参数作为参考,即模型具备了遗忘能力。
学完Python后,我开始学习Python,Python我感觉从某个角度来说,和JavaScript很像,虽然是第一次接触Python,但是对于软件工程的学生来说,只做到能读懂代码还是很轻松的,我很快就完成了Python学习阶段,只学会了基础的语法和特性,Python的代码真的很简洁,写起来比Java得劲多了,但是Python还有很多进阶技巧我没来得及学,这个日后一定要补上。
TensorFlow框架把模型都封装好了,不改模型的话,只需要用它的api把运算图构建出来就好了,这个过程还好,理解神经网络后很快就上手了,但是一些机器学习领域的术语很让我困扰,不过还是在不断实践和查阅资料的过程中搞明白了。
课设完成了,准确率还行,只预测后一天的价格情况还好,越往后越跑偏,但是考虑到本身股票一天之内就没多大变化,所以这个准确率虽然高,但多少给人一点自欺欺人的感觉,说实话我不认为股票有什么规律可以用神经网络来模拟,股票作为一个多人博弈的过程,它很多影响因素在于外界,我认为单从历史数据预测未来不是很把握,所以对于这个准确率我还是蛮惊讶的,期末又和老师以及其他同学交流过,我这套代码只能说是实现了,在数据预处理和超参数调整方面还有进步空间,马上要考研了,近期可能不会有很多时间来改进了,待以后慢慢摸索学习吧
相对误差的平均值 0.03125852369012719