时间序列预测入门到实战十· Transformer 登场注意力与时序本文是「码海寻道」《时间序列预测入门到实战》系列的第 10 篇。循环、卷积都讲过了现在轮到这几年最耀眼的主角——Transformer。它横扫了 NLP 和 CV自然也被大举搬到时序上。但这一篇我不只讲它怎么work更要诚实地告诉你把原版 Transformer 直接搬来做时序会水土不服在哪。这三个坑正是后面两篇Informer、PatchTST存在的理由。一、注意力让模型自己决定该看哪里RNN 沿固定顺序传递记忆CNN 在固定窗口里卷积。注意力机制Self-Attention给了第三种可能每个位置直接关注序列里所有其他位置按相关性加权聚合信息。它的机制是Query / Key / Value每个位置生成一个Query我想找什么、一个Key我是什么、一个Value我能提供什么用 Query 和所有 Key 算相似度得到一组注意力权重该关注谁、关注多少用这组权重对所有 Value 加权求和。直觉上预测时模型自己学会要预测下一小时该重点看昨天此刻、上周此刻还是刚刚这几步——不再是 RNN 那种固定的顺序遗忘也不是 CNN 那种固定的窗口。QKV 用查字典来理解最顺Query 是你手里的检索词“我想找和当前最像的时刻”每个位置的 Key 是它贴的标签“我是个尖峰”“我是个低谷”Value 是它真正的内容。检索时拿 Query 去和每个 Key 比一比有多配算点积相似度越配的给越高的权重最后按权重把各家的 Value 揉成一份答案。所谓注意力权重就是这张该信谁几分的分配表——而且它是模型根据内容临时算出来的不是写死的这正是注意力比固定窗口灵活的根源。那个 √d 的除法缩放点积也不是摆设向量维度 d 越高Query·Key 的点积天然越大直接丢进 softmax 会让最大那项被推到接近 1、其余全压到 0——注意力过度自信地只盯一个点梯度还几乎消失。除以 √d 把点积的尺度拉回来softmax 才平滑训练才稳。名字里的缩放就是指这一下。两大优势① 任意两个时刻一步直达长依赖不再衰减② 可以完全并行不像 RNN 要一步步来。二、位置编码注意力天生没有顺序感但注意力有个对时序致命的特性它是排列不变的——把输入顺序打乱输出竟然一样因为它只算两两相似度根本不知道谁先谁后。对时间序列来说顺序就是一切这可不行。补救办法是位置编码Positional Encoding给每个位置注入一个可区分的位置信号正弦函数或可学习向量加到输入上让模型能感知先后。importtorch,torch.nnasnn,mathclassPositionalEncoding(nn.Module):def__init__(self,d_model,max_len5000):super().__init__()petorch.zeros(max_len,d_model)postorch.arange(max_len).unsqueeze(1)divtorch.exp(torch.arange(0,d_model,2)*(-math.log(10000)/d_model))pe[:,0::2]torch.sin(pos*div)pe[:,1::2]torch.cos(pos*div)self.register_buffer(pe,pe)defforward(self,x):# x: (B, L, d_model)returnxself.pe[:x.size(1)]配上多头注意力、前馈网络、残差和 LayerNorm就是一个标准 Transformer 编码器多头是什么与其算一套注意力不如把向量拆成好几份、并行算好几套每套每个头自己学一种关注模式——有的头盯最近几步有的头盯上周同刻有的头盯整体水平。最后把各头的结果拼起来。就像同一份数据交给几个视角不同的分析师同时看再汇总比单一视角更全面。代码里的nhead8就是 8 个头。classTSFormer(nn.Module):def__init__(self,d_model64,nhead8,layers3,horizon24):super().__init__()self.projnn.Linear(1,d_model)self.posPositionalEncoding(d_model)encnn.TransformerEncoderLayer(d_model,nhead,batch_firstTrue)self.encodernn.TransformerEncoder(enc,layers)self.headnn.Linear(d_model,horizon)defforward(self,x):# x: (B, L, 1)hself.encoder(self.pos(self.proj(x)))returnself.head(h[:,-1])三、三个水土不服重点原版 Transformer 是为语言设计的搬到时序上有三处硬伤① 复杂度 O(L²)长序列扛不住。注意力要算每两个位置的相似度序列长度 L 一大注意力矩阵就是 L×L显存和算力平方级爆炸。而时序动辄成百上千步——这直接催生了 Informer 等高效注意力变体下一篇。② 逐点注意力语义太薄。一个词有丰富语义但单个时间点只是一个数字信息量极低。在孤立的点之间算注意力抓不到一段上升一个尖峰这类局部形态——这催生了 PatchTST 的分块思想第 12 篇。③ 数据饥渴 归纳偏置弱。Transformer 假设少、要大数据喂。在中小规模时序上它那点位置编码不足以弥补缺失的时序归纳偏置很容易过拟合反而输给简单模型。四、说点实话参考结论直接搬来的原版vanillaTransformer在时序 benchmark 上常常打不过精心设计的简单模型。这不是 Transformer 不行而是它需要被改造才能适配时序。学术界随之分成两条路改进注意力效率让它能吃长序列 —— Informer、Autoformer下一篇反思 Transformer 本身它对时序真的必要吗 —— DLinear、PatchTST第 12 篇。这两条路构成了接下来两篇的主线。小结注意力让每个位置直接关注所有位置长依赖一步直达、可并行模型自己学该看哪里注意力排列不变必须靠位置编码补上顺序感搬到时序的三个坑O(L²) 复杂度、逐点语义太薄、数据饥渴/归纳偏置弱原版 Transformer 未必打得过简单模型这催生了高效注意力和反思派两条技术路线。下一篇我们看第一条路怎么走——Informer 和 Autoformer如何把 O(L²) 的注意力瘦身让 Transformer 真正吃得下长序列。思考题注意力让任意两个时刻一步直达这对捕捉长依赖是优点。但对于一条平滑、强局部相关的时序这种人人都能连人人的自由会不会反而成了容易过拟合的缺点Transformer 正式登场。下一篇看 Informer / Autoformer 如何驯服 O(L²)让注意力吃下超长序列。
10.时间序列预测入门到实战: Transformer 登场:注意力与时序
发布时间:2026/7/16 4:13:52
时间序列预测入门到实战十· Transformer 登场注意力与时序本文是「码海寻道」《时间序列预测入门到实战》系列的第 10 篇。循环、卷积都讲过了现在轮到这几年最耀眼的主角——Transformer。它横扫了 NLP 和 CV自然也被大举搬到时序上。但这一篇我不只讲它怎么work更要诚实地告诉你把原版 Transformer 直接搬来做时序会水土不服在哪。这三个坑正是后面两篇Informer、PatchTST存在的理由。一、注意力让模型自己决定该看哪里RNN 沿固定顺序传递记忆CNN 在固定窗口里卷积。注意力机制Self-Attention给了第三种可能每个位置直接关注序列里所有其他位置按相关性加权聚合信息。它的机制是Query / Key / Value每个位置生成一个Query我想找什么、一个Key我是什么、一个Value我能提供什么用 Query 和所有 Key 算相似度得到一组注意力权重该关注谁、关注多少用这组权重对所有 Value 加权求和。直觉上预测时模型自己学会要预测下一小时该重点看昨天此刻、上周此刻还是刚刚这几步——不再是 RNN 那种固定的顺序遗忘也不是 CNN 那种固定的窗口。QKV 用查字典来理解最顺Query 是你手里的检索词“我想找和当前最像的时刻”每个位置的 Key 是它贴的标签“我是个尖峰”“我是个低谷”Value 是它真正的内容。检索时拿 Query 去和每个 Key 比一比有多配算点积相似度越配的给越高的权重最后按权重把各家的 Value 揉成一份答案。所谓注意力权重就是这张该信谁几分的分配表——而且它是模型根据内容临时算出来的不是写死的这正是注意力比固定窗口灵活的根源。那个 √d 的除法缩放点积也不是摆设向量维度 d 越高Query·Key 的点积天然越大直接丢进 softmax 会让最大那项被推到接近 1、其余全压到 0——注意力过度自信地只盯一个点梯度还几乎消失。除以 √d 把点积的尺度拉回来softmax 才平滑训练才稳。名字里的缩放就是指这一下。两大优势① 任意两个时刻一步直达长依赖不再衰减② 可以完全并行不像 RNN 要一步步来。二、位置编码注意力天生没有顺序感但注意力有个对时序致命的特性它是排列不变的——把输入顺序打乱输出竟然一样因为它只算两两相似度根本不知道谁先谁后。对时间序列来说顺序就是一切这可不行。补救办法是位置编码Positional Encoding给每个位置注入一个可区分的位置信号正弦函数或可学习向量加到输入上让模型能感知先后。importtorch,torch.nnasnn,mathclassPositionalEncoding(nn.Module):def__init__(self,d_model,max_len5000):super().__init__()petorch.zeros(max_len,d_model)postorch.arange(max_len).unsqueeze(1)divtorch.exp(torch.arange(0,d_model,2)*(-math.log(10000)/d_model))pe[:,0::2]torch.sin(pos*div)pe[:,1::2]torch.cos(pos*div)self.register_buffer(pe,pe)defforward(self,x):# x: (B, L, d_model)returnxself.pe[:x.size(1)]配上多头注意力、前馈网络、残差和 LayerNorm就是一个标准 Transformer 编码器多头是什么与其算一套注意力不如把向量拆成好几份、并行算好几套每套每个头自己学一种关注模式——有的头盯最近几步有的头盯上周同刻有的头盯整体水平。最后把各头的结果拼起来。就像同一份数据交给几个视角不同的分析师同时看再汇总比单一视角更全面。代码里的nhead8就是 8 个头。classTSFormer(nn.Module):def__init__(self,d_model64,nhead8,layers3,horizon24):super().__init__()self.projnn.Linear(1,d_model)self.posPositionalEncoding(d_model)encnn.TransformerEncoderLayer(d_model,nhead,batch_firstTrue)self.encodernn.TransformerEncoder(enc,layers)self.headnn.Linear(d_model,horizon)defforward(self,x):# x: (B, L, 1)hself.encoder(self.pos(self.proj(x)))returnself.head(h[:,-1])三、三个水土不服重点原版 Transformer 是为语言设计的搬到时序上有三处硬伤① 复杂度 O(L²)长序列扛不住。注意力要算每两个位置的相似度序列长度 L 一大注意力矩阵就是 L×L显存和算力平方级爆炸。而时序动辄成百上千步——这直接催生了 Informer 等高效注意力变体下一篇。② 逐点注意力语义太薄。一个词有丰富语义但单个时间点只是一个数字信息量极低。在孤立的点之间算注意力抓不到一段上升一个尖峰这类局部形态——这催生了 PatchTST 的分块思想第 12 篇。③ 数据饥渴 归纳偏置弱。Transformer 假设少、要大数据喂。在中小规模时序上它那点位置编码不足以弥补缺失的时序归纳偏置很容易过拟合反而输给简单模型。四、说点实话参考结论直接搬来的原版vanillaTransformer在时序 benchmark 上常常打不过精心设计的简单模型。这不是 Transformer 不行而是它需要被改造才能适配时序。学术界随之分成两条路改进注意力效率让它能吃长序列 —— Informer、Autoformer下一篇反思 Transformer 本身它对时序真的必要吗 —— DLinear、PatchTST第 12 篇。这两条路构成了接下来两篇的主线。小结注意力让每个位置直接关注所有位置长依赖一步直达、可并行模型自己学该看哪里注意力排列不变必须靠位置编码补上顺序感搬到时序的三个坑O(L²) 复杂度、逐点语义太薄、数据饥渴/归纳偏置弱原版 Transformer 未必打得过简单模型这催生了高效注意力和反思派两条技术路线。下一篇我们看第一条路怎么走——Informer 和 Autoformer如何把 O(L²) 的注意力瘦身让 Transformer 真正吃得下长序列。思考题注意力让任意两个时刻一步直达这对捕捉长依赖是优点。但对于一条平滑、强局部相关的时序这种人人都能连人人的自由会不会反而成了容易过拟合的缺点Transformer 正式登场。下一篇看 Informer / Autoformer 如何驯服 O(L²)让注意力吃下超长序列。