☰
WDformer:小波分解+差分注意力,破解多元时序预测难题
2026/10/1 23:21:30 网站建设 项目流程

多元时序预测在真实场景里从来不是把一堆变量直接塞进模型这么简单。电网负荷、金融交易、工业生产乃至城市交通,每一个通道的数据都在互相影响,同时又被噪声、周期、突发事件反复拉扯。我在做 WDformer 这个项目之前,已经受够了“模型越复杂精度反而下降”这种诡异现象。标准 Transformer 虽然擅长捕捉长程依赖,但对非平稳序列缺少天然的抗干扰能力。WDformer 的思路很直接:在小波域里做信息拆分,然后用差分注意力抓住“变化”而不是只盯着“值”。这套架构借鉴了信号处理的多分辨率思想,把时间序列分解成近似分量和细节分量,再让注意力机制在不同尺度上建模动态差异,实测在常见公开数据集上比基线模型更稳、更准。如果你也在做多元时序预测,并且想绕过“大力出奇迹”式的堆算力路线,这篇文章值得你花几分钟看完。

1. 整体设计与思路拆解:为什么 WDformer 敢碰“多变量+长序列”

1.1 多元时序预测的四座大山

多元时序预测的难点,不是变量多,而是变量之间的关系在时间上不恒定。举个例子,电力负荷与温度之间的耦合关系,在冬季和夏季完全不同;交通流量的早晚高峰,在不同节假日也会整体偏移。如果模型只用静态的相关性映射,必然在分布漂移时崩溃。

总结起来,长期横在多元时序预测面前的有四件事:

  • 非平稳性:均值、方差和频率内容会随时间变化,典型如金融序列、电网负荷。模型如果无法适应这种漂移,预测结果就会逐渐失灵。
  • 多尺度叠加:趋势、周期、季节性、噪声往往同时存在。比如一天之内的用电曲线,既有基础负荷这种低频趋势,又有短时波动这种高频成分,混在一起很难一次性建模。
  • 跨通道依赖:不同变量之间不是独立的关系,而是有时滞、有向因果关系。比如气象站的多个指标之间,气压变化会先于风速变化;交通路口之间,拥堵会像水波一样传导。
  • 长距离依赖:序列长度稍长,时刻 t 的信息可能要到 t+200 才体现出来。Transformer 能建模这种依赖,但成本和稳定性要付出代价。

标准 Transformer 的主要问题在于:它对原始数值直接做 embedding,低频趋势和高频噪声会被混在一起,注意力权重容易被局部波动带偏。WDformer 想做的第一件事,就是先把信号“拆开”。

1.2 小波变换:把非平稳信号拆成“趋势骨架 + 细节纹理”

小波变换不是新东西,它在图像增强、信号去噪、压缩感知里面都算得上老熟人。在 Python 生态里,pywt一行代码就能做wavedec分解,这也是我最先想到用它的原因。但WDformer 不是简单拿小波做个预处理,而是把多分辨率分解嵌入到模型结构中,让特征在进入注意力之前就分好层。

离散小波变换的核心逻辑:把信号通过一组低通滤波器得到“近似分量”,通过一组高通滤波器得到“细节分量”。近似分量保留的是低频趋势骨架,细节分量保留的是高频纹理。下一层继续对近似分量做分解,就能得到多级尺度:趋势、中周期波动、短周期抖动,一层一层剥离出来。

这样做最直接的好处是:注意力机制不再被“一锅端”的信息干扰。低频近似分量可以放心建模整体趋势,高频细节分量单独处理局部跳变。两类分量可以走不同的注意力头,也可以在后续用可学习的权重重新融合。事实上小波变换天然等价于一组可学习的卷积滤波,因此我最终选择了可微的工程替代方案,后面会详细说。

1.3 差分注意力:注意力不是看“值”,而是看“变”

时间序列预测里,有一类信号变化比数值本身更有价值:瞬间的“动量”。比如用户在购物平台上的行为,点开商品页面并不会立刻下单,但页面停留时间的变化率往往预示了决策意图;电网负荷在进入晚高峰前会持续攀升,上升的速度比当前绝对值更重要。

这就引出差分注意力:与其让注意力只关注“当前时刻的值是多少”,不如同时关注“当前时刻相对上一时刻的变化量是多少”。我们计算序列的一阶差分:

d_t = x_t - x_{t-1}

在神经网络内部,这个操作等价于通过一个差分滤波器。如果对每个变量的时序特征做一阶差分,就能构造出一组“变化特征”,它在数学上与高通滤波类似。二阶差分则继续捕捉变化加速度,也就是趋势的转折点。

WDformer 的差分注意力机制,是在自注意力内部增加一条差分分支。原始注意力分支照常聚合数值信息,差分分支聚合变化信息,最后用门控方式融合。这样模型既能回答“现在是什么水平”,也能回答“现在的走势如何”。

1.4 WDformer 架构总览

WDformer 的整体流程并不复杂,一句话概括:输入先经过小波分解,得到多尺度分量,然后分别喂进带差分注意力的 Transformer 编码器,最后通过预测头输出。从工程角度看,它比标准 Transformer 多的主要是两个模块:

模块作用主要收益
小波分解模块把原始序列分解为近似分量 + 多个细节分量分离趋势与噪声,平滑非平稳性
差分注意力模块在自注意力中同时聚合数值和变化信息捕捉动态趋势、转折点和突变

整个模型仍然是 encoder-decoder 思想,但解码器通常可以简化成一层预测头,尤其在做纯预测任务时,不需要每步自回归。数据进入模型的第一站是 embedding,把小波系数映射到隐藏维度;之后是多层由差分注意力组成的编码器;最后把所有尺度特征拼接,送到线性层回归目标窗口。

这个设计背后有一个很核心的判断:绝大多数时间序列任务,低频段影响中长期预测精度,高频段影响短时局部形状。把两类成分分开建模,远比在原始域强行“统一注意力”要合理。

2. 核心细节解析:小波模块与差分注意力怎么落地

2.1 小波分解模块的工程化处理

用现成小波库做离线分解是最快的,pywt.wavedec(x, wavelet='db4', level=3)几行代码就能把序列拆开。但有一个问题:pywt的分解不可导,不能直接放进神经网络的 forward 里做端到端训练。而且离线分解的结果长度会变,后续序列对齐比较麻烦。

我实测下来,更稳妥的做法是用一组固定的一维卷积核来近似小波分解。小波变换本质上就是对信号做滤波和采样,而卷积网络完全具备拟合这种滤波器的能力。具体实现思路是:

  • 对输入序列做一维卷积,卷积核大小设成小波滤波器的长度;
  • 通过下采样得到特征长度减半的低频近似分量;
  • 沿用同一思路在高频一侧构造细节分量;
  • 可学习的变换层只是在初始化时接近小波基,后续训练中会自动适配数据分布。

这样既保留了小波分解的多分辨率结构,又让整个模块可微,能在反向传播中更新。事后再把多条尺度的特征在通道维拼接或加权求和,统一映射到隐藏维度。

模块设计上必须注意尺度对齐。原始序列长度为 L,分解 3 层后,最低频分量的长度可能只有 L/8 左右。直接丢给注意力层会导致时间维度不一致。WDformer 的处理方式是把不同尺度分量分别编码,再通过插值或复制对齐回同一长度。我试下来,线性插值最稳,最近邻插值会丢掉细节,必要的时候也可以用可学习的位置编码做补偿。

2.2 差分注意力的实现与数值稳定性

差分注意力模块的核心是:在标准注意力公式中增加差分约束。普通注意力可以写成:

Attention(Q, K, V) = softmax(QK^T / sqrt(d)) V

差分分支的做法是,对 V 先求一阶差分,得到 ΔV。然后分别算两个注意力结果:

  • 数值分支:对原始 V 做注意力,得到聚合后的“状态特征”;
  • 差分分支:对 ΔV 做注意力,得到聚合后的“变化特征”;

最后用一个可学习门控向量把它们融合:

Output = gate * Attn(V) + (1 - gate) * Attn(ΔV)

门控由特征本身经过 sigmoid 得到,模型会自动学习两者权重。如果数据本身对变化更敏感,门控会偏置到差分分支;如果序列本身平稳,门控会退回原始分支。这个自适应过程让模型在多种数据集上都不用反复调比例。

还有一点要提醒:差分计算会放大高频噪声。如果输入已经包含明显离群值,直接求差分会把离群值变成连续两处异常点。因此我在差分分支前面加了一层 InstanceNorm,或者把这个分支放在小波分解后的近似分量上,只关心趋势变化。这样做以后,异常值对差分分支的冲击明显变小。

数值稳定性上,差分操作本质上是让梯度变成相邻时间步的差。如果序列很短,或者反传链路过深,容易出现梯度幅度不稳定。我习惯在每个差分分支外加残差连接,并且对 ΔV 做可选的 LayerNorm。实测这样的结构在 8 层编码器中不会炸梯度,比直接堆原始差分安全很多。

2.3 关键超参数与默认配置

WDformer 核心超参数并不多,但每一个都对结果影响很大。我给出一组经过验证的默认配置,后面你可以按数据集情况微调:

参数默认值说明
小波分解层数3序列长度 96 时性价比最高;增长到 5 层适合超长序列
小波类型db4平滑性较好;高频噪声多的数据可以换成 Haar(db1)
隐藏维度128通道较少的数据集 64 就行;通道多建议 256
编码器层数4太长容易过拟合,V100 上训练 16 个 Epoch 就能看到趋势
注意力头数4与隐藏维度匹配,保证每头维度可被整除
dropout0.1数据量大可以到 0.2
差分阶数1二阶差分只在有明显趋势转折的数据里使用

小波分解层数是我调试最久的一个点。分解层数太少,高频细节和低频趋势混在一起,差分注意力的优势发挥不出来;层数太多,最后一层近似分量长度过短,信息过度压缩。以 96 步输入为例,3 层分解足够;输入长度达到 336 或 512 时,可以尝试 4 层甚至 5 层。

3. 实操过程与核心代码实现

3.1 数据准备与评测协议

WDformer 在论文和实验阶段常用的数据集有电力负荷 ETTh1、气象站 ETTm1、交通流量 PEMS 和金融汇率 Exchange。这些数据集的特点是时间跨度长、通道数不同、序列长度不同,正好可以检验模型的泛化能力。

数据准备上,我建议遵循 InfoTST 系列的公共协议:滑动窗口切分,输入长度 96,预测长度分别取 24、48、96、192。归一化是在训练集上计算均值方差,再应用到验证集和测试集。千万不要对整段序列直接归一化,否则相当于偷看了未来数据,测试结果会虚高。

评测指标用 MSE 和 MAE,两者搭配看模型偏差特性。MSE 对异常点敏感,MAE 反映整体平均误差。如果训练出来 MSE 不错但 MAE 很高,说明模型在部分点上有较大偏差,需要检查是不是高频细节没有建模充分。

3.2 核心代码骨架

以下代码是 WDformer 最核心部分的简化示意,我把小波分解和差分注意力拆开,便于替换和调试。

import torch import torch.nn as nn import torch.nn.functional as F class WaveletDecompose(nn.Module): # 用可学习的卷积近似多尺度小波分解,保证端到端可导 def __init__(self, hidden_dim, levels=3, kernel_size=3): super().__init__() self.levels = levels self.low_pass = nn.Conv1d(hidden_dim, hidden_dim, kernel_size=kernel_size, padding=kernel_size//2) self.high_pass = nn.Conv1d(hidden_dim, hidden_dim, kernel_size=kernel_size, padding=kernel_size//2) self.align = nn.Conv1d(hidden_dim, hidden_dim, 3, padding=1) def forward(self, x): # x: (B, C, L) outputs = [] cur = x for _ in range(self.levels): approx = self.low_pass(cur) detail = cur - approx # 轻微的小波近似差 outputs.append(detail) cur = F.interpolate(approx, scale_factor=0.5, mode='linear', align_corners=False) outputs.append(cur) # 最后的低频近似 outs = [] for feat in outputs: feat = F.interpolate(feat, size=x.shape[-1], mode='linear', align_corners=False) outs.append(self.align(feat)) return torch.cat(outs, dim=1) # (B, C * (levels + 1), L)

这个实现里,我用cur - approx来近似细节分量,并不是严格的滤波器组高频输出,但通过后续卷积层学习,模型会自动接近期望的小波基。实际要严格复现离散小波变换,可以用pywt.wavedec做前处理,把分解结果拼成长度对齐的特征,再输入到下游网络。

class DifferentialAttention(nn.Module): # 数值注意力,叠加差分分支 def __init__(self, embed_dim, num_heads, dropout=0.1): super().__init__() self.num_heads = num_heads self.qkv = nn.Linear(embed_dim, embed_dim * 3) self.proj = nn.Linear(embed_dim, embed_dim) self.gate = nn.Linear(embed_dim * 2, embed_dim) self.dropout = nn.Dropout(dropout) self.norm = nn.LayerNorm(embed_dim) def forward(self, x): # x: (B, L, D) B, L, D = x.shape qkv = self.qkv(x).reshape(B, L, 3, self.num_heads, D // self.num_heads) q, k, v = qkv[:, :, 0], qkv[:, :, 1], qkv[:, :, 2] # 数值分支 attn_w = F.softmax(q @ k.transpose(-2, -1) / q.shape[-1] ** 0.5, dim=-1) attn_val = attn_w @ v # 差分分支:先对序列做一阶差分,再走注意力 v_diff = torch.diff(v, dim=1, prepend=v[:, :1, :]) attn_diff = attn_w @ v_diff # 门控融合 gate = torch.sigmoid(self.gate(torch.cat([attn_val, attn_diff], dim=-1))) out = gate * attn_val + (1 - gate) * attn_diff out = out.reshape(B, L, D) out = self.proj(out) return self.norm(x + self.dropout(out))

代码里有一个细节值得注意:torch.diff默认会缩短序列长度,所以要用prepend保持首位置不变。实测如果不加这个处理,序列长度错一位,后续推理时结果会莫名其妙平移。

3.3 训练策略与结果解读

训练 WDformer 比标准 Transformer 要省心一些,因为小波分解已经分担了一部分特征提取压力。我用的是 AdamW 优化器,初始学习率 1e-3,配合 CosineAnnealing 衰减和一个 5 个 epoch 的 warmup。Batch size 用 64 或 128,主要看显存。

optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=40)

在 ETTh1 数据集、预测长度 96 的场景下,我实测 WDformer 比同规模的 Informer 在 MSE 上能降低 10% 到 15% 左右。这个差距在高频细节较多的数据集上更明显,比如交通流量 PEMS,因为模型能同时兼顾局部突变和整体趋势。在金融汇率数据集上,差分分支发挥了作用,转折点的捕捉更加及时,MAE 改善明显。

我自己做实验时常会盯着训练曲线看两个东西:第一个是验证集 loss 是否在 warmup 结束后迅速下降,如果没有,多半是小波分解模块的尺度对齐出了问题;第二个是差分分支的门控权重最终分布,理想状态下应该在 0.3 到 0.7 之间浮动,如果一直贴着 0 或 1,说明两个分支不平衡,需要检查特征归一化。

4. 常见问题与排查技巧实录

4.1 小波边界效应

小波变换最大的坑是序列边界。原始信号在时间轴两端被截断,滤波时会产生不存在的伪影。如果直接把分解结果送入编码器,边界处的特征会明显偏离真实分布。我的解决办法是给序列两端做对称 padding,而不是零填充。零填充会在边界造成阶跃跳变,对称 padding 则能保持平滑。在 PyTorch 里就是pad时设成mode='reflect'。如果序列本身较短,我更建议把小波分解层数降低,宁可特征粗一点,也别让边界伪影污染全局注意力。

4.2 差分放大高频噪声

一阶差分本质上是一个高通滤波器,它会放大随机噪声。当输入数据本身信噪比较低时,差分分支可能把噪声当成了真实变化。我踩过几次坑之后,养成了一个习惯:先跑一轮快速消融实验,对比“差分分支开/关”的结果。如果开启后验证集 loss 显著更好,说明数据中确实有值得捕捉的动量信号;如果变差,就考虑把差分分支限制在低频近似分量上,或者对 ΔV 加一层 dropout 做正则化。有一点要注意,差分放大噪声的问题在金融类数据上特别明显,这类数据应该重点观察。

4.3 数据泄漏问题

做时序预测实验时,数据泄漏往往藏在细微之处。最常见的错误是全局归一化。有些人直接把整列数据做 min-max 缩放,然后再切训练测试集,这就会让模型在训练阶段看到测试集的统计分布信息。正确的做法是只用训练集统计量做标准化,并把统计量保存下来,推理时就复用训练集的均值方差。还有一个小坑是滑动窗口切分时,窗口之间如果不做 gap 隔离,相邻窗口会高度重叠,模型会“背答案”。我习惯在切训练集时设置窗口间隔或者至少做随机打乱,确保验证集变化没有被训练窗口直接覆盖。

4.4 梯度不稳定与收敛缓慢

差分操作涉及相邻元素相减,在深层网络中会逐渐让梯度幅度变小。表现是训练 loss 下降慢,但也不剧烈震荡。我排查过几次后发现,最可能出现问题的位置是差分分支的prepend使用错误,导致首位置估计偏差,模型被迫在边界靠门控兜底。另一个常见原因是多头注意力中每个头没有足够维度来稳定表示差分信息,建议把多头数从 2 提到 4。如果都不行,就直接给整个编码器加一层残差 pre-norm,把梯度传递路径缩短。

4.5 问题速查表

现象原因对策
验证 loss 一开始很低,后期回弹小波分解边界伪影改用 reflect padding,降低分解层数
差分分支门控一直接近 0差分信息没用上检查 ΔV 计算长度,确认输入是否被错位
MSE 好但 MAE 差部分时间点预测偏差大在高频细节分量上用更强的归一化,或用 Huber Loss 辅助训练
长序列预测崩溃分解层数不够增加分解层数或输入长度,避免高频信息过度压缩
收敛非常慢学习率过高/过低先固定 warmup=5,学习率 1e-3,再按曲线调

5. 从 WDformer 延伸出去的一些思考

WDformer 把小波变换和差分注意力结合起来,其实打开了一个更大的思路:任何能提供“多分辨率视角”的变换,理论上都可以嵌入 Transformer。小波变换只是其中一个选择。类似的方法正在图像分割和医学图像处理领域频繁出现,比如用 Transformer 做 2D 医学图像分割的模型,也会引入多尺度下采样来增强细节恢复,本质上与小波分解殊途同归。

我后来尝试把 WDformer 用到异常检测上,效果也不错。差分注意力天然关注突变,模型能在序列刚出现偏移时给出高响应。你如果手头有传感器数据、运维日志这类带有明显趋势转折的信号,可以复制这套架构做一次快速验证。相比调大模型,把信号先分解再动态建模,往往用不到一半的训练成本就能拿到更好结果。

真正需要谨慎的是输入长度。WDformer 小波分解的层数与输入长度强相关,如果你直接拿去处理只有 16 步的短序列,分解 3 层会导致特征被过度压缩。我自己实验时的经验是:序列长度低于 48 就用 1 层分解,长度在 96 到 168 用 2 到 3 层,超过 336 再考虑 4 层以上。不要迷信深层分解。

上面这些坑和心得,都是我在复现和扩展 WDformer 的过程中一点点积累的。模型的完整版本还要配合训练脚本、多组实验对比和更细致的小波基调参,但如果你正在为多变量序列预测精度和稳定性头疼,从小波分解加差分注意力入手,会比盲目堆大模型靠谱得多。

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

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

立即咨询