【深度学习】【python】LSTM实现用于时间序列预测 中文注释版

【深度学习】【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)

猜你喜欢

转载自blog.csdn.net/hanss2/article/details/81002551
今日推荐