TimesNet及其后续改进

TimesNet是一种基于CNN的时序预测模型,提出了周期内与周期间的理念,将时序变化基于多周期转换为二维张量,能够捕捉时间序列中复杂的模式,并对未来进行准确的预测,在短期预测、插值、分类、异常检测等领域效果均非常出色。

TimesNet: Temporal 2D-Variation Modeling for General Time Series Analysis (2023)

当前改进方向:

  1. 多尺度周期检测融合
    • FFT+小波变换结合:同时捕捉全局周期性(FFT)和局部细节(小波变换)
    • 频率掩码机制:可学习的频率选择,增强重要频率成分
    • 周期一致性验证:通过多方法交叉验证提升周期检测鲁棒性
  2. 高效卷积架构
    • 深度可分离卷积:大幅减少计算量同时保持表现力
    • 多尺度卷积核:并行处理不同时间尺度模式
    • 自适应权重:动态调整多尺度特征贡献
  3. 智能周期融合
    • 置信度加权:基于幅度和小波一致性的周期权重
    • 多周期协同:不再依赖单一周期,而是多周期模式融合
Hyplus目录

1 模型背景

传统方法在处理时间序列的复杂变化时面临挑战,因为它们通常试图直接从一维时间序列中捕捉这些变化,而忽略了时间序列的多周期性(Multi-periodicity):

  • 现实世界的时序数据往往是多种过程叠加。如交通数据的日变化和周变化,天气数据的日变化和年变化等。这种内在的多周期属性使得时序变化极其复杂。
  • 对于某一特定周期过程,其内部每个时间点的时序变化不仅仅与临近时刻有关,也与邻近周期高度相关,即呈现周期内(Intraperiod)与周期间(Interperiod)两种时序变化。其中周期内变化对应着一个周期内的短期过程,周期间变化则可以反应连续周期间的长期趋势。

注:若数据没有明显的周期性,则时序变化被周期内变化主导,等价于周期长度无穷大的情况。

基于上述观察,多周期属性自然地启发了一个模块化(Modular)的设计思路,即一个模块捕捉由某一特定周期主导的时序变化。这种模块化的设计思路可以将复杂的时间变化分解开,从而有利于后续建模。但是,受限于时间序列的固有的一维结构,原始序列难以同时表现出周期内与周期间两种不同的时序变化。

TimesNet通过将一维时序数据扩展至二维空间来捕捉时间序列的多周期性,每个二维张量的列和行分别反应了周期内与周期间的时序变化,即得到了二维时序变化(Temporal 2D-variations),实现周期内与周期间变化的统一建模。

下图表示时序数据的多周期与二维时序变化:


2 模型结构

相关阅读:从傅里叶变换到快速傅里叶变换小波变换在时序预测中的应用

TimesNet模型通过模块化结构将复杂时序变化分解至不同周期,并通过将原始一维时间序列转化至二维空间实现了周期内与周期间变化的统一建模。

2.1 时序变化方法

从一维至二维的时序变化(Temporal Variations)如下图所示:

为了统一表示周期内与周期间的时序变化,首先需要发掘时间序列的周期性。

对于一个时间长度为T、通道维度为C的一维时间序列\mathbf{X}_{\text{1D}} \in \mathbb{R}^{T\times C},其周期性可以由时间维度的快速傅立叶变换(Fast Fourier Transform,FFT)计算得到,详细过程如下:

\mathbf{A}=\text{Avg}(\text{Amp}(\text{FFT}(\mathbf{X}_{\text{1D}})))\\ \\
f_1,\cdots,f_k= \underset{f_*\in \{1,\cdots,[\frac{T}{2}]\}}{\arg\text{Topk}}  (\mathbf{A})\\
p_1,\cdots,p_k=\left \lceil \frac {T}{f_1} \right \rceil ,\cdots,\left \lceil \frac {T}{f_k} \right \rceil

其中,\text{FFT}(\cdot)\text{Amp}(\cdot)分别表示快速傅里叶变换(用于获取频域表示)和振幅(Amplitude)值的计算(详见FFT-在TimesNet中的应用)。\mathbf{A} \in \mathbb{R}^{T}代表了\mathbf{X}_{\text{1D}}中每个频率分量的强度,通过\text{Avg}(\cdot)在通道维度C上取均值得到;注意\mathbf{A}的第j个值A_j表示第j个频率的周期基函数的强度,其与周期长度\left \lceil \frac {T}{f_1} \right \rceil相对应。考虑到频域的稀疏性,并为了避免无意义的高频所带来的噪声,只选择前k个振幅值(k为超参数),并得到具有未归一化振幅\{A_{f_1},\cdots,A_{f_k}\}的最显著(强度最大)的频率\{f_1,\cdots,f_k\},其对应着最显著的k个周期长度\{p_1,\cdots,p_k\}。由于频域的共轭性,只需考虑\{1,\cdots,[\frac{T}{2}]\}范围内的频率。上述详细过程可简记为:

\mathbf{A},\{f_1,\cdots,f_k\},\{p_1,\cdots,p_k\}=\text{Period}(\mathbf{X}_{\text{1D}})

接下来,如图所示,基于选定的周期对原始的一维时间序列进行折叠,该过程可形式化为:

\mathbf{X}_{\text{2D}}^i=\text{Reshape}_{p_i,f_i}(\text{Padding}(\mathbf{X}_{\text{2D}})),\ i \in \{1,\cdots,k\}

其中,\text{Padding}(\cdot)为在序列末尾补0,使得序列长度可以被p_i整除。通过上述操作,可以得到一组二维张量\{\mathbf{X}_{\text{2D}}^1,\cdots,\mathbf{X}_{\text{2D}}^k\}\mathbf{X}_{\text{2D}}^i对应着由周期p_i主导的二维时序变化。

需要注意的是,对于上述二维向量,其每列与每行分别对应着相邻的时刻与相邻的周期,而临近的时刻与周期往往蕴含着相似的时序变化。因此,上述二维张量会表现出二维局部性(2D Locality),从而可以很容易通过2D卷积捕捉信息。

2.2 TimesBlock

TimesBlock是TimesNet的核心模块,负责发现时间序列的多周期性,并从转换后的二维张量中提取复杂的时间变化。TimesNet由堆叠的TimesBlock组成,主要架构(左)与各重要子过程(右)如下图所示:

输入序列首先经过嵌入层得到深度特征\mathbf{X}_{\text{1D}}^0\in \mathbb{R}^{T\times d_{\text{model}}},对于第l层TimesBlock,其输入为\mathbf{X}_{\text{1D}}^{l-1}\in \mathbb{R}^{T\times d_{\text{model}}},之后通过2D卷积提取二维时序变化得到\mathbf{X}_{\text{1D}}^{l},即:

\mathbf{X}_{\text{1D}}^{l}=\text{TimesBlock}(\mathbf{X}_{\text{1D}}^{l-1})+\mathbf{X}_{\text{1D}}^{l-1}

TimesBlock的各子过程详解如下:

  1. 一维变换至二维——快速傅里叶变换(FFT)、Reshape:对输入的一维时序特征\mathbf{X}_{\text{1D}}^{l-1}提取周期,并将之重塑成为二维张量来表示二维时序变化(同上一节所述)
\mathbf{A}^{l-1},\{f_1,\cdots,f_k\},\{p_1,\cdots,p_k\}=\text{Period}(\mathbf{X}_{\text{1D}}^{l-1})\\
\mathbf{X}_{\text{2D}}^{l,i}=\text{Reshape}_{p_i,f_i}(\text{Padding}(\mathbf{X}_{\text{2D}}^{l-1})),\ i \in \{1,\cdots,k\}
  1. 提取二维时序变化表征——Inception块:对于得到的一组二维张量\{\mathbf{X}_{\text{2D}}^{l,1},\cdots,\mathbf{X}_{\text{2D}}^{l,k}\},由于其具有二维局部性,因此可以使用2D卷积提取信息,多尺度二维卷积核同时捕捉周期内变化和周期间变化。此处选取了经典的参数高效(Parameter-efficient)的Inception模型
\mathbf{\widehat{X}}_{\text{2D}}^{l,i}=\text{Inception}(\mathbf{X}_{\text{2D}}^{l,i})
  1. 二维变换至一维——Reshape Back:经过Inception块处理后所提取的时序特征,将其重塑回一维向量\mathbf{\widehat{X}}_{\text{1D}}^{l,i} \in \mathbb{R}^{T\times d_{\text{model}}}以便进行信息聚合,其中\text{Trunc}(\cdot)表示将第1步Reshape中\text{Padding}(\cdot)操作补充的0去除
\mathbf{\widehat{X}}_{\text{1D}}^{l,i}=\text{Trunc}(\text{Reshape}_{1,(p_i,f_i)}(\mathbf{\widehat{X}}_{\text{2D}}^{l,i})),\ i=\{1,\cdots,k\}
  1. 自适应融合(Adaptive Aggregation):类似Autoformer中的设计,将得到的一维表征\{\mathbf{\widehat{X}}_{\text{1D}}^{l,1},\cdots,\mathbf{\widehat{X}}_{\text{1D}}^{l,k}\}以其对应频率的强度{\mathbf{A}_{f_1}^{l-1},\cdots,\mathbf{A}_{f_k}^{l-1}\}进行加权求和,得到最终输出
\mathbf{\widehat{A}}_{f_1}^{l-1},\cdots,\mathbf{\widehat{A}}_{f_k}^{l-1}=\text{Softmax}(\mathbf{A}_{f_1}^{l-1},\cdots,\mathbf{A}_{f_k}^{l-1})\\
\mathbf{X}_{\text{1D}}^{l}=\sum\limits_{i=1}^k \mathbf{\widehat{A}}_{f_i}^{l-1} \times \mathbf{\widehat{X}}_{\text{1D}}^{l,i}

通过上述设计,TimesNet完成了“多个周期分别提取二维时序变化,再进行自适应融合”的时序变化建模过程。

注意,由于TimesNet将一维时序特征转换为二维张量进行分析,因此可以直接采用先进的视觉骨干网络进行特征提取,例如Swin Transformer、ResNeXt、ConvNeXt等。这种设计也使得时序分析任务可以直接受益于蓬勃发展的视觉骨干网络

2.3 源码解析

预测任务:

def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec):
    # Normalization from Non-stationary Transformer
    means = x_enc.mean(1, keepdim=True).detach()
    x_enc = x_enc - means
    stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5)
    x_enc /= stdev
    print(x_enc.shape)  # [32, 96, 862]
    # embedding
    enc_out = self.enc_embedding(x_enc, x_mark_enc) # [B,T,C]
    print(enc_out.shape)    # [32, 96, 512]
    enc_out = self.predict_linear(enc_out.permute(0, 2, 1)).permute(0, 2, 1)    # align temporal dimension
    print(enc_out.shape)    # [32, 192, 512]
    # TimesNet
    for i in range(self.layer):
        enc_out = self.layer_norm(self.model[i](enc_out))
    # porject back
    dec_out = self.projection(enc_out)

    # De-Normalization from Non-stationary Transformer
    dec_out = dec_out * (stdev[:, 0, :].unsqueeze(1).repeat(1, self.pred_len + self.seq_len, 1))
    dec_out = dec_out + (means[:, 0, :].unsqueeze(1).repeat(1, self.pred_len + self.seq_len, 1))
    return dec_out

模型结构:

def FFT_for_Period(x, k=2):
    # [B, T, C]
    xf = torch.fft.rfft(x, dim=1)
    # find period by amplitudes
    frequency_list = abs(xf).mean(0).mean(-1)
    # 屏蔽直流fenquency
    frequency_list[0] = 0
    # 获取top k个周期长度
    _, top_list = torch.topk(frequency_list, k)
    top_list = top_list.detach().cpu().numpy()
    # 计算一个时间序列包含的周期数,T // top_list
    period = x.shape[1] // top_list
    # 返回周期数和周期权重
    return period, abs(xf).mean(-1)[:, top_list]

class TimesBlock(nn.Module):
    def __init__(self, configs):
        super(TimesBlock, self).__init__()
        self.seq_len = configs.seq_len
        self.pred_len = configs.pred_len
        self.k = configs.top_k
        # parameter-efficient design
        self.conv = nn.Sequential(
            Inception_Block_V1(configs.d_model, configs.d_ff, num_kernels=configs.num_kernels),
            nn.GELU(),
            Inception_Block_V1(configs.d_ff, configs.d_model, num_kernels=configs.num_kernels)
        )

    def forward(self, x):
        B, T, N = x.size()
        period_list, period_weight = FFT_for_Period(x, self.k)

        res = []
        for i in range(self.k):
            # 获取周期数
            period = period_list[i]
            # padding
            if (self.seq_len + self.pred_len) % period != 0:
                length = (((self.seq_len + self.pred_len) // period) + 1) * period
                padding = torch.zeros([x.shape[0], (length - (self.seq_len + self.pred_len)), x.shape[2]]).to(x.device)
                out = torch.cat([x, padding], dim=1)
            else:
                length = (self.seq_len + self.pred_len)
                out = x
            # reshape, [32, 512, 39, 5]
            out = out.reshape(B, length // period, period, N).permute(0, 3, 1, 2).contiguous()
            # 2D conv: from 1d Variation to 2d Variation
            out = self.conv(out)
            # reshape back
            out = out.permute(0, 2, 3, 1).reshape(B, -1, N) # [32, 192, 512]
            res.append(out[:, :(self.seq_len + self.pred_len), :])
        res = torch.stack(res, dim=-1)
        # adaptive aggregation,将不同周期的输出加权求和
        period_weight = F.softmax(period_weight, dim=1)
        period_weight = period_weight.unsqueeze(1).unsqueeze(1).repeat(1, T, N, 1)
        res = torch.sum(res * period_weight, -1)
        # residual connection
        res = res + x
        return res

3 实验

Times在长时/短时预测、缺失值填补、异常检测、分类五大任务上进行了实验,涵盖36个数据集、81种不同的实验设置,详见时间序列任务数据集简介

同时,对比了19种不同的深度方法,包含各种基于RNN、CNN、MLP、Transformer的模型,例如N-BEATS(2019)、Autoformer(2021)、LSSL(2022)、N-Hits(2022)、FEDformer(2022)、Dlinear(2023)等。

3.1 总体结果

各任务具体实验结果见论文,TimesNet在五项任务上均达到了SOTA。

模型性能对比见下图左,视觉骨干网络的泛化性(将TimesBlock中的Inception网络替换为不同的视觉骨干网络,例如ResNet,ConvNext,Swin Transformer)见下图右,可见更先进的视觉骨干网络可以带来更优秀的效果:

3.2 表征分析

为了进一步探索TimesNet的效果来源,论文进行了表征分析(Representation Analysis),展示了“模型底层-顶层表征之间的CKA相似度”与“模型效果”之间的关系。其中,CKA相似度越低,代表模型底层-顶层之间的表征差异越大,即更加层次化的表征:

从可视化中可以观察到:

  • 在预测与异常检测任务中,效果越好的模型往往底层-顶层的表征相似度越高,表明任务期待更加底层的表征(Low-level Representations)
  • 在分类与缺失值填补任务中,效果越好的模型往往底层-顶层的表征相似度越低,表明该任务需要层次化表征(Hierarchical Representation)

得益于2D空间中的卷积操作,TimesNet可以根据不同任务学习合适的表征,例如预测与异常检测任务中,学习到低层次表征;而分类与缺失值填补任务中,学习到层次化的抽象特征。这也进一步证明了TimesNet作为基础模型的任务泛化性。

3.3 二维时序变化可视化

为了佐证二维时序变化的分析,论文中可视化了一个样例,其中Period方向反应周期内变化,而Frequency方向代表周期间变化:

在上图中可以看出转化至二维空间的时序数据具有明显的二维局部性(2D Locality),这也印证了使用视觉骨干网络提取二维时序变化的合理性。


4 其他教程与衍生模型

原版TimesNet模型讲解:

改进模型与应用:


5 改进方向探讨

TimesNet的核心创新在于将时序问题转化为视觉问题,这也为改进提供了明确的主线。以下是几个有潜力的改进方向(AI生成的备忘笔记,仅供参考),从易到难排列:

方向一:增强二维变换的鲁棒性与适应性

当前方法有几个可以优化的点:

  1. 周期检测的鲁棒性提升

    • 问题:FFT对噪声和非平稳数据敏感,可能导致检测的周期不准确
    • 改进思路
      • 结合自相关函数小波变换等多方法进行周期验证
      • 引入滑动窗口的多尺度周期检测,适应时变周期
      • 使用学习型的周期检测模块,让模型自己学习最优的reshape策略
  2. 非整数周期的处理优化

    • 问题:当前padding + truncate会引入噪声或丢失信息
    • 改进思路
      • 采用插值方法进行精确的二维重塑
      • 设计可变的二维网格,允许非矩形的二维表示

方向二:改进视觉骨干网络

TimesNet可以受益于视觉骨干网络的发展,对于此有如下具体方向:

  1. 注意力增强的二维卷积

    • 思路:在Inception块中引入2D注意力机制(如CBAM、SE模块)
    • 优势:让模型关注二维空间中更重要的区域
    • 这与"An attention-enhanced TimesNet..."(2025)论文思路一致
  2. 现代视觉架构的适配

    • 尝试:ConvNeXt V2、RepVGG、Vision Transformer等最新视觉架构
    • 关键:需要平衡性能与计算复杂度,时序数据通常比图像数据规模小

方向三:多尺度与层次化建模

  1. 层次化的TimesBlock

    • 思路:设计不同层关注不同时间尺度的层次化结构
    • 浅层 → 短周期,深层 → 长周期
    • 类似UNet的编码器-解码器结构,在二维空间中进行多尺度特征融合
  2. 周期间的关系建模

    • 当前局限:不同周期的二维表示是独立处理的
    • 改进:设计跨周期的交互模块,让不同周期的信息能够相互增强

方向四:处理复杂时序模式

  1. 非平稳性建模

    • 结合思路:借鉴Non-stationary Transformer的de-stationary思路
    • 在TimesNet前后加入平稳化-反平稳化模块
    • 或者在二维变换时考虑时序的局部统计特性
  2. 外部变量融合

    • 问题:当前模型主要处理纯时序,外部变量利用不足
    • 改进:在二维卷积中设计多模态融合模块,将外部变量作为额外通道

方向五:效率优化

  1. 动态周期选择

    • 思路:不是固定选择top-k个周期,而是根据输入样本自适应选择周期数量
    • 使用轻量级网络预测每个样本的最优k值
  2. 稀疏化处理

    • 针对:长序列预测时的计算瓶颈
    • 方法:在二维空间中使用稀疏卷积自适应池化

具体实施建议

按以下优先级尝试实施:

  • 初级(快速验证):
# 在Inception块后加入2D注意力
class EnhancedInceptionBlock(nn.Module):
    def __init__(self, d_model, d_ff, num_kernels=3):
        super().__init__()
        self.inception = Inception_Block_V1(d_model, d_ff, num_kernels)
        self.attention = CBAM(d_ff)  # 2D注意力
        self.out_proj = nn.Linear(d_ff, d_model)
  • 中级(结构改进):

    • 实现层次化TimesNet,不同层关注不同尺度周期
    • 加入周期验证模块,提升FFT的鲁棒性
  • 高级(理论创新):

    • 设计可学习的二维变换机制
    • 开发非平稳时序的二维表示理论

实验设计建议

改进时重点关注这些评估维度:

  1. 不同数据特性:平稳vs非平稳、强周期vs弱周期、多周期vs单周期
  2. 不同任务:您提到TimesNet在五大任务表现不同,改进时考虑任务特定的优化
  3. 计算效率:FLOPs、内存占用、推理速度的trade-off

《TimesNet及其后续改进》有2条评论

  1. Pingback: 小波变换及其在时序预测中的应用简介 – Hyperplasma
  2. Pingback: 从傅里叶变换到快速傅里叶变换 – Hyperplasma

发表评论