☰
15个Transformer变体实战:长时间序列预测代码汇总与调参指南
2026/10/6 10:40:36 网站建设 项目流程

简介:基于Transformer的长时间序列预测与分类算法代码合集,涵盖Autoformer、Informer、PEDformer、Crossformer、TimesNet、DLinear等十五个主流时间序列模型,并配套电力负荷、ETT油温、外汇汇率、病情变化、交通车流量、天气观测等真实数据集。面向需要复现或对比不同Transformer变体性能的研究者、算法工程师与竞赛选手,可减少从零搭建与调参成本,快速完成多模型实验。压缩包共一千三百七十八个文件,约一百八十二点二MB,以PDF论文说明、Shell训练脚本、Python核心代码、npy与CSV数据文件为主,另有少量可视化图片和Notebook示例。目录按算法模块组织,已有三千四百六十七人浏览学习。包内除了各模型训练推理脚本,还包含数据预处理流程、超参数配置、环境依赖说明与实验日志,适合直接修改数据路径后运行测试,也可以对照PDF内容理解各算法的设计动机与适用差异,显著缩短基线对比和环境配置时间。

1. 长时间序列预测的“长”是把双刃剑:15个Transformer变体到底在解决什么

Transformer在长序列预测上有个反直觉的短板:序列越长,自注意力越记不住远期信息,因为每个位置要和所有位置算相似度,长度一上来,注意力权重就被均摊。长时间序列预测(LTSF)恰恰要求模型记住几百步之前的周期与趋势,这就是 Autoformer、PEDformer、Informer 这些变体扎堆的理由——它们不是推翻Transformer,而是改注意力的计算方式。这份15个算法代码汇总的价值在于把训练、评估、预测统一成一套命令行入口,你不用为每个模型重写数据处理和评估脚本。适合做电力负荷、交通流量、气象预报、金融日频预测的从业者拿来当基线对比和调参起点。

2. 拿到代码包先做三件事:环境、数据格式、跑通最小demo

2.1 为什么是这15个模型:按注意力机制给算法分组

标题里提到的“15个算法”,落到代码包里通常就是models/目录下每个子目录一个模型类。先别急着跑,把这十几个模型按注意力怎么改分成四组,后面调参才有方向。

分组模型核心改动
稀疏注意力Informer、Pyraformer减少参与注意力计算的query/key数量,Informer用ProbSparse采样,Pyraformer用金字塔多尺度图
分解与自相关Autoformer、ETSformer把原始序列先拆成趋势项和季节项,Autoformer用自相关替代attention做周期匹配
频域PEDformer、FiLM变换到傅里叶频域后只保留部分频率分量做注意力,长周期信号在频域更稀疏
分块PatchTST、Crossformer、LightTS把输入序列切成patch再编码,支持更长输出
分布修正Nonstationary Transformer先反平稳化再平稳化,缓解训练和测试分布漂移
基线DLinear、SCINet、TimesNet、Triformer、Vanilla Transformer线性或非Transformer结构,用来验证Transformer是否真的有增益

这六组的调参入口完全不同:稀疏注意力组先看采样比例,频域组看频率阶数,分块组看patch长度。如果把PEDformer当Informer调,大概率改半天找不到头绪。

2.2 环境与仓库结构:从requirements到运行入口

这类汇总代码包的环境不复杂,Python 3.8或3.9、PyTorch 1.13左右就够,再加 numpy、pandas、scipy、sklearn、matplotlib。装的时候别一把梭,常见做法是先建一个干净的虚拟环境,再按requirements装。

# 建立虚拟环境并激活,隔离依赖 python -m venv venv && source venv/bin/activate pip install torch==1.13.1 pip install numpy pandas scipy scikit-learn matplotlib

第一行建虚拟环境并激活是隔离依赖,避免和机器上其他项目冲突;第二行装torch,老代码包用1.13最稳,2.x也能跑但偶尔有接口变动,遇到兼容报错就降回1.13;第三行是通用数据科学库。如果你的汇总包自带requirements.txt,直接 pip install -r requirements.txt 也行,但torch那行单独装更可控。

目录结构只看这几个位置就够了:data/ 放整理好的CSV数据集;models/ 是15个模型的实现;run.py 是所有实验的统一入口;scripts/或experiments/ 里是论文复现shell脚本,里面带着每个数据集和模型的推荐参数,是调参第一参考。装完先检查入口:python run.py --help,如果能打印参数说明,说明环境基本通了。

2.3 最小复现:用ETTh1跑通Informer的训练和结果输出

确认环境后,第一次跑通不要追求精度,用最短命令验证全链路。以Informer和ETTh1为例,最小训练命令长这样:

# 最小复现命令:先保证数据读取、训练、保存、测试链路全部通 python run.py \ --model Informer \ --data ETTh1 \ --features M \ --seq_len 96 \ --label_len 48 \ --pred_len 168 \ --d_model 512 \ --n_heads 8 \ --e_layers 2 \ --d_layers 1 \ --dropout 0.05 \ --learning_rate 0.0001 \ --batch_size 32 \ --train_epochs 10 \ --patience 3 \ --seed 2024

各参数含义:--model选算法名;--data指定数据集,代码包内置ETTh1/ETTm1等名称;--features M表示多变量输入多变量输出,S是单变量,MS是多变量预测单变量;--seq_len是回溯窗口96小时,--label_len是decoder起始提示长度48,--pred_len是预测未来168小时。--d_model和--n_heads是Transformer核心维度参数,ETTh1这种7通道数据,512和8是Informer论文的典型搭配。--patience是早停轮数,验证集连续3轮不降就停。

这行命令在单卡上大约十几分钟能跑完。跑完看输出:程序会打印best valid loss、test MSE、test MAE,并生成结果文件。数据流是:data_loader按seq_len+label_len+pred_len切窗口,encoder吃前96步,decoder吃48步真实值拼接接下来168步的占位,输出重建,MSE在反归一化后计算。

验证一下训练结果是否真的能用,跑一次测试模式,--train_epochs设为0,表示跳过训练直接加载已有checkpoint:

# 测试模式:仅加载训练好的模型,输出测试集MSE/MAE python run.py \ --model Informer \ --data ETTh1 \ --features M \ --seq_len 96 --label_len 48 --pred_len 168 \ --d_model 512 --n_heads 8 --e_layers 2 --d_layers 1 \ --dropout 0.05 --learning_rate 0.0001 --batch_size 32 \ --train_epochs 0 --seed 2024

能否跳过训练取决于checkpoint是否存在于包内预设的结果目录,如果上次训练被patience提前终止,模型也会保存。test模式不仅打印指标,还会把预测结果存成pred.npy和true.npy,后续可视化全靠这两个文件。第一次跑通后不要急着换模型,先理解这一条链路:数据读取、窗口切分、训练、保存、测试、输出,15个算法全都复用这套流程。

3. 数据预处理与实验协议:从ETT到自定义数据的边界

3.1 ETT数据集为什么是默认选择

ETT(Electricity Transformer Temperature)系列是这类代码包的默认数据集,它来自电力变压器,包含油温OT和6条外部负载数据,7列数值字段,小时级(ETTh1/ETTh2)和15分钟级(ETTm1/ETTm2)两种粒度都有。选它当默认实验集有三个原因:第一,均匀采样、无缺失值,免去数据清洗环节;第二,有明确的周期性和趋势漂移,能区分模型捕捉周期能力的好坏;第三,规模适中,单卡几分钟到半小时出一个结果,适合快速对比。

ETT的官方划分协议通常是train/valid/test按12/4/4比例顺序切分,也就是前60%训练、20%验证、20%测试。注意是严格按时间顺序切,绝不随机。有些汇总包会改成6/2/2,跑对比实验时先看一眼包里的默认划分,所有模型用同一套就行。评估指标默认是MSE和MAE,MSE对离群点敏感,MAE更贴近业务平均误差,报告结果时两个都留。

数据文件的标准形态是CSV,第一列是日期时间,后面是数值特征。ETT的时间戳格式类似2016-07-01 00:00:00,其余列是浮点数。如果你的数据时间戳不是统一间隔,代码包的data_loader一般会报错或对齐失败,这一点在下一节展开。

3.2 换自己的数据:CSV格式、归一化和滑窗参数

自己业务数据接入这套代码,核心是CSV格式对齐。常见做法是先把数据整理成两列以上的表:第一列时间戳,格式固定为YYYY-MM-DD HH:MM:SS;后面每列一个数值特征。缺失值先处理,线性插值在绝大多数场景够用,突变性的缺失用前向填充更稳妥。

归一化是这里最容易出错的一步。很多包的DataLoader里内置了StandardScaler,但标准化参数必须只在训练集上fit。手动处理时,正确写法是先按时间顺序切分,再fit训练段:

import pandas as pd from sklearn.preprocessing import StandardScaler df = pd.read_csv('my_data.csv', parse_dates=['date']) train_df = df.iloc[:int(len(df)*0.6)] valid_df = df.iloc[int(len(df)*0.6):int(len(df)*0.8)] test_df = df.iloc[int(len(df)*0.8):] scaler = StandardScaler() # 只对训练段fit,测试段的分布信息不能混进mean/std scaler.fit(train_df.drop(columns=['date']).values) for split in (train_df, valid_df, test_df): values = split.drop(columns=['date']).values scaled = scaler.transform(values) # 保存成包内data目录要求的CSV格式

逻辑说明:先按时间顺序把原始表切成三段,然后只对训练段fit得到mean和std,再对三段分别transform。这样保证验证集和测试集的分布信息不泄漏进归一化参数。有些新手把全量数据fit一遍,测试集MSE会虚低,换到线上就出问题。

滑窗参数决定模型的观测视野:seq_len是看多长历史,pred_len是预测多远,label_len只对带decoder的模型有意义。常见比例是seq_len=pred_len×2,比如pred_len=168时seq_len=336。窗口数量等于总长度减去seq_len+pred_len(对decoder模型还要减去label_len),数据太短时优先缩短seq_len而不是pred_len。

3.3 模型统一入口:run.py的六个必传参数

所有模型共用run.py,理解这六个必传参数,就能控制任意一个实验:

参数作用典型值影响
--model选择models/目录下的模型类名Informer / Autoformer / PEDformer / PatchTST / DLinear决定网络结构和可调超参
--data选择data/下的数据集名ETTh1 / ETTh2 / ETTm1 / 自定义名决定数据文件读取路径和窗口总数
--features输入输出结构M / S / MSM多变量到多变量;S单变量到单变量;MS多变量到单变量
--seq_len输入序列长度96 / 336越大历史信息越足,但计算量和显存上涨
--label_lendecoder的提示序列长度48 / 96只对Informer/Autoformer/PEDformer等带decoder的模型有效
--pred_len预测序列长度168 / 336 / 720越大误差越高,显存占用越高

六个参数中,pred_len对结果的影响最大。预测跨度从168拉到720,所有模型误差都会上涨,差异在于谁涨得慢。线上决定pred_len时不要拍脑袋,看业务提前期需求,同时准备两个档位对比。

这里还有两个容易被忽略的参数:--itr表示重复实验次数,取3时程序会连跑3次并输出均值方差,论文里常用3或5,日常调试取1就够了;--use_gpu默认等于True,多卡机器上--use_multi_gpu配合--devices指定卡号,单卡不用管。调PEDformer这类模型时,先把这六个参数固定,只动它的频域超参,否则换了模型又换数据,出了问题不知道怎么归因。

4. 分组跑15个算法:按预测长度做精度对比的策略

4.1 按预测长度对比:168、336、720三档怎么跑

15个模型逐个调参不现实,常见做法是固定数据集、固定seq_len=96,只改pred_len,三个档位各跑一遍。这一轮的价值不是刷SOTA,而是看模型在预测长度变长时误差是否失控。脚本化跑批量实验:

for model in Informer Autoformer PEDformer PatchTST DLinear; do for pred_len in 168 336 720; do python run.py \ --model $model \ --data ETTh1 \ --features M \ --seq_len 96 \ --label_len 48 \ --pred_len $pred_len \ --d_model 256 \ --n_heads 8 \ --e_layers 2 \ --d_layers 1 \ --dropout 0.05 \ --train_epochs 10 \ --patience 3 \ --seed 2024 done done

这个脚本会依次跑Informer的168/336/720,然后Autoformer、PEDformer、PatchTST、DLinear,共15次实验。d_model统一设256,是为了在一个不算大的容量下公平对比,论文复现时的推荐参数可以后续再逐个替换。跑完把每个模型的test MSE/MAE记录到表格,就能看到:哪个模型在720档的误差同比上升最少。

注意:批量实验建议先只跑168档确认链路正常,确认每个模型的命令行参数都齐全后再放720档过夜,省得睡醒发现PEDformer因缺频域参数中途报错。

跑完一轮对比大约需要几个小时。中间任何一次失败不会中断整个循环,但输出日志要看,常见失败原因是PEDformer或Autoformer需要额外参数没提供,比如频域类模型在部分包里要求--n_order、--mode_index等参数存在,命令行带少了会直接报错。所以第一次跑PEDformer之前,先看包里它的default参数列表。

4.2 误差区间与模型定位:别只看MSE一个数

同一份ETTh1数据上,不同模型组的误差表现有比较清晰的分层,理解这个分层比记住数字有用。Autoformer和PEDformer靠自相关或频域分解,在336和720档位通常能保持相对低的MSE,因为长周期信号被显式建模了。PatchTST在patch_size合适时误差很稳,尤其是720档,它把序列切成小块后由编码器直接映射到长输出,不依赖长长的decoder。Informer在中短期比如168档有速度优势,到720档误差涨得比分解类快。DLinear在ETT这类强周期数据上往往不输给大多数Transformer,这是正常现象,不是代码有问题。

如果你跑出来的相对趋势和上面相反,比如PEDformer在720档比DLinear还差一大截,优先排查两件事:一是频域参数是不是被改过,二是归一化是否泄漏。很多人在这时候开始怀疑模型没有意义,其实先跑满一轮再下结论。出现方向异常时,下一步不是继续调参,而是去看每个模型在验证集上的loss曲线有没有震荡,震荡通常意味着学习率过大或数据切分有问题。

记录实验结果时,MSE、MAE之外,把每个模型的训练时间、显存峰值、参数总量一起记。线上选型时,精度差0.01但推理时间长一倍,对生产不一定划算。训练时间是调参的硬约束,Informer在ETTh1上一个epoch大约半分钟以内,PatchTST更快,Autoformer因为有自相关计算会慢一些。

4.3 结果可视化:把pred和true拼成一条曲线

数值表看不出预测错在哪,可视化能。跑完测试后,包里会在结果目录输出预测值和真实值的numpy数组,直接用它们画长序列对比图:

import numpy as np import matplotlib.pyplot as plt pred = np.load('pred.npy') # 形状 [样本数, pred_len, 特征数] true = np.load('true.npy') # 每个预测窗口取最后时间步,拼接成连续曲线 pred_series = pred[:, -1, 0] true_series = true[:, -1, 0] plt.figure(figsize=(12, 4)) plt.plot(true_series[:500], label='True', linewidth=1.2) plt.plot(pred_series[:500], label='Pred', linewidth=1.2, alpha=0.8) plt.legend() plt.title('ETTh1 OT prediction') plt.tight_layout() plt.savefig('pred_vs_true.png', dpi=150)

逻辑说明:pred.npy的维度是[窗口数, 预测步长, 特征数],不要直接把它当连续预测曲线来画,那会输出很多平行线段。取pred[:, -1, 0]意思是每个窗口只取最后一步预测,再把所有窗口拼起来,得到一条等长于测试集的连续预测线。第0个特征对应ETT里的OT油温,这是业务最关心的保护对象,也是普遍预测误差最小的字段。

看这张图有几个判断要点:如果Pred曲线在波峰处整体偏低,模型在低估峰值,常见原因是MSE对离群峰值惩罚太重,模型学会了求稳;如果Pred相对True滞后几个点,序列对齐或滑窗切分可能有问题;如果Pred几乎是一条水平线,模型把所有波动都平均掉了,大概率特征学习没有起效,先检查标签是否被误归一化。作图时画500个点足够暴露问题,画全部上万点反而看不清细节。

5. 调参与避坑:长时间序列Transformer的5个常见坑

5.1 数据泄漏与标签长度:两个隐蔽的设置错误

第一个坑:归一化泄漏。现象是验证集和测试集MSE低得可疑,比论文结果还好,但拿到新数据预测时误差暴涨。原因多半是数据预处理里用全量数据的均值和标准差做了StandardScaler。解决方法是严格按3.2节的顺序:先切分再fit训练段。检查方式也简单,打印scaler.mean_和scaler.var_,再手动算一下训练段的均值和方差,对不上就有泄漏。

第二个坑:把label_len当成预测长度。现象是有人把--label_len设为和--pred_len一样甚至更大,然后发现Informer等模型显存翻了倍,训练变慢。原因在于label_len是decoder输入中真实观测部分的长度,不是要预测的步数;它给decoder提供“最近一段真实值”作为起始提示,常见做法是seq_len的一半,也就是96配48。解决方法是固定label_len=seq_len/2,只有做消融实验时才单独动它。PatchTST和DLinear不接收label_len参数,传了也会被忽略,不用奇怪。

5.2 显存与超参:pred_len和d_model怎么定

第三个坑:pred_len拉长后显存溢出。现象是pred_len从168改成720,直接OOM。原因是带decoder的模型(Informer、Autoformer、PEDformer)在解码阶段一次性生成整个pred_len长度的序列,显存占用随预测长度线性甚至更陡地增长。解决顺序是:先调小batch_size到16或8;再把seq_len同步调大,给encoder更多上下文;还不行就换PatchTST这类纯encoder输出长的模型。注意batch_size调小后要同步把learning_rate略降,不然梯度噪声变大,loss会震荡。

第四个坑:d_model在小数据集上盲目用512。现象是训练loss下降很快,验证loss却抬升,典型过拟合。原因很简单,ETTh1只有7个特征,d_model=512意味着embedding层把7维映射到512维,参数大量冗余。解决方法是d_model设为128或256起步,观察验证loss不再下降再升到512。对比实验里所有模型都用同一d_model才公平,这一点在批量跑脚本时尤其要记住。

5.3 PEDformer频域参数:调坏之后的排查思路

第五个坑:PEDformer的频域参数被乱调后性能暴跌。现象是PEDformer跑出来的MSE比DLinear还高出一大截,但没改参数之前明明正常。原因多半是动了n_order或mode_index一类的频域分量参数。PEDformer把序列变换到傅里叶域后,只保留若干个频率分量做注意力,n_order控制保留的模态数量,mode_index控制分量选择范围。调小n_order会丢掉信息,调大会引入噪声,而且这两个参数的合理区间和seq_len、pred_len耦合,不能单独拍脑袋。

解决方法是:先恢复默认值(常见是n_order=3,mode_index按包内默认的0到某个范围),确认模型回到基线;再逐个变量改回去,看到底是哪个参数导致劣化。排查用频谱图最直观:把输入序列做FFT,看能量集中在哪几个频率上,n_order应该覆盖能量峰值附近的分量个数。如果你在models目录里找不到PEDformer.py,多半文件名写的是FEDformer.py,命令行 --model 传和类名一致的那个即可。这一步是典型的参数玄学现场,但只要回到默认再逐个变量验证,就能定位到原因。

6. 进阶验证:用DLinear做消融,判断误差来自模型还是数据

6.1 为什么必须跑一遍DLinear

15个Transformer跑完,最后一定要补跑一次DLinear。它只有两层线性映射,训练一分钟内出结果,却是判断工作方向的关键指标:

# 线性基线:验证Transformer在这份数据上是否真的有增益 python run.py \ --model DLinear \ --data ETTh1 \ --features M \ --seq_len 96 \ --label_len 0 \ --pred_len 168 \ --train_epochs 10 \ --patience 3 \ --seed 2024

如果DLinear的MSE和Informer接近甚至更好,直接说明这份数据的预测主要靠线性趋势和周期叠加,注意力结构带来的边际收益有限,继续调Transformer的隐藏层不如去补特征工程或外部变量。如果PEDformer和PatchTST显著低于DLinear,说明数据里确实有Transformer能抓住的非线性时序关联,继续深挖才有价值。有人拿合成正弦数据测试,所有Transformer都能把周期拟合像样,一旦换成突变和缺失较多的工业数据,差距立刻拉开。真实项目先看数据形态,再决定投入哪类模型。

6.2 三个验证技巧:多随机种子、分通道误差、分段误差曲线

验证模型稳定性,单跑一次不够。把同一组参数换seed跑五次,取MSE均值和标准差再下结论:标准差大于均值10%,基本可以判定训练不稳定,优先排查学习率和数据切分;跑五次不用改代码,循环改seed即可。

第二个技巧是分通道误差。ETT有7列特征,全局MSE掩盖了单通道差异。把pred和true按特征维度分离,逐列算MSE:通常OT油温误差最小,负载类特征误差大;如果反过来,说明数据预处理里某列的特征顺序已经错位。第三个技巧是分段误差曲线,对pred.npy按预测步长维度取平均,画误差随前进步数的曲线:误差在第30步以后快速上升,说明模型只学会了短期延续;误差全程平稳,说明预测长度还可以继续拉长,业务提前期可以设得更长。

我自己的习惯是每个项目先跑DLinear,再跑一个最强的Transformer,两者差距决定了后续调参投入。以前为了在ETTh1上把720档指标刷高,我曾把PEDformer的频域参数改到面目全非,结果换到真实业务数据上完全失效,后来老老实实从基线做起,用上面这套验证流程把大量时间省了回来。希望这套验证路径也能帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询