【猜测】-双注意LSTM自动编码器记载
1 猜测-双注意LSTM自动编码器复现github链接:https://github.com/JulesBelveze/time-series-autoencoder.git
论文:A Dual-Stage Attention-Based Recurrent Neural Network for Time Series Prediction:https://arxiv.org/abs/1704.02971
1.1 复现环境设置
python版本:python3.8.20
cuda版本:cuda111
包版本环境参考:
Package Version Editable project location
-------------------- ------------ ---------------------------
build 1.2.2.post1
CacheControl 0.14.2
certifi 2025.1.31
charset-normalizer 3.4.1
cleo 2.1.0
colorama 0.4.6
contourpy 1.1.1
crashtest 0.4.1
cycler 0.10.0
distlib 0.3.9
dulwich 0.21.7
fastjsonschema 2.21.1
filelock 3.16.1
fonttools 4.56.0
future 0.18.2
idna 3.10
importlib_metadata 8.5.0
importlib_resources6.4.5
installer 0.7.0
jaraco.classes 3.4.0
joblib 0.15.1
keyring 24.3.1
kiwisolver 1.2.0
matplotlib 3.2.1
more-itertools 10.5.0
msgpack 1.1.0
numpy 1.21.0
packaging 24.2
pandas 1.1.5
pexpect 4.9.0
pillow 10.4.0
pip 24.3.1
pkginfo 1.12.1.2
platformdirs 4.3.6
poetry 1.8.5
poetry-core 1.9.1
poetry-plugin-export 1.8.0
protobuf 5.29.3
ptyprocess 0.7.0
pyparsing 2.4.7
pyproject_hooks 1.2.0
python-dateutil 2.8.1
pytz 2025.1
pywin32-ctypes 0.2.3
rapidfuzz 3.9.7
requests 2.32.3
requests-toolbelt 1.0.0
scikit-learn 0.23.1
scipy 1.4.1
setuptools 75.3.0
shellingham 1.5.4
six 1.15.0
sklearn 0.0
tensorboardX 2.6.2.2
threadpoolctl 2.1.0
tomli 2.2.1
tomlkit 0.13.2
torch 1.9.1+cu111
torchaudio 0.9.1
torchvision 0.10.1+cu111
tqdm 4.46.1
trove-classifiers 2025.2.18.16
tsa 0.1.0 D:\temp\Pytorch双注意LSTM自动编码器
typing_extensions 4.12.2
urllib3 2.2.3
virtualenv 20.29.2
wheel 0.45.1
zipp 3.20.2
注:
vscode设置:
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python Debugger: Current File with Arguments",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"cwd":"${fileDirname}",
"console": "integratedTerminal",
// "args": [
// "--ckpt", "output/checkpoint-5000.ckpt"// 添加 --ckpt 参数及其值
// ]
}
]
}
1.2 数据流记载
源代码所用数据字段:
| 列名 | 含义 | 单位 |
| ------------- | ------------------ | -------- |
| Date_Time | 日期和时间 | - |
| CO(GT) | 一氧化碳浓度 | mg/m³ |
| PT08.S1(CO) | 一氧化碳传感器响应值 | 无量纲|
| NMHC(GT) | 非甲烷烃浓度 | µg/m³ |
| C6H6(GT) | 苯浓度 | µg/m³ |
| PT08.S2(NMHC) | 非甲烷烃传感器响应值 | 无量纲 |
| NOx(GT) | 氮氧化物浓度 | µg/m³ |
| PT08.S3(NOx)| 氮氧化物传感器响应值 | 无量纲 |
| NO2(GT) | 二氧化氮浓度 | µg/m³ |
| PT08.S4(NO2)| 二氧化氮传感器响应值 | 无量纲 |
| PT08.S5(O3) | 臭氧传感器响应值 | 无量纲|
| T | 温度 | °C |
| RH | 相对湿度 | % |
| AH | 绝对湿度 | g/m³ |
将时间序列数据转换为适合时间序列猜测的格式,详细来说,它通过滑动窗口的方式从输入数据 X 和标签 y 中提取特性和标签,并天生一个 TensorDataset。提取特性和标签,猜测的是后面的猜测窗口长度的标签。下面我将详细表明 X、y 和 target 的取数逻辑,并指出 y 取数可能存在的问题。
1.2.1 构建Dataset
(1) X 的取数
[*]X 是输入特性数据,形状为 (nb_obs, nb_features),其中 nb_obs 是样本数目,nb_features 是特性数目。
[*]通过滑动窗口的方式,从 X 中提取长度为 seq_length 的序列:features.append(torch.FloatTensor(X).unsqueeze(0))
[*]比方,假如 seq_length = 10,则每次提取 X,即从第 i 个时间步开始的 10 个时间步的特性数据。
[*]unsqueeze(0) 是为了增加一个批次维度。
(2) y 的取数
[*]y 是目标值(标签),通常是与 X 对应的输出值。
[*]代码中从 y 中提取的是滞后一期的汗青值(y):y_hist.append(torch.FloatTensor(y).unsqueeze(0))
[*]比方,假如 seq_length = 10,则提取的是 y,即从第 i-1 个时间步开始的 10 个时间步的标签值。
[*]这里 y 的使用可能有问题,因为 y 是前一个时间步的值,而不是当前时间步的值。假如 y 是当前时间步的标签,那么这里应该直接使用 y。
(3) target 的取数
[*]target 是猜测的目标值,即将来 prediction_window 个时间步的标签值:target.append(torch.FloatTensor(y))
[*]比方,假如 seq_length = 10 且 prediction_window = 5,则提取的是 y,即从第 i+10 个时间步开始的 5 个时间步的标签值。
1.2.2 举例说明
假设有以下数据:
[*]X 和 y 的长度为 20。
[*]seq_length = 3,prediction_window = 2。
(1)X 的取数
[*]当 i = 1 时,提取 X。
[*]当 i = 2 时,提取 X。
[*]以此类推。
(2)y 的取数
[*]当 i = 1 时,提取 y(即 y)。
[*]当 i = 2 时,提取 y。
[*]以此类推。
(3)target 的取数
[*]当 i = 1 时,提取 y(即 y)。
[*]当 i = 2 时,提取 y。
[*]以此类推。
1.2.3 y 取数的问题
在代码中,y 的取数逻辑是:
y_hist.append(torch.FloatTensor(y).unsqueeze(0))
这里使用了 y,即前一个时间步的值。假如 y 是当前时间步的标签,那么这里应该直接使用 y,而不是 y。修正后的代码应该是:
y_hist.append(torch.FloatTensor(y).unsqueeze(0))
修正后的代码
def frame_series(self, X, y=None): ''' Function used to prepare the data for time series prediction :param X: set of features :param y: targeted value to predict :return: TensorDataset ''' nb_obs, nb_features = X.shape features, target, y_hist = [], [], [] for i in range(1, nb_obs - self.seq_length - self.prediction_window): features.append(torch.FloatTensor(X).unsqueeze(0))
# 修正后的 y 取数逻辑 y_hist.append(torch.FloatTensor(y).unsqueeze(0))
features_var, y_hist_var = torch.cat(features), torch.cat(y_hist) if y is not None: for i in range(1, nb_obs - self.seq_length - self.prediction_window): target.append( torch.FloatTensor(y)) target_var = torch.cat(target) return TensorDataset(features_var, y_hist_var, target_var) return TensorDataset(features_var) 1.2.4 总结
[*]X 的取数是滑动窗口提取特性序列。
[*]y 的取数逻辑存在问题,不应使用 y,而应直接使用 y。
[*]target 的取数是提取将来 prediction_window 个时间步的标签值。
这段代码的数据流可以分为以下几个步调:
[*] 数据预处置处罚:
[*]调用 self.preprocess_data() 方法,天生训练集和测试集的特性和标签:X_train, X_test, y_train, y_test。
[*]从 X_train 中获取特性的数目 nb_features。
[*] 数据集封装:
[*]调用 self.frame_series(X_train, y_train) 方法,将训练集的特性和标签封装成一个 train_dataset 对象。
[*]调用 self.frame_series(X_test, y_test) 方法,将测试集的特性和标签封装成一个 test_dataset 对象。
[*] DataLoader 创建:
[*]使用 DataLoader 类创建 train_iter,用于加载训练数据集。参数包括 batch_size(批次巨细)、shuffle=False(不打乱数据)、drop_last=True(丢弃末了一个不完整的批次)。
[*]使用 DataLoader 类创建 test_iter,用于加载测试数据集。参数与 train_iter 相同。
[*] 返回效果:
[*]返回 train_iter(训练数据加载器)、test_iter(测试数据加载器)和 nb_features(特性数目)。
1.2.5 数据流总结:
[*]输入:原始数据通过 self.preprocess_data() 进行预处置处罚,天生特性和标签。
[*]处置处罚:特性和标签被封装成 Dataset 对象,然后通过 DataLoader 进行批次加载。
[*]输出:返回训练和测试的 DataLoader 对象,以及特性数目。
1.2.6 数据流图示:
原始数据 → preprocess_data() → (X_train, X_test, y_train, y_test) → frame_series() → (train_dataset, test_dataset) → DataLoader() → (train_iter, test_iter)
1.2.7 参考:
[*]DataLoader 是 PyTorch 中用于批量加载数据的工具,支持多线程加载、数据打乱等功能。
[*]Dataset 是 PyTorch 中用于封装数据集的基类,通常需要实现 __len__ 和 __getitem__ 方法。
为了更好地明确数据维度的变化情况,我们可以通过一个详细的例子来渐渐分析代码中的数据维度变化。假设我们有一个时间序列数据集,包罗以下列:
[*]date: 时间戳
[*]feature1: 数值特性
[*]feature2: 数值特性
[*]category: 种别特性
[*]target: 目标值
2 数据维度变化流程
[*] 原始数据 (data):
[*]假设数据集有 1000 行,5 列(date, feature1, feature2, category, target)。
[*]维度:(1000, 5)
[*] 预处置处罚 (preprocess_data):
[*]X = data.drop('target', axis=1):去掉目标列,剩下 4 列。
[*]维度:(1000, 4)
[*]y = data['target']:目标列。
[*]维度:(1000,)
[*]X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, shuffle=False):
[*]X_train 维度:(800, 4)
[*]X_test 维度:(200, 4)
[*]y_train 维度:(800,)
[*]y_test 维度:(200,)
[*]X_train = preprocessor.fit_transform(X_train):颠末 ColumnTransformer 处置处罚,假设 category 列被编码为 3 个新列。
[*]维度:(800, 5)(feature1, feature2, category_encoded_1, category_encoded_2, category_encoded_3)
[*]X_test = preprocessor.transform(X_test):
[*]维度:(200, 5)
[*] 时间序列帧化 (frame_series):
[*]假设 seq_length = 10,prediction_window = 1。
[*]nb_obs, nb_features = X_train.shape:
[*]nb_obs = 800, nb_features = 5
[*]features 和 y_hist 的天生:
[*]对于 i 从 1 到 800 - 10 - 1 = 789,每次取 10 个时间步的数据。
[*]features 维度:(789, 10, 5)
[*]y_hist 维度:(789, 10)
[*]target 的天生:
[*]对于 i 从 1 到 789,每次取 1 个时间步的目标值。
[*]target 维度:(789, 1)
[*]TensorDataset 的天生:
[*]features_var 维度:(789, 10, 5)
[*]y_hist_var 维度:(789, 10)
[*]target_var 维度:(789, 1)
[*] DataLoader (get_loaders):
[*]train_iter = DataLoader(train_dataset, batch_size=32, shuffle=False, drop_last=True):
[*]每个 batch 的维度:(32, 10, 5)(特性),(32, 10)(汗青目标),(32, 1)(目标)
[*]test_iter = DataLoader(test_dataset, batch_size=32, shuffle=False, drop_last=True):
[*]每个 batch 的维度:(32, 10, 5)(特性),(32, 10)(汗青目标),(32, 1)(目标)
2.1 流程图
原始数据 (1000, 5)
|
v
预处理 (X_train: 800, 5, y_train: 800)
|
v
时间序列帧化 (features: 789, 10, 5, y_hist: 789, 10, target: 789, 1)
|
v
DataLoader (batch_size=32, features: 32, 10, 5, y_hist: 32, 10, target: 32, 1)
2.2 总结
通过上述步调,可以看到数据从原始形式渐渐转换为适合时间序列模型训练的格式。每个步调中的数据维度变化如下:
[*]原始数据:(1000, 5)
[*]预处置处罚后:(800, 5)(训练集特性),(800,)(训练集目标)
[*]时间序列帧化后:(789, 10, 5)(特性),(789, 10)(汗青目标),(789, 1)(目标)
[*]DataLoader 中:(32, 10, 5)(特性),(32, 10)(汗青目标),(32, 1)(目标)
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]