Transformer长序列预测代码包全攻略:从Autoformer到PatchTST
简介面向长时间序列预测与分类任务的研究者和工程师资源包整合了15种基于Transformer的代表性算法代码包括Autoformer、PEDformer、Informer、Crossformer、ETSformer、Pyraformer、TimesNet、Reformer、DLinear等覆盖电力负荷、ETT油温、外汇、病情、交通车流量及天气等典型数据集可直接迁移到自己的实验场景。压缩包共含1378个文件以PDF说明文档、Shell运行脚本、Python源码及pyc编译文件为主同时附有npy预处理数据和CSV原始数据集整体大小182.2MB目录结构便于快速检索。目前已有3467人学习下载。通过对比各模型在不同数据上的预测效果可系统掌握Transformer系模型的架构差异、训练配置与调参技巧适合算法对比、论文复现及长期序列预测入门进阶。1. Transformer长时间序列代码包从Autoformer到PatchTST这份汇总能帮你省下什么做长时间序列预测的人如今绕不开Transformer——Autoformer每次发布都要把SOTA往前推一截Informer把注意力复杂度从O(L²)压到O(LlogL)PatchTST又用patch把序列建模重新定义了一遍。但真到动手跑实验第一关往往不是原理而是代码论文主页链接失效、GitHub仓库里缺数据、版本对不上。这份汇总代码的核心价值是把Autoformer、FEDformer、Informer、PatchTST、DLinear、iTransformer等15个长序列预测算法的源码、数据装载器和训练脚本收在一个工程里。目录层次统一命令行参数风格一致下载解压之后不用再挨个去不同仓库里对齐环境直接按一个模子跑就行。它适合三类人补论文实验基线的研究生、做算法选型评估的工程师、刚接触序列预测想尽快跑通一条完整pipeline的新手。它的目标不是把Transformer原理再讲一遍而是让你在一个工作日内把至少三五个模型跑出可比的结果并且知道每个模型的边界在哪。2. 15个算法怎么选稀疏注意力、频率分解与线性基线的定位拿到一个包含15个模型的工程最忌讳的是上来就逐个跑一遍。先花半小时把算法分类看清楚后面所有实验才有意义。这一章按注意力机制和建模思路把这批模型拆成几个阵营每个阵营告诉你它解决了什么、适合哪些数据。2.1 稀疏注意力阵营Informer、LogTrans与PyraformerInformer是这个汇总里最常被第一个跑通的模型。它提出的ProbSparse Attention不做全量点积而是先算每个query的稀疏度只保留信息量最大的那批query参与attention计算把复杂度从O(L²)降到O(LlogL)。LogTrans走的是另一条路用LogSparse让每个query只看指数步长范围内的keyPyraformer则用金字塔结构在不同尺度上做注意力聚合。这三个模型共同的特点是“拿Transformer骨架换效率”适合序列长度几千以上、显存吃紧的场景。实际跑实验时这一类往往表现最稳。Informer的代码结构后来被很多仓库继承run.py、exp_main.py、models目录的划分方式几乎成了时间序列Transformer的默认工程范式。如果只挑一个模型作为全仓库的sanity check我一般选Informer因为它训练快、资源占用可控、出问题容易排查。2.2 分解与频率阵营Autoformer、FEDformer与ETSformerAutoformer的核心是序列分解加自相关机制。它先把序列拆成趋势项和季节项再用自相关取代原来的点对点注意力按周期相似度聚合信息。FEDformer把输入变换到频域在傅里叶域和小波域做稀疏表示对强周期信号特别敏感。ETSformer则把指数平滑思想融进Transformer结构趋势建模更直接。这里要特别提醒一个命名坑标题和很多博客里写的“PEDformer”在开源代码里几乎全部对应FEDformer也就是Frequency Enhanced Decomposed Transformer。你下载的汇总包里最有可能出现的是FEDformer文件夹运行命令也是--model FEDformer。如果实在找不到PEDformer这个名字别怀疑自己下错了包先把models目录列出来看一眼。这三个模型适合气温、电力负荷、流感这种带明显季节周期的数据。很多人喜欢造一个正弦波CSV来验证Transformer预测正弦数据的效果这类单一强频率的玩具数据恰好是Autoformer和FEDformer最擅长的场景跑出来的曲线会非常漂亮。2.3 线性与补丁阵营DLinear、PatchTST与iTransformerDLinear严格说不是Transformer但长序列预测领域你几乎不可能绕开它。Autoformer的论文里就专门跟DLinear做过对比结论是DLinear在某些数据上甚至反超Transformer。这类汇总包把它收进来就是为了给所有Transformer模型提供一个强基线。先跑DLinear再跑Transformer你才知道Transformer到底值不值得上。PatchTST把时间序列切成patch每个patch当成一个token输入Transformer相当于把注意力粒度从单点提升到局部片段。iTransformer则更激进直接把“变量维度”当作token时间步的信息靠内部FFT和卷积处理。这两个模型打破了一个默认假设——“时间步必须等于token”是理解Transformer架构扩展方向的好样本。2.4 选型速查表模型核心机制复杂度特征适合场景InformerProbSparse AttentionO(LlogL)长序列、显存敏感LogTransLogSparse AttentionO(L(logL)²)超长序列、日志数据Pyraformer金字塔注意力近似O(L)极长序列、多层次周期Autoformer序列分解自相关接近O(LlogL)强周期、趋势明显FEDformer频域稀疏增强O(L)级别强季节性、多周期叠加ETSformer指数平滑TransformerO(LlogL)趋势季节混合DLinear线性分解线性全场景基线PatchTSTPatch嵌入TransformerO(LlogL)多变量预测iTransformer变量维度token化O(L²)变量数多、序列中等Crossformer跨维度注意力O(L1.5)多变量交叉依赖TimesNet2D时序变化与周期相关多周期信号SCINet多分辨率采样线性长序列、降采样场景StemGNN图谱方法与图结构相关多变量强耦合剩下一两个模型通常是同仓库里附带的小改进版本选型思路逃不出上面这些阵营。我的建议是上Transformer之前先跑DLinear数据周期特征强重点试Autoformer和FEDformer序列太长显存不够Informer优先。3. 跑通第一个预测实验数据放哪、命令怎么敲、参数怎么改这一章解决的是从下载到出指标的全过程。照着做半小时内你屏幕上应该能看到test mse和test mae。3.1 数据放对位置CSV约定与日期解析这类汇总工程的数据目录一般是 ./dataset下面按数据集分子目录比如ETT-small、weather、exchange_rate。ETT是电力变压器温度数据集ETTh1是小时级ETTm1是15分钟级WTH是气象站数据ILI是流感比例。先打开一个CSV看看结构$ head -5 dataset/ETT-small/ETTh1.csv date,HUFL,HULL,MUFL,LLUFL,MUFL_1,OT 2016-07-01 00:00:00,5.327,5.512,0.447,0.439,0.784,5.412 2016-07-01 01:00:00,5.301,5.465,0.441,0.434,0.776,5.390 2016-07-01 02:00:00,5.287,5.438,0.438,0.432,0.772,5.365注意两个硬性约定第一列必须叫date时间格式必须是“yyyy-MM-dd HH:mm:ss”第二列以后全是数值列最后一列通常是target列。data_loader用正则解析日期如果你自己的数据只有日期没有小时或者列名写作DateTime轻则报KeyError重则loss全程NaN。如果只是想快速验证流程不想去找公开数据可以自己造一个正弦波CSV放进去。很多入门者验证Transformer预测正弦数据都用这招生成两列date和valuevaluesin(2πt/24)直接按训练脚本跑模型收敛快、可视化效果直观。这个包对自定义CSV没有额外限制只要列名和日期格式对它就行。3.2 单模型训练命令行参数在讲什么确认数据集就位后先用Autoformer跑一次完整训练加测试。这个系列的命令行参数跨模型通用学会一组就等于会了所有。python -u run.py \ --model Autoformer \ --data ETTh1 \ --root_path ./dataset/ETT-small/ \ --data_path ETTh1.csv \ --features M \ --target OT \ --seq_len 96 \ --label_len 48 \ --pred_len 96 \ --e_layers 2 \ --d_layers 1 \ --factor 3 \ --batch_size 32 \ --use_gpu 1--features三个取值要分清M表示多变量预测多变量输入所有列、预测所有列S表示单变量预测单变量MS表示输入多变量但只预测--target指定的单变量。--target对应CSV里的预测目标列名。--seq_len是回看窗口--label_len是decoder里“已知尾部”的长度--pred_len是要预测的步数。Informer、Autoformer这套架构里label_len不建议设成0它负责给decoder提供已知真值尾部设太小会影响训练稳定性。--e_layers和--d_layers分别控制编码器和解码器层数显存不足时先砍e_layers。--factor是稀疏注意力或自相关的采样因子调小直接降低计算量但也可能牺牲精度。日志会打印每一轮的train loss和val loss训练结束后自动跑测试集输出best val loss、test mse和test mae。看到这三项说明整条链路已经通了。3.3 用循环把多个模型串起来单模型跑通之后下一步是把多个模型放到同一数据集上对比。这时候不建议开多个终端并行跑显存会互相挤兑日志也会混在一起。我一般写成串行循环for model in Autoformer FEDformer Informer DLinear PatchTST do echo $model on ETTh1 | tee -a exp_logs.txt python -u run.py \ --model $model \ --data ETTh1 \ --features M \ --target OT \ --seq_len 96 --label_len 48 --pred_len 96 \ --batch_size 32 --use_gpu 1 \ exp_logs.txt 21 done这里用追加而不是覆盖防止后面的模型把前面的日志冲掉。tee -a是为了让屏幕上也实时看到当前跑的是哪个模型。跑完直接grep日志文件就能拿到所有模型的指标对比。如果只有CPU把--use_gpu改成0ETTh1这种小数据集每个模型大概多花几分钟不至于等不起。提示训练日志里如果同时出现best val loss和test mse以test mse为准做模型对比。best val loss只是选checkpoint用的不代表最终测试表现。4. 拆开黑匣子Embedding、稀疏注意力与序列分解的实现细节网上讲transformer模型详解的文章很多但对着这份汇总里的源码读一遍你会发现三件事embedding不是简单线性映射注意力不一定非要全量计算长期预测离不开序列分解。这一章挑三个最关键的实现细节讲透。4.1 Embedding与位置编码时间特征怎么变成向量这类代码包的Embedding模块通常由三部分相加组成数值embedding、时间特征embedding、位置编码。TokenEmbedding最常用的实现是1D卷积kernel_size为3padding_mode设为circularclass TokenEmbedding(nn.Module): def __init__(self, c_in, d_model): super().__init__() self.tokenConv nn.Conv1d( in_channelsc_in, out_channelsd_model, kernel_size3, padding1, padding_modecircular ) def forward(self, x): # x: [batch, seq_len, c_in] x self.tokenConv(x.permute(0, 2, 1)).transpose(1, 2) return x用卷积而不是全连接做embedding好处是能保留相邻时间步的局部平滑信息。circular padding的意义在于序列两端不丢周期信息——对时间序列来说开头和结尾很可能是同一个周期的不同相位。时间特征embedding接收的是x_mark也就是hour、weekday、month这些扩展列通过线性层压到d_model维。三者相加后过dropout得到最终输入。这个模块在代码里通常叫DataEmbedding不管是Autoformer还是Informer、PatchTST换汤不换药。如果你要改输入变量的数量改c_in就行要改时间特征粒度改freq参数比如freqh表示小时级特征freqt会细化到分钟。4.2 稀疏注意力与自相关效率到底从哪来Informer的ProbSparse Attention在源码里看起来不复杂但理解它需要抓住一个点不是所有query都值得计算。常见实现里先算出每个query的稀疏性得分再取top-u个query参与后续attentionL_K K.shape[-2] u int(self.factor * np.ceil(np.log(L_K))) # 采样query数量 # 对每个query计算近似稀疏度 score self.measure_scores(Q, K) # 内部逻辑点积减去logsumexp top_u_idx score.topk(u, dim1).indices # 只对top-u的query做完整attention Q_reduced Q.gather(1, top_u_idx.unsqueeze(-1).expand(-1, -1, Q.shape[-1])) attn torch.softmax(Q_reduced K.transpose(-2, -1) / math.sqrt(d_k), dim-1) Vfactor取3时每个query只对数个key做计算序列长度越长节省的算力越明显。这就是Informer能处理长序列的底气。Autoformer的自相关则完全换了一套思路它用FFT把query序列变换到频域找出能量最强的周期再按周期偏移对不同子序列做聚合q_fft torch.fft.rfft(query, dim-1) freqs torch.argmax(q_fft.abs(), dim-1, keepdimTrue) periods (query.shape[-1] // freqs).clamp(min1)这只是找主周期的直观示意实际代码还会取topk周期做时延聚合。核心思想是时间序列的相似性不一定体现在相邻点上更可能体现在相同相位上。自相关正是从频域视角捕捉这种远程依赖这也是Autoformer在长周期数据上比传统Transformer稳的原因。4.3 序列分解移动平均的前后paddingAutoformer、ETSformer、DLinear都依赖序列分解模块把原始序列拆成趋势项加季节项。最常见的实现是移动平均class moving_avg(nn.Module): def __init__(self, kernel_size, stride): super().__init__() self.avg nn.AvgPool1d(kernel_sizekernel_size, stridestride, padding0) def forward(self, x): # x: [batch, seq_len, features] front x[:, 0:1, :].repeat(1, (self.avg.kernel_size[0] - 1) // 2, 1) end x[:, -1:, :].repeat(1, (self.avg.kernel_size[0] - 1) // 2, 1) x torch.cat([front, x, end], dim1) return self.avg(x.permute(0, 2, 1)).permute(0, 2, 1)这段代码的玄机在padding。AvgPool1d会缩短序列长度所以要在序列两端各补(kernel_size-1)//2个点。前端复制第一个值后端复制最后一个值这样趋势项的端点不会出现突变。kernel_size必须是奇数否则两端补的点数不对称趋势项在边界会歪。这个细节直接决定预测序列前几个点的质量很多跑出来的曲线开头明显偏离十有八九是这里出了问题。为什么用AvgPool1d而不是直接卷积做平滑因为池化层没有可学习参数训练更稳定反向传播简单序列分解模块不需要引入额外参数量。ETSformer里还加了可学习的分解层但基础版都是这个结构。5. 常见问题与避坑五个最容易翻车的现场这一章写的都是真实跑代码时高频出现的坑每一条我都按现象、原因、解决三步拆开。遇到了直接照做。5.1 命名不一致与数据格式的坑现象解压代码包后在models目录和脚本参数里都找不到PEDformer直接执行--model PEDformer报ModuleNotFoundError。原因社区里这个算法几乎统一叫FEDformer即Frequency Enhanced Decomposed Transformer标题里的PEDformer大概率是文章笔误或习惯性简写。解决先执行ls models看一下真实目录名用FEDformer作为--model参数启动。如果一定要保留旧的拼写习惯可以在models里加一个别名文件# models/fedformer.py 里实际定义 FEDformer # 在 models/pedformer.py 里加一行 from models.fedformer import FEDformer现象自己准备的数据集一训练loss全程是NaN或者加载时报KeyError: date。原因data_loader对日期列的解析依赖“date”这个列名和“yyyy-MM-dd HH:mm:ss”格式列名不同或时间格式缺了秒段都会解析失败。解决统一列名和时间格式用pandas先洗一遍再放进去import pandas as pd df pd.read_csv(your_data.csv) df.columns [date] list(df.columns[1:]) df[date] pd.to_datetime(df.date).dt.strftime(%Y-%m-%d %H:%M:%S) df.to_csv(dataset/custom/clean.csv, indexFalse)如果只是做冒烟测试先拿仓库自带的ETTh1.csv跑通再换自己的数据能少踩很多无谓的雷。5.2 算力与选型的坑现象设置seq_len336、pred_len720后batch_size32直接CUDA out of memory换到batch_size16还是爆。原因注意力计算量和序列长度强相关即便Informer做了稀疏化336的历史窗口加720的预测长度中间特征图尺寸依然不小。解决按下面顺序依次调整直到能跑起来python -u run.py --model Informer \ --batch_size 8 \ --e_layers 1 \ --factor 1 \ --use_amp先砍batch_size再砍encoder层数最后降factor。如果这三步都做完还在OOM说明这个长度的实验应该先上DLinear这种线性模型Transformer等资源充足再试。现象同样的ETTh1数据Autoformer跑出来的MSE比DLinear还高。原因Autoformer论文里明确承认过DLinear这类线性分解模型在某些数据上的表现能反超Transformer。Transformer不是默认上分工具它的优势集中在长序列、多周期、大样本场景。解决每次做实验前先跑一轮DLinear当基线。如果DLinear已经达到业务指标就不要硬上Transformer如果Transformer明显更好再继续往下调参。这个习惯能帮你省掉大量无效训练时间。现象同一套参数把batch_size从16改成64后最终test mse波动很大。原因这个系列代码默认随机种子不固定数据装载顺序、dropout、attention采样都会变小batch下梯度噪声本来就大。解决训练命令里固定seedpython -u run.py --model Autoformer --seed 42 ...固定seed之后多次跑的结果应该基本一致。调batch_size时同步把learning_rate按比例调整经验值是batch翻倍、lr也翻倍但在这套代码里我习惯反向操作——先降batch再降lr训练更稳。6. 进阶用法把15个模型整理成你自己的对比基线跑通三五个模型之后下一步是把整个仓库变成你自己的实验工具而不是每次手动记录指标。我的做法是统一日志命名写好收集脚本让结果自动汇总成表。先给每个实验建独立日志for model in Autoformer FEDformer Informer DLinear PatchTST iTransformer do python -u run.py \ --model $model --data ETTh1 \ --seq_len 96 --label_len 48 --pred_len 96 \ --batch_size 32 --seed 42 --use_gpu 1 \ 21 | tee logs/${model}_96.log done跑完之后用grep把关键指标抽出来再把结果统一解析成jsonimport re, glob, json rows [] for f in glob.glob(logs/*.log): text open(f).read() model f.split(/)[-1].split(_)[0] mse re.search(rtest_mse:([\d.]), text) mae re.search(rtest_mae:([\d.]), text) if mse and mae: rows.append({ model: model, mse: float(mse.group(1)), mae: float(mae.group(1)) }) rows.sort(keylambda x: x[mse]) print(json.dumps(rows, indent2))这样每一个pred_len对应一份结果表96、336、720三个预测长度各跑一轮你就能看清每个模型对预测长度的敏感度——有些模型短预测很准、长预测崩盘有些模型恰恰相反。这个视角对选型比单看一组指标有用得多。如果想加自己的模型套路也很固定在models目录里复制一个现有模型文件改成你的类名把forward逻辑改掉run.py大多是基于--model参数动态加载models目录下的文件不需要改入口代码。改完先用短预测长度跑一轮确认loss能降下来再拉长seq_len和pred_len做正式对比。我自己第一次拿这个包做实验时就栽在PEDformer命名上排查了两天才意识到是FEDformer。从那以后每次拿到新的汇总包都强制自己先ls一遍models目录、先跑一轮DLinear基线、再固定seed和batch这一套流程走下来翻车率降了一大半。希望帮到你。本文还有配套的精品资源点击获取