tensorflow--LTSM,GRU

1、LTSM

传统循环网络RNN可以通过记忆体实现短期记忆进行连续数据的预测。但是当连续数据的序列变长时,会使展开时间步长过长,在反向传播更新参数时,梯度要按照时间步连续相乘,会导致梯度消失。所以在1997年Hochreitere等人提出了LTSM(长短记忆网络)。LTSM中引入了三个门限:

LTSM01.png

  • 细胞态:表征长期记忆
  • 候选态: 等待存入长期记忆的候选态(归纳出的、待存入细胞态的新知识)
  • 记忆体: 短期记忆,属于长期记忆的一部分
  • xt: 当前时刻的输入特征
  • ht-1: 上个时刻的短期记忆
  • wi,wf,wo: 待训练参数矩阵
  • bi,bf,bo: 待训练偏置项
  • σ: sigmoid激活函数(使门限的范围在0-1之间)
  • wc: 待训练参数矩阵
  • bc: 待训练偏置项

1.1、 LSTM计算过程

举个栗子(来源于视频老师):LSTM就是你听我讲课的过程,你现在脑袋里记住的内容,是今天ppt第1页到第45页的长期记忆ct。这个长期记忆ct由两部分组成:一部分是ppt第1页到第44页的内容,也就是上一时刻的长期记忆ct-1。你不可能一字不差的记住全部内容,你会不自觉的忘掉一部分,所以上个时刻的长期记忆ct-1要乘以遗忘门,这个成绩项表示留存在你脑中的对过去的记忆。我现在讲的内容是新知识,是即将存入你脑中的现在的记忆。现在的记忆由两部分组成:一部分是我正在讲的第45页ppt,是当前时刻的输入xt;还有一部分是第44页ppt的短期记忆留存,这是上一时刻的短期记忆ht-1。你的脑袋把当前时刻的输入xt和上一时刻的短期记忆ht-1归纳形成即将存入你脑中的现在的记忆ct波浪号。现在的记忆ct波浪号乘以输入门与过去记忆一同存储为长期记忆。当你把这一讲复述给你的朋友时,你不可能一字不落的讲出来,你讲的是存留在你脑中的长期记忆,经过输出门筛选后的内容,这就是记忆体的输出ht。当有多层循环网络时,第二层循环网络的输入xt就是第一层循环网络的输出ht。输入第二层网络的是第一层网络提取出的精华。你可以认为我现在扮演的就是第一层循环网络,每一页ppt我都是从一篇一篇论文中提取出的精华,输出给你;作为第二层循环网络的你,接收到的数据,是我的长期记忆过tanh激活函数乘以输出门提取出的短期记忆ht。这就是LSTM的计算过程。

1.2、TF描述LSTM

tf.keras.layers.LSTM(
    记忆体个数,
    return_sequences=是否有返回输出
)
return_sequences=True  # 各时间同步输出ht
return_sequences=False  # 仅最后时间步输出ht(默认)

# 例
model = tf.keras.layers.LSTM(
    LSTM(80, return_sequences=True),
    Dropout(0.2),
    LSTM(100),  # 仅最后时间步输出ht
    Dropout(0.2),
    Dense(1)
)

1.3、LSTM实现股票预测

import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
from tensorflow.keras.layers import Dense, Dropout, LSTM
import os
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error
import math


maotai = pd.read_csv("./SH600519.csv")  # 读取股票文件

training_set = maotai.iloc[0:2126, 2:3].values  # 前2126天的开盘价作为训练集,取C列开盘价
test_set = maotai.iloc[2126:, 2:3]  # 后300天的开盘价作为测试集


# 归一化
sc = MinMaxScaler(feature_range=(0, 1))  # 进行归一化,归一化到(0,1)之间
training_set_scaled = sc.fit_transform(training_set)  # 训练集上进行归一化
test_set = sc.transform(test_set)  # 利用训练集的属性对测试集进行归一化

x_train = []
y_train = []

x_test = []
y_test = []


# 提取连续60天的开盘价作为输入特征x_train,第61天的数据作为标签
for i in range(60, len(training_set_scaled)):
    x_train.append(training_set_scaled[i-60: i, 0])
    y_train.append(training_set_scaled[i, 0])


np.random.seed(8)
np.random.shuffle(x_train)
np.random.seed(8)
np.random.shuffle(y_train)
tf.random.set_seed(8)

x_train, y_train = np.array(x_train), np.array(y_train)

# 使x_train符合RNN输入要求: [送入样本数, 循环核时间展开步数, 每个时间同步输入特征个数]
# 此处整个数据集送入,送入样本数为x_train.shape[0]组数据:输入60个开盘价,预测第61天的开盘价,
# 循环核展开步数为60;每个时间步进入的特征是第一天的开盘价,只有一个数据,故每个时间步
# 输入特征个数为1
x_train = np.reshape(x_train, (x_train.shape[0], 60, 1))

# 同上处理测试集
for i in range(60, len(test_set)):
    x_test.append(test_set[i-60:i, 0])
    y_test.append(test_set[i, 0])

x_test, y_test = np.array(x_test), np.array(y_test)
x_test = np.reshape(x_test, (x_test.shape[0], 60, 1))


model = tf.keras.Sequential([
    LSTM(80, return_sequences=True),
    Dropout(0.2),
    LSTM(100),
    Dropout(0.2),
    Dense(1)
])


model.compile(optimizer=tf.keras.optimizers.Adam(0.001),
              loss="mean_squared_error")

check_point_save_path = "./checkpoint_stock/lstm_stock.ckpt"

if os.path.exists(check_point_save_path + ".index"):
    print("******load model******")
    model.load_weights(check_point_save_path)

cp_callback = tf.keras.callbacks.ModelCheckpoint(
    filepath=check_point_save_path,
    save_weights_only=True,
    save_best_only=True,
    monitor="val_loss"
)

history = model.fit(x_train, y_train, batch_size=64, epochs=50, 
    validation_data=(x_test, y_test), validation_freq=1, callbacks=[cp_callback])

model.summary()

with open("./lstm__stock_weight.txt", "w") as f:
    for v in model.trainable_variables:
        f.write(str(v.name) + "\n")
        f.write(str(v.shape) + "\n")
        f.write(str(v.numpy()) + "\n")


loss = history.history["loss"]
val_loss = history.history["val_loss"]

plt.plot(loss, label="Training Loss")
plt.plot(val_loss, label="Validation Loss")
plt.title("Training and Validation Loss")
plt.legend()
plt.show()

# 测试集输入模型进行预测
predictd_stock_price = model.predict(x_test)

# 对预测数据进行还原,反归一化
predictd_stock_price = sc.inverse_transform(predictd_stock_price)

# 对真实数据进行还原,反归一化
real_stock_price = sc.inverse_transform(test_set[60:])

# 画出真实数据和预测数据的对比曲线
plt.plot(real_stock_price, color="red", label="MaoTai Stock Price")
plt.plot(predictd_stock_price, color="blue", label="Predicted MaoTai Stock Price")
plt.title("MaoTai Stock Price Rrediction")
plt.xlabel("Time")
plt.ylabel("MaoTai Stock Price")
plt.legend()
plt.show()


#  评价模型:均方误差,均方根误差,平均绝对误差
mse = mean_squared_error(predictd_stock_price, real_stock_price)
rmse = math.sqrt(mse)
mae = mean_absolute_error(predictd_stock_price, real_stock_price)
print("均方误差: %.6f" % mse)
print("均方根误差: %.6f" % rmse)
print("平均绝对误差: %.6f" % mae)

部分结果如下:

均方误差: 3709.382565
均方根误差: 60.904701
平均绝对误差: 53.672697

2、GRU

在2014年cho等人简化了LSTM结构,提出了GRU网络。GRU使记忆体ht融合了长期记忆和短期记忆。ht包含了过去信息ht-1和现在信息ht波浪号。现在信息是过去信息ht-1过重置门与当前输入共同决定。两个门限的取值范围也是0到1之间。前向传播时直接使用记忆体更新公式,就可以算出每个时刻的ht值了


GRU.png

2.1、TF描述GRU层

tf.keras.layers.GRU(
    记忆体个数,
    return_sequences=是否有返回输出
)
return_sequences=True  # 各时间同步输出ht
return_sequences=False  # 仅最后时间步输出ht(默认)

# 例
model = tf.keras.layers.GRU(
    GRU(80, return_sequences=True),
    Dropout(0.2),
    GRU(100),  # 仅最后时间步输出ht
    Dropout(0.2),
    Dense(1)
)

2.2、GRU实现股票预测代码

import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
from tensorflow.keras.layers import Dense, Dropout, GRU
import os
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error
import math


maotai = pd.read_csv("./SH600519.csv")  # 读取股票文件

training_set = maotai.iloc[0:2126, 2:3].values  # 前2126天的开盘价作为训练集,取C列开盘价
test_set = maotai.iloc[2126:, 2:3]  # 后300天的开盘价作为测试集


# 归一化
sc = MinMaxScaler(feature_range=(0, 1))  # 进行归一化,归一化到(0,1)之间
training_set_scaled = sc.fit_transform(training_set)  # 训练集上进行归一化
test_set = sc.transform(test_set)  # 利用训练集的属性对测试集进行归一化

x_train = []
y_train = []

x_test = []
y_test = []


# 提取连续60天的开盘价作为输入特征x_train,第61天的数据作为标签
for i in range(60, len(training_set_scaled)):
    x_train.append(training_set_scaled[i-60: i, 0])
    y_train.append(training_set_scaled[i, 0])


np.random.seed(8)
np.random.shuffle(x_train)
np.random.seed(8)
np.random.shuffle(y_train)
tf.random.set_seed(8)

x_train, y_train = np.array(x_train), np.array(y_train)

# 使x_train符合RNN输入要求: [送入样本数, 循环核时间展开步数, 每个时间同步输入特征个数]
# 此处整个数据集送入,送入样本数为x_train.shape[0]组数据:输入60个开盘价,预测第61天的开盘价,
# 循环核展开步数为60;每个时间步进入的特征是第一天的开盘价,只有一个数据,故每个时间步
# 输入特征个数为1
x_train = np.reshape(x_train, (x_train.shape[0], 60, 1))

# 同上处理测试集
for i in range(60, len(test_set)):
    x_test.append(test_set[i-60:i, 0])
    y_test.append(test_set[i, 0])

x_test, y_test = np.array(x_test), np.array(y_test)
x_test = np.reshape(x_test, (x_test.shape[0], 60, 1))


model = tf.keras.Sequential([
    GRU(80, return_sequences=True),
    Dropout(0.2),
    GRU(100),
    Dropout(0.2),
    Dense(1)
])


model.compile(optimizer=tf.keras.optimizers.Adam(0.001),
              loss="mean_squared_error")

check_point_save_path = "./checkpoint_stock/gru_stock.ckpt"

if os.path.exists(check_point_save_path + ".index"):
    print("******load model******")
    model.load_weights(check_point_save_path)

cp_callback = tf.keras.callbacks.ModelCheckpoint(
    filepath=check_point_save_path,
    save_weights_only=True,
    save_best_only=True,
    monitor="val_loss"
)

history = model.fit(x_train, y_train, batch_size=64, epochs=50, 
    validation_data=(x_test, y_test), validation_freq=1, callbacks=[cp_callback])

model.summary()

with open("./gru__stock_weight.txt", "w") as f:
    for v in model.trainable_variables:
        f.write(str(v.name) + "\n")
        f.write(str(v.shape) + "\n")
        f.write(str(v.numpy()) + "\n")


loss = history.history["loss"]
val_loss = history.history["val_loss"]

plt.plot(loss, label="Training Loss")
plt.plot(val_loss, label="Validation Loss")
plt.title("Training and Validation Loss")
plt.legend()
plt.show()

# 测试集输入模型进行预测
predictd_stock_price = model.predict(x_test)

# 对预测数据进行还原,反归一化
predictd_stock_price = sc.inverse_transform(predictd_stock_price)

# 对真实数据进行还原,反归一化
real_stock_price = sc.inverse_transform(test_set[60:])

# 画出真实数据和预测数据的对比曲线
plt.plot(real_stock_price, color="red", label="MaoTai Stock Price")
plt.plot(predictd_stock_price, color="blue", label="Predicted MaoTai Stock Price")
plt.title("MaoTai Stock Price Rrediction")
plt.xlabel("Time")
plt.ylabel("MaoTai Stock Price")
plt.legend()
plt.show()


#  评价模型:均方误差,均方根误差,平均绝对误差
mse = mean_squared_error(predictd_stock_price, real_stock_price)
rmse = math.sqrt(mse)
mae = mean_absolute_error(predictd_stock_price, real_stock_price)
print("均方误差: %.6f" % mse)
print("均方根误差: %.6f" % rmse)
print("平均绝对误差: %.6f" % mae)

部分结果如下:

均方误差: 863.598247
均方根误差: 29.387042
平均绝对误差: 24.093177
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。