小言_互联网的博客

【TensorFlow实战】LSTM原理及实现,进行海表温度及股价预测

371人阅读  评论(0)

本文简单介绍了LSTM网络原理,并展示了LSTM网络的TensorFlow实现,进行了海表温度及股价预测的实验。源代码见https://github.com/Su-Lemon/lstm-master

一 引言

LSTM 是一种RNN特殊的类型, 可以避免常规RNN的梯度消失问题,用来处理长序列的数据。LSTM 通过刻意的设计来避免长期依赖问题。

二 LSTM模型结构

2.1 整体结构

LSTM模型结构示意如下图所示。

每一条黑线传输着一整个向量,从一个节点的输出到其他节点的输入。方框中的圆圈代表运算操作( 如向量的和) ,而中间的方框就是学习到的神经网络层。合在一起的线表示向量的连接,分开的线表示内容被复制,然后分发到不同的位置。

这种结构的核心思想是引入了一个叫做细胞状态的连接,这个细胞状态用来存放想要记忆的东西。

  • 忘记门:决定什么时候需要把以前的状态忘记;
  • 输入门:决定什么时候加入新的状态;
  • 输出门:决定什么时候需要把状态和输入放在一起输出。

从字面意思可以看出,简单RNN 只是把上一次的状态当成本次的输入一起输出。而LSTM 在状态的更新和状态是否参与输入都做了灵活的选择, 具体选什么,则一起交给神经网络的训练机制来训练。

2.2 忘记门


忘记门,是控制是否遗忘的,在LSTM中即以一定的概率控制是否遗忘上一层的隐藏细胞状态。

图中输入的有上一序列的隐藏状态 h t 1 h_{t-1} 和本序列数据 x t x_{t} ,通过一个激活函数,一般是sigmoid,得到忘记门的输出 f t f_{t} 。由于sigmoid的输出 f t f_{t} [ 0 , 1 ] [0,1] 之间,因此这里的输出 f t f_{t} 代表了忘记上一层隐藏细胞状态的概率。用数学表达式即为上图右侧所示。其中 W f W_{f} , U f U_{f} , b f b_{f} 为线性关系的系数和偏置, σ σ 为sigmoid激活函数。

2.3 输入门


输入门,负责处理当前序列位置的输入。

从图中可以看到输入门由两部分组成,第一部分使用了sigmoid激活函数,输出为 i t i_{t} 第二部分使用了tanh激活函数,输出为 a t a_{t} ,两者的结果后面会相乘再去更新细胞状态。用数学表达式即为上图右侧所示。

2.4 输出门


从图中可以看出,隐藏状态 h t h_{t} 的更新由两部分组成,第一部分是 o t o_{t} ,它由上一序列的隐藏状态 h t 1 h_{t-1} 和本序列数据 x t x_{t} ,以及激活函数sigmoid得到,第二部分由隐藏状态 C t C_{t} 和tanh激活函数组成, 用数学表达式即为上图右侧所示。

三 TensorFlow搭建LSTM网络

下面展示了利用TensorFlow创建Encoder-Decoder 框架的LSTM网络的过程。完整的实验源码请前往https://github.com/Su-Lemon/lstm-master下载。

import tensorflow as tf
import numpy as np
import pandas as pd

from ..configs import config as cfg
pd.options.mode.chained_assignment = None  # default='warn'


class Net(object):
    def __init__(self):
        self.encoder_input = []
        self.expected_output = []
        self.decode_input = []
        self.losses = {}

        self.tcells = []
        self.Mcell = []
        self.reshaped_outputs = []

    def createNet(self, sess):
        for i in range(cfg.FLAGS.seq_len):
            self.encoder_input.append(
                tf.placeholder(tf.float32, shape=(None, cfg.FLAGS.input_dim)))
            self.expected_output.append(
                tf.placeholder(tf.float32, shape=(None, cfg.FLAGS.output_dim)))
            self.decode_input.append(
                tf.placeholder(tf.float32, shape=(None, cfg.FLAGS.input_dim)))

        # Create LSTM(GRU)
        for i in range(cfg.FLAGS.layers_num):
            self.tcells.append(tf.contrib.rnn.GRUCell(cfg.FLAGS.hidden_dim))
        self.Mcell = tf.contrib.rnn.MultiRNNCell(self.tcells)

        # Connected by Encoder-Decoder
        dec_outputs, dec_memory = tf.contrib.legacy_seq2seq.basic_rnn_seq2seq(
            self.encoder_input, self.decode_input, self.Mcell)

        # Create output leyer
        for ii in dec_outputs:
            self.reshaped_outputs.append(
                tf.contrib.layers.fully_connected(ii, cfg.FLAGS.output_dim,
                                                  activation_fn=None))
        # L2 loss
        output_loss = 0
        for _y, _Y in zip(self.reshaped_outputs, self.expected_output):
            output_loss += tf.reduce_mean(tf.pow(_y - _Y, 2))
        self.losses['output_loss'] = output_loss

        # generalization capacity
        reg_loss = 0
        for tf_var in tf.trainable_variables():
            if not ("fully_connected" in tf_var.name):
                # print(tf_var.name)
                reg_loss += tf.reduce_mean(tf.nn.l2_loss(tf_var))
        self.losses['reg_loss'] = reg_loss

        loss = output_loss + cfg.FLAGS.lambda_l2_reg * reg_loss
        self.losses['loss'] = loss
        return self.losses

    def trainer(self, sess, dataset, train_op, isTrain):
        X, Y = dataset.generateData(isTrain=True)
        feed_dict = {self.encoder_input[t]: X[t] for t in range(len(self.encoder_input))}
        feed_dict.update({self.expected_output[t]: Y[t] for t in range(len(self.expected_output))})

        c = np.concatenate(([np.zeros_like(Y[0])], Y[:-1]), axis=0)
        feed_dict.update({self.decode_input[t]: c[t] for t in range(len(c))})

        if isTrain:
            _, loss_t = sess.run([train_op, self.losses['loss']], feed_dict)
            return loss_t
        else:
            output_lossv, reg_lossv, loss_t = sess.run(
                [self.losses['output_loss'], self.losses['reg_loss'],
                 self.losses['loss']],
                feed_dict)
            print("-----------------")
            print(output_lossv, reg_lossv)
            return loss_t


    def demo(self, sess, dataset):
        X, Y = dataset.generateData(isTrain=False)
        feed_dict = {self.encoder_input[t]: X[t] for t in range(cfg.FLAGS.seq_len)}
        c = np.concatenate(
            ([np.zeros_like(Y[0])], Y[0:cfg.FLAGS.seq_len - 1]), axis=0)
        feed_dict.update(
            {self.decode_input[t]: c[t] for t in range(len(c))})
        outputs = np.array(sess.run([self.reshaped_outputs], feed_dict)[0])
        return outputs

部分地区海表温度预测结果:

2018全球海表温度热力图:


转载:https://blog.csdn.net/BreakingDawn0/article/details/104462178
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场