简介:这份资源面向时间序列预测方向的研究者与毕业设计开发者,针对官方Informer模型仅支持固定长度预测、难以满足论文实验需求的痛点,在原始代码基础上扩展了滚动长期预测能力:首次预测未来24个时间点后自动回填结果并继续预测下一段,无需手动填补,便于评估固定时间段内的预测精度,也可对接自动爬取数据形成实际应用。资源包共131个文件,以53个py源码与64个pyc编译文件为核心,辅以5个xml配置、5个csv数据集、1个yml环境文件及1个png可视化结果图,压缩包约1.01MB,结构紧凑便于直接运行与二次开发。目前已有5941人学习下载,适合希望复现顶会模型、开展长序列预测实验或撰写相关论文的读者参考,可快速获得可运行的滚动预测方案与结果可视化示例。
1. 魔改 Informer 做滚动长期预测:一个能直接跑通的时间序列科研项目
时间序列预测这个方向,很多同学卡在同一个地方:论文里的模型跑得通,但一到自己的数据就翻车。尤其是长期预测场景,标准 Informer 在长序列上会出现误差累积、注意力发散的问题,预测步长一拉长,曲线就开始“放飞自我”。这个项目做的事情很具体——在 Informer 基础上做魔改,实现滚动长期预测,并且把结果可视化出来,适合做毕业设计、科研实验或者个人开发者想深入理解 Transformer 类时序模型的人。它不是调包跑个 demo,而是把模型结构、训练流程、滚动预测策略和可视化都拆开给你看。下面我按“能跑起来 → 能看懂 → 能改”的顺序,把这个项目的关键部分拆一遍。
2. 项目架构与核心模块:从数据到预测的完整链路
2.1 整体目录结构与模块职责
拿到源码后,先别急着跑main.py。我一般会先花十分钟把目录扫一遍,搞清楚数据从哪进、模型在哪定义、结果往哪写。这个项目的结构比较典型,常见做法是分成配置、数据、模型、训练、预测、可视化几个部分:
project/ ├── configs/ │ └── default.yaml # 模型超参、数据路径、预测步长 ├── data/ │ ├── dataset.py # 数据集加载与滑动窗口切分 │ └── preprocess.py # 归一化、缺失值处理 ├── models/ │ ├── informer.py # 魔改后的 Informer 主体 │ ├── attention.py # 稀疏注意力与滚动注意力 │ └── embedding.py # 时间特征嵌入 ├── train.py # 训练入口 ├── predict.py # 滚动长期预测入口 ├── visualize.py # 结果可视化 └── utils/ ├── metrics.py # MAE、MSE、RMSE └── logger.py # 日志与 checkpoint 管理这个划分的好处是职责清晰:models/里只放网络结构,data/里只处理数据,train.py和predict.py分别对应训练和推理。你要改模型,基本只动models/;要换数据,只动data/和配置。很多同学把训练逻辑和模型定义混在一个文件里,改起来牵一发动全身,这个项目没有这个问题。
2.2 魔改点一:滚动长期预测的窗口策略
标准 Informer 做的是“一次性预测未来 N 步”,但长期预测里这种方式误差会累积。这个项目改成滚动预测:每次只预测一小段,然后把预测结果拼回输入,继续预测下一段。核心逻辑在predict.py里:
def rolling_predict(model, initial_input, pred_len, roll_step): """ model: 训练好的模型 initial_input: 初始输入窗口 [batch, seq_len, features] pred_len: 总预测长度 roll_step: 每次滚动的步长 """ preds = [] current_input = initial_input.clone() steps = pred_len // roll_step for i in range(steps): # 模型输出未来 roll_step 步 with torch.no_grad(): out = model(current_input) # [batch, roll_step, features] preds.append(out) # 把预测结果拼接到输入末尾,去掉最老的部分 current_input = torch.cat( [current_input[:, roll_step:, :], out], dim=1 ) return torch.cat(preds, dim=1) # [batch, pred_len, features]这里的关键参数是roll_step。它决定了每次滚动预测多少步。设得太小,滚动次数多,推理慢;设得太大,又退化成一次性预测,失去滚动的意义。我一般会先设成预测总长度的 1/4 到 1/8,比如预测 96 步,roll_step取 12 或 24。另外注意current_input的拼接方式:每次去掉最旧的roll_step步,把新预测的拼到末尾,保持输入窗口长度不变。这个细节如果写错,输入长度会越来越长,最后直接爆显存。
2.3 魔改点二:稀疏注意力与蒸馏层的配合
Informer 原版用了 ProbSparse 注意力来降低复杂度,但这个项目在长期预测场景下做了调整。标准 ProbSparse 在极长序列上会丢失一些关键的时间依赖,项目里改成“局部稀疏 + 全局稠密”的混合策略。核心在attention.py:
class HybridAttention(nn.Module): def __init__(self, d_model, n_heads, local_window=24): super().__init__() self.local_window = local_window self.global_attn = nn.MultiheadAttention(d_model, n_heads) self.local_attn = nn.MultiheadAttention(d_model, n_heads) def forward(self, x): # x: [seq_len, batch, d_model] seq_len = x.size(0) # 全局注意力:对所有位置做标准注意力 global_out, _ = self.global_attn(x, x, x) # 局部注意力:只对窗口内的位置计算 local_out = torch.zeros_like(global_out) for i in range(0, seq_len, self.local_window): end = min(i + self.local_window, seq_len) window = x[i:end] out, _ = self.local_attn(window, window, window) local_out[i:end] = out # 加权融合 return 0.5 * global_out + 0.5 * local_out这个混合注意力的思路是:全局注意力保证长距离依赖不丢,局部注意力保证近邻细节不被稀释。local_window控制局部窗口大小,默认 24,对应一天 24 小时的数据粒度。如果你的数据是分钟级,这个值要相应调大。融合权重 0.5/0.5 是个经验值,实际调参时可以试 0.3/0.7 或 0.7/0.3,看验证集效果。
2.4 数据加载与滑动窗口切分
数据部分最容易被忽视,但长期预测的效果好坏,一半取决于窗口切分是否合理。dataset.py里的做法是:
class TimeSeriesDataset(Dataset): def __init__(self, data, input_len, pred_len, stride=1): self.data = data self.input_len = input_len self.pred_len = pred_len self.stride = stride def __len__(self): return (len(self.data) - self.input_len - self.pred_len) // self.stride + 1 def __getitem__(self, idx): start = idx * self.stride x = self.data[start : start + self.input_len] y = self.data[start + self.input_len : start + self.input_len + self.pred_len] return torch.FloatTensor(x), torch.FloatTensor(y)input_len是历史窗口长度,pred_len是预测长度,stride控制采样步长。训练时stride一般设 1,让样本尽量多;验证和测试时可以设大一点,减少计算量。注意__len__里的计算:要保证最后一个样本的y不越界,所以减去了input_len + pred_len。这个边界条件如果写错,训练时会在最后一个 batch 报索引越界。
3. 跑通训练与预测:从配置到结果可视化
3.1 环境准备与依赖安装
这个项目依赖比较标准,PyTorch + NumPy + Pandas + Matplotlib。我一般会先建一个干净的虚拟环境,避免和系统里的包冲突:
conda create -n informer_roll python=3.9 conda activate informer_roll pip install torch==1.13.1 numpy pandas matplotlib pyyaml tqdmPyTorch 版本建议 1.13 以上,因为用到了torch.no_grad()和nn.MultiheadAttention的一些新特性。如果你有 GPU,装对应 CUDA 版本的 torch 就行。装完之后跑一句python -c "import torch; print(torch.cuda.is_available())"确认 GPU 能用。
3.2 配置文件解读与修改
configs/default.yaml是训练和预测的总控,关键字段如下:
data: path: "./data/ETT.csv" # 数据文件路径 input_len: 96 # 历史窗口长度 pred_len: 336 # 预测长度 stride: 1 # 采样步长 model: d_model: 512 # 模型维度 n_heads: 8 # 注意力头数 local_window: 24 # 局部注意力窗口 dropout: 0.1 train: batch_size: 32 epochs: 50 lr: 0.0001 patience: 5 # 早停耐心值 predict: roll_step: 24 # 滚动预测步长input_len和pred_len是最重要的两个参数。长期预测场景下,pred_len通常是input_len的 2 到 4 倍。比如输入 96 步,预测 336 步。roll_step设成 24,意味着每次滚动预测 24 步,总共滚 14 次。如果你发现预测曲线在后期抖动厉害,先把roll_step调小试试。
3.3 启动训练与日志观察
训练入口是train.py,直接跑:
python train.py --config configs/default.yaml训练过程中会打印每个 epoch 的 train loss 和 val loss。我一般会盯着 val loss 看,如果连续 5 个 epoch 不下降,早停就会触发。日志里还会保存最好的 checkpoint 到checkpoints/best.pth。注意:如果 val loss 一开始就比 train loss 高很多,大概率是过拟合了,可以把dropout调到 0.2 或 0.3,或者减小d_model。
3.4 滚动预测与结果可视化
训练完之后跑预测:
python predict.py --config configs/default.yaml --checkpoint checkpoints/best.pth预测结果会保存成.npy文件,然后visualize.py会读取并画图:
import matplotlib.pyplot as plt import numpy as np def plot_prediction(gt, pred, save_path): """ gt: 真实值 [pred_len] pred: 预测值 [pred_len] """ plt.figure(figsize=(12, 5)) plt.plot(gt, label="Ground Truth", color="blue") plt.plot(pred, label="Prediction", color="red", linestyle="--") plt.xlabel("Time Step") plt.ylabel("Value") plt.title("Rolling Long-term Prediction") plt.legend() plt.grid(True) plt.savefig(save_path, dpi=150) plt.close()画出来的图会直观展示预测曲线和真实曲线的贴合程度。长期预测里,前几十步通常贴得很好,后面会逐渐偏离。如果偏离太快,回去检查roll_step和local_window的设置。
4. 避坑与常见问题排查
4.1 预测结果全是直线或常数
现象:可视化出来的预测曲线几乎是一条水平线,没有任何波动。
原因:最常见的是数据归一化出了问题。如果归一化时用了全局均值方差,但预测时没有做反归一化,或者反归一化用错了参数,输出就会被“压平”。
解决:检查preprocess.py里的归一化和反归一化是否成对出现,确保预测结果先反归一化再画图。另外确认输入数据没有全零或全 NaN。
4.2 训练 loss 不下降或震荡严重
现象:train loss 在第一个 epoch 之后就不动了,或者上下剧烈震荡。
原因:学习率太大是首要嫌疑。长期预测的 loss 尺度通常比较大,lr=0.0001起步比较稳。如果用了默认的 0.001 或 0.01,很容易震荡。
解决:把lr降到 1e-4 或 5e-5,同时加一个学习率预热(warmup)策略。如果还不行,检查数据里有没有异常值,做个 clip 或平滑。
4.3 显存溢出(OOM)
现象:训练到一半报CUDA out of memory。
原因:input_len或pred_len设得太大,或者batch_size太大。Informer 的注意力矩阵是 O(n²) 的,序列长度翻倍,显存占用翻四倍。
解决:先把batch_size减半,如果还不够,减小d_model或n_heads。另外确认roll_step不要设得太小,滚动次数太多也会累积显存。
4.4 滚动预测后期误差爆炸
现象:预测的前 50 步还行,100 步之后完全偏离真实值。
原因:滚动预测的本质是把预测值当真实值用,误差会逐步累积。如果模型本身在单步预测上就不够准,滚动起来必然爆炸。
解决:先评估单步预测的 MAE,如果单步误差就大,回去调模型;如果单步还行,把roll_step调小,增加滚动次数但每次预测更短,误差累积会慢一些。另外可以在滚动时对预测值做一个简单的平滑滤波。
4.5 可视化中文乱码
现象:图表标题或坐标轴的中文显示成方框。
原因:Matplotlib 默认字体不支持中文。
解决:在visualize.py开头加两行:
plt.rcParams["font.sans-serif"] = ["SimHei"] plt.rcParams["axes.unicode_minus"] = False如果系统里没有 SimHei,换成Microsoft YaHei或WenQuanYi Micro Hei。
5. 二次开发与改造思路:从能跑到好用
5.1 换数据集:适配自己的时序数据
这个项目默认用的是 ETT 格式的数据,但你的数据大概率不是这个格式。改造的第一步是把data/preprocess.py里的读取逻辑换成你自己的。常见做法是写一个load_custom_data函数,返回一个[T, features]的 numpy 数组,然后复用现有的滑动窗口切分。注意两点:一是时间列要单独处理,不能直接当特征喂进去;二是如果有缺失值,先做插值再归一化,不要直接填零。
5.2 改模型:替换注意力机制或嵌入方式
如果你想试不同的注意力变体,只需要改models/attention.py里的HybridAttention类,保持输入输出维度一致即可。比如换成 Autoformer 的自相关注意力,或者加一个频域分支。嵌入部分在models/embedding.py,默认是“值嵌入 + 时间特征嵌入”相加。如果你有额外的静态特征(比如设备 ID、地区编码),可以在这里加一个 embedding 层拼进去。
5.3 调参策略:先粗后细,别一上来就网格搜索
我一般会按这个顺序调:先固定d_model=512、n_heads=8,调lr和batch_size,让训练能稳定下降;然后调input_len和pred_len,看长期预测的极限在哪;最后微调local_window和roll_step,优化滚动预测的细节。网格搜索很费时间,建议先用随机搜索跑 20 组,找到大致范围再细化。
5.4 验证改造效果:别只看 loss,要看曲线
改完模型或数据之后,不要只盯着 train loss 和 val loss。长期预测的核心指标是预测曲线和真实曲线的贴合度,尤其是后半段。我习惯把 MAE、RMSE 和可视化图一起看:MAE 告诉你平均误差,RMSE 告诉你大偏差的严重程度,曲线图告诉你误差在时间上的分布。如果 MAE 降了但曲线后半段还是飞,说明模型在长距离依赖上没学好,回去检查注意力窗口和滚动策略。
5.5 一个实用技巧:保存中间预测结果做对比
每次改完模型跑预测,我都会把预测结果保存成带时间戳的.npy文件,比如pred_20240101_roll24.npy。这样后面可以一次性加载多个结果画在同一张图上对比。这个习惯帮我省了很多重复训练的时间——有时候改了一个参数,效果变差了,直接和之前的曲线一对比就知道问题出在哪。
从那以后我每次改模型结构或者滚动策略,都强制走一遍“单步预测 → 滚动预测 → 可视化对比”的流程,不再只看 loss 就下结论。希望这个项目的拆解能帮到你,拿到源码后先跑通默认配置,再按自己的数据一步步改,别一上来就大改。
本文还有配套的精品资源,点击获取