【深度学习】【python】LSTM实现用于时间序列预测 中文注释版
环境要求
- python3.5
- tensorflow 1.4
- pytorch 0.2.0
本程序只需要tensorflow.
程序如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#source: "https://github.com/xiaohu2015/tensorflow/
"""LSTM模型:用于时间序列预测/回归"""
import sys
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
def batch_iterate(num_batchs, batch_size, num_steps):
"""根据sin cos函数生成用于mini batch的样本"""
start = 0
# 有num_batchs个batch;
for i in range(num_batchs):
# xo: 生成的序列变量:维度[batch_size, num_steps];
xo = np.arange(start, start+batch_size*num_steps).reshape(
[batch_size, num_steps])/(10.0*np.pi)
# 生成序列值x;
x = np.sin(xo)
# 生成序列值y;
y = np.cos(xo)
# 更新步数;
start += num_steps
# 返回当前batch的样本;
# yield 是一个类似 return 的关键字,迭代一次遇到yield时就返回yield后面(右边)的值;
yield (x[:, :, np.newaxis], y[:, :, np.newaxis], xo)
class LstmRegression(object):
"""lstm类:时间序列预测"""
def __init__(self, in_size, out_size, num_steps=20, cell_size=20, batch_size=50,
num_lstm_layers=2, keep_prob=0.5, is_training=True):
"""
-----------变量说明-----------------
:参数 in_size : int, 输入维度;
:参数 out_size : int, 输出维度;
:参数 num_steps : int, 时间步数;
:参数 cell_size : int, lstm cell数量;
:参数 batch_size : int, mini bacth数量;
:参数 num_lstm_layers: int, lstm layers数量;
:参数 keep_prob : float, 设置神经元被选中的概率;
:参数 is_training : bool, True:training model/False:test model;
"""
# 参数设置;
self.in_size = in_size
self.out_size = out_size
self.num_steps = num_steps
self.cell_size = cell_size
self.batch_size = batch_size
self.num_lstm_layers = num_lstm_layers
self.keep_prob = keep_prob
self.is_training = is_training
# 创建模型;
self.__build_model__()
def __build_model__(self):
"""创建lstm模型的内部函数."""
# 输入输出的占位符;
self.x = tf.placeholder(tf.float32, shape=[None, self.num_steps, self.in_size])
self.y = tf.placeholder(tf.float32, shape=[None, self.num_steps, self.out_size])
# 添加第一个层:输入层;
# variable_scope:作用域:把variable封装在variable_scope;直接在各个ops,function之间传递variable reference;
with tf.variable_scope("input"):
# 将x reshape成 2-D tensor;
inputs = tf.reshape(self.x, shape=[-1, self.in_size]) #[batch_size*num_steps, in_size]
# 创建input层参数;
W, b = self._get_weight_bias(self.in_size, self.cell_size)
# 计算W*x+b;
inputs = tf.nn.xw_plus_b(inputs, W, b, name="input_xW_plus_b")
# 将inputs reshape成3-D tensor;
inputs = tf.reshape(inputs, shape=[-1, self.num_steps, self.cell_size]) #[batch_size, num_steps, in_size]
# 对inputs进行Dropout;
if self.is_training and self.keep_prob < 1.0:
inputs = tf.nn.dropout(inputs, keep_prob=self.keep_prob)
# 构造lstm cells;
lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(self.cell_size, forget_bias=1.0, state_is_tuple=True)
# 对lstm_cells进行Dropout;
if self.is_training and self.keep_prob < 1.0:
lstm_cell = tf.nn.rnn_cell.DropoutWrapper(lstm_cell, output_keep_prob=self.keep_prob)
# 构造Multi Cell;
# 这个函数里面主要这两个参数,第一个参数就是输入的RNN实例形成的列表,第二个参数就是让状态是一个元组,官方推荐就是用True;
cell = tf.nn.rnn_cell.MultiRNNCell([lstm_cell]*self.num_lstm_layers)
# 对Multi Cell初始化;
self.init_state = cell.zero_state(self.batch_size, dtype=tf.float32)
# 添加第二个层:lstm层;
with tf.variable_scope("LSTM"):
# 声明该层输出的计算(输入的是上一层的输出"inputs");
outputs, final_state = tf.nn.dynamic_rnn(cell, inputs, initial_state=self.init_state)
# 更新final_state;
self.final_state = final_state
# 添加第三个层:输出层;
with tf.variable_scope("output"):
# 将上一层lstm层的输出reshape;
output = tf.reshape(outputs, shape=[-1, self.cell_size])
# 创建output层参数;
W, b = self._get_weight_bias(self.cell_size, self.out_size)
# 声明该层输出的计算;
output = tf.nn.xw_plus_b(output, W, b, name="output")
# 更新模型的pred;
self.pred = output
# 声明模型损失的计算;(self.pred对比self.y);
# sequence_loss_by_example():这个函数用于计算所有examples的加权交叉熵损失;
# 计算所有examples(假设一句话有n个单词,一个单词及单词所对应的label就是一个example,所有example就是一句话中所有单词)的加权交叉熵损失;
losses = tf.nn.seq2seq.sequence_loss_by_example([tf.reshape(self.pred, [-1,])], [tf.reshape(self.y, [-1,])],
[tf.ones([self.batch_size*self.num_steps])], average_across_timesteps=True,
softmax_loss_function=self._ms_cost)
# 声明模型最终的cost;
self.cost = tf.reduce_sum(losses)/tf.to_float(self.batch_size)
def _ms_cost(self, y_pred, y_target):
"""平方损失函数"""
return 0.5*tf.square(y_pred - y_target)
def _get_weight_bias(self, in_size, out_size):
"""构造weight/bias变量"""
weights = tf.get_variable("weight", shape=[in_size, out_size],
initializer=tf.random_normal_initializer(mean=0.0, stddev=1.0))
biases = tf.get_variable("bias", shape=[out_size,], initializer=tf.constant_initializer(0.1))
return weights, biases
"""主函数"""
if __name__ == "__main__":
# 训练参数设置;
batch_size = 50
in_size = 1
out_size = 1
cell_size = 10
num_steps = 20
lr = 0.002
num_batchs = 200
n_epochs = 10
# 开始执行;
with tf.Session() as sess:
# 声明了两个LstmRegression实例;pred_model在"model"声明域内共享model的参数;
with tf.variable_scope("model", reuse=None):
model = LstmRegression(in_size, out_size, num_steps=num_steps, cell_size=cell_size,
batch_size=batch_size, num_lstm_layers=2, keep_prob=0.5, is_training=True)
with tf.variable_scope("model", reuse=True):
pred_model = LstmRegression(in_size, out_size, num_steps=num_steps, cell_size=cell_size,
batch_size=batch_size, num_lstm_layers=2, keep_prob=1.0, is_training=False)
# 声明训练方式;
train_op = tf.train.AdamOptimizer(lr).minimize(model.cost)
# 声明cost的计算方式;
tf.summary.scalar("cost", model.cost)
#
merged = tf.merge_all_summaries()
# 写日志;
writer = tf.train.SummaryWriter("logs", sess.graph)
# 执行初始化;
sess.run(tf.global_variables_initializer())
# 初始步数;
global_steps = 0
# 执行模型的初始化;
state = sess.run(model.init_state)]
# 多个训练epoch开始;
for epoch in range(n_epochs):
# 声明损失;
losses = 0
# 执行多个batch的 训练、代价计算、模型最终state计算;
for x, y, xo in batch_iterate(num_batchs, batch_size, num_steps):
_, cost, state = sess.run([train_op, model.cost, model.final_state], feed_dict={model.x: x,
model.y: y, model.init_state: state})
# 计算losses;
losses += cost/num_batchs
# 输出loss详情;
print("Epoch {0}, cost {1}".format(epoch, losses))
# 使用pred_model模型预测;
# 画图;
plt.ion()
plt.show()
# 执行pred_model的初始化;
state = sess.run(pred_model.init_state)
# 执行多个batch的 预测(pred_model.pred)、模型最终state(pred_model.final_state)(其实就是模型参数)计算;
for x, y, xo in batch_iterate(num_batchs, batch_size, num_steps):
# 执行计算;
pred, state = sess.run([pred_model.pred, pred_model.final_state], feed_dict={pred_model.x: x,
pred_model.y: y, pred_model.init_state: state })
# 画图显示结果;
plt.plot(xo[0, :], y[0].flatten(), 'r', xo[0, :], pred.flatten()[:num_steps], 'b--')
plt.ylim((-1.2, 1.2))
plt.draw()
plt.pause(0.3)