ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Informer源码逐行注释解析:从环境搭建到ProbSparse调参实战

Informer源码逐行注释解析:从环境搭建到ProbSparse调参实战 简介这是一份面向深度学习与时间序列预测方向的Informer代码详细注释版资源适合正在研读Informer论文、需要逐行理解模型实现细节的研究生、算法工程师及竞赛选手。资源对官方代码进行了逐行中文注释覆盖数据加载、模型结构、训练与推理全流程能有效降低源码阅读门槛帮助读者快速掌握长序列时间序列预测的核心机制。压缩包共63个文件约62.33MB以py源码与pyc缓存为主辅以xml配置、png示意图、sh运行脚本、csv数据集及pth权重文件另含yml环境配置、Dockerfile与ipynb实验笔记目录结构完整便于按模块检索。目前已有663人学习下载。读者可借助注释理解注意力机制、编码解码结构与实验脚本的对应关系结合示例数据与预训练权重复现实验并参考论文引用信息规范使用是入门与进阶Informer的实用参考资料。1. 从一份逐行注释的 Informer 源码说起为什么值得拆如果你最近在跑长序列时序预测大概率绕不开 Informer 这个模型。论文里那套 ProbSparse 注意力、自注意力蒸馏、生成式解码器看公式能懂个七七八八但真到复现的时候很多人卡在同一个地方官方代码能跑通却不知道每一行在干什么改一个参数就翻车。这份 Informer2020-main 的逐行注释版解决的正是这个断层——它不是又一份跑分脚本而是把exp_informer.py、model.py、attn.py、embed.py这些核心文件逐行拆开讲清楚连data_loader.py里时间特征怎么拼、masking.py里三角掩码怎么生成都标了注释。适合两类人一类是刚接触时序 Transformer、想照着代码理解论文细节的新手另一类是要在 ETT、WTH 这类数据集上做二次开发、需要改模型结构或换数据管道的熟手。下面我按「这份资源是什么 → 怎么跑起来 → 参数怎么调 → 坑在哪」的顺序把整个包拆一遍。2. 目录结构与核心模块先搞清楚每个文件在干什么拿到一个源码包最忌讳上来就python main_informer.py一把梭。先把目录结构过一遍知道哪个文件负责哪块后面调参和排错才有方向。这份包的结构基本沿用了 Informer 官方仓库的组织方式但注释密度高很多尤其是exp和models两个目录。2.1 顶层文件与数据目录根目录下几个关键文件先认一下文件/目录作用main_informer.py命令行入口解析参数并调用exp_informer.pyrequirements.txtPython 依赖清单含 torch、numpy、pandas 等environment.ymlconda 环境导出文件适合直接复现环境Dockerfile容器化构建脚本适合部署到服务器Makefile封装了训练/测试的快捷命令data/数据集目录内含 ETT 子目录和data_loader.pyexp/实验逻辑exp_informer.py是训练/验证/测试的主循环models/模型定义model.py、attn.py、embed.py、encoder.py、decoder.pyutils/工具函数metrics.py、masking.py、timefeatures.py、tools.pyscripts/各数据集的启动脚本如ETTh1.sh、ETTm1.sh、WTH.shcheckpoints/训练权重保存目录里面已有一个 ETTh1 的预训练权重文件夹img/论文配图和结果图data.png、informer.png、result_multivariate.png等data/ETT/下放的是 ETT 系列 CSVdata/data_loader.py负责读 CSV、切训练/验证/测试、做标准化、生成时间特征。utils/timefeatures.py是时间特征的核心把小时、星期、月份这些周期信息编码成额外通道拼到输入里。utils/masking.py生成两类掩码ProbMask 用于 ProbSparse 注意力TriangularCausalMask 用于解码器的因果卷积。models/attn.py里是 FullAttention、ProbAttention、AttentionLayer 三个类是整个模型最值得逐行读的地方。2.2 模型文件的分工models/model.py定义Informer类把嵌入层、编码器、解码器串起来forward里能看到enc_out和dec_out的完整流向。models/embed.py包含DataEmbedding、TokenEmbedding、PositionalEmbedding、TemporalEmbedding、FixedEmbedding几个类负责把原始序列变成模型能吃的张量。models/encoder.py里是EncoderLayer和ConvLayer自注意力蒸馏就发生在ConvLayer的maxpool上。models/decoder.py的DecoderLayer里能看到生成式解码怎么用cross_attention把编码器输出和解码器输入对齐。提示读这份代码建议按main_informer.py→exp_informer.py→model.py→attn.py的顺序先跑通再回头抠细节不然容易被ProbMask绕晕。3. 环境搭建与跑通第一个实验从 conda 到 ETTh1环境这一步翻车的人最多尤其是 torch 版本和 CUDA 对不上。这份包给了environment.yml和requirements.txt两份依赖我一般优先用 conda 走environment.yml因为 torch 的 CUDA 版本在 conda 里更好控。3.1 用 conda 复现环境# 从 environment.yml 创建环境名字按文件里写的来 conda env create -f environment.yml # 激活环境 conda activate informer # 验证 torch 和 CUDA 是否可用 python -c import torch; print(torch.__version__, torch.cuda.is_available())environment.yml里锁定了 python、torch、numpy、pandas、scikit-learn 等版本避免手动装出一堆冲突。如果 conda 装得太慢可以退而用 pip# 用 requirements.txt 装依赖建议先建一个干净的 venv python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install -r requirements.txtrequirements.txt里没有锁死 CUDA 版本所以 pip 装出来的 torch 可能是 CPU 版跑大模型会慢到怀疑人生。装完一定用上面那行torch.cuda.is_available()确认一下返回False就说明装成 CPU 版了得去 torch 官网按 CUDA 版本重装。3.2 跑通 ETTh1 单变量预测环境好了之后先别急着改参数用scripts/ETTh1.sh里的默认配置跑一遍确认整条链路是通的。# 直接执行脚本里面封装了 main_informer.py 的完整参数 bash scripts/ETTh1.sh打开scripts/ETTh1.sh能看到类似这样的命令python -u main_informer.py \ --model informer \ --data ETTh1 \ --root_path ./data/ETT/ \ --data_path ETTh1.csv \ --features S \ --seq_len 96 \ --label_len 48 \ --pred_len 24 \ --e_layers 2 \ --d_layers 1 \ --attn prob \ --des Exp \ --itr 1几个参数先解释清楚--features S表示单变量预测只预测 OT 这一列--seq_len 96是编码器输入长度--label_len 48是解码器起始 token 长度--pred_len 24是要预测的未来步数--attn prob指定用 ProbSparse 注意力改成full就是标准全注意力方便对比。--e_layers 2和--d_layers 1分别是编码器和解码器层数。跑完在checkpoints/下会生成一个带完整参数名的文件夹里面存checkpoint.pth。3.3 多变量和不同数据集怎么切想跑多变量把--features改成M--data_path换成ETTm1.csv或WTH.csv--data对应改成ETTm1或WTH。scripts/下已经给了ETTm1.sh、ETTh2.sh、WTH.sh直接改脚本里的--pred_len就能做 96、192、336、720 不同预测长度的实验。注意 WTH 数据集的列数和 ETT 不一样--enc_in和--dec_in要跟着改不然会在DataEmbedding里报维度不匹配。注意第一次跑建议把--itr设成 1--train_epochs调小到 2 或 3先确认 loss 在降、显存没爆再放开跑完整实验。4. 核心参数怎么调ProbSparse、蒸馏与解码器跑通之后真正决定效果的是几个关键参数。这一章把attn.py、encoder.py、decoder.py里和参数强相关的逻辑拆开讲知道每个参数动的是哪块代码调起来才不是玄学。4.1 ProbSparse 注意力的采样因子models/attn.py里ProbAttention的__init__有个factor参数默认是 5。它的作用是控制 query 采样数量u factor * ln(L_Q)L_Q 是 query 长度。factor 越大采样的 query 越多注意力越接近全注意力精度可能略升但速度下降factor 越小采样越少速度越快但可能丢信息。# attn.py 中 ProbAttention 的关键逻辑注释版里标得很细 class ProbAttention(nn.Module): def __init__(self, mask_flagTrue, factor5, scaleNone, attention_dropout0.1, output_attentionFalse): super(ProbAttention, self).__init__() self.factor factor # 控制采样 query 数量越大越接近全注意力 self.scale scale self.mask_flag mask_flag self.output_attention output_attention self.dropout nn.Dropout(attention_dropout) def _prob_QK(self, Q, K, sample_k, n_top): # sample_k factor * ln(L_K)n_top factor * ln(L_Q) B, H, L_K, E K.shape _, _, L_Q, _ Q.shape # 随机采样 K计算 Q 与采样 K 的相似度挑出 top-u 的 query ...调参经验序列长度 96 到 336 时 factor 保持 5 基本够用如果--pred_len拉到 720 且发现预测曲线明显滞后可以把 factor 提到 8 或 10 试试但训练时间会涨。反过来如果只是做快速验证、不在乎那零点几个点的 MSEfactor 降到 3 能省不少时间。4.2 自注意力蒸馏的 maxpool 与编码器层数models/encoder.py的ConvLayer里有一层MaxPool1d(kernel_size3, stride2, padding1)这就是论文里的自注意力蒸馏。每经过一个ConvLayer序列长度减半显存占用大幅下降。--e_layers决定堆几层EncoderLayer每层后面跟一个ConvLayer。# encoder.py 中 ConvLayer 的蒸馏逻辑 class ConvLayer(nn.Module): def __init__(self, c_in): super(ConvLayer, self).__init__() self.downConv nn.Conv1d(in_channelsc_in, out_channelsc_in, kernel_size3, padding2, padding_modecircular) self.norm nn.BatchNorm1d(c_in) self.activation nn.ELU() self.maxPool nn.MaxPool1d(kernel_size3, stride2, padding1) # 长度减半 def forward(self, x): x self.downConv(x.permute(0, 2, 1)) x self.norm(x) x self.activation(x) x self.maxPool(x) x x.transpose(1, 2) return x--e_layers从 2 加到 3 或 4理论上能提精度但显存和训练时间同步上涨。ETTh1 这种数据量2 层通常够WTH 数据量大、周期复杂可以试 3 层。注意--d_layers一般保持 1解码器堆太深收益很小反而容易过拟合。4.3 生成式解码器的 label_len 与 pred_lenmodels/decoder.py的DecoderLayer里解码器输入由两部分拼成前面label_len个 token 是已知的真实值start token后面pred_len个是占位零。--label_len设得太短解码器拿不到足够上下文设得太长又和编码器输入重叠浪费。常见做法是label_len seq_len // 2比如seq_len96时label_len48。# exp_informer.py 中构造解码器输入的关键片段 # dec_inp 前 label_len 用真实值后 pred_len 用零填充 dec_inp torch.zeros_like(batch_y[:, -self.args.pred_len:, :]).float() dec_inp torch.cat([batch_y[:, :self.args.label_len, :], dec_inp], dim1).float().to(self.device)--pred_len直接决定预测窗口ETT 系列常用 24、48、96、168、336、720。注意pred_len越大解码器那部分零填充越长模型要凭空生成的信息越多MSE 上升是正常的别一看到 720 的指标比 24 差就以为代码有问题。提示调参时把--attn在prob和full之间切一次对比同一组seq_len/pred_len下的 MSE 和训练耗时能直观感受到 ProbSparse 到底省在哪。5. 避坑与排查那些注释里没写但一定会遇到的事注释再详细也挡不住环境和数据层面的坑。这一章列几条我实际踩过的按「现象 → 原因 → 解决」写遇到类似报错可以直接对号入座。5.1 现象RuntimeError: Expected all tensors to be on the same device原因模型在 GPU 上但某一步构造的dec_inp或时间特征还在 CPU 上。exp_informer.py里dec_inp那行如果忘了.to(self.device)或者data_loader.py里timeenc返回的张量没跟着搬就会报这个。解决检查exp_informer.py里所有torch.zeros_like、torch.cat之后的张量是否都.to(self.device)data_loader.py的__getitem__返回的seq_x, seq_y, seq_x_mark, seq_y_mark在exp_informer.py的_process_one_batch里统一搬一次。5.2 现象loss 一直是 nan原因学习率太大或者输入没做标准化。ETT 原始数据里 OT 列的量纲和其他列差很多data_loader.py里StandardScaler如果没生效梯度直接炸。解决确认data_loader.py里self.scaler.fit(train_data)和transform都走了把--learning_rate从默认 1e-4 降到 1e-5 试一轮检查--loss用的是mse还是maemse对异常值更敏感。5.3 现象KeyError: OT或列名对不上原因--data_path指向的 CSV 列名和data_loader.py里硬编码的目标列不一致。ETT 数据集目标列叫OTWTH 数据集目标列名不同。解决打开 CSV 看一眼表头确认data_loader.py里cols list(df.columns)之后取的self.target是不是存在WTH 要把--target参数显式传成对应列名。5.4 现象显存爆了CUDA out of memory原因--batch_size太大或者--seq_len拉太长。ProbSparse 虽然省显存但--e_layers多了之后中间激活还是占地方。解决先把--batch_size减半再不行把--seq_len从 96 降到 48 验证一下确认--attn是prob不是full--e_layers超过 3 时考虑用--distil确认蒸馏层生效。5.5 现象测试指标和论文对不上原因随机种子没固定或者--itr跑了多次取了某一次的结果。Informer 对初始化敏感不同 seed 下 MSE 能差几个点。解决在main_informer.py里固定torch.manual_seed、np.random.seed--itr设成 1 先对齐单次结果确认--features、--seq_len、--pred_len和论文表格里的设置完全一致差一个参数指标就对不上。6. 进阶改模型结构和换数据管道的具体手法跑通默认配置只是起点这份注释版真正的价值在于让你敢改。举两个最常见的二次开发场景一个是换数据管道一个是改注意力模块。换数据管道时核心是改data/data_loader.py里的Dataset_ETT_hour或Dataset_Custom。如果你有自己的 CSV最省事的做法是继承Dataset_Custom重写__read_data__里的列选择逻辑class Dataset_Custom(Dataset): def __init__(self, root_path, flagtrain, sizeNone, featuresS, data_pathETTh1.csv, targetOT, scaleTrue, timeenc0, freqh): # size [seq_len, label_len, pred_len] ... def __read_data__(self): self.scaler StandardScaler() df_raw pd.read_csv(os.path.join(self.root_path, self.data_path)) # 按自己的列名改这里border1s/border2s 控制切分比例 cols list(df_raw.columns) cols.remove(self.target) cols.remove(date) df_raw df_raw[[date] cols [self.target]] ...改完记得同步--enc_in和--dec_in它们等于输入特征维度单变量是 1多变量是列数减一去掉 date 列。--freq也要跟着数据的时间粒度改小时数据用h分钟数据用t。改注意力模块时models/attn.py里AttentionLayer是统一入口FullAttention和ProbAttention都通过它调用。想加自己的注意力实现一个forward(Q, K, V, attn_mask, tauNone, deltaNone)返回(output, attn)的类然后在AttentionLayer里按attention参数分发即可。注释版里ProbAttention的_prob_QK和_get_initial_context标得很细照着改不容易错。验证改动是否有效别只看最后一个 epoch 的 loss。我一般会做三件事固定 seed 跑三次取均值把--attn在prob和full之间切一次做对照把预测曲线和真实曲线画在一张图上肉眼看滞后和过拟合。utils/metrics.py里的metric函数返回 MAE、MSE、RMSE、MAPE、MSPE直接拿来用就行。从那以后我每次拿到一份带注释的源码都强制先跑通默认脚本、再固定 seed 复现一次指标、最后才动结构这三步少一步后面都得返工。希望这份拆解帮到你需要的话把包下下来对着attn.py和exp_informer.py的注释走一遍比看十篇论文解读都实在。本文还有配套的精品资源点击获取
返回列表