Transformers 中的 PatchTST 模型详解:基于 Patch 与通道独立的多元时序预测与自监督表征学习
【免费下载链接】transformers🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers
导读
本文围绕 🤗 Transformers 开源仓库中 PatchTST 时间序列 Transformer 模型展开,涵盖其核心设计思想(子序列级 Patch 切分、通道独立、掩码自监督预训练)、完整配置参数说明,以及其在预测(Prediction)、分类(Classification)、回归(Regression)与预训练(Pretraining)四大任务上的实际用法。读完本文,你将能够基于 PatchTSTConfig 从零配置模型、加载预训练权重,并把 PatchTST 应用到多元时间序列的长程预测与表征学习中。
PatchTST 是什么:模型概述
PatchTST(Patch Time Series Transformer)最早由 Yuqi Nie、Nam H. Nguyen、Phanwadee Sinthong 与 Jayant Kalagnanam 在论文《A Time Series is Worth 64 Words: Long-term Forecasting with Transformers》中提出。该模型于 2023-11-13 被贡献至 Hugging Face Transformers 仓库,并由 IBM 与 Hugging Face 团队共同维护,相关实现位于 src/transformers/models/patchtst/。
从论文摘要看,PatchTST 的设计目标是为多元时间序列预测与自监督表征学习提供一种高效的 Transformer 方案。它的有效性来自两个关键组件:
- 子序列级 Patch 切分(patching):把时间序列分割成若干子序列片段(patch),作为 Transformer 的输入 token;
- 通道独立(channel-independence):每个通道是一条单变量时间序列,所有序列共享同一套 embedding 与 Transformer 权重。
论文指出 Patch 化设计天然带来三重收益:
- 局部语义信息被保留在 embedding 中;
- 在给定相同回看窗口(look-back window)时,注意力图的计算量与内存占用呈平方级缩减;
- 模型可以关注更长的历史。
而通道独立的 Patch 时间序列 Transformer(PatchTST)与当时的 SOTA Transformer 模型相比,能显著提升长程预测精度;同时论文将其应用于自监督预训练任务,在大型数据集上取得了优于有监督训练的下游微调性能,跨数据集迁移掩码预训练表征也能带来 SOTA 级别的预测精度。
注意:原文模型论文于 2022-11-27 发布,模型于 2023-11-13 贡献到 Transformers。仓库当前文档声明该模型默认检查点为
ibm-granite/granite-timeseries-patchtst(见 configuration_patchtst.py 的@auto_docstring装饰器)。
架构总览
在 Transformers 仓库的实现里,PatchTST 前向数据流可以清晰概括为一条流水线。以 PatchTSTModel.forward 为入口,处理过程依次为:
- 输入缩放:
PatchTSTScaler根据配置对输入past_values做标准化,返回缩放后的数据及loc(均值)、scale(标准差); - Patch 化:
PatchTSTPatchify沿时间维用unfold把缩放后的序列切成[batch_size, num_channels, num_patches, patch_length]的张量; - 掩码(可选):若开启预训练掩码(
do_mask_input),PatchTSTMasking随机或按预测式掩码 patch; - Transformer Encoder:
PatchTSTEncoder先通过PatchTSTEmbedding将每个 patch 线性投影为d_model维向量,再加上PatchTSTPositionalEncoding,随后堆叠多层PatchTSTEncoderLayer; - 输出:Encoder 输出的
last_hidden_state形状为[batch_size, num_channels, num_patches, d_model](若use_cls_token=True则为num_patches+1)。
关键模块类(如PatchTSTAttention、PatchTSTEncoderLayer、PatchTSTPatchify、PatchTSTMasking、各类 scaler 与 head)均定义在 modeling_patchtst.py 中。其中PatchTSTEncoderLayer按「时间维注意力 →(可选)通道维注意力 → 前馈网络」的三子层结构组织,允许各通道分别 attend 时间位置,也可通过channel_attention=True开启通道之间的互相注意力。
快速上手:配置与基本使用
PatchTSTConfig是模型的配置类,位于 configuration_patchtst.py,源码 docstring 给出了最简用法:
from transformers import PatchTSTConfig, PatchTSTModel # Initializing an PatchTST configuration with 12 time steps for prediction configuration = PatchTSTConfig(prediction_length=12) # Randomly initializing a model (with random weights) from the configuration model = PatchTSTModel(configuration) # Accessing the model configuration configuration = model.config这里有一个值得注意的细节:直接构造的是随机初始化权重的模型,用于训练从零开始。若要进行推理或迁移学习,应使用PatchTSTForPrediction.from_pretrained("namctin/patchtst_etth1_forecast")之类的方式加载 Hub 上的预训练权重。仓库的attribute_map(configuration_patchtst.py)将通用命名hidden_size、num_attention_heads、num_hidden_layers分别映射到 PatchTST 专属的d_model、num_attention_heads、num_hidden_layers,因此从AutoConfig/AutoModel体系加载时接口与其他模型保持一致。
在 Auto API 层面,PatchTST 已注册到以下映射(见 auto_mappings.py 与 modeling_auto.py):
AutoConfig→PatchTSTConfigAutoModel→PatchTSTModel- 时间序列分类映射(
MODEL_FOR_TIME_SERIES_CLASSIFICATION_MAPPING)→PatchTSTForClassification - 时间序列回归映射(
MODEL_FOR_TIME_SERIES_REGRESSION_MAPPING)→PatchTSTForRegression
PatchTSTConfig 全部参数详解
以下参数表综合自 configuration_patchtst.py 的默认值与 docstring,均以实际仓库实现为准。
输入与数据形状
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
num_input_channels | int | 1 | 输入序列的通道数,即多元时间序列的变量维度 |
context_length | int | 32 | 输入序列(回看窗口)的时间步长度 |
prediction_length | int | 24 | 模型要输出的预测水平(horizon) |
scaling | str/bool/None | "std" | 输入缩放方式。"mean"用均值缩放,"std"用标准差缩放,None表示不缩放;若传True等价于"mean" |
关于scaling,代码层面在 modeling_patchtst.py 的PatchTSTScaler中选择底层 scaler:"mean"/True→PatchTSTMeanScaler,"std"→PatchTSTStdScaler,其余 →PatchTSTNOPScaler(恒等缩放)。PatchTSTStdScaler沿时间维统计loc与scale并执行(data - loc) / scale标准化,且设置minimum_scale=1e-5防止除零;PatchTSTMeanScaler则用加权平均绝对值作为缩放因子。
输出与损失
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
distribution_output | str | "student_t" | 当loss="nll"时使用的分布发射头,可选"student_t"、"normal"、"negative_binomial" |
loss | str/None | "mse" | 模型损失。参数化分布对应负对数似然"nll",点估计对应均方误差"mse" |
num_targets | int | 1 | 回归/分类任务的输出目标数;对分类任务即类别数 |
output_range | list/None | None | 回归任务的输出值范围,用于约束模型输出值落在给定区间内 |
num_parallel_samples | int | 100 | 概率预测时并行生成的样本数 |
从实现看,loss == "mse"时 head 使用线性层(点估计),否则根据distribution_output构造StudentTOutput、NormalOutput或NegativeBinomialOutput(三者来自 time_series_utils.py 的公共实现),训练时以负对数似然为损失。若设置output_range=[low, high],回归头在线性输出后套用torch.sigmoid(x) * (high - low) + low把预测值约束到区间内(见 modeling_patchtst.py)。
Patch 切分
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
patch_length | int | 1 | patch 切分的片段长度 |
patch_stride | int | 1 | patch 切分的滑动步长 |
patch 数量由PatchTSTPatchify计算:num_patches = (max(context_length, patch_length) - patch_length) // patch_stride + 1(modeling_patchtst.py)。若context_length <= patch_length会抛出异常,因为序列长度必须大于 patch 长度。对回看窗口不整除的残余部分,实现会用sequence_start = context_length - new_sequence_length从序列末尾对齐开始切片(即只取能被 patch 完全覆盖的最后一段),这是把一段长历史“浓缩”为若干 token 的关键。
Transformer 结构
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
num_hidden_layers | int | 3 | Encoder 层数 |
d_model | int | 128 | Embedding / 隐藏维度(通用命名hidden_size映射到它) |
num_attention_heads | int | 4 | 每层注意力头数 |
share_embedding | bool | True | 是否让所有通道共享输入 embedding |
channel_attention | bool | False | 是否在 Transformer 中开启通道注意力块,让各通道互相 attend |
ffn_dim | int | 512 | Transformer 前馈网络中间层维度 |
norm_type | str | "batchnorm" | 每层归一化类型,可选"batchnorm"或"layernorm" |
norm_eps | float | 1e-5 | 归一化分母中用于数值稳定的小量 |
attention_dropout | float | 0.0 | 注意力 dropout 概率(配置类属性,默认 0.0) |
positional_dropout | float | 0.0 | 位置编码层 dropout |
path_dropout | float | 0.0 | 残差路径(drop path)dropout |
ff_dropout | float | 0.0 | 前馈网络两层之间的 dropout |
bias | bool | True | 前馈网络是否加 bias |
activation_function | str | "gelu" | Transformer 中的激活函数,支持"gelu"与"relu" |
pre_norm | bool | True | 为True时归一化在自注意力之前(Pre-LN);否则在残差块之后 |
positional_encoding_type | str | "sincos" | 位置编码类型,支持"random"与"sincos" |
use_cls_token | bool | False | 是否使用 cls token |
init_std | float | 0.02 | 截断正态权重初始化的标准差 |
其中PatchTSTBatchNorm是一种把 BatchNorm 应用到时间维(sequence)的实现:先transpose(1, 2)再执行nn.BatchNorm1d(d_model)(modeling_patchtst.py),这与普通 NLP Transformer 的 LayerNorm 归一化维度策略不同,是 PatchTST 官方实现保留的风格,可通过norm_type切换。
sincos位置编码沿用 Transformer 原始三角函数方案,并做了去均值、按std*10归一化的处理,且参数被设为requires_grad=False(不参与训练);random位置编码则为可学习的nn.Parameter(modeling_patchtst.py)。若use_cls_token=True,位置编码长度会 +1,cls token 会拼接在 patch token 序列最前面。
预训练掩码
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
do_mask_input | bool | None | 预训练阶段是否对输入施加掩码 |
mask_type | str | "random" | 掩码类型,目前仅支持"random"与"forecast" |
random_mask_ratio | float | 0.5 | 随机预训练时对输入数据的掩码比例 |
num_forecast_mask_patches | int/list | [2](源码默认(2,)) | 每个 batch 样本末尾被掩码的 patch 数。若为 int,则所有样本掩码数相同;若为 list,则各样本按 list 内数值随机掩码,仅用于 forecast 预训练 |
channel_consistent_masking | bool | False | 若为True,所有通道采用相同的掩码模式 |
unmasked_channel_indices | list/None | None | 预训练时不被掩码的通道索引,取值在 1 到num_input_channels之间 |
mask_value | int | 0 | 掩码 patch 位置填充的值 |
掩码逻辑分为两种,均由PatchTSTMasking调度(modeling_patchtst.py):
random_masking(L175-L230):按random_mask_ratio对 patch 做类 MAE 的随机掩码——按随机噪声排序,保留前len_keep个 patch,其余填充mask_value;mask_ratio必须满足0 <= ratio < 1;forecast_masking(L233-L298):把每个样本末尾的 K 个 patch掩掉,模拟“看过去预测未来”的任务形态;若给定 list 长度,会在 batch 内按比例混合多种掩码长度(要求每个值满足0 < K < 总 patch 数)。
两者的输出都会附带回原形状的 mask 张量,供计算仅作用于被掩码 patch 的重建损失。
五个模型类的定位与用法
仓库在 modeling_patchtst.py 中导出了五个与任务对应的模型类(__all__,见文件尾部),对应文档中的PatchTSTModel、PatchTSTForPrediction、PatchTSTForClassification、PatchTSTForPretraining、PatchTSTForRegression。
PatchTSTModel:基础 Transformer 编码器
PatchTSTModel是只有 Encoder 的基础模型,包含缩放器(scaler)、patch 化器(patchifier)、可选掩码模块与编码器栈。它用于特征提取(feature extraction),例如为下游自定义 head 获取时间序列的表征。forward 的完整签名与示例见 PatchTSTModel,典型调用如下:
from huggingface_hub import hf_hub_download import torch from transformers import PatchTSTModel file = hf_hub_download( repo_id="hf-internal-testing/etth1-hourly-batch", filename="train-batch.pt", repo_type="dataset" ) batch = torch.load(file) model = PatchTSTModel.from_pretrained("namctin/patchtst_etth1_pretrain") # during training, one provides both past and future values outputs = model( past_values=batch["past_values"], future_values=batch["future_values"], ) last_hidden_state = outputs.last_hidden_state其输入输出要点:
past_values:[bs, sequence_length, num_input_channels]的过去观测序列(必填);past_observed_mask:[bs, sequence_length, num_input_channels]的布尔张量,1 表示观测到、0 表示缺失(NaN 被零填充的位置);缺省时全为 1;future_values:供训练期提供标签的预测目标;- 输出
PatchTSTModelOutput除last_hidden_state、hidden_states、attentions外,还返回mask、loc、scale、patch_input,方便上游任务头做反缩放与掩码重建(L748-L773)。
PatchTSTForPrediction:长程预测(确定性 + 概率性)
预测模型由PatchTSTModel+PatchTSTPredictionHead组成(L1560-L1698)。预测头会根据loss配置选择线性点估计头,或student_t/normal/negative_binomial分布头;share_projection(默认True)决定所有通道是否共享同一投影层,use_cls_token/pooling_type决定如何把 patch 维聚合到预测。文档示例:
from huggingface_hub import hf_hub_download import torch from transformers import PatchTSTConfig, PatchTSTForPrediction file = hf_hub_download( repo_id="hf-internal-testing/etth1-hourly-batch", filename="train-batch.pt", repo_type="dataset" ) batch = torch.load(file) # Prediction task with 7 input channels and prediction length is 96 model = PatchTSTForPrediction.from_pretrained("namctin/patchtst_etth1_forecast") # during training, one provides both past and future values outputs = model( past_values=batch["past_values"], future_values=batch["future_values"], ) loss = outputs.loss loss.backward() # during inference, one only provides past values, the model outputs future values outputs = model(past_values=batch["past_values"]) prediction_outputs = outputs.prediction_outputs实现上,训练损失在点估计模式为MSELoss;分布模式下把 head 输出套上distribution_output.distribution(y_hat, loc, scale)计算负对数似然并用weighted_average做 mask 感知的平均(L1672-L1682)。确定性预测时模型输出会先经y_hat * scale + loc反缩放还原到原始量纲,这一点对实际使用至关重要。
若需概率性预测(不确定性量化),可调用model.generate(past_values=..., past_observed_mask=...):分布头下会采样num_parallel_samples条路径,返回SamplePatchTSTOutput.sequences,形状为[bs, num_samples, prediction_length, num_input_channels](L1701-L1746)。
PatchTSTForPretraining:掩码自监督预训练
自监督预训练通过掩码 patch 重建实现,整体等价于针对时间序列的 MAE 风格任务:先随机或 forecast 掩码,再让模型重建被掩码的部分,用 MSE 只统计被掩码 patch 的损失。类构造时会强制把do_mask_input置为True(L1212-L1218)。文档示例同时覆盖两种掩码策略的配置写法:
from huggingface_hub import hf_hub_download import torch from transformers import PatchTSTConfig, PatchTSTForPretraining file = hf_hub_download( repo_id="hf-internal-testing/etth1-hourly-batch", filename="train-batch.pt", repo_type="dataset" ) batch = torch.load(file) # Config for random mask pretraining config = PatchTSTConfig( num_input_channels=7, context_length=512, patch_length=12, stride=12, mask_type='random', random_mask_ratio=0.4, use_cls_token=True, ) # Config for forecast mask pretraining config = PatchTSTConfig( num_input_channels=7, context_length=512, patch_length=12, stride=12, mask_type='forecast', num_forecast_mask_patches=5, use_cls_token=True, ) model = PatchTSTForPretraining(config) # during training, one provides both past and future values outputs = model(past_values=batch["past_values"]) loss = outputs.loss loss.backward()(注:示例中stride=12属于 docstring 的历史别名写法;在当前配置类中对应参数名为patch_stride,请以 PatchTSTConfig 定义为准。)
预训练头PatchTSTMaskPretrainHead把d_model维的隐藏态线性映射回patch_length维以重建 patch(L1179-L1204);若use_cls_token=True会先剔除 cls token 再计算重建。masked loss 的具体计算为:(mse(x_hat, patch_input).mean(-1) * mask).sum() / (mask.sum() + 1e-10)(L1309-L1312),即只对掩码 patch 求平均。预训练得到的 Encoder 表征可迁移到下游数据集或微调到预测任务。
PatchTSTForClassification:时间序列分类
把 PatchTST 用于时间序列分类时,配置中num_targets表示类别数。分类头先按use_cls_token(取首个 token)或pooling_type(mean/max池化)把 patch 维聚合为每个通道的向量,flatten后经线性层映射到num_targets(L1324-L1358)。类初始化时会自动关闭掩码(若do_mask_input=True会发出警告并置为False)。文档示例:
from transformers import PatchTSTConfig, PatchTSTForClassification # classification task with two input channels and 3 classes config = PatchTSTConfig( num_input_channels=2, num_targets=3, context_length=512, patch_length=12, stride=12, use_cls_token=True, ) model = PatchTSTForClassification(config=config) # during inference, one only provides past values past_values = torch.randn(20, 512, 2) outputs = model(past_values=past_values) labels = outputs.prediction_logits提供target_values标签时,forward 内部使用CrossEntropyLoss计算分类损失(L1437-L1440),输出为PatchTSTForClassificationOutput.loss与prediction_logits。
PatchTSTForRegression:时间序列回归
回归模型将整个序列池化为num_channels * d_model维向量,再用线性/分布头投影到num_targets个目标值(L1749-L1834)。同样,构造回归模型时会自动关闭掩码。文档示例:
from transformers import PatchTSTConfig, PatchTSTForRegression # Regression task with 6 input channels and regress 2 targets model = PatchTSTForRegression.from_pretrained("namctin/patchtst_etth1_regression") # during inference, one only provides past values, the model outputs future values past_values = torch.randn(20, 512, 6) outputs = model(past_values=past_values) regression_outputs = outputs.regression_outputs回归模式下可设置output_range约束输出区间,也可以像预测任务一样配合loss="nll"使用分布头获得概率式输出并调用generate采样(L1911-L1951)。
从源码理解 PatchTST 的实现细节
数据形状流转
理解 PatchTST 的关键在于其张量维度转换,测试文件 test_modeling_patchtst.py 中构造输入的方式直观展示了这一约定:
- 模型输入
past_values:[bs, context_length, num_input_channels]; - patch 化后:
[bs, num_input_channels, num_patches, patch_length]; - Encoder 输出隐藏态:
[bs, num_input_channels, num_patches, d_model](token 序列维被移到通道之后); - 预测输出:
[bs, prediction_length, num_input_channels]。
注意力实现与加速后端
PatchTSTEncoderLayer的第一子层把 batch 与通道维合并为bs * num_channels,使时间 token 之间做标准自注意力;只有开启channel_attention时才额外执行一次沿通道维的注意力(L464-L543)。注意力接口通过ALL_ATTENTION_FUNCTIONS.get_interface按config._attn_implementation分发,类声明支持 flash attention 与 SDPA(_supports_flash_attn = True、_supports_sdpa = True、_supports_flex_attn = True,见 modeling_patchtst.py),即可以在较新 GPU 上通过attn_implementation="flash_attention_2"或"sdpa"进一步加速,且不需要past_key_values缓存式生成(模型不带因果解码结构)。
测试与验证
PatchTST 的统一测试套件位于 tests/models/patchtst/test_modeling_patchtst.py,通过ModelTesterMixin与PipelineTesterMixin覆盖了 5 个模型类的配置序列化、前向输出、注意力输出(has_attentions = True)、梯度、断点续训等通用契约,并注册了 feature-extraction pipeline。该测试中还为分类任务生成target_values标签、为预训练移除future_values(L184-L200),可作为理解不同任务输入约定的参考。
使用技巧与注意事项
根据模型文档(Usage tips)与源码约束,使用 PatchTST 时值得留意以下几点:
- 一个模型家族覆盖多种任务:除长程预测外,同一套 patch + 通道独立骨架可直接复用到时间序列分类(
PatchTSTForClassification)与回归(PatchTSTForRegression),无需为不同任务重写骨干。 - 观察掩码要配套使用:真实数据常含缺失值,替换 NaN 为 0 后必须同时传入
past_observed_mask,否则缩放统计会被缺失值污染。 - 反缩放是预测正确性的关键:确定性预测返回的是还原后的原始量纲值;若自行取隐藏态接自定义头,需自行应用
y_hat * scale + loc。 - Patch 参数决定 token 数与算力:
patch_length与patch_stride共同决定num_patches,即注意力序列长度;patch 越大、stride 越大,token 越少、注意力的时间和内存开销越小,这也是该模型能处理更长历史的根因。 - 预训练 vs. 微调:构造预测/分类/回归模型时
do_mask_input会被自动关闭;预训练任务在预训练完骨干后,可通过共享权重把任务头接到PatchTSTModel上做有监督微调。
延伸资源
- 仓库内该模型的中文可阅读源码入口:模型实现、模型配置、测试套件;
- 原始论文《A Time Series is Worth 64 Words: Long-term Forecasting with Transformers》(Yuqi Nie et al.)以及原作者的官方 PatchTST 参考实现,贡献者 namctin、gsinthong、diepi、vijaye12、wmgifford 与 kashif 在论文发布次日即把模型代码合入本仓库;
- 模型家族(
ibm-granite/granite-timeseries-patchtst等)可直接用上述from_pretrained方式加载用于推理或微调,若需概率式预测请配合loss="nll"与generate()使用。
【免费下载链接】transformers🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考