数据集和代码:链接:https://pan.baidu.com/s/1hwk7rRJr_pZgKbUBWI6TNQ
提取码:jwpl
数据集是精简排序过的,我们唯一需要用到的属性就是[‘Lane 1 Flow (Veh/5 Minutes)’]。
任务就是用前12个连续时刻的状态数据[St0,St1,…,St11]预测第13个时刻的状态pSt12。
我就min-max归一化了一下,没特别处理。其中lags=12就是时间步,也就是time_step,所有数据都被我做成了三维的矩阵,与LSTM的输入输出[batch_size,time_step,feature_num]对应:
#数据集处理:
trainData=np.array(list(pd.read_csv('train.csv', lineterminator='\n')['Lane 1 Flow (Veh/5 Minutes)']))
testData=np.array(list(pd.read_csv('test.csv',lineterminator='\n')['Lane 1 Flow (Veh/5 Minutes)']))
trainLen=len(trainData)
testLen=len(testData)
combineData=np.append(trainData,testData)
scl=MinMaxScaler()
combineData=scl.fit_transform(combineData.reshape(-1, 1))
min=scl.data_min_
max=scl.data_max_
trainData=combineData[:trainLen]
testData=combineData[trainLen:trainLen+testLen]
lags=12
train=[]
test=[]
#虽然特征只有一维,但我们还是做成[batch_size,time_step,feature_num]的形式
for i in range(lags,trainLen):
train.append(trainData[i-lags:i+1])
for i in range(lags,testLen):
test.append(testData[i-lags:i+1])
train=np.array(train)
test=np.array(test)
x_train=train[:,:-1]
y_train=train[:,-1,np.newaxis]
x_test=test[:,:-1]
y_test=test[:,-1,np.newaxis]
tensorflow搭建神经网络的流程是建立计算图,编译计算图,然后传入数据,也就是静态图(2.0有动态图了,不过没用过)。计算图其实就是张量tensor和数据流向flow组成的,张量其实就是矩阵,也就是说tensorflow实现神经网络的本质实际上就是自定义了一个大的矩阵运算函数,LSTM、GRU都可以理解为一种封装好的复杂矩阵运算。
Tensorflow中的LSTM接受一个形状为[batch_size,time_step,feature_num]的矩阵,输出一个形状为[batch_size,time_step,rnn_units]的矩阵,batch_size即batch的大小,time_step是时间步,也就是本题中的lags=12,feature_num是每项数据的属性列数量,本题中只有一个[‘Lane 1 Flow (Veh/5 Minutes)’],所以为1,rnn_units即RNN神经元的数量。
RNN的处理过程,可以理解为,对于接受的矩阵[batch_size,time_step,feature_num]进行batch_size次操作;在每个batch的操作中,又进行time_step次计算,每次计算的是t-1时刻的状态,输出的是模型预测的t时刻的状态。比如对于每个batch:
然后LSTM的输入输出就是batch_size个这样的矩阵的拼接。
即用t0-t11这样12个时刻的状态数据,预测t13的状态,不考虑batch_size,ti时刻状态用Sti表示,投入LSTM的输入是序列[St0,St1,…,St11],而LSTM的输出是序列[pSt1,pSt2,…,pSt12]。
其中pSti代表LSTM根据输入i-1时刻的输入状态,预测的i时刻的状态。
所以对于从LSTM输出的数据,就有两种处理方法;
1.把整个输出[pSt1,pSt2,…,pSt12]后面接一层全连接层,这样的理论依据是可以包含以往数据的信息。
2.只取出最后的输出pSt12作为结果,舍弃[pSt1,pSt2,…,pSt11]
同样的损失函数的计算也就分为对[pSt1,pSt2,…,pSt12]和[St1,St2,…,St11,St12(y)]算损失函数和只对pSt12和St12(y)算损失函数。
我的代码里是直接取了pSt12作为结果,只对pSt12和St12(y)算损失函数。
#定义神经网络:
feature_num=1
batch_size=128
epochs=4
time_step=12
pre_num=1
x_in=tf.placeholder(tf.float32, [None, time_step,feature_num])
y_in=tf.placeholder(tf.float32, [None, pre_num,feature_num])
batch=tf.shape(x_in)[0]
#定义常量
rnn_unit=32 #hidden layer units
output_size=1
lr=5e-4 #学习率
#输入层、输出层权重、偏置(relu)
weights={
'out':tf.Variable(tf.random_normal([rnn_unit,1]))
}
biases={
'out':tf.Variable(tf.constant(0.1,shape=[1,]))
}
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, x_in,initial_state=init_state, dtype=tf.float32) #output_rnn是记录lstm每个输出节点的结果,final_states是最后一个cell的结果
output=output_rnn[:,time_step-pre_num:time_step,:]
output=tf.reshape(output,[-1,rnn_unit])
w_out = weights['out']
b_out = biases['out']
pred = tf.matmul(output, w_out) + b_out
loss = tf.losses.mean_squared_error(tf.reshape(pred, [-1]), tf.reshape(y_in, [-1]))
#tf.reduce_mean(tf.square(tf.reshape(pred, [-1]) - tf.reshape(y_in, [-1])))
train_op = tf.train.AdamOptimizer(lr).minimize(loss)
这里主要说一下学习率的问题,学习率设高了无法通过递归下降到极值点,学习率设低了也可能会因为学习率太小而下降到局部极值点,从而成为局部最优,两种都不能产生比较好的模型:
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print('模型训练:')
for i in range(epochs):
for j in range(len(x_train)//batch_size):
_,pre_loss=sess.run([train_op,loss],feed_dict={x_in:x_train[j*batch_size:(j+1)*batch_size],y_in:y_train[j*batch_size:(j+1)*batch_size]})
if (len(x_train) % batch_size != 0):
_,pre_loss=sess.run([train_op,loss],feed_dict={x_in: x_train[(len(x_train) // batch_size) * batch_size:len(x_train)],y_in:y_train[(len(x_train) // batch_size) * batch_size:len(x_train)]})
print(i,'th epaoch,last batch:',pre_loss)
print('模型预测:')
resPre=[]
for i in range(len(x_test)//batch_size):
predList=sess.run(pred,feed_dict={x_in:x_test[i*batch_size:(i+1)*batch_size]})
for j in predList:
resPre.append(j[0]);
if (len(x_test)%batch_size!=0):
predList=sess.run(pred,feed_dict={x_in:x_test[(len(x_test)//batch_size)*batch_size:len(x_test)]})
for j in predList:
resPre.append(j[0]);
accRes=[]
for i in y_test:accRes.append(i[0][0])
resPre=np.array(resPre)
accRes=np.array(accRes)
print(sess.run(tf.losses.mean_squared_error(resPre, accRes)))
plt.plot(list(range(len(accRes))), accRes, color='b')
plt.plot(list(range(len(resPre))), resPre, color='r')
plt.show()