Transformer时间序列预测:从Informer到TimesFM的完整演进

Transformer时间序列预测:从Informer到TimesFM的完整演进

一、引言

Transformer 在 NLP 取得巨大成功后,时间序列预测领域也经历了一场"Transformer 革命"。从 Informer 解决长序列效率问题,到 Autoformer 引入频域分解,再到 Google 的 TimesFM 基础模型,Transformer 时序预测正走向大一统。

本文将覆盖从原理到实战的完整路线:Informer→Autoformer→PatchTST→TimesFM。

二、为什么Transformer适合时间序列

传统方法 局限 Transformer优势
ARIMA/ETS 仅线性,单变量 非线性,多变量
LSTM/GRU 长序列梯度消失 自注意力全局建模
Prophet 需人工特征 自动学习模式
XGBoost 需滚动窗口 直接映射序列到序列

三、Informer:高效长序列预测

3.1 ProbSparse注意力

python 复制代码
import torch
import torch.nn as nn
import numpy as np

class ProbSparseAttention(nn.Module):
    """Informer核心:概率稀疏自注意力 O(L·logL)"""
    
    def __init__(self, d_model=512, n_heads=8, factor=5):
        super().__init__()
        self.d_model = d_model
        self.n_heads = n_heads
        self.factor = factor  # 采样因子
        self.d_k = d_model // n_heads
        
        self.W_q = nn.Linear(d_model, d_model)
        self.W_k = nn.Linear(d_model, d_model)
        self.W_v = nn.Linear(d_model, d_model)
        self.W_o = nn.Linear(d_model, d_model)
    
    def _prob_QK(self, Q, K, sample_k, n_top):
        """概率稀疏度量 M(q_i, K) = max_j{q_i·k_j^T/√d} - mean_j{q_i·k_j^T/√d}"""
        B, H, L_Q, D = Q.shape
        _, _, L_K, _ = K.shape
        
        # 随机采样 K 的一部分来计算稀疏性度量
        index_sample = torch.randint(L_K, (L_Q, sample_k))
        K_sample = K[:, :, index_sample, :]  # [B,H,L_Q,sample_k,D]
        
        # 计算 Q-K 点积(采样部分)
        Q_K_sample = torch.matmul(
            Q.unsqueeze(-2),     # [B,H,L_Q,1,D]
            K_sample.transpose(-2, -1)  # [B,H,L_Q,D,sample_k]
        ).squeeze(-2) / np.sqrt(D)  # [B,H,L_Q,sample_k]
        
        # M度量 = max - mean
        M = Q_K_sample.max(dim=-1)[0] - Q_K_sample.mean(dim=-1)
        
        # 选择 top-u 个查询
        M_top = M.topk(n_top, sorted=False)[1]  # [B,H,n_top]
        
        return M_top
    
    def forward(self, queries, keys, values):
        B, L, _ = queries.shape
        H, D = self.n_heads, self.d_k
        
        # 线性投影
        Q = self.W_q(queries).view(B, -1, H, D).transpose(1, 2)
        K = self.W_k(keys).view(B, -1, H, D).transpose(1, 2)
        V = self.W_v(values).view(B, -1, H, D).transpose(1, 2)
        
        # 1. 计算稀疏性度量,选择 top-u
        u = self.factor * int(np.log(L))
        M_top = self._prob_QK(Q, K, sample_k=int(np.log(L)), n_top=u)
        
        # 2. 只计算 top-u 个查询的完整注意力
        Q_reduce = Q.gather(2, M_top.unsqueeze(-1).expand(-1, -1, -1, D))
        
        # 标准注意力计算(只对top-u查询)
        attn = torch.matmul(Q_reduce, K.transpose(-2, -1)) / np.sqrt(D)
        attn = torch.softmax(attn, dim=-1)
        
        # 3. 对 top-u 查询计算输出
        context = torch.matmul(attn, V)  # [B,H,u,D]
        
        # 4. 填充:非top-u查询用V的均值替代
        V_mean = V.mean(dim=2).unsqueeze(2).expand(-1, -1, L - u, -1)
        out = torch.cat([context, V_mean], dim=2)
        
        return self.W_o(out.transpose(1, 2).contiguous().view(B, L, -1))

3.2 蒸馏层

python 复制代码
class DistillingLayer(nn.Module):
    """自注意力蒸馏:Conv1d + MaxPool → 减半序列长度"""
    
    def __init__(self, d_model):
        super().__init__()
        self.conv = nn.Conv1d(d_model, d_model, 3, padding=1)
        self.norm = nn.BatchNorm1d(d_model)
        self.pool = nn.MaxPool1d(3, stride=2, padding=1)
    
    def forward(self, x):
        # x: [B, L, D] → [B, D, L]
        x = x.transpose(1, 2)
        x = self.conv(x)
        x = self.norm(x)
        x = torch.relu(x)
        x = self.pool(x)  # 长度减半
        return x.transpose(1, 2)

四、Autoformer:频域分解

4.1 序列分解模块

python 复制代码
class SeriesDecomposition(nn.Module):
    """移动平均分解:序列 → 趋势项 + 季节项"""
    
    def __init__(self, kernel_size=25):
        super().__init__()
        self.moving_avg = nn.AvgPool1d(
            kernel_size=kernel_size,
            stride=1,
            padding=kernel_size // 2
        )
    
    def forward(self, x):
        """x: [B, L, D]"""
        # 趋势项:移动平均
        trend = self.moving_avg(x.transpose(1, 2)).transpose(1, 2)
        # 季节项:原始 - 趋势
        seasonal = x - trend
        return seasonal, trend

4.2 Auto-Correlation 频域注意力

python 复制代码
class AutoCorrelation(nn.Module):
    """自相关机制:用FFT高效计算周期相似性"""
    
    def __init__(self, d_model=512, n_heads=8, top_k=3):
        super().__init__()
        self.n_heads = n_heads
        self.d_k = d_model // n_heads
        self.top_k = top_k  # 保留最强的k个周期
        
        self.W_qkv = nn.Linear(d_model, d_model * 3)
        self.W_o = nn.Linear(d_model, d_model)
    
    def time_delay_agg(self, values, corr_indices):
        """基于最强周期的时延聚合"""
        B, H, L, D = values.shape
        top_k = corr_indices.shape[-1]
        
        # 按索引 gather + Roll
        aligned_values = []
        for k in range(top_k):
            idx = corr_indices[:, :, :, k]  # [B,H,L]
            # Roll操作:将时间序列按 idx 移位
            v_k = torch.gather(values, 2,
                idx.unsqueeze(-1).expand(-1, -1, -1, D))
            aligned_values.append(v_k)
        
        # 拼接并投影
        aligned = torch.stack(aligned_values, dim=-1)  # [B,H,L,D,top_k]
        return aligned.mean(dim=-1)
    
    def forward(self, x):
        B, L, D_in = x.shape
        H = self.n_heads
        
        # QKV投影
        qkv = self.W_qkv(x).reshape(B, L, 3, H, self.d_k).permute(2, 0, 3, 1, 4)
        Q, K, V = qkv[0], qkv[1], qkv[2]
        
        # 频域自相关: R(τ) = FFT^{-1}(S_xy(f))
        # S_xy(f) = FFT(Q)_f · conj(FFT(K)_f)
        Q_fft = torch.fft.rfft(Q, dim=2)
        K_fft = torch.fft.rfft(K, dim=2)
        
        # 频域相乘
        S = Q_fft * torch.conj(K_fft)
        
        # 逆FFT得到时域自相关
        corr = torch.fft.irfft(S, dim=2)  # [B,H,L]
        
        # 选择最强的 top_k 个延迟
        top_corr, top_indices = torch.topk(corr, self.top_k, dim=2)
        
        # 时延聚合
        out = self.time_delay_agg(V, top_indices)
        
        return self.W_o(out.transpose(1, 2).reshape(B, L, D_in))

五、PatchTST:分块革命

python 复制代码
class PatchTST(nn.Module):
    """将时间序列分割为重叠patches,用ViT风格处理"""
    
    def __init__(self, patch_len=16, stride=8, d_model=128, n_layers=3):
        super().__init__()
        self.patch_len = patch_len
        self.stride = stride
        
        # Patch嵌入: 每个patch → d_model维
        self.patch_embed = nn.Linear(patch_len, d_model)
        
        # 可学习位置编码
        self.pos_embed = nn.Parameter(torch.randn(1, 512, d_model))
        
        # Transformer编码器
        self.encoder = nn.TransformerEncoder(
            nn.TransformerEncoderLayer(d_model, nhead=8, batch_first=True),
            num_layers=n_layers
        )
        
        # 输出头
        self.head = nn.Linear(d_model, patch_len)
    
    def forward(self, x):
        """x: [B, L, V] L=序列长度, V=变量数"""
        B, L, V = x.shape
        
        # 1. 分块 (Patching)
        patches = x.unfold(dimension=1, size=self.patch_len, step=self.stride)
        # [B, num_patches, V, patch_len]
        num_patches = patches.shape[1]
        
        # 2. 独立通道策略(每个变量独立处理)
        patches = patches.permute(0, 2, 1, 3)  # [B, V, num_patches, patch_len]
        patches = patches.reshape(B * V, num_patches, self.patch_len)
        
        # 3. Patch嵌入
        embeds = self.patch_embed(patches)  # [B*V, num_patches, d_model]
        embeds = embeds + self.pos_embed[:, :num_patches, :]
        
        # 4. Transformer编码
        encoded = self.encoder(embeds)
        
        # 5. 输出预测
        pred = self.head(encoded)  # [B*V, num_patches, patch_len]
        
        # 6. 重组
        pred = pred.reshape(B, V, num_patches, self.patch_len)
        pred = pred.permute(0, 2, 1, 3)  # [B, num_patches, V, patch_len]
        
        # 用最后一个patch的预测作为最终输出
        return pred[:, -1, :, :]  # [B, V, patch_len]

六、TimesFM:时序基础模型

python 复制代码
import timesfm

# 加载预训练 TimesFM 模型
model = timesfm.TimesFm(
    context_len=512,   # 历史窗口
    horizon_len=128,   # 预测长度
    input_patch_len=32,
    output_patch_len=128,
    num_layers=20,
    model_dims=1280,
)

# 加载权重
model.load_from_checkpoint("google/timesfm-1.0-200m")

# 零样本预测
forecast = model.forecast(
    historical_values,
    horizon=128
)
print(f"预测: {forecast.shape}")

# 与传统方法对比
# TimesFM优势:
# 1. 预训练:在1000亿+时间点上训练
# 2. 零样本:无需微调即可预测新序列
# 3. 上下文学习:类似LLM的In-Context Learning
# 4. 多频率:日/周/月/年频率无缝切换

七、异常检测

python 复制代码
class AnomalyDetector(nn.Module):
    """基于预测误差的时间序列异常检测"""
    
    def __init__(self, predictor, threshold_percentile=95):
        self.predictor = predictor
        self.threshold = threshold_percentile
    
    def detect(self, sequence, window=96, horizon=24):
        """滑动窗口预测 → 计算误差 → 标记异常"""
        anomalies = []
        reconstruction_errors = []
        
        for i in range(0, len(sequence) - window - horizon):
            # 历史窗口
            hist = sequence[i:i+window]
            # 真实未来值
            true_future = sequence[i+window:i+window+horizon]
            
            # 预测
            pred = self.predictor(hist.unsqueeze(0))
            
            # 重建误差
            error = torch.abs(pred - true_future).mean(dim=-1)
            reconstruction_errors.append(error.item())
            
            # 阈值判断
            if error > self.error_threshold:
                anomalies.append(i + window)
        
        return anomalies, reconstruction_errors
    
    def fit_threshold(self, train_errors):
        """从训练数据学习异常阈值"""
        self.error_threshold = np.percentile(
            train_errors, self.threshold_percentile
        )

八、总结

模型 核心创新 适合场景
Informer ProbSparse注意力+蒸馏 极长序列(1000+)
Autoformer FFT自相关+趋势分解 强周期序列
PatchTST 分块+独立通道 多变量通用预测
TimesFM 预训练基础模型 零样本快速预测

选择建议:数据充足训练PatchTST,长序列用Informer,零样本用TimesFM。

相关推荐
SEONIB_Explorer1 小时前
跨境电商新手零门槛教程:AI 一键生成 TikTok/Ins 投放短视频,5 步 60 秒出片
人工智能·音视频·跨境电商·视频制作·veonib
中微极客1 小时前
用LangChain 0.3构建生产级RAG与Agent:从API集成到Streamlit部署
数据库·人工智能·langchain
海上彼尚2 小时前
Nodejs也能写Agent - 22.LangGraph篇 - 上下文工程
前端·javascript·人工智能·langchain·node.js
Tangyuewei2 小时前
单 Agent 不够用了:AI 编程进入舰队模式
人工智能
艾斯特_2 小时前
工作流与多Agent协作:LangGraph、MCP和A2A的应用分层
人工智能·python·ai
悟天特斯2 小时前
智慧楼宇AI节能:从数据采集到智能决策的全链路实践
大数据·人工智能
腾视科技AIoT2 小时前
私有云时代来临:AI NAS如何重塑你的数字生活?
人工智能·ai·生活·nas·企业存储·ainas·家庭存储
IT小盘2 小时前
04-大模型流式输出原理-SSE与Python实现
开发语言·网络·人工智能·python