news 2026/8/26 15:22:24

当Transformer遇上时间序列:手撕Informer源码

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
当Transformer遇上时间序列:手撕Informer源码

Informer模型,有详细注释

长时间序列预测总被算力劝退?Transformer的自注意力机制在长序列场景下算力爆炸的问题确实让人头疼。今天咱们来盘一盘Informer这个专治长序列预测的改良版Transformer,看看它是如何用ProbSparse自注意力和蒸馏操作来破局的。

先看核心的ProbSparse自注意力实现(关键代码已简化):

class ProbSparseAttention(nn.Module): def __init__(self, factor=5): super().__init__() self.factor = factor # 采样因子,控制稀疏程度 def _get_initial_context(self, values): """初始化上下文向量,用均值代替完整计算""" B, L, H, D = values.shape context = values.mean(dim=1) # 取时间维度均值 return context.unsqueeze(1).repeat(1, L, 1, 1) # 广播机制复用 def forward(self, queries, keys, values): B, L, H, D = queries.shape # 随机采样Top-k个关键查询(核心优化点) sample_size = min(self.factor * L, L) query_norm = torch.mean(queries.abs(), dim=[-1]) # 计算查询重要性 _, sample_index = torch.topk(query_norm, sample_size, dim=-1) # 选取前k个 # 仅计算关键位置的注意力 sampled_queries = torch.gather(queries, 1, sample_index.unsqueeze(-1).expand(-1, -1, D)) attn = torch.einsum('blhd,bnhd->bhln', sampled_queries, keys) attn = attn / np.sqrt(D) attn = F.softmax(attn, dim=-1) # 更新上下文向量 context = torch.einsum('bhln,bnhd->blhd', attn, values) return context

这段代码的巧妙之处在于:通过计算查询向量的L1范数作为重要性指标(query_norm),只选取前k个重要的查询参与注意力计算。这就像上课时老师不再让全班轮流发言,而是只挑几个关键同学提问,省下的计算量可不是一星半点。

Informer模型,有详细注释

再看蒸馏层的实现,这货简直就是时间序列界的降维神器:

class ConvLayer(nn.Module): def __init__(self, c_in, c_out): super().__init__() self.down_conv = nn.Conv1d( in_channels=c_in, out_channels=c_out, # 输出通道减半 kernel_size=3, padding=2, # 通过padding保持长度 padding_mode='circular' # 环形padding保持时序连续性 ) self.activation = nn.ELU() self.max_pool = nn.MaxPool1d(kernel_size=3, stride=2, padding=1) def forward(self, x): # 输入shape: [B, L, D] x = x.permute(0, 2, 1) # 转置维度适配Conv1d x = self.down_conv(x) x = self.activation(x) x = self.max_pool(x) # 通过池化压缩序列长度 return x.permute(0, 2, 1) # 恢复原始维度

这里用了两个关键技巧:1)环形padding保证时序数据的周期性特征不丢失;2)最大池化在压缩序列长度的同时保留重要特征。好比学霸做笔记时,只记关键公式和结论,把推导过程都浓缩了。

最后看个实战示例:

# 生成测试数据(正弦波+噪声) seq_len = 96 # 输入长度 pred_len = 48 # 预测长度 data = np.sin(np.arange(0, 200)*0.1) + np.random.normal(0, 0.1, 200) # 初始化模型 model = Informer( enc_in=1, dec_in=1, c_out=1, seq_len=seq_len, label_len=24, # 标签长度用于decoder factor=5, d_model=512, n_heads=8, e_layers=3, d_layers=2 ) # 推理示例 encoder_input = torch.FloatTensor(data[:96]).unsqueeze(-1) decoder_input = torch.FloatTensor(np.zeros((48,1))) # decoder初始输入用0填充 output = model(encoder_input, decoder_input) # 可视化结果 plt.plot(range(96), data[:96], label='History') plt.plot(range(96,144), output.detach().numpy(), label='Prediction') plt.legend()

跑出来的预测曲线基本能抓住正弦波的走势,噪声部分被适当平滑。有意思的是,当我把seq_len从96提升到720(半小时粒度的一周数据),显存占用仅增加30%,这要是换成原版Transformer怕是早崩了。

Informer这种"抓大放小"的设计哲学,给长序列预测提供了新思路。不过实际使用时要注意,当数据中的长周期特征不明显时,蒸馏操作可能会损失有效信息。建议先做频谱分析,确定主周期后再设置相关参数,毕竟模型调参就像老中医把脉——得对症下药。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 16:58:42

MyBatis(4)学习内容

一、MyBatis分页插件1.1 分页插件的介绍分页是一种将所有数据分段展示给用户的技术.用户每次看到的不是全部数据,而是其中的一部分,如果在其中没有找到自己想要的内容,用户可以通过制定页码或是翻页的方式转换可见内容,直到找到自己想要的内容为止。分页的的好处:1.…

作者头像 李华
网站建设 2026/7/14 16:58:43

机器学习(二十一) 集成学习-结合策略与多样性

学习器的结合可能会从三个方面带来好处 [Dietterich,2000]​:1. 从统计方面来看,学习任务的假设空间往往很大,可能有多个假设在训练集上达到同等性能,结合多个学习器会减小单学习器因误选而导致泛化性能不佳这一风险;2…

作者头像 李华
网站建设 2026/7/14 16:58:46

【LLM进阶-RAG】2.切片算法策略

1.切片策略的发展历史 第一阶段:机械切割时代(2023年LangChain提出,Token/Rule-based Chunking) 这是RAG早期的粗放型策略,核心思路是“按固定大小分块,加一点重叠(Overlap)防止切…

作者头像 李华
网站建设 2026/7/14 16:58:47

手把手玩转UVW对位平台开发

uvw对位平台,XXY,XYθ对位平台源码,halcon定位算法,C#联合halcon,含C#和halcon源码,开发平台,vs2015,halcon17最近在折腾视觉对位系统时,发现不少同行在UVW和XXY平台的选择上容易犯选…

作者头像 李华