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

本文深入解析LSTM网络的工作原理,展示其如何解决长期依赖问题,并通过TensorFlow实现海表温度及股价预测的实验。LSTM作为一种特殊类型的RNN,有效避免了梯度消失,适用于处理序列数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

获取更多内容,请访问博主的个人博客 爱吃猫的小鱼干的Blog

一 引言

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

二 LSTM模型结构

2.1 整体结构

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

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

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

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

2.2 忘记门

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

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

2.3 输入门

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

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

2.4 输出门

输出门
从图中可以看出,隐藏状态 h t h_{t} ht的更新由两部分组成,第一部分是 o t o_{t} ot,它由上一序列的隐藏状态 h t − 1 h_{t-1} ht1和本序列数据 x t x_{t} xt,以及激活函数sigmoid得到,第二部分由隐藏状态 C t C_{t} Ct和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全球海表温度热力图:
在这里插入图片描述

获取更多内容,请访问博主的个人博客 爱吃猫的小鱼干的Blog

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值