在理解 LSTM(长短期记忆网络)之前,我们先简单回顾一下普通神经网络。普通神经网络就像是一个 “信息处理器”,它接收输入数据,经过一系列复杂的计算,然后给出输出结果。但是,普通神经网络在处理一些有顺序的数据,比如时间序列数据或者自然语言句子时,就显得有些力不从心。
这时候,循环神经网络(RNN)登场了。RNN 就像一个有 “记忆” 的神经网络,它能处理序列数据。想象一下,我们要预测一句话的下一个单词,RNN 可以根据前面已经出现的单词来做出预测,因为它能够记住之前处理过的信息。它通过一种特殊的结构,让信息在网络中循环传递,从而捕捉序列中的依赖关系。
二、RNN 的困境与 LSTM 的诞生
然而,RNN 也有自己的问题,那就是 “记忆” 会随着时间的推移而逐渐消失,这就是所谓的梯度消失问题。简单来说,当我们处理很长的序列时,RNN 很难记住很久之前的信息,就像我们在背诵一篇很长的文章时,可能读到后面就忘了前面的内容。
为了解决这个问题,LSTM 应运而生。LSTM 是一种特殊的 RNN,它就像是给 RNN 配备了一个 “超级记忆模块”,能够有效地处理长序列数据,避免梯度消失问题。
三、LSTM 的核心组件
细胞状态(Cell State):可以把细胞状态想象成一条贯穿 LSTM 整个单元的 “高速公路”,信息可以在这条 “公路” 上顺畅地流动,几乎不会受到干扰。这就像是我们的大脑中,有一条专门用来存储重要信息的通道,信息可以在上面快速传递,不容易丢失。门控机制:LSTM 通过三种 “门” 来控制信息的流动,分别是输入门、遗忘门和输出门。遗忘门:遗忘门决定了哪些信息需要从细胞状态中被 “忘记”。就像我们整理书架,遗忘门会决定哪些旧书可以被清理掉,为新书腾出空间。输入门:输入门负责决定哪些新信息可以被添加到细胞状态中。这就好比我们去书店买书,输入门决定了哪些新书可以被放到我们的书架上。输出门:输出门决定了细胞状态中的哪些信息会被输出,作为 LSTM 单元的最终结果。这就像我们从书架上挑选出要阅读的书,输出门决定了哪些信息会被 “拿出来” 使用。
四、LSTM 的工作过程
初始化:LSTM 单元开始工作时,细胞状态和隐藏状态都被初始化为一些值,通常是零向量。
- 遗忘阶段:遗忘门根据当前的输入和上一时刻的隐藏状态,决定细胞状态中哪些信息需要被遗忘。它输出一个 0 到 1 之间的向量,0 表示完全遗忘,1 表示完全保留。
- 输入阶段:输入门根据当前的输入和上一时刻的隐藏状态,决定哪些新信息需要被添加到细胞状态中。同时,一个候选细胞状态会被生成,它包含了可能要添加到细胞状态中的新信息。
- 更新细胞状态:根据遗忘门和输入门的输出,细胞状态被更新。遗忘门决定哪些旧信息被保留,输入门决定哪些新信息被添加。
- 输出阶段:输出门根据当前的细胞状态和上一时刻的隐藏状态,决定细胞状态中的哪些信息会被输出。这个输出就是 LSTM 单元在当前时刻的最终结果。
五、LSTM 的应用
LSTM 在很多领域都有广泛的应用。在自然语言处理中,它可以用于文本分类、机器翻译、语音识别等任务。比如在机器翻译中,LSTM 可以处理源语言句子中的每个单词,记住句子的语义信息,然后将其翻译成目标语言。在时间序列预测中,LSTM 可以根据历史数据预测未来的趋势,比如预测股票价格、天气变化等。总之,LSTM 凭借其独特的结构和强大的记忆能力,成为了处理序列数据的重要工具,为许多领域的发展带来了新的突破。
(1)打开Spyder软件,在目录D:\zwPython\zwrk\1_Quant_TensorFlow,新建文件
# -*- coding: utf-8 -*-
"""
Created on Tue Feb 18 09:34:20 2025
52-LSYM81-1
长短期记忆神经网络股票预测1
@author: Administrator
"""
import sys, os
sys.path.append("topqt/")
import numpy as np
import pandas as pd
import tushare as ts
import plotly as py
import plotly.figure_factory as pyff
import math
import arrow
import ffn
import pypinyin
import pandas_datareader as pdr
import matplotlib.pyplot as plt
import zsys2025 # 20250213
import ztools2025 as zt
import ztools_str as zstr
import ztools_data2025 as zdat
import ztools_draw2025 as zdr
import ztools_tq2025 as ztq # 20250213
import zai_keras2025 as zks
import tensorflow as tf
from tensorflow.keras.models import Sequential, load_model
from tensorflow.keras.layers import Dense, Input, Dropout
from tensorflow.keras.optimizers import RMSprop
from tensorflow.keras.utils import plot_model
from tensorflow.keras.callbacks import TensorBoard
import tensorlayer as tl
# 1
print('\n#1,set.sys')
pd.set_option('display.width', 450)
pd.set_option('display.float_format', zt.xfloat3)
rlog = os.path.join('tmp', 'log_tmp')
# 注意:tf.gfile.DeleteRecursively 在 TensorFlow 2.x 中已被弃用,使用 tf.io.gfile.rmtree 替代
if os.path.exists(rlog):
tf.io.gfile.rmtree(rlog)
#2.1
print('\n#2.1,读取数据')
rss, fsgn, ksgn = 'tmp1/', 'TDS2_sz50', 'avg'
xlst = zsys2025.TDS_xlst9
zt.prx('xlst', xlst)
num_in,num_out=len(xlst),1
print('\nnum_in,num_out:', num_in, num_out)
#
df_train, df_test, x_train, y_train, x_test, y_test = zdat.frd_TDS(rss, fsgn, ksgn, xlst)
print('\ndf_test.tail()')
print(df_test.tail())
print('\nx_train.shape,', x_train.shape)
print('\ntype(x_train),', type(x_train))
#
#2.2
print('\n#2.2,转换数据格式shape')
rxn,txn=x_train.shape[0],x_test.shape[0]
x_train,x_test = x_train.reshape(rxn,num_in,-1),x_test.reshape(txn,num_in,-1)
print('\nx_train.shape,',x_train.shape)
print('\ntype(x_train),',type(x_train))
#
# 3
print('\n#3,model建立神经网络模型')
mx = zks.lstm010(num_in, num_out)
#
mx.summary()
plot_model(mx, to_file=os.path.join('tmp1', 'lstm0101_52.png'))
# 4 模型训练
print('\n#4 模型训练 fit') # 设置 profile_batch=0 禁用性能分析 verbose=0
tbCallBack = TensorBoard(log_dir=rlog, write_graph=True, write_images=True, profile_batch=0)
tn0 = arrow.now()
mx.fit(x_train, y_train, epochs=50, batch_size=512, callbacks=[tbCallBack])
tn = zt.timNSec('', tn0, True)
# 确保保存模型的目录存在
model_save_dir = os.path.join('tmp1')
if not os.path.exists(model_save_dir):
os.makedirs(model_save_dir)
model_save_path = os.path.join(model_save_dir, 'lstm0101_52.dat')
mx.save(model_save_path)
# 5 利用模型进行预测 predict
print('\n#5 模型预测 predict')
tn0 = arrow.now()
y_pred = mx.predict(x_test)
tn = zt.timNSec('', tn0, True)
df_test['y_pred'] = zdat.ds4x(y_pred, df_test.index, True)
df_test.to_csv(os.path.join('tmp1', 'lstm0101_52.csv'), index=False)
#6
print('\n#6 acc准确度分析')
print('\nky0=10')
df=df_test
dacc,dfx,a10=ztq.ai_acc_xed2ext(df.y,df.y_pred,ky0=10,fgDebug=True)
(2)程序输出结果
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)]
Type "copyright", "credits" or "license" for more information.
IPython 7.12.0 -- An enhanced Interactive Python.
runfile('D:/zwPython/zwrk/1_Quant_TensorFlow/52-LSYM81-1.py', wdir='D:/zwPython/zwrk/1_Quant_TensorFlow')
d:\zwpython\py37\python-3.7.6.amd64\lib\site-packages\pandas_datareader\compat\__init__.py:7: FutureWarning:
pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
Using TensorFlow backend.
d:\zwpython\py37\python-3.7.6.amd64\lib\site-packages\sklearn\externals\joblib\__init__.py:15: FutureWarning:
sklearn.externals.joblib is deprecated in 0.21 and will be removed in 0.23. Please import this functionality directly from joblib, which can be installed with: pip install joblib. If this warning is raised when loading pickled models, you may need to re-serialize those models with scikit-learn 0.21+.
#1,set.sys
#2.1,读取数据
xlst
['open', 'high', 'low', 'close', 'volume', 'avg', 'ma_2', 'ma_3', 'ma_5', 'ma_10', 'ma_15', 'ma_20', 'ma_25', 'ma_30', 'ma_50', 'ma_100', 'xyear', 'xmonth', 'xday', 'xday_week', 'xday_year', 'xweek_year']
num_in,num_out: 22 1
df_test.tail()
open high low close ... y price price_next price_change
94939 4.390 4.510 4.380 4.510 ... 4.580 4.450 4.580 102.921
94940 4.490 4.490 4.420 4.430 ... 4.580 4.460 4.580 102.691
94941 4.440 4.530 4.420 4.500 ... 4.580 4.470 4.580 102.461
94942 4.490 4.510 4.460 4.480 ... 4.590 4.490 4.590 102.227
94943 4.490 4.530 4.490 4.520 ... 4.590 4.510 4.590 101.774
[5 rows x 26 columns]
x_train.shape, (116761, 22)
type(x_train), <class 'numpy.ndarray'>
#2.2,转换数据格式shape
x_train.shape, (116761, 22, 1)
type(x_train), <class 'numpy.ndarray'>
#3,model建立神经网络模型
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
lstm (LSTM) (None, 176) 125312
_________________________________________________________________
dense (Dense) (None, 1) 177
=================================================================
Total params: 125,489
Trainable params: 125,489
Non-trainable params: 0
_________________________________________________________________
#4 模型训练 fit
Train on 116761 samples
Epoch 1/50
53760/116761 [============>.................] - ETA: 19s - loss: 396.5423 - accuracy: 0.0012
loss: 1.3456 - accuracy: 0.0012
Epoch 50/50
116761/116761 [==============================] - 33s 282us/sample - loss: 1.3161 - accuracy: 0.0012
1634.35 s, 10:33:50 ,t0, 10:06:35
WARNING:tensorflow:AutoGraph could not transform <function canonicalize_signatures.<locals>.signature_wrapper at 0x000002261BFEA048> and will run it as-is.
Please report this to the TensorFlow team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output.
Cause: Bad argument number for Name: 3, expecting 4
WARNING: AutoGraph could not transform <function canonicalize_signatures.<locals>.signature_wrapper at 0x000002261BFEA048> and will run it as-is.
Please report this to the TensorFlow team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output.
Cause: Bad argument number for Name: 3, expecting 4
WARNING:tensorflow:From d:\zwpython\py37\python-3.7.6.amd64\lib\site-packages\tensorflow_core\python\ops\resource_variable_ops.py:1786: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
Instructions for updating:
If using Keras pass *_constraint arguments to layers.
INFO:tensorflow:Assets written to: tmp1\lstm0101_52.dat\assets
#5 模型预测 predict
14.28 s, 10:34:06 ,t0, 10:33:52
#6 acc准确度分析
ky0=10
ky0=10; n_df9,94944,n_dfk,85022
acc: 89.55%; MSE:29019.88, MAE:22.72, RMSE:170.35, r2score:0.29, @ky0:10.00
(3)程序代码注释
# -*- coding: utf-8 -*-
"""
Created on Tue Feb 18 09:34:20 2025
52-LSYM81-1
长短期记忆神经网络股票预测1
@author: Administrator
"""
# 导入sys和os模块,sys模块提供了一些变量和函数,用于操作Python解释器;os模块提供了与操作系统进行交互的功能
import sys, os
# 将"topqt/"目录添加到Python的模块搜索路径中,这样Python就可以在该目录下查找模块并导入使用
sys.path.append("topqt/")
# 导入numpy库,它是Python中用于科学计算的基础库,提供了高效的多维数组对象和各种数学函数
import numpy as np
# 导入pandas库,它是用于数据处理和分析的强大库,提供了DataFrame等数据结构
import pandas as pd
# 导入tushare库,它是一个免费、开源的python财经数据接口包,可用于获取股票等金融数据
import tushare as ts
# 导入plotly库,它是一个交互式可视化库,用于创建各种图表
import plotly as py
# 导入plotly的figure_factory模块,该模块提供了创建一些特殊图表的函数
import plotly.figure_factory as pyff
# 导入math模块,提供了许多数学函数
import math
# 导入arrow模块,它是一个用于处理日期和时间的库,比Python内置的datetime模块更方便
import arrow
# 导入ffn库,它是一个用于金融数据分析的库,提供了各种金融计算和分析工具
import ffn
# 导入pypinyin库,用于将汉字转换为拼音
import pypinyin
# 导入pandas_datareader库,用于从各种数据源读取金融数据
import pandas_datareader as pdr
# 导入matplotlib.pyplot库,它是Python中常用的绘图库
import matplotlib.pyplot as plt
# 导入自定义模块zsys2025,可能包含一些自定义的系统配置和常量
import zsys2025 # 20250213
# 导入自定义模块ztools2025,可能包含一些自定义的工具函数
import ztools2025 as zt
# 导入自定义模块ztools_str,可能包含一些字符串处理的工具函数
import ztools_str as zstr
# 导入自定义模块ztools_data2025,可能包含一些数据处理的工具函数
import ztools_data2025 as zdat
# 导入自定义模块ztools_draw2025,可能包含一些绘图的工具函数
import ztools_draw2025 as zdr
# 导入自定义模块ztools_tq2025,可能包含一些与tushare相关的工具函数
import ztools_tq2025 as ztq # 20250213
# 导入自定义模块zai_keras2025,可能包含一些与Keras相关的自定义函数
import zai_keras2025 as zks
# 导入tensorflow库,它是一个广泛使用的深度学习框架
import tensorflow as tf
# 从tensorflow.keras.models模块中导入Sequential和load_model函数
# Sequential用于创建顺序模型,load_model用于加载已保存的模型
from tensorflow.keras.models import Sequential, load_model
# 从tensorflow.keras.layers模块中导入Dense、Input和Dropout层
# Dense是全连接层,Input是输入层,Dropout用于防止过拟合
from tensorflow.keras.layers import Dense, Input, Dropout
# 从tensorflow.keras.optimizers模块中导入RMSprop优化器
from tensorflow.keras.optimizers import RMSprop
# 从tensorflow.keras.utils模块中导入plot_model函数,用于绘制模型的结构示意图
from tensorflow.keras.utils import plot_model
# 从tensorflow.keras.callbacks模块中导入TensorBoard回调函数,用于可视化训练过程
from tensorflow.keras.callbacks import TensorBoard
# 导入tensorlayer库,它是一个基于TensorFlow的深度学习库
import tensorlayer as tl
# 1
print('\n#1,set.sys')
# 设置pandas显示宽度为450个字符,方便查看数据
pd.set_option('display.width', 450)
# 设置pandas显示浮点数的格式,调用zt.xfloat3函数进行格式化
pd.set_option('display.float_format', zt.xfloat3)
# 定义日志文件的存储路径,将其存储在'tmp'目录下的'log_tmp'文件夹中
rlog = os.path.join('tmp', 'log_tmp')
# 注意:tf.gfile.DeleteRecursively 在 TensorFlow 2.x 中已被弃用,使用 tf.io.gfile.rmtree 替代
# 检查日志文件路径是否存在,如果存在则删除该路径下的所有文件和文件夹
if os.path.exists(rlog):
tf.io.gfile.rmtree(rlog)
#2.1
print('\n#2.1,读取数据')
# 定义数据存储的根路径
rss = 'tmp1/'
# 定义数据文件的标识
fsgn = 'TDS2_sz50'
# 定义数据的关键字
ksgn = 'avg'
# 从zsys2025模块中获取TDS_xlst9列表,该列表可能包含数据的特征列名
xlst = zsys2025.TDS_xlst9
# 调用zt.prx函数打印xlst列表的内容
zt.prx('xlst', xlst)
# 计算输入特征的数量,即xlst列表的长度
num_in = len(xlst)
# 定义输出的数量为1
num_out = 1
# 打印输入和输出的数量
print('\nnum_in,num_out:', num_in, num_out)
# 调用zdat.frd_TDS函数从指定路径读取数据,并将数据划分为训练集和测试集
# df_train是训练集的DataFrame,df_test是测试集的DataFrame
# x_train是训练集的特征数据,y_train是训练集的标签数据
# x_test是测试集的特征数据,y_test是测试集的标签数据
df_train, df_test, x_train, y_train, x_test, y_test = zdat.frd_TDS(rss, fsgn, ksgn, xlst)
# 打印测试集的最后几行数据
print('\ndf_test.tail()')
print(df_test.tail())
# 打印训练集特征数据的形状
print('\nx_train.shape,', x_train.shape)
# 打印训练集特征数据的类型
print('\ntype(x_train),', type(x_train))
#
#2.2
print('\n#2.2,转换数据格式shape')
# 获取训练集和测试集特征数据的样本数量
rxn = x_train.shape[0]
txn = x_test.shape[0]
# 将训练集和测试集的特征数据转换为适合LSTM模型输入的形状
# LSTM模型通常需要输入三维数据,形状为(样本数量, 时间步长, 特征数量)
x_train = x_train.reshape(rxn, num_in, -1)
x_test = x_test.reshape(txn, num_in, -1)
# 打印转换后训练集特征数据的形状
print('\nx_train.shape,', x_train.shape)
# 打印转换后训练集特征数据的类型
print('\ntype(x_train),', type(x_train))
#
# 3
print('\n#3,model建立神经网络模型')
# 调用zks.lstm010函数创建一个LSTM模型,传入输入和输出的数量作为参数
mx = zks.lstm010(num_in, num_out)
# 打印模型的概要信息,包括模型的层数、每层的参数数量等
mx.summary()
# 绘制模型的结构示意图,并保存为'tmp1'目录下的'lstm0101_52.png'文件
plot_model(mx, to_file=os.path.join('tmp1', 'lstm0101_52.png'))
# 4 模型训练
print('\n#4 模型训练 fit') # 设置 profile_batch=0 禁用性能分析 verbose=0
# 创建一个TensorBoard回调函数,用于记录训练过程的日志信息
# log_dir指定日志文件的存储路径,write_graph表示是否记录模型的图结构,write_images表示是否记录模型的权重图像
# profile_batch=0表示禁用性能分析
tbCallBack = TensorBoard(log_dir=rlog, write_graph=True, write_images=True, profile_batch=0)
# 记录训练开始的时间
tn0 = arrow.now()
# 使用训练集数据对模型进行训练
# epochs表示训练的轮数,batch_size表示每个批次的样本数量,callbacks表示要使用的回调函数
mx.fit(x_train, y_train, epochs=50, batch_size=512, callbacks=[tbCallBack])
# 计算训练所花费的时间,并打印出来
tn = zt.timNSec('', tn0, True)
# 确保保存模型的目录存在
model_save_dir = os.path.join('tmp1')
if not os.path.exists(model_save_dir):
os.makedirs(model_save_dir)
# 定义模型保存的路径
model_save_path = os.path.join(model_save_dir, 'lstm0101_52.dat')
# 保存训练好的模型
mx.save(model_save_path)
# 5 利用模型进行预测 predict
print('\n#5 模型预测 predict')
# 记录预测开始的时间
tn0 = arrow.now()
# 使用训练好的模型对测试集数据进行预测
y_pred = mx.predict(x_test)
# 计算预测所花费的时间,并打印出来
tn = zt.timNSec('', tn0, True)
# 将预测结果转换为适合DataFrame存储的格式,并添加到测试集的DataFrame中
df_test['y_pred'] = zdat.ds4x(y_pred, df_test.index, True)
# 将包含预测结果的测试集DataFrame保存为CSV文件
df_test.to_csv(os.path.join('tmp1', 'lstm0101_52.csv'), index=False)
#6
print('\n#6 acc准确度分析')
print('\nky0=10')
# 将测试集的DataFrame赋值给df变量
df = df_test
# 调用ztq.ai_acc_xed2ext函数对预测结果进行准确度分析
# df.y是测试集的真实标签,df.y_pred是模型的预测标签
# ky0是一个参数,可能用于控制分析的范围或精度,fgDebug=True表示开启调试模式
dacc, dfx, a10 = ztq.ai_acc_xed2ext(df.y, df.y_pred, ky0=10, fgDebug=True)
(4)程序涉及的函数
# 定义一个名为 lstm010 的函数,用于构建一个简单的 LSTM(长短期记忆网络)模型
# num_in 是函数的一个必需参数,表示输入特征的数量
# num_out 是函数的一个可选参数,默认值为 1,表示模型输出的数量
def lstm010(num_in, num_out=1):
# 创建一个 Sequential 模型实例
# Sequential 模型是 Keras 中最简单的模型类型,它是一个线性堆叠的层序列
model = Sequential()
#
# 向模型中添加一个 LSTM 层
# LSTM 层是长短期记忆网络的核心层,能够处理序列数据并捕捉长期依赖关系
# num_in * 8 表示该 LSTM 层的神经元数量,通常根据输入特征数量进行一定倍数的扩展
# input_shape=(num_in, 1) 指定了输入数据的形状
# 这里的 num_in 表示时间步长,即每个样本包含的时间步数
# 1 表示每个时间步的特征数量
model.add(LSTM(num_in * 8, input_shape=(num_in, 1)))
# 向模型中添加一个全连接层(Dense 层)
# 全连接层将 LSTM 层的输出进行线性变换,输出一个标量值
# 这里的 1 表示该层的神经元数量,也就是模型的输出维度
model.add(layers.Dense(1))
#
# 编译模型,为模型的训练配置损失函数、优化器和评估指标
# loss='mse' 表示使用均方误差(Mean Squared Error)作为损失函数
# 均方误差常用于回归问题,它衡量了预测值与真实值之间的平均平方误差
# optimizer='rmsprop' 表示使用 RMSProp 优化器来更新模型的参数
# RMSProp 是一种自适应学习率的优化算法,能够在训练过程中自动调整学习率
# metrics=['accuracy'] 表示在训练和评估过程中使用准确率作为评估指标
# 虽然准确率通常用于分类问题,但在这里可能只是为了方便查看模型的性能
model.compile(loss='mse', optimizer='rmsprop', metrics=['accuracy'])
#
# 返回编译好的模型
return model
发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/907100
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!