RitterLiu 2018-09-04
这一部分主要涉及循环神经网络的理论,讲的可能会比较简略。
RNN全称循环神经网络(Recurrent Neural Networks),是用来处理序列数据的。在传统的神经网络模型中,从输入层到隐含层再到输出层,层与层之间是全连接的,每层之间的节点是无连接的。但是这种普通的神经网络对于很多关于时间序列的问题却无能无力。例如,你要预测句子的下一个单词是什么,一般需要用到前面的单词,因为一个句子中前后单词并不是独立的。RNN之所以称为循环神经网路,即一个序列当前的输出与前面的输出也有关。具体的表现形式为网络会对前面时刻的信息进行记忆并应用于当前输出的计算中,即隐藏层之间的节点不再无连接而是有连接的,并且隐藏层的输入不仅包括输入层的输出还包括上一时刻隐藏层的输出。
说了这么多,用一张图表示,就是这个样子。
传统的神经网络中,数据从输入层输入,在隐藏层加工,从输出层输出。RNN不同的就是在隐藏层的加工方法不一样,后一个节点不仅受输入层输入的影响,还包受上一个节点的影响。
展开来就是这个样子:
图中的x
t−1
xt−1 ,x
t
xt , x
t+1
xt+1就是不同时刻的输入,每个x都具有input layer的n维特征,依次进入循环神经网络以后,隐藏层输出s
t
st受到上一时刻s
t−1
st−1的隐藏层输出以及此刻输入层输入x
t
xt 的两方影响。
如果要更详细地了解tensorflow对RNN的解释,清戳官方tensorflow.RNN
另外推荐的学习资料:WildML
LSTM全称长短期记忆人工神经网络(Long-Short Term Memory),是对RNN的变种。举个例子,假设我们试着去预测“I grew up in France… 中间隔了好多好多字……I speak fluent __”下划线的词。我们拍脑瓜子想这个词应该是French。对于循环神经网络来说,当前的信息建议下一个词可能是一种语言的名字,但是如果需要弄清楚是什么语言,我们是需要离当前下划线位置很远的“France” 这个词信息。相关信息和当前预测位置之间的间隔变得相当的大,在这个间隔不断增大时,RNN 会丧失学习到连接如此远的信息的能力。
这个时候就需要LSTM登场了。在LSTM中,我们可以控制丢弃什么信息,存放什么信息。
具体的理论这里就不多说了,推荐一篇博文Understanding LSTM Networks,里面有对LSTM详细的介绍,有网友作出的翻译请戳[译] 理解 LSTM 网络
在对理论有理解的基础上,我们使用LSTM对股票每日最高价进行预测。在本例中,仅使用一维特征。
数据格式如下:
本例取每日最高价作为输入特征[x],后一天的最高价最为标签[y]
获取数据,请戳stock_dataset.csv,密码:md9l
import pandas as pd import numpy as np import matplotlib.pyplot as plt import tensorflow f=open('stock_dataset.csv') df=pd.read_csv(f) #读入股票数据 data=np.array(df['最高价']) #获取最高价序列 data=data[::-1] #反转,使数据按照日期先后顺序排列 #以折线图展示data plt.figure() plt.plot(data) plt.show() normalize_data=(data-np.mean(data))/np.std(data) #标准化 normalize_data=normalize_data[:,np.newaxis] #增加维度 #———————————————————形成训练集————————————————————— #设置常量 time_step=20 #时间步 rnn_unit=10 #hidden layer units batch_size=60 #每一批次训练多少个样例 input_size=1 #输入层维度 output_size=1 #输出层维度 lr=0.0006 #学习率 train_x,train_y=[],[] #训练集 for i in range(len(normalize_data)-time_step-1): x=normalize_data[i:i+time_step] y=normalize_data[i+1:i+time_step+1] train_x.append(x.tolist()) train_y.append(y.tolist()) 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 26 27 28
出来的train_x就是像这个样子:
[[[-1.59618],……中间还有18个……, [-1.56340]] …… [[-1.59202] [-1.58244]]] 1 2 3
是一个shape为[-1,time_step,input__size]的矩阵
X=tf.placeholder(tf.float32, [None,time_step,input_size]) #每批次输入网络的tensor Y=tf.placeholder(tf.float32, [None,time_step,output_size]) #每批次tensor对应的标签 #输入层、输出层权重、偏置 weights={ 'in':tf.Variable(tf.random_normal([input_size,rnn_unit])), 'out':tf.Variable(tf.random_normal([rnn_unit,1])) } biases={ 'in':tf.Variable(tf.constant(0.1,shape=[rnn_unit])), 'out':tf.Variable(tf.constant(0.1,shape=[1])) } 1 2 3 4 5 6 7 8 9 10 11 12
def lstm(batch): #参数:输入网络批次数目 w_in=weights['in'] b_in=biases['in'] input=tf.reshape(X,[-1,input_size]) #需要将tensor转成2维进行计算,计算后的结果作为隐藏层的输入 input_rnn=tf.matmul(input,w_in)+b_in input_rnn=tf.reshape(input_rnn,[-1,time_step,rnn_unit]) #将tensor转成3维,作为lstm cell的输入 cell=tf.nn.rnn_cell.BasicLSTMCell(rnn_unit) init_state=cell.zero_state(batch,dtype=tf.float32) 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]) #作为输出层的输入 w_out=weights['out'] b_out=biases['out'] pred=tf.matmul(output,w_out)+b_out return pred,final_states 1 2 3 4 5 6 7 8 9 10 11 12 13 14
def train_lstm(): global batch_size pred,_=rnn(batch_size) #损失函数 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()) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) #重复训练10000次 for i in range(10000): step=0 start=0 end=start+batch_size while(end<len(train_x)): _,loss_=sess.run([train_op,loss],feed_dict={X:train_x[start:end],Y:train_y[start:end]}) start+=batch_size end=start+batch_size #每10步保存一次参数 if step%10==0: print(i,step,loss_) print("保存模型:",saver.save(sess,'stock.model')) step+=1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
def prediction(): pred,_=lstm(1) #预测时只输入[1,time_step,input_size]的测试数据 saver=tf.train.Saver(tf.global_variables()) with tf.Session() as sess: #参数恢复 module_file = tf.train.latest_checkpoint(base_path+'module2/') saver.restore(sess, module_file) #取训练集最后一行为测试样本。shape=[1,time_step,input_size] prev_seq=train_x[-1] predict=[] #得到之后100个预测结果 for i in range(100): next_seq=sess.run(pred,feed_dict={X:[prev_seq]}) predict.append(next_seq[-1]) #每次得到最后一个时间步的预测结果,与之前的数据加在一起,形成新的测试样本 prev_seq=np.vstack((prev_seq[1:],next_seq[-1])) #以折线图表示结果 plt.figure() plt.plot(list(range(len(normalize_data))), normalize_data, color='b') plt.plot(list(range(len(normalize_data), len(normalize_data) + len(predict))), predict, color='r') plt.show() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
完整代码
这一讲只有把最高价作为特征,去预测之后的最高价趋势,下一讲会增加输入的特征维度,把最低价、开盘价、收盘价、交易额等作为输入的特征对之后的最高价进行预测。
注:本文在介绍RNN和LSTM的部分,出处若涉及版权问题或原文链接错误,请指正,必会马上修改。