当前位置:   article > 正文

【TensorFlow】使用RNN预测时间序列_international-airline-passengers.csv

international-airline-passengers.csv

现有一个时间序列international-airline-passengers.csv,怎么使用RNN来预测呢?本文就对其进行详细的阐述。

本时间序列一共144行,数据量很小,但是用其来学习RNN的使用已经足够了。

使用RNN预测时间序列的整体思路是:

  1. 取时间序列的第二列(international-airline-passengers.csv的第一列数据为时间,未在本次程序中使用),由于第二列值差异较大,所以本文采用“(原值-平均值)/标准差”的方法对数据进行标准化处理,前80%的数据作为训练集train_x,后20%的数据作为测试集test_x。
  2. 设置RNN的参数:input_dim=1、seq_size=5、hidden_dim=100
  3. 训练集和测试集的标签分别记为train_y、test_y,train_x和train_y的值错开了一个单位,test_x和test_y的值也是错开一个单位,便于计算cost值
  4. RNN模型的输出out为5个值的一维数组

实现程序

读CSV文件、数据标准化data_loader.py:

  1. import csv
  2. import numpy as np
  3. import matplotlib.pyplot as plt
  4. def load_series(filename, series_idx=1):
  5. try:
  6. with open(filename) as csvfile:
  7. csvreader = csv.reader(csvfile)
  8. data = [float(row[series_idx]) for row in csvreader if len(row) > 0]
  9. # 数据标准化,可以使数据的浮动差异不那么大,使预测结果更准确。np.mean求平均值,np.std求标准差。
  10. normalized_data = (data - np.mean(data)) / np.std(data)
  11. return normalized_data
  12. except IOError:
  13. return None
  14. # 把数据切分成80%训练集、20%测试集
  15. def split_data(data, percent_train=0.80):
  16. num_rows = len(data)
  17. train_data, test_data = [], []
  18. for idx, row in enumerate(data):
  19. if idx < num_rows * percent_train:
  20. train_data.append(row)
  21. else:
  22. test_data.append(row)
  23. return train_data, test_data
  24. if __name__ == '__main__':
  25. timeseries = load_series('international-airline-passengers.csv')
  26. print(np.shape(timeseries))
  27. plt.figure()
  28. plt.plot(timeseries)
  29. plt.show()

144条数据的显示结果:

模型训练rnn_ts.py:

  1. import numpy as np
  2. import tensorflow as tf
  3. from tensorflow.contrib import rnn
  4. import data_loader
  5. import matplotlib.pyplot as plt
  6. class SeriesPredictor:
  7. def __init__(self, input_dim, seq_size, hidden_dim):
  8. # Hyperparameters
  9. self.input_dim = input_dim
  10. self.seq_size = seq_size
  11. self.hidden_dim = hidden_dim
  12. # Weight variables and input placeholders
  13. self.W_out = tf.Variable(tf.random_normal([hidden_dim, 1]), name='W_out')
  14. self.b_out = tf.Variable(tf.random_normal([1]), name='b_out')
  15. self.x = tf.placeholder(tf.float32, [None, seq_size, input_dim])
  16. # 5个小片段,有5个预测值
  17. self.y = tf.placeholder(tf.float32, [None, seq_size])
  18. # Cost optimizer
  19. self.cost = tf.reduce_mean(tf.square(self.model() - self.y))
  20. self.train_op = tf.train.AdamOptimizer(learning_rate=0.01).minimize(self.cost)
  21. # Auxiliary ops
  22. self.saver = tf.train.Saver()
  23. def model(self):
  24. """
  25. :param x: inputs of size [T, batch_size, input_size]
  26. :param W: matrix of fully-connected output layer weights
  27. :param b: vector of fully-connected output layer biases
  28. """
  29. cell = rnn.BasicLSTMCell(self.hidden_dim)
  30. outputs, states = tf.nn.dynamic_rnn(cell, self.x, dtype=tf.float32)
  31. num_examples = tf.shape(self.x)[0]
  32. W_repeated = tf.tile(tf.expand_dims(self.W_out, 0), [num_examples, 1, 1])
  33. out = tf.matmul(outputs, W_repeated) + self.b_out
  34. out = tf.squeeze(out)
  35. # 返回长度为5的一维数组
  36. return out
  37. def train(self, train_x, train_y, test_x, test_y):
  38. with tf.Session() as sess:
  39. tf.get_variable_scope().reuse_variables()
  40. sess.run(tf.global_variables_initializer())
  41. max_patience = 3
  42. patience = max_patience
  43. # 最小err指定为无限
  44. min_test_err = float('inf')
  45. step = 0
  46. # test_err出现3次浮动停下
  47. while patience > 0:
  48. _, train_err = sess.run([self.train_op, self.cost], feed_dict={self.x: train_x, self.y: train_y})
  49. if step % 100 == 0:
  50. test_err = sess.run(self.cost, feed_dict={self.x: test_x, self.y: test_y})
  51. print('step:{}\t\ttrain err:{}\t\ttest err:{}'.format(step, train_err, test_err))
  52. if test_err < min_test_err:
  53. min_test_err = test_err
  54. patience = max_patience
  55. else:
  56. patience -= 1
  57. step += 1
  58. save_path = self.saver.save(sess, './model/')
  59. print('Model saved to {}'.format(save_path))
  60. def test(self, sess, test_x):
  61. tf.get_variable_scope().reuse_variables()
  62. self.saver.restore(sess, './model/')
  63. output = sess.run(self.model(), feed_dict={self.x: test_x})
  64. return output
  65. def plot_results(train_x, predictions, actual, filename):
  66. plt.figure()
  67. num_train = len(train_x)
  68. # 训练集。plt.plot(x,y,format_string,**kwargs) x轴数据,y轴数据
  69. plt.plot(list(range(num_train)), train_x, color='b', label='training data')
  70. # 预测集
  71. plt.plot(list(range(num_train, num_train + len(predictions))), predictions, color='r', label='predicted')
  72. # 真实值
  73. plt.plot(list(range(num_train, num_train + len(actual))), actual, color='g', label='test_data')
  74. # 加图例
  75. plt.legend()
  76. if filename is not None:
  77. plt.savefig(filename)
  78. else:
  79. plt.show()
  80. if __name__ == '__main__':
  81. # 序列长度,基于一个小片段去预测下一个值
  82. seq_size = 5
  83. predictor = SeriesPredictor(input_dim=1, seq_size=seq_size, hidden_dim=100)
  84. data = data_loader.load_series('international-airline-passengers.csv')
  85. # 数据切分成训练集,测试集
  86. train_data, actual_vals = data_loader.split_data(data)
  87. train_x, train_y = [], []
  88. for i in range(len(train_data) - seq_size - 1):
  89. # 训练数据和标签错开了1个单位
  90. train_x.append(np.expand_dims(train_data[i:i + seq_size], axis=1).tolist())
  91. train_y.append(train_data[i + 1: i + seq_size + 1])
  92. test_x, test_y = [], []
  93. for i in range(len(actual_vals) - seq_size - 1):
  94. test_x.append(np.expand_dims(actual_vals[i:i + seq_size], axis=1).tolist())
  95. test_y.append(actual_vals[i + 1: i + seq_size + 1])
  96. predictor.train(train_x, train_y, test_x, test_y)
  97. with tf.Session() as sess:
  98. # [:, 0]为什么是0呢?不应该是-1么?
  99. # 1、用训练好的模型'./model/'预测,所以第一个值也是基于前面序列预测到的。
  100. # 2、画图时使预测值和真实值具有对照性。
  101. predicted_vals = predictor.test(sess, test_x)[:, 0]
  102. print('predicted_vals', np.shape(predicted_vals))
  103. plot_results(train_data, predicted_vals, actual_vals, 'predictions.png')
  104. # 拿出训练集最后5个数据
  105. prev_seq = train_x[-1]
  106. predicted_vals = []
  107. for i in range(20):
  108. next_seq = predictor.test(sess, [prev_seq])
  109. # 把预测的结果当做当前的结果值,继续预测。
  110. predicted_vals.append(next_seq[-1])
  111. # np.vstack:按垂直方向(行顺序)堆叠数组构成一个新的数组;np.hstack:按水平方向(列顺序)堆叠数组构成一个新的数组
  112. # prev_seq[1:]取第二至第五个数据,一共4个数据
  113. prev_seq = np.vstack((prev_seq[1:], next_seq[-1]))
  114. plot_results(train_data, predicted_vals, actual_vals, 'hallucinations.png')

运行结果:

  1. step:0 train err:1.8898743391036987 test err:2.7799108028411865
  2. step:100 train err:0.04205527901649475 test err:0.2253977209329605
  3. step:200 train err:0.039602071046829224 test err:0.28264862298965454
  4. step:300 train err:0.03779347985982895 test err:0.2434949427843094
  5. step:400 train err:0.03636837378144264 test err:0.2533899247646332
  6. Model saved to ./model/
  7. predicted_vals (22,)

predictions.png:

hallucinations.png:

停止迭代方法大概有三种:

  1. 精度大于某个阈值停下来。例:acc>=0.98停下来;
  2. 测试err出现几次浮动停下来;
  3. 迭代次数达到XXX次停下来。

本文采用的是第二种方法。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/354554
推荐阅读
  

闽ICP备14008679号