ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

PyTorch多变量时间序列预测:DeepAR、Informer、Transformer与RNN实战对比

PyTorch多变量时间序列预测:DeepAR、Informer、Transformer与RNN实战对比 简介这份资源面向时间序列预测方向的研究者、算法工程师与高年级学生聚焦用PyTorch复现并改进DeepAR、Informer、Transformer、RNN等经典模型解决多变量时序分析与预测问题覆盖金融、气象、工业等场景。压缩包共61个文件约55.25MB以49个Python实现文件为主配套4个gz数据集、4张png结果图以及txt说明、docx附赠文档、json与md说明代码按data、models、exp、test等模块组织便于按实验脚本逐项复现。已有95人学习下载。读者可拿到各模型的完整实现与训练脚本、概率预测与点预测的对比实验、多变量数据加载与特征工程工具以及指标计算、概率预测可视化等辅助模块适合在此基础上做二次开发与模型改进。1. 从一份「模型全家桶」说起多变量时间序列预测到底难在哪电力负荷曲线、交通流量、工业设备振动、零售销量这些数据有一个共同点它们不是孤立的一列数而是多个变量互相纠缠着随时间演化。你拿到的往往是一张[时间步, 变量数]的表想预测未来一段时间的走势。单变量预测那套「一列历史推一列未来」的做法在多变量场景下会立刻暴露问题——变量之间的相关性被丢掉了而恰恰是这些相关性里藏着预测的线索。这份标题里提到的方案本质是把 DeepAR、Informer、Transformer、RNN 这几类经典模型放进同一个 PyTorch 工程里用统一的数据接口和训练流程做多变量时间序列分析与预测。它解决的不是「哪个模型最强」这种问题而是「我手上这批多变量数据到底该用哪类模型、怎么快速横向对比」。适合已经会写 PyTorch 训练循环、但面对时间序列时不知道从哪下手的工程师也适合想把 LSTM 时间序列预测 Python 那套老流程升级到注意力机制的人。下面按「先立住原理、再动手复现、最后讲坑」的顺序拆开讲。2. 四类模型的分工DeepAR、Informer、Transformer、RNN 各自解决什么2.1 先搞清楚它们不是同一层的替代品很多人一上来就问「Informer 和 Transformer 哪个准」这个问题本身就问偏了。这几类模型的差异不在精度高低而在它们对时间序列的建模假设不同。RNN含 LSTM、GRU是自回归的逐点递推结构隐状态沿时间轴传递天然适合捕捉短期依赖和序列顺序。它的短板是长序列上梯度传播路径太长且无法并行训练慢。LSTM 时间序列预测 Python 生态里最成熟的方案就是它代码简单、调参直观作为基线非常合适。Transformer 用自注意力一次性看到整个序列任意两个时间步之间的依赖路径长度都是 1长程依赖建模能力强且可并行。但标准自注意力的计算复杂度是序列长度的平方长序列上显存和耗时都会爆炸。Informer 是针对长序列预测做的改进版核心是 ProbSparse 稀疏注意力把注意力复杂度从 O(L²) 降到 O(L log L)同时用蒸馏机制逐层压缩序列长度。它适合输入序列很长比如上千步的预测任务。DeepAR 是另一条路线它不直接输出点预测而是输出概率分布的参数比如高斯分布的均值和方差用自回归方式逐点采样天然给出预测区间。多变量场景下它把所有变量的历史一起喂进去共享一个网络适合需要不确定性量化的业务。模型建模方式长序列能力是否输出概率并行训练RNN/LSTM逐点递推弱否否Transformer全局自注意力中否是Informer稀疏注意力蒸馏强否是DeepAR自回归分布输出中是否2.2 统一数据接口是复现的前提四类模型要放在一个工程里对比第一件事不是写模型而是把数据格式统一。多变量时间序列的常见组织方式是滑动窗口给定历史长度context_length和预测长度pred_length从原始序列上切出[context_length, num_vars]的输入和[pred_length, num_vars]的目标。import torch from torch.utils.data import Dataset class MultiVarWindowDataset(Dataset): def __init__(self, data, context_length168, pred_length24): # data: [total_steps, num_vars] 的 float32 张量 self.data torch.as_tensor(data, dtypetorch.float32) self.context_length context_length self.pred_length pred_length self.num_samples len(self.data) - context_length - pred_length 1 def __len__(self): return self.num_samples def __getitem__(self, idx): x self.data[idx : idx self.context_length] # 历史窗口 y self.data[idx self.context_length : idx self.context_length self.pred_length] # 预测目标 return x, y这段代码的关键在num_samples的计算总长度减去窗口长度再减预测长度加一少加这个一就会在最后一个样本上越界。context_length和pred_length是最需要根据业务调整的两个参数——电力负荷常用 168一周小时数预测 24交通流量常用 96 预测 12。窗口切好后RNN 类模型直接按时间维喂入Transformer 和 Informer 需要额外做位置编码DeepAR 则要在目标上做分布假设。提示多变量数据务必先做标准化且标准化参数只能用训练集统计验证和测试集复用训练集的均值和方差否则会引入未来信息。3. 用 PyTorch 把四类模型跑通从环境到训练循环3.1 环境搭建与依赖确认PyTorch 环境搭建是绕不过去的第一步。CUDA 和 PyTorch 版本必须对齐装错了要么用不上 GPU要么直接报错。常见做法是用 conda 建独立环境再按官方命令装对应 CUDA 版本的包。conda create -n ts_pred python3.10 -y conda activate ts_pred # 按本机 CUDA 版本选择下面以 CUDA 11.8 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install numpy pandas scikit-learn matplotlib装完先验证 GPU 是否可用这一步别省import torch print(torch.__version__) print(torch.cuda.is_available()) # 必须为 True 才走 GPU print(torch.cuda.get_device_name(0)) # 确认识别到正确显卡如果cuda.is_available()返回 False八成是 CUDA 版本和 PyTorch 包不匹配或者驱动太旧。Ubuntu 安装 PyTorch 和 WSL 环境下排查思路一样先看nvidia-smi输出的 CUDA 版本再对照 PyTorch 官网的版本矩阵重装。Anaconda 配置 PyTorch 环境时别在 base 环境里装污染了很难清理。3.2 RNN 基线最短路径先跑出一个能看的数任何对比都要有基线。LSTM 结构简单、收敛稳定先用它把整条链路跑通确认数据管道、损失函数、评估指标都没问题再去上复杂模型。import torch.nn as nn class LSTMForecaster(nn.Module): def __init__(self, num_vars, hidden_size64, num_layers2, pred_length24): super().__init__() self.lstm nn.LSTM( input_sizenum_vars, hidden_sizehidden_size, num_layersnum_layers, batch_firstTrue, ) self.head nn.Linear(hidden_size, num_vars * pred_length) self.pred_length pred_length self.num_vars num_vars def forward(self, x): # x: [batch, context_length, num_vars] out, _ self.lstm(x) last out[:, -1, :] # 取最后时间步的隐状态 y self.head(last) # [batch, num_vars * pred_length] return y.view(-1, self.pred_length, self.num_vars)hidden_size从 64 起步num_layers两层通常够用再深容易过拟合小数据集。head一次性输出整个预测窗口比逐点递推快很多代价是丢掉了预测步之间的自回归依赖。如果业务对多步一致性要求高可以改成逐点输出再滚动但训练会慢一个量级。3.3 Transformer 与 Informer位置编码和注意力掩码是重点Transformer 用在时间序列上位置编码不能照搬 NLP 那套固定正弦编码就完事因为时间序列的周期性和绝对位置都重要。常见做法是把位置编码和可学习的时间特征小时、星期、月份拼接。class PositionalEncoding(nn.Module): def __init__(self, d_model, max_len5000): super().__init__() pe torch.zeros(max_len, d_model) position torch.arange(0, max_len).unsqueeze(1).float() div torch.exp(torch.arange(0, d_model, 2).float() * (-torch.log(torch.tensor(10000.0)) / d_model)) pe[:, 0::2] torch.sin(position * div) pe[:, 1::2] torch.cos(position * div) self.register_buffer(pe, pe.unsqueeze(0)) # [1, max_len, d_model] def forward(self, x): return x self.pe[:, :x.size(1)]register_buffer让pe跟着模型走 GPU 但不参与梯度更新这是标准写法。Informer 的 ProbSparse 注意力实现要复杂得多核心是只对「查询稀疏性」高的那部分 query 做注意力计算其余用均值填充。自己手写容易出错建议先用标准 Transformer 跑通再替换注意力模块做对比。Transformer 预测正弦数据是验证实现正确性的经典手段如果模型连正弦都拟合不了说明位置编码或掩码写错了。训练时注意解码器输入要右移一位且用因果掩码防止看到未来。3.4 DeepAR把点预测换成分布预测DeepAR 的输出不是一条线而是一个分布的参数。以高斯为例网络输出均值和标准差损失用负对数似然。class DeepARHead(nn.Module): def __init__(self, hidden_size, num_vars): super().__init__() self.mu nn.Linear(hidden_size, num_vars) self.sigma nn.Linear(hidden_size, num_vars) def forward(self, h): mu self.mu(h) sigma torch.nn.functional.softplus(self.sigma(h)) 1e-6 # 保证正数 return mu, sigma def gaussian_nll(y, mu, sigma): # y, mu, sigma: [batch, pred_length, num_vars] return (torch.log(sigma) 0.5 * torch.log(2 * torch.tensor(3.14159)) 0.5 * ((y - mu) / sigma) ** 2).mean()softplus加一个小常数是为了防止标准差趋近 0 导致数值爆炸这个1e-6是血泪经验去掉之后训练到中期很容易出 NaN。DeepAR 训练时每个时间步都算一次损失推理时从分布里采样再喂回下一步所以推理速度比一次性输出的模型慢。4. 多变量预测的避坑清单五个真实翻车现场4.1 现象验证损失比训练损失低很多原因数据泄漏。最常见的是标准化用了全量数据的均值方差或者滑动窗口切分时训练集和验证集有重叠。时间序列不能随机划分必须按时间先后切。解决先切分再标准化训练集算出的均值方差存下来给验证测试用。窗口切分时在训练集和验证集之间留出至少一个context_length的间隔。4.2 现象模型预测出来是一条直线原因多变量里某些变量量纲差异太大比如一个变量范围是 0 到 1另一个是 0 到 10000梯度被大量纲变量主导小量纲变量学不动。解决每个变量单独标准化或者用 RobustScaler 抗异常值。检查输入张量的每个通道统计量确认没有某个通道方差异常大。4.3 现象Informer 训练显存爆掉原因序列长度设得太长或者 batch size 没跟着调。稀疏注意力虽然降了复杂度但常数项不小序列上千步时显存占用依然可观。解决先把context_length降到 336 或 512 试跑确认能跑通再往上加。开启混合精度训练torch.cuda.amp能省不少显存。4.4 现象Transformer 训练不收敛损失震荡原因学习率太大或者没用 warmup。Transformer 对学习率敏感直接上 1e-3 很容易发散。解决用 AdamW学习率从 1e-4 起步加线性 warmup 前 10% 步数。梯度裁剪设 1.0防止梯度爆炸。4.5 现象DeepAR 推理结果每次都不一样原因这是设计如此DeepAR 是概率模型每次从分布采样结果都不同。解决需要确定性输出时取多次采样的均值或中位数。评估时用分位数损失或 CRPS不要用 MSE 直接比否则对概率模型不公平。5. 进阶技巧怎么判断一个模型值不值得上生产跑通不等于能用。我一般会做三件事来判断一个时间序列模型是否值得投入生产。第一做滚动预测验证。不要只在一个固定测试集上算一次指标而是模拟真实场景用前 N 步预测后 M 步然后窗口往后滑重复几十次看指标的均值和方差。方差大的模型上线后表现会很不稳定。第二和朴素基线比。季节性朴素法拿去年同期的值当预测在很多业务上强得离谱。如果你的 Transformer 打不过它说明模型没学到真东西先回去查数据和特征。第三看预测区间的覆盖率。如果业务需要不确定性量化DeepAR 这类概率模型要检查 80% 和 95% 预测区间的实际覆盖率是否接近名义值。覆盖率严重偏低说明分布假设不对可能要换负二项或 Student-t。验证项合格标准不达标先查滚动预测指标方差相对均值小于 20%数据平稳性、窗口长度对比朴素基线至少提升 10%特征工程、模型容量预测区间覆盖率与名义值偏差小于 5%分布假设、损失函数最后说个习惯我每次换模型前都会把基线结果和随机种子固定下来存成文件不然调了两周回头发现还不如第一版连后悔药都没得吃。多变量时间序列预测没有银弹DeepAR、Informer、Transformer、RNN 各有各的适用面把数据管道和评估流程做扎实比追新模型重要得多。希望帮到你。本文还有配套的精品资源点击获取
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表