想象你手里有一卷很长的生活底片——比如一座城市一整年的气温记录,每秒一格,长得一眼望不到头。直接盯着整卷底片找规律,眼睛很快就花了:今天和昨天的走势明明有关联,可中间隔着几千格,细节早就糊成一团;底片上的灰尘(也就是噪声)还把局部纹理盖得密密麻麻。一位聪明的整理师想了个办法:先把底片按固定宽度裁成一格格标准小照片,统一调亮度、贴上编号、扫描成数字,再请一位“相册整理师”通盘打量小照片之间的亲疏关系,最后拼出下一张照片的样子。这就是 PatchTST 的核心思路——先把时间序列切成小块(Patch),再交给 Transformer 去品味块与块的关联,最终一次性输出未来多步预测。本篇文章就用这位整理师的故事,带你从头看懂 PatchTST 的每一个关键环节。
一句话价值:PatchTST 是目前时间序列深度学习预测的主流基线之一,掌握“分块 + Transformer 改造”的整套思路,能直接提升你在电力、金融、工业等场景中构建长序列预测模型的能力。
可视化演示
本节配有交互动效(进入视口后自动加载,约 3KB)。
时间序列分块策略 分块参数说明 分块将长序列压缩为少量patch token,大幅降低计算量 通道独立性设计 原始Transformer: O(336²) = 112,896 PatchTST时间序列分块Transformer可视化:分块策略、通道独立、Transformer编码及预测效果。
痛点背景
整理师小 P 摊开一卷三百天的气温底片,每秒一格,长到在灯箱上绕了三圈。她想直接看出“明天大概多少度”,可盯着整卷看了一会儿就眼花:远处的走势和近处的波动叠在一起,底片上的灰尘(噪声)还把局部纹理盖得模模糊糊。她心想:这样硬看,难怪什么都看不出来。
这正是直接拿长序列训练 Transformer 的困境。时间序列通常表示为一个矩阵 X,行是时间,列是变量。朴素做法把每个时间点当做一个 token 送进注意力层,序列一长,注意力矩阵就变成 L×L 的巨型方阵,算力吃紧;而相距遥远的 token 之间,注意力权重早被噪声稀释,模型很难抓住真正有用的长程依赖,局部细节更是一闪而过。
先把输入的定义写清楚。一条长度为 L、共有 C 个变量通道的时间序列,记作:
小 P 把底片重新卷起来叹了口气:直接整卷硬看是死路。她决定换个思路——像剪照片一样先把底片裁成小段,让每段内部的纹理先清晰起来,再观察段与段的关系。于是,“分块”的想法诞生了。
- $X$整段输入序列,表示成一张 L 行 C 列的二维表格
- $L$时间维长度,即底片上总共有多少个采样点
- $C$变量通道数,比如同时采集了温度和湿度两路数据
分块策略
小 P 拿出裁纸刀,定下两条规则:每张照片宽 P 格,每裁一刀往前滑动 S 格。这样底片被切成一组互相重叠的小照片,每张都有完整清晰的局部纹理。关键问题是:P 和 S 怎么定?定得太宽,一整天的变化被塞进一块,细节糊掉;定得太窄,又退回逐点建模的老路。
这就是 PatchTST 的核心操作——分块(Patching)。Patch 长度 P 决定每块包含多少个连续时间点,步长 S 决定相邻两块的重叠程度。分块把“每个时间点一个 token”变成“每段窗口一个 token”,token 数量从 L 降到约 L/S,后续注意力计算量大幅减少。如果序列尾部不足一个 patch,就做边界补齐:补零或复制最后一段。
第 i 个 patch 是原序列的一个连续切片,个数由长度、块宽和步长共同决定:
底片剪好了,一格格小照片整齐地摆在台面上。小 P 松了一口气:接下来要处理的“对象”从几千个时间点变成了几十张照片,清爽多了。
- $x_p^{(i)}$第 i 个 patch,它就是底片上从 t_i 到 t_i+P 的这一小段照片
- $t_i$第 i 个 patch 的起始位置,由步长累加得到
- $N$patch 总数,由序列长度、patch 长度和步长共同决定,向下取整后加 2(首尾各补一段)
实例归一化
剪出来的照片有的在深夜拍(均值低、波动小),有的在正午拍(均值高、波动大)。直接放一起对比,亮度差异会干扰判断。小 P 先把每张照片的亮度调到统一标准——减去平均亮度,除以亮度波动,让每张照片的“明暗基线”一致。
这就是实例归一化(Instance Normalization,简称 IN)。它对每个样本、每个变量通道独立计算均值 μ 和标准差 σ,然后做标准化。做完后序列均值为 0、方差为 1,消除了不同时间段分布偏移的影响。注意这一步是在“切块之前”对整段原始序列做的,和 Transformer 内部的 LayerNorm 分工不同:一个管输入尺度,一个管深层特征。
预测完成后,还要把输出的均值方差“翻译”回原始尺度,即反归一化,让预测数值落在原数据的量纲内:
小 P 调好亮度后,才发现“深夜照片”和“正午照片”确实藏着不同的局部规律——之前被明暗差异掩盖的模式,现在清清楚楚地浮现出来。
- $\mu_c$第 c 个通道在时间维上的均值,代表这段序列的“平均亮度”
- $\sigma_c$第 c 个通道的标准差,衡量序列围绕均值波动的幅度
- $\hat{X}$标准化后的序列,均值归零、方差归一,公式中 ε 是防止除以零的小常数
嵌入编码
照片是图像,Transformer 只认数字。小 P 把每张照片扫描成一串像素向量,并在照片背面写上序号,防止整理时把顺序弄乱。这一步在模型里叫嵌入(Embedding):把原始数值变成模型能消化的向量。
分块后的每个 patch 形状为 [P](一串长度为 P 的数值)。通过一个可学习线性层(Patch Embedding),把它映射为 d_model 维向量:
映射之后还要加上位置编码(Positional Encoding)。$E_{pos}$ 是给每个 patch 预先算好的“顺序标签向量”,让模型知道哪张照片在前、哪张在后。PatchTST 的一个关键设计是通道共享:不同变量通道(温度、湿度、电价……)共用同一套嵌入和后续注意力参数,既大幅减少参数量,又让各通道学到统一的局部模式。
台面上整整齐齐摆着小 P 的“数字照片”,全部编好号。现在,就等相册整理师大驾光临了。
- $W_e, b_e$可学习的线性映射参数,把 P 维的 patch 压缩成 d_model 维向量
- $E_{pos}$位置编码矩阵,每行对应一个 patch 的顺序标签
- $Z$加上位置信息后的 patch 向量序列,是 Transformer 编码器的真正输入
注意力机制
相册整理师上场了。她不会一张张孤立地看照片,而是把每张照片的摘要向量同时摊开,两两比对:夏日午后的照片和深夜的海边照片有没有呼应?节假日的用电曲线和上周同一天像不像?比对之后,给关系密切的照片分配更高的“关注权重”。
这就是自注意力(Self-Attention)。嵌入向量 Z 分别乘上三个权重矩阵,得到查询 Q、键 K、值 V。注意力分数等于 Q 与 K 的点积除以 √d_k 再做 softmax——分数高代表两个 token 关联强,输出就是按权重汇总的 V。PatchTST 还用了多头注意力(Multi-Head Attention),相当于好几位整理师从不同角度同时审视照片,最后把意见合并;多个变量通道之间则共享注意力权重,进一步压低参数量。
几轮比对之后,整理师心里有数了:哪些照片是“老朋友”,哪些素不相识。她把这些亲疏关系牢牢记住,准备开始拼下一张照片。
- $Q, K, V$查询、键、值,由嵌入向量 Z 乘三个权重矩阵得到,“查询”负责提问,“键”负责被匹配,“值”才是真正要取的信息
- $QK^T$点积打分矩阵,衡量两两之间的相关程度
- $/\sqrt{d_k}$缩放因子,防止点积数值过大导致 softmax 进入饱和区
- softmax 后乘 V把分数归一化成权重,再对 V 做加权求和,输出融合全局信息的向量
预测头
看完全部照片,小 P 要开工预测下一张了。她把所有照片的“观后感”汇总成一条长长的工作笔记(展平向量),再经过一道线性变换,直接画出未来 24 小时的气温曲线草图——不是一段一段地猜,而是一口气画出整段未来。
Transformer 编码器输出的特征 Z^(L) 形状为 [N, d_model],N 个 patch 每个都有 d_model 维。预测头先把这些向量展平成一维,再通过线性层映射到目标长度 T,一次输出未来 T 步的预测。不同变量通道各走各的预测头,互不干扰,保留了通道独立性;这也避开了逐点自回归的“误差累积”问题——草图是一次成型,不用一步错步步错。
草图完成后,别忘了把之前“调暗的亮度”调回来——反归一化一上,预测曲线立刻变回真实的温度数值。小 P 看着纸上完整的未来曲线,满意地点了点头。
- $Z^{(L)}$最后一层编码器输出的特征,N 行 d_model 列
- $\text{Flatten}$把 N×d_model 展平成一条 N·d_model 维的长向量
- $W_h, b_h$输出层的权重和偏置,把长向量映射到未来 T 步的预测值
效果优势
同样一卷底片,老方法要盯着每一个时间点做两两比对,等于数万次对比;小 P 的方法先把底片剪成几十张照片,只需在这些照片之间做比对,工作量骤降,而且照片上的局部纹理看得更清。这就是 PatchTST “又快又准”的秘密。
量化来看,原始 Transformer 的自注意力复杂度是 O(L²),L 是序列长度。分块后 token 数约为 L/S,复杂度降为 O((L/S)²)。当 L=1000、S=10 时,注意力矩阵从 100 万格缩到 1 万格,整整两个数量级。此外,每个 patch 聚合了 P 个连续时间点的信息,天然具备局部感受野,比逐点建模更抗噪声;参数大幅减少也缓解了过拟合,泛化能力随之提升。在多个长序列预测基准上,PatchTST 正是靠这套组合拳刷新了最好成绩。
小 P 的整理法既省力气又抓得住重点——效率与精度双赢。她把这套方法命名为“先剪照片,再看关系”,工整地写进了工作手册。
- $O(L^2)$逐点建模时,L 个 token 两两计算注意力分数,矩阵规模是 L×L
- $N \approx L/S$分块后 token 数量从 L 骤降到约 L/S
- $O((L/S)^2)$新复杂度,注意力矩阵变成 N×N
实践调参
每个整理师都有自己的趁手工具参数:照片剪多宽、每刀挪几步、请几位整理师同时看(注意力头数)、看几轮(编码器层数)。参数调得合适,整理又快又准;调得离谱,再好的底片也白搭。
实践中的常见配置:patch 长度 P 取 16 或 24,步长 S 取 8 或 12(约为 P 的一半到三分之一),编码器 2-4 层,注意力头数 4-8。预测总长度 T 根据业务定,比如未来 24 小时或未来 7 天。训练损失常用预测值与真实值的均方误差(MSE),验证时把数据集严格按时间顺序切出训练/验证/测试三段,防止未来信息泄漏。
小 P 把工作台参数记进笔记本:P=24、S=12、两层编码器、四个注意力头。下次再来一卷底片,她就能直接按这套流程开工了。
- $\hat{y}_{c,t}, y_{c,t}$第 c 个通道第 t 步的预测值与真实值
- 双重求和对每个通道、每个未来时刻的误差平方累加
- $\frac{1}{CT}$除以总项数求平均,得到最终的均方误差
AI 应用场景
电网短期负荷预测
阶段:数据预处理与预测建模
解决的问题:电网调度需要预测未来 24 小时负荷曲线。传统 ARIMA 难以捕捉早晚高峰的局部模式与跨天相似性;直接用整段序列训练 Transformer 又因序列过长、噪声多而效果差,注意力被大量无关时段稀释。
具体案例:某省级电网把过去 14 天每 15 分钟一条的负荷记录(共 1344 个点)按 patch 长度 24、步长 12 分块,用 PatchTST 预测未来 96 个点(未来 24 小时)。分块后模型先看清晨、午间、晚高峰各块内的局部纹理,再利用注意力关联“今天晚高峰与昨天晚高峰”的跨天模式,MAPE 比 ARIMA 降低约 30%。
金融波动率预测
阶段:特征提取与序列回归
解决的问题:5 分钟 K 线波动率序列长且噪声大,传统 GARCH 模型强假设线性关系,深度模型逐点建模则计算代价高、局部突变被抹平。整理师小 P 的分块思路在这里同样适用:先把波动率曲线剪成小段,捕捉“开盘急涨急跌”这类局部模式,再关联隔夜与开盘的长期依赖。
具体案例:某量化团队用 PatchTST 预测次日 5 分钟波动率曲线,输入过去 5 天共 1440 个点,patch 长度 48、步长 24,输出未来 288 个点。回测中用于期权定价的波动率预测,夏普比率较 GARCH 基线提升明显。
工业设备预测性维护
阶段:传感器信号异常预测
解决的问题:设备振动传感器持续采集高频信号,异常往往体现在几秒内的局部突变,而设备劣化又是跨小时、跨天的缓慢趋势。逐点建模既算不动又抓不住局部异常;PatchTST 分块让模型聚焦局部波形,再通过全局注意力关联同类故障的历史模式。
具体案例:风电齿轮箱振动数据的剩余寿命预测中,工程师把每 10 分钟一段的振动序列分块后输入 PatchTST,模型提前 3 小时预警异常状态,误报率低于 LSTM 基线,给运维留出了宝贵的检修窗口。
Python 演示
import numpy as np def generate_series(length=480): """生成带趋势和噪声的正弦序列, 模拟连续采样的温度数据""" t = np.arange(length) return np.sin(2 * np.pi * t / 24) + 0.01 * t + 0.1 * np.random.randn(length) def instance_norm(x, eps=1e-5): """按样本做标准化, 抹平序列均值与方差的分布偏移""" mu = x.mean(axis=-1, keepdims=True) sigma = x.std(axis=-1, keepdims=True) return (x - mu) / (sigma + eps), mu, sigma def patchify(x, patch_len=24, stride=12): """滑动窗口切分, 把一维序列切成若干固定长度的小块""" n_patches = (len(x) - patch_len) // stride + 1 patches = [x[i * stride:i * stride + patch_len] for i in range(n_patches)] return np.stack(patches) def linear_map(patches, in_dim, out_dim, seed=42): """可学习的线性嵌入, 每个 Patch 压缩成一个 d_model 维向量""" rng = np.random.RandomState(seed) W = rng.randn(in_dim, out_dim) * 0.05 b = rng.randn(out_dim) * 0.01 return patches @ W + b def attention(z, seed=7): """极简自注意力, 每个 Patch 向量两两打分后按亲疏加权汇总""" rng = np.random.RandomState(seed) d = z.shape[-1] W_q = rng.randn(d, d) * 0.05 W_k = rng.randn(d, d) * 0.05 W_v = rng.randn(d, d) * 0.05 q = z @ W_q k = z @ W_k v = z @ W_v scores = q @ k.T / np.sqrt(d) weights = np.exp(scores - scores.max(axis=-1, keepdims=True)) weights = weights / weights.sum(axis=-1, keepdims=True) return weights @ v def predict(series, patch_len=24, stride=12, d_model=32, horizon=24): """极简 PatchTST 推理: 归一化 -> 分块 -> 嵌入 -> 注意力 -> 预测头""" x_norm, mu, sigma = instance_norm(series) patches = patchify(x_norm, patch_len, stride) z = linear_map(patches, patch_len, d_model) z = z + np.arange(z.shape[0])[:, None] * 0.001 # 简化位置编码, 标记先后顺序 context = attention(z) rng = np.random.RandomState(0) W_head = rng.randn(context.shape[-1], horizon) * 0.05 y_norm = context.mean(axis=0) @ W_head # 全局摘要映射到未来 horizon 步 return y_norm * sigma[0] + mu[0] # 反归一化还原到原始尺度 if __name__ == "__main__": data = generate_series(480) forecast = predict(data, horizon=24) print("未来 24 步预测(前 5 个):", np.round(forecast[:5], 3))
sigma = x.std(axis=-1, keepdims=True)按样本最后一维(时间轴)求标准差,keepdims 保持维度便于广播,和均值一起构成归一化所需的“亮度基准”n_patches = (len(x) - patch_len) // stride + 1计算能切出多少块:总长度减去窗口长度,除以步长后向下取整patches = [x[i * stride:i * stride + patch_len] for i in range(n_patches)]滑动窗口取块,每块长度 patch_len,窗口每次移动 stride 步,对应“裁纸刀”的动作W = rng.randn(in_dim, out_dim) * 0.05随机初始化线性映射权重;乘以 0.05 让初始值偏小,避免嵌入向量数值过大scores = q @ k.T / np.sqrt(d)注意力打分:查询与键做点积后除以维度平方根,防止分数过大weights = np.exp(scores - scores.max(axis=-1, keepdims=True))softmax 的分子,先减最大值防止指数爆炸,数值稳定性技巧context.mean(axis=0) @ W_head简化预测头:把每个 patch 的特征取平均得到全局摘要,再映射到未来 horizon 步return y_norm * sigma[0] + mu[0]反归一化:把标准化尺度下的预测还原为原始数据的量纲,对应“把调暗的亮度调回来”
常见误区
误区patch 长度 P 越大,每块包含的信息越多,模型效果一定更好。干脆把整个序列都塞进一个 patch,不是最省事吗?
正解P 过大会把不同模式的信号混在同一块里,局部细节被“平均”掉,注意力反而难以分辨块内的结构;P 过小又退化成逐点建模。P 要和步长 S 一起决定 token 数量与感受野,通常参考数据周期来选,比如日周期数据 P 取 24 的约数。
为何常见:直观上“信息多 = 效果好”,忽略了块内混叠和计算效率之间的平衡。
误区patch 本身是一小段连续数据,模型能从内容推断先后顺序,再加位置编码是多余的。
正解patch 内部有顺序,但 patch 之间谁先谁后,只有位置编码能告诉模型。没有它,注意力矩阵会把所有 patch 当作无序集合,完全丢失先后依赖——就像把照片顺序打乱再让整理师找规律,亲疏关系全乱了。
为何常见:混淆了“块内有序”与“块间有序”,低估了 Transformer 对顺序的天然无感。
误区Transformer 内部已经有 LayerNorm,再做实例归一化不是重复了吗?
正解LayerNorm 在特征维度上做,处理的是深层特征的尺度;实例归一化在样本的时间维度上做,消除的是不同时间段均值方差的分布漂移。反归一化保证输出回到原量纲。二者分工不同,不能互相替代。
为何常见:看到“归一化”三个字就觉得是同一个东西,没有细看作用在哪个维度。
误区既然名字里带 Transformer,性能提升当然都归功于自注意力机制。
正解注意力只是其中一环。分块提供局部感受野,实例归一化消除分布漂移,通道共享减少过拟合,预测头直接多步输出避免误差累积——这些因素协同贡献。论文消融实验里去掉任何一环,精度都会明显下降。
为何常见:模型名字自带光环,默认注意力“一人立功”,忽略了工程细节的合力。
误区步长 S=1 时相邻 patch 完全重叠,每个时间点都被覆盖到,信息零丢失,效果肯定最好。
正解S 小确实保留更多重叠信息,但 token 数接近 L,注意力复杂度又回到 O(L²),分块的意义被抵消。论文实验表明,适度的 S(如 P/2 或 P/3)在精度与效率之间最优。
为何常见:只盯着“信息无损”,没算算复杂度账——代价是省下的算力又烧回去了。
面试题
Q1. PatchTST 中的"Patch"指的是什么?
- A.把时间序列切成若干固定长度的小块← 正确答案
- B.对时间序列整体做傅里叶变换
- C.把时间序列随机打乱再重组
- D.把每个时间点单独作为一个 token
答案:A。Patch 是把原始序列按固定长度 P 切出的小块,类似图像处理中的 patch。B 是频域方法,C 会破坏时序顺序,D 是原始 Transformer 的逐点做法,都不是 PatchTST 的分块思路。
Q2. 若序列长度 L=100,patch 长度 P=20,步长 S=10,分块数量 N 约为多少?
- A.9 块,比正常情况偏少
- B.10 块,与公式计算吻合← 正确答案
- C.20 块,相当于等长分割
- D.5 块,明显少于预期值
答案:B。代入公式 N = ⌊(L−P)/S⌋ + 2 = ⌊(100−20)/10⌋ + 2 = 8 + 2 = 10。C 是把 L 直接除以 P 得到 5 再翻倍,属于误算;A 和 D 是常见估算错误。
Q3. 实例归一化(Instance Normalization)在 PatchTST 中的作用包括哪些?
- A.消除序列均值和方差的分布偏移← 正确答案
- B.让不同变量通道的量纲可比← 正确答案
- C.提升模型对分布漂移的鲁棒性← 正确答案
- D.将 patch 总数直接减少一半
答案:ABC。实例归一化对每个样本每个通道减均值除标准差,使分布对齐到零均值单位方差,因此 A、B、C 都正确。它只改变数值尺度,不改变分块数量,D 错。
Q4. PatchTST 将注意力复杂度从 O(L²) 降为 O((L/S)²),根本原因是什么?
- A.patch 数量远超原始时间步的数量
- B.token 数量从 L 减少到约 L/S← 正确答案
- C.注意力头数从 8 个缩减到 2 个
- D.编码器层数从 6 层减少到 3 层
答案:B。注意力复杂度取决于 token 数量 N 的平方。分块后 N ≈ L/S,所以复杂度是 (L/S)²。A 说反了;C、D 是模型结构改动,与分块无关。
Q5. 位置编码在 PatchTST 中的主要作用是什么?
- A.记录 patch 在原始序列中的顺序← 正确答案
- B.放大不同 patch 的数值差异
- C.替代归一化完成分布对齐
- D.减少多头注意力的参数
答案:A。Transformer 本身对顺序无感,位置编码给每个 patch 贴上“第几张”的标签,让注意力知道先后关系。B 曲解了编码目的,C、D 与位置编码无关。
Q6. 分块时若序列长度不能被 patch 长度整除,常见的处理方式有哪些?
- A.尾部补零或复制最后一段拼满← 正确答案
- B.直接丢弃尾部不足一段的数据← 正确答案
- C.调整步长让所有位置都覆盖到← 正确答案
- D.将整个序列整体平移后再切
答案:ABC。补零/复制、丢弃不足段、调整步长都是工程上处理尾部残段的可行手段。D 整体平移并不能解决“最后一段不满”的问题,属于无效操作。
Q7. 关于 patch 长度 P 的选择,下列说法正确的是哪一项?
- A.P 越大局部信息完整但块数越少← 正确答案
- B.P 越小越好因为细节永不丢失
- C.P 不影响模型预测的效果
- D.P 只影响速度不影响精度
答案:A。P 决定每块包含多少连续时间点,P 大则局部上下文完整但 token 数变少,P 小则反之。B 忽略块内混叠,C、D 都否认了 P 对精度的影响,均错误。
Q8. 关于通道共享(channel-wise sharing)在 PatchTST 中的含义与收益,下列说法正确的有哪些?
- A.多个变量通道共用同一套嵌入参数← 正确答案
- B.减少模型参数并缓解过拟合风险← 正确答案
- C.让不同变量通道互相交换数值
- D.大幅缩短每个 batch 的训练时间
答案:AB。通道共享指多个变量通道共用嵌入和注意力权重,参数变少、过拟合风险降低,A、B 正确。共享不等于交换数值,C 错;参数减少不等于训练必然加速,D 不是共享的直接收益。
Q9. PatchTST 预测头直接输出未来 T 步预测,与逐点自回归相比的优势是什么?
- A.避免误差逐点累积,一次得到整段预测← 正确答案
- B.预测结果总是比自回归更平滑
- C.完全不需要依赖任何历史数据
- D.计算复杂度比分块建模更低
答案:A。直接多步输出没有“上一步误差喂给下一步”的链条,误差不会逐点累积;B 说“总是”过于绝对,平滑度与数据有关;C 违背预测基本前提;D 对比对象错误。
Q10. 训练 PatchTST 预测模型时,最常用的损失函数是哪一个?
- A.预测值与真实值之间的均方误差← 正确答案
- B.图像分类任务常用的交叉熵损失
- C.对比学习中使用的 InfoNCE 损失
- D.生成对抗网络的判别器损失
答案:A。时序预测是回归任务,均方误差(MSE)衡量预测曲线与真实曲线的数值差距,是最常用的损失。B 用于分类,C 用于学习表征,D 用于对抗生成,都不适用。