当前快播:据说,Transformer 不能有效地进行时间序列预测?
简介
几个月前,我们介绍了 Informer 这个模型,相关论文 (Zhou, Haoyi, et al., 2021) 是一篇获得了 AAAI 2021 最佳论文奖的时间序列论文。我们也展示了一个使用 Informer 进行多变量概率预测的例子。在本文中,我们讨论以下问题: Transformer 模型对时间序列预测真的有效吗?我们给出的答案是,它们真的有效。
首先,我们将会提供一些实验证据,展示其真正的有效性。我们的对比实验将表明, DLinear 这个简单线性模型并没有像说的那样比 transformer 好。当我们在同等模型大小和相同设定的情况下对比时,我们发现基于 transformer 的模型在我们关注的测试标准上表现得更好。其次,我们将会介绍 Autoformer 模型,相关论文 (Wu, Haixu, et al., 2021) 在 Informer 模型问世后发表在 NeurIPS 2021 上。Autoformer 的模型现在已经可以在 Transformers 中 使用。最后,我们还会讨论 DLinear 模型,该模型是一个简单的前向网络,使用了 Autoformer 中的分解层 (decomposition layer)。DLinear 模型是在 Are Transformers Effective for Time Series Forecasting? 这篇论文中提出的,文中声称其性能在时间序列预测领域超越了 transformer 系列的算法。
下面我们开始!
(资料图片仅供参考)
评估 Transformer 系列模型 和 DLinear 模型
在 AAAI 2023 的论文 Are Transformers Effective for Time Series Forecasting? 中,作者声称 transformer 系列模型在时间序列预测方面并不有效。他们拿基于 transformer 的模型与一个简单的线性模型 DLinear 作对比。DLinear 使用了 Autoformer 中的 decomposition layer 结构 (下文将会介绍),作者声称其性能超越了基于 transformer 的模型。但事实真的是这样吗?我们接下来看看。
上表展示了 Autoformer 和 DLinear 在三个论文中用到的数据集上的表现。结果说明 Autoformer 在三个数据集上表现都超越了 DLinear 模型。
接下来,我们将介绍 Autoformer 和 DLinear 模型,演示我们如何在上表 Traffic 数据集上对比它们的性能,并为结果提供一些可解释性。
先说结论:一个简单的线性模型可能在某些特定情况下更有优势,但可能无法像 transformer 之类的复杂模型那样处理协方差信息。
Autoformer 详细介绍
Autoformer 基于传统的时间序列方法: 把时间序列分解为季节性 (seasonality) 以及趋势 - 周期 (trend-cycle) 这些要素。这通过加入分解层 ( Decomposition Layer ) 来实现,以此来增强模型获取这些信息的能力。此外,Autoformer 中还独创了自相关 (auto-correlation) 机制,替换掉了传统 transformer 中的自注意力 (self-attention)。该机制使得模型可以利用注意力机制中周期性的依赖,提升了总体性能。
下面,我们将深入探讨 Autoformer 的这两大主要贡献: 分解层 ( Decomposition Layer ) 和自相关机制 ( Autocorrelation Mechanism )。相关代码也会提供出来。
分解层
分解是一个时间序列领域十分常用的方法,但在 Autoformer 以前都没有被密集集成入深度学习模型中。我们先简单介绍这一概念,随后会使用 PyTorch 代码演示这一思路是如何应用到 Autoformer 中的。
时间序列分解
在时间序列分析中,分解 (decomposition) 是把一个时间序列拆分成三个系统性要素的方法: 趋势周期 (trend-cycle) 、季节性变动 (seasonal variation) 和随机波动 (random fluctuations)。趋势要素代表了时间序列的长期走势方向; 季节要素反映了一些反复出现的模式,例如以一年或一季度为周期出现的模式; 而随机 (无规律) 因素则反映了数据中无法被上述两种要素解释的随机噪声。
有两种主流的分解方法: 加法分解和乘法分解,这在 statsmodels 这个库里都有实现。通过分解时间序列到这三个要素,我们能更好地理解和建模数据中潜在的模式。
但怎样把分解集成进 transformer 结构呢?我们可以参考参考 Autoformer 的做法。
Autoformer 中的分解
Autoformer 把分解作为一个内部计算操作集成到模型中,如上图所示。可以看到,编码器和解码器都使用了分解模块来集合 trend-cyclical 信息,并从序列中渐进地提取 seasonal 信息。这种内部分解的概念已经从 Autoformer 中展示了其有效性。所以很多其它的时间序列论文也开始采用这一方法,例如 FEDformer (Zhou, Tian, et al., ICML 2022) 和 DLinear (Zeng, Ailing, et al., AAAI 2023),这更说明了其在时间序列建模中的意义。
现在,我们正式地给分解层做出定义:
对一个长度为 的序列 ,分解层返回的 定义如下:
对应的 PyTorch 代码实现是:
import torchfrom torch import nnclass DecompositionLayer(): """ Returns the trend and the seasonal parts of the time series. """ def __init__(self, kernel_size): super().__init__() _size = kernel_size = (kernel_size=kernel_size, stride=1, padding=0) # moving average def forward(self, x): """Input shape: Batch x Time x EMBED_DIM""" # padding on the both ends of time series num_of_pads = (_size - 1) // 2 front = x[:, 0:1, :].repeat(1, num_of_pads, 1) end = x[:, -1:, :].repeat(1, num_of_pads, 1) x_padded = ([front, x, end], dim=1) # calculate the trend and seasonal part of the series x_trend = (x_(0, 2, 1)).permute(0, 2, 1) x_seasonal = x - x_trend return x_seasonal, x_trend
可见,代码非常简单,可以很方便地用在其它模型中,正如 DLinear 那样。下面,我们讲解第二个创新点: 注意力 (自相关) 机制 。
注意力 (自相关) 机制
除了分解层之外,Autoformer 还使用了一个原创的自相关 (autocorrelation) 机制,可以完美替换自注意力 (self-attention) 机制。在 最原始的时间序列 transformer 模型 中,注意力权重是在时域计算并逐点聚合的。而从上图中可以看出,Autoformer 不同的是它在频域计算这些 (使用 快速傅立叶变换),然后通过时延聚合它们。
接下来部分,我们深入细节,并使用代码作出讲解。
时域的注意力机制
理论上讲,给定一个时间延迟 ,一个离散变量的 自相关性 可以用来衡量这个变量当前时刻 的值和过去时刻 的值之间的“关系”(皮尔逊相关性,pearson correlation):
使用自相关性,Autoformer 提取了 query 和 key 之间基于频域的相互依赖,而不是像之前那样两两之间的点乘。可以把这个操作看成是自注意力中 的替换。
实际操作中,query 和 key 之间的自相关是通过 FFT 一次性针对 所有时间延迟计算出来的。通过这种方法,自相关机制达到了 的时间复杂度 ( 是输入时间长度),这个速度和 Informer 的 ProbSparse attention 接近。值得一提的是,使用 FFT 计算自相关性的理论基础是 Wiener–Khinchin theorem,这里我们不细讲了。
现在,我们来看看相应的 PyTorch 代码:
import torchdef autocorrelation(query_states, key_states): """ Computes autocorrelation(Q,K) using ``. Think about it as a replacement for the QK^T in the self-attention. Assumption: states are resized to same shape of [batch_size, time_length, embedding_dim]. """ query_states_fft = (query_states, dim=1) key_states_fft = (key_states, dim=1) attn_weights = query_states_fft * (key_states_fft) attn_weights = (attn_weights, dim=1) return attn_weights
代码非常简洁! 请注意这只是 autocorrelation(Q,K)
的部分实现,完整实现请参考 Transformers 中的代码。
接下来,我们将看到如何使用时延值聚合我们的 attn_weights
,这个过程被称为时延聚合 ( Time Delay Aggregation )。
时延聚合
我们用 来表示自相关 (即 attn_weights
)。那么问题是: 我们应该如何聚合这些 到 上面?在标准的自注意力机制中,这种聚合通过点乘完成。但在 Autoformer 中,我们使用了一种不同的方法。首先我们在时延 上对齐 ,计算在这些时延下它对应的值,这个操作叫作 Rolling 。接下来,我们将对齐的 和自相关的值进行逐点的乘法运算。在上图中,你可以看到在左边是基于时延对 进行的 Rolling 操作; 而右边就展示了与自相关进行的逐点乘法。
整个过程可以用以下公式总结:
就是这样!需要注意的是, 是一个超参数,我们称之为 autocorrelation_factor
(类似于 Informer 里的 sampling_factor
) ; 而 softmax 是在乘法操作之前运用到自相关上面的。
现在,我们已经可以看看最终的代码了:
import torchimport mathdef time_delay_aggregation(attn_weights, value_states, autocorrelation_factor=2): """ Computes aggregation as value_(delay)* top_k_autocorrelations(delay). The final result is the autocorrelation-attention output. Think about it as a replacement of the dot-product between attn_weights and value states. The autocorrelation_factor is used to find top k autocorrelations delays. Assumption: value_states and attn_weights shape: [batch_size, time_length, embedding_dim] """ bsz, num_heads, tgt_len, channel = ... time_length = value_(1) autocorrelations = attn_(bsz, num_heads, tgt_len, channel) # find top k autocorrelations delays top_k = int(autocorrelation_factor * (time_length)) autocorrelations_mean = (autocorrelations, dim=(1, -1)) # bsz x tgt_len top_k_autocorrelations, top_k_delays = (autocorrelations_mean, top_k, dim=1) # apply softmax on the channel dim top_k_autocorrelations = (top_k_autocorrelations, dim=-1) # bsz x top_k # compute aggregation: value_(delay)* top_k_autocorrelations(delay) delays_agg = _like(value_states).float() # bsz x time_length x channel for i in range(top_k): value_states_roll_delay = value_(shifts=-int(top_k_delays[i]), dims=1) top_k_at_delay = top_k_autocorrelations[:, i] # aggregation top_k_resized = top_k_at_(-1, 1, 1).repeat(num_heads, tgt_len, channel) delays_agg += value_states_roll_delay * top_k_resized attn_output = delays_() return attn_output
完成!Autoformer 模型现在已经可以在 Transformers 中 使用 了,名字就叫 AutoformerModel
。
针对这个模型,我们要对比单变量 transformer 模型与 DLinear 的性能,DLinear 本质也是单变量的。后面我们也会展示两个多变量 transformer 模型的性能 (在同一数据上训练的)。
DLinear 详细介绍
实际上,DLinear 结构非常简单,仅仅是从 Autoformer 的 DecompositionLayer
上连接全连接层。它使用 DecompositionLayer
来分解输入的世界序列到残差部分 (季节性) 和趋势部分。前向过程中,每个部分都被输入到各自的线性层,并被映射成 prediction_length
长度的输出。最终的输出就是两个输入的和:
def forward(self, context): seasonal, trend = (context) seasonal_output = _seasonal(seasonal) trend_output = _trend(trend) return seasonal_output + trend_output
在这种设定下,首先我们把输入的序列映射成 prediction-length * hidden
维度 (通过 linear_seasonal
和 linear_trend
两个层) ; 得到的结果会被相加起来,并转换为 (prediction_length, hidden)
形状; 最后,维度为 hidden
的隐性表征会被映射到某种分布的参数上。
在我们的测评中,我们使用 GluonTS 中 DLinear 的实现。
示例: Traffic 数据集
我们希望用实验结果展示库中基于 transformer 模型的性能,这里我们使用 Traffic 数据集,该数据集有 862 条时间序列数据。我们将在每条时间序列上训练一个共享的模型 (单变量设定)。每个时间序列都代表了一个传感器的占有率值,值的范围在 0 到 1 之间。下面的这些超参数我们将在所有模型中保持一致。
# Traffic prediction_length is 24. Reference:# /awslabs/gluonts/blob/6605ab1278b6bf92d5e47343efcf0d22bc50b2ec/src/gluonts/dataset/repository/_#L105prediction_length = 24context_length = prediction_length*2batch_size = 128num_batches_per_epoch = 100epochs = 50scaling = "std"
使用的 transformer 模型都很小:
encoder_layers=2decoder_layers=2d_model=16
这里我们不再讲解如何用 Autoformer
训练模型,读者可以参考之前两篇博客 (TimeSeriesTransformer 和 Informer) 并替换模型为 Autoformer
、替换数据集为 traffic
。我们也训练了现成的模型放在 HuggingFace Hub 上,稍后的评测将会使用这里的模型。
载入数据集
首先安装必要的库:
!pip install -q transformers datasets evaluate accelerate "gluonts[torch]" ujson tqdm
traffic
数据集 (Lai et al. (2017)) 包含了旧金山的交通数据。它包含 862 条以小时为时间单位的时间序列,代表了道路占有率的数值,其数值范围为 ,记录了旧金山湾区高速公路从 2015 年到 2016 年的数据。
from import get_datasetdataset = get_dataset("traffic")freq = _length = _length
我们可视化一条时间序列看看,并画出训练和测试集的划分:
import as plttrain_example = next(iter())test_example = next(iter())num_of_samples = 4*prediction_lengthfigure, axes = ()(train_example["target"][-num_of_samples:], color="blue")( test_example["target"][-num_of_samples - prediction_length :], color="red", alpha=,)()
定义训练和测试集划分:
train_dataset = _dataset =
定义数据变换
接下来,我们定义数据的变换,尤其是时间相关特征的制作 (基于数据集本身和一些普适做法)。
我们定义一个 Chain
,代表 GluonTS 中一系列的变换 (这类似图像里 )。这让我们将一系列变换集成到一个处理流水线中。
下面代码中,每个变换都添加了注释,用以说明它们的作用。从更高层次讲,我们将遍历每一个时间序列,并添加或删除一些特征:
from transformers import PretrainedConfigfrom _feature import time_features_from_frequency_strfrom _names import FieldNamefrom import ( AddAgeFeature, AddObservedValuesIndicator, AddTimeFeatures, AsNumpyArray, Chain, ExpectedNumInstanceSampler, RemoveFields, SelectFields, SetField, TestSplitSampler, Transformation, ValidationSplitSampler, VstackFeatures, RenameFields,)def create_transformation(freq: str, config: PretrainedConfig) -> Transformation: # create a list of fields to remove later remove_field_names = [] if _static_real_features == 0: remove_field_(_STATIC_REAL) if _dynamic_real_features == 0: remove_field_(_DYNAMIC_REAL) if _static_categorical_features == 0: remove_field_(_STATIC_CAT) return Chain( # step 1: remove static/dynamic fields if not specified [RemoveFields(field_names=remove_field_names)] # step 2: convert the data to NumPy (potentially not needed) + ( [ AsNumpyArray( field=_STATIC_CAT, expected_ndim=1, dtype=int, ) ] if _static_categorical_features > 0 else [] ) + ( [ AsNumpyArray( field=_STATIC_REAL, expected_ndim=1, ) ] if _static_real_features > 0 else [] ) + [ AsNumpyArray( field=, # we expect an extra dim for the multivariate case: expected_ndim=1 if _size == 1 else 2, ), # step 3: handle the NaN's by filling in the target with zero # and return the mask (which is in the observed values) # true for observed values, false for nan's # the decoder uses this mask (no loss is incurred for unobserved values) # see loss_weights inside the xxxForPrediction model AddObservedValuesIndicator( target_field=, output_field=_VALUES, ), # step 4: add temporal features based on freq of the dataset # these serve as positional encodings AddTimeFeatures( start_field=, target_field=, output_field=_TIME, time_features=time_features_from_frequency_str(freq), pred_length=_length, ), # step 5: add another temporal feature (just a single number) # tells the model where in the life the value of the time series is # sort of running counter AddAgeFeature( target_field=, output_field=_AGE, pred_length=_length, log_scale=True, ), # step 6: vertically stack all the temporal features into the key FEAT_TIME VstackFeatures( output_field=_TIME, input_fields=[_TIME, _AGE] + ( [_DYNAMIC_REAL] if _dynamic_real_features > 0 else [] ), ), # step 7: rename to match HuggingFace names RenameFields( mapping={ _STATIC_CAT: "static_categorical_features", _STATIC_REAL: "static_real_features", _TIME: "time_features", : "values", _VALUES: "observed_mask", } ), ] )
定义 InstanceSplitter
我们需要创建一个 InstanceSplitter
,用来给训练、验证和测试集提供采样窗口,得到一段时间的内的时间序列 (我们不可能把完整的整段数据输入给模型,毕竟时间太长,而且也有内存限制)。
这个实例分割工具每一次将会随机选取 context_length
长度的数据,以及紧随其后的 prediction_length
长度的窗口,并为相应的窗口标注 past_
或 future_
。这样可以保证 values
能被分为 past_values
和随后的 future_values
,各自作为编码器和解码器的输入。除了 values
,对于 time_series_fields
中的其它 key 对应的数据也是一样。
from import InstanceSplitterfrom import InstanceSamplerfrom typing import Optionaldef create_instance_splitter( config: PretrainedConfig, mode: str, train_sampler: Optional[InstanceSampler] = None, validation_sampler: Optional[InstanceSampler] = None,) -> Transformation: assert mode in ["train", "validation", "test"] instance_sampler = { "train": train_sampler or ExpectedNumInstanceSampler( num_instances=, min_future=_length ), "validation": validation_sampler or ValidationSplitSampler(min_future=_length), "test": TestSplitSampler(), }[mode] return InstanceSplitter( target_field="values", is_pad_field=_PAD, start_field=, forecast_start_field=_START, instance_sampler=instance_sampler, past_length=_length + max(_sequence), future_length=_length, time_series_fields=["time_features", "observed_mask"], )
创建 PyTorch 的 DataLoader
接下来就该创建 PyTorch DataLoader 了: 这让我们能把数据整理成 batch 的形式,即 (input, output) 对的形式,或者说是 ( past_values
, future_values
) 的形式。
from typing import Iterableimport torchfrom import Cyclic, Cachedfrom import as_stacked_batchesdef create_train_dataloader( config: PretrainedConfig, freq, data, batch_size: int, num_batches_per_epoch: int, shuffle_buffer_length: Optional[int] = None, cache_data: bool = True, **kwargs,) -> Iterable: PREDICTION_INPUT_NAMES = [ "past_time_features", "past_values", "past_observed_mask", "future_time_features", ] if _static_categorical_features > 0: PREDICTION_INPUT_("static_categorical_features") if _static_real_features > 0: PREDICTION_INPUT_("static_real_features") TRAINING_INPUT_NAMES = PREDICTION_INPUT_NAMES + [ "future_values", "future_observed_mask", ] transformation = create_transformation(freq, config) transformed_data = (data, is_train=True) if cache_data: transformed_data = Cached(transformed_data) # we initialize a Training instance instance_splitter = create_instance_splitter(config, "train") # the instance splitter will sample a window of # context length + lags + prediction length (from the 366 possible transformed time series) # randomly from within the target time series and return an iterator. stream = Cyclic(transformed_data).stream() training_instances = instance_(stream, is_train=True) return as_stacked_batches( training_instances, batch_size=batch_size, shuffle_buffer_length=shuffle_buffer_length, field_names=TRAINING_INPUT_NAMES, output_type=, num_batches_per_epoch=num_batches_per_epoch, )def create_test_dataloader( config: PretrainedConfig, freq, data, batch_size: int, **kwargs,): PREDICTION_INPUT_NAMES = [ "past_time_features", "past_values", "past_observed_mask", "future_time_features", ] if _static_categorical_features > 0: PREDICTION_INPUT_("static_categorical_features") if _static_real_features > 0: PREDICTION_INPUT_("static_real_features") transformation = create_transformation(freq, config) transformed_data = (data, is_train=False) # we create a Test Instance splitter which will sample the very last # context window seen during training only for the encoder. instance_sampler = create_instance_splitter(config, "test") # we apply the transformations in test mode testing_instances = instance_(transformed_data, is_train=False) return as_stacked_batches( testing_instances, batch_size=batch_size, output_type=, field_names=PREDICTION_INPUT_NAMES, )
在 Autoformer 上评测
我们已经在这个数据集上预训练了一个 Autoformer 了,所以我们可以直接拿来模型在测试集上测一下:
from transformers import AutoformerConfig, AutoformerForPredictionconfig = _pretrained("kashif/autoformer-traffic-hourly")model = _pretrained("kashif/autoformer-traffic-hourly")test_dataloader = create_test_dataloader( config=config, freq=freq, data=test_dataset, batch_size=64,)
在推理时,我们使用模型的 generate()
方法来预测 prediction_length
步的未来数据,基于最近使用的对应时间序列的窗口长度。
from accelerate import Acceleratoraccelerator = Accelerator()device = (device)()forecasts_ = []for batch in test_dataloader: outputs = ( static_categorical_features=batch["static_categorical_features"].to(device) if _static_categorical_features > 0 else None, static_real_features=batch["static_real_features"].to(device) if _static_real_features > 0 else None, past_time_features=batch["past_time_features"].to(device), past_values=batch["past_values"].to(device), future_time_features=batch["future_time_features"].to(device), past_observed_mask=batch["past_observed_mask"].to(device), ) forecasts_.append(().numpy())
模型输出的数据形状是 ( batch_size
, number of samples
, prediction length
, input_size
)。
在下面这个例子中,我们为预测接下来 24 小时的交通数据而得到了 100 条可能的数值,而 batch size 是 64:
forecasts_[0].shape>>> (64, 100, 24)
我们在垂直方向把它们堆叠起来 (使用 函数),以此获取所有测试集时间序列的预测: 我们有
7
个滚动的窗口,所以有 7 * 862 = 6034
个预测。
import numpy as npforecasts = (forecasts_)print()>>> (6034, 100, 24)
我们可以把预测结果和 ground truth 做个对比。为此,我们使用 Evaluate 这个库,它里面包含了 MASE 的度量方法。
我们对每个时间序列用这一度量标准计算相应的值,并算出其平均值:
from import tqdmfrom evaluate import loadfrom _feature import get_seasonalitymase_metric = load("evaluate-metric/mase")forecast_median = (forecasts, 1)mase_metrics = []for item_id, ts in enumerate(tqdm(test_dataset)): training_data = ts["target"][:-prediction_length] ground_truth = ts["target"][-prediction_length:] mase = mase_( predictions=forecast_median[item_id], references=(ground_truth), training=(training_data), periodicity=get_seasonality(freq)) mase_(mase["mase"])
所以 Autoformer 模型的结果是:
print(f"Autoformer univariate MASE: {(mase_metrics):.3f}")>>> Autoformer univariate MASE:
我们还可以画出任意时间序列预测针对其 ground truth 的对比,这需要以下函数:
import as mdatesimport pandas as pdtest_ds = list(test_dataset)def plot(ts_index): fig, ax = () index = _range( start=test_ds[ts_index][], periods=len(test_ds[ts_index][]), freq=test_ds[ts_index][].freq, ).to_timestamp() ( index[-5*prediction_length:], test_ds[ts_index]["target"][-5*prediction_length:], label="actual", ) ( index[-prediction_length:], (forecasts[ts_index], axis=0), label="median", ) ().autofmt_xdate() (loc="best") ()
比如,测试集中第四个时间序列的结果对比,画出来是这样:
plot(4)
在 DLinear 上评测
gluonts
提供了一种 DLinear 的实现,我们将使用这个实现区训练、测评该算法:
from _ import DLinearEstimator# Define the DLinear model with the same parameters as the Autoformer modelestimator = DLinearEstimator( prediction_length=_length, context_length=_length*2, scaling=scaling, hidden_dimension=2, batch_size=batch_size, num_batches_per_epoch=num_batches_per_epoch, trainer_kwargs=dict(max_epochs=epochs))
训练模型:
predictor = ( training_data=train_dataset, cache_data=True, shuffle_buffer_length=1024)>>> INFO:pytorch__summary: | Name | Type | Params --------------------------------------- 0 | model | DLinearModel | K --------------------------------------- K Trainable params 0 Non-trainable params K Total params Total estimated model params size (MB) Training: 0it [00:00, ?it/s] ... INFO:pytorch__zero:Epoch 49, global step 5000: 'train_loss' was not in top 1 INFO:pytorch__zero:`` stopped: `max_epochs=50` reached.
在测试集上评测:
from import make_evaluation_predictions, Evaluatorforecast_it, ts_it = make_evaluation_predictions( dataset=, predictor=predictor,)d_linear_forecasts = list(forecast_it)d_linear_tss = list(ts_it)evaluator = Evaluator()agg_metrics, _ = evaluator(iter(d_linear_tss), iter(d_linear_forecasts))
所以 DLinear 对应的结果是:
dlinear_mase = agg_metrics["MASE"]print(f"DLinear MASE: {dlinear_mase:.3f}")>>> DLinear MASE:
同样地,我们画出预测结果与 ground truth 的对比曲线图:
def plot_gluonts(index): (d_linear_tss[index][-4 * _length:].to_timestamp(), label="target") d_linear_forecasts[index].plot(show_label=True, color='g') () ().autofmt_xdate() ()
plot_gluonts(4)
实际上, traffic
数据集在平日和周末会出现传感器中模式的分布偏移。那我们还应该怎么做呢?由于 DLinear 没有足够的能力去处理协方差信息,或者说是任何的日期时间的特征,我们给出的窗口大小无法覆盖全面,使得让模型有足够信息去知道当前是在预测平日数据还是周末数据。因此模型只会去预测更为普适的结果,这就导致其预测分布偏向平日数据,因而导致对周末数据的预测变得更差。当然,如果我们给一个足够大的窗口,一个线性模型也可以识别出周末的模式,但当我们的数据中存在以月或以季度为单位的模式分布时,那就需要更大的窗口了。
总结
所以 transformer 模型和线性模型对比的结论是什么呢?不同模型在测试集上的 MASE 指标如下所示:
可以看到,我们去年引入的 最原始的 Transformer 模型 获得了最好的性能指标。其次,多变量模型一般都比对应的单变量模型更差,原因在于序列间的相关性关系一般都较难预测。额外添加的波动通常会损坏预测结果,或者模型可能会学到一些错误的相关性信息。最近的一些论文,如 CrossFormer (ICLR 23) 和 CARD 也在尝试解决这些 transformer 模型中的问题。 多变量模型通常在训练数据足够大的时候才会表现得好。但当我们与单变量模型在小的公开数据集上对比时,通常单变量模型会表现得更好。相对于线性模型,通常其相应尺寸的单变量 transformer 模型或其它神经网络类模型会表现得更好。
总结来讲,transformer 模型在时间序列预测领域,远没有达到要被淘汰的境地。 然而大规模训练数据对它巨大潜力的挖掘是至关重要的,这一点不像 CV 或 NLP 领域,时间序列预测缺乏大规模公开数据集。 当前绝大多数的时间序列预训练模型也不过是在诸如 UCR & UEA 这样的少量样本上训练的。 即使这些基准数据集为时间序列预测的发展进步提供了基石,其较小的规模和泛化性的缺失使得大规模预训练仍然面临诸多困难。
所以对于时间序列预测领域来讲,发展大规模、强泛化性的数据集 (就像 CV 领域的 ImageNet 一样) 是当前最重要的事情。这将会极大地促进时间序列分析领域与训练模型的发展研究,提升与训练模型在时间序列预测方面的能力。
声明
我们诚挚感谢 Lysandre Debut 和 Pedro Cuenca 提供的深刻见解和对本项目的帮助。
英文原文: /blog/autoformer
作者: Eli Simhayev, Kashif Rasul, Niels Rogge
译者: Hoi2022
审校/排版: zhongdongy (阿东)
标签:
- 当前快播:据说,Transformer 不能有效地进行时间序列预测?
- 思考乐教育:受托人购买207.8万股股份董事会相信公司股价严重低估公司表现及相关价值
- 天天亮点!抵制请托拉票等不当行为 中国科协发布“十不准”规范严把院士推选“入口关”
- 法国总统马克龙:骚乱顶峰已过去,仍需保持警惕 速看料
- 《腹黑医生爱上我》25‖双顾(魏野)_天天热点
- 焦点讯息:iQOO 11S发布:骁龙旗舰+200W闪充,售价3799元起
- 持续做多!百亿私募仓位指数创近8周新高,对7月行情信心再上移
- 亚运测试赛激战正酣 老场馆“微改造”焕发“新活力”_快消息
- 天天信息:广康生化25亿元投资项目拟落子宜昌 打造特种化学品新材料项目生产基地
- 金华市政府与浙江联通签署浙中人工智能产业园项目框架合作协议|世界新资讯
- 波罗的海干散货运价指数周二继续下跌,因海岬型和巴拿马型船运价指数下跌 天天观天下
- “丑女”汉字雕塑引争议!景区回应:别抠字眼 今日关注
- 观察:温州生态园开发22亿元私募获上交所受理
- 没毕业签了劳动合同是否有效
- 中超第25轮上海海港3比0击败深圳队 天天微速讯
- 鲁媒:费莱尼对中超判罚忍无可忍,未来4轮是崔康熙第二道难关-今日热搜
- 每日报道:中国碳中和(01372.HK)将协助及推动济源市碳达峰碳中和工作
- 中国人权研究会在日内瓦举行“中国的人权理念与实践”主题边会
- 小年糕相册制作电脑版软件(小年糕相册制作电脑版)
- 康耐特光学(02276.HK)7月4日认购1.6亿元理财产品
- 全球最新:中国科学家获得2023年欧洲发明家奖
- 全球看点:臭脚怎么治疗最好最快方法(臭脚怎么治疗)
- 世界热消息:女孩瞒父母见男友家长,菜让她心凉
- 世界球精选!瑞士ins博主Kristina Bazan 行走的梨型身材穿搭教科书
- 热门看点:中国A股汽车板块周二走强
- 世界快报:小米手机顾客特征
- 海口住房公积金缴存指南|每日资讯
- 环球最新:适合女性开的小型车,比亚迪海鸥,实力不错
- 当前消息!东风本田全新英仕派上市,售价18.28万-25.88万元
- word文档的页眉页脚怎么操作_word文档的页眉页脚怎么删除_微资讯
- 英国“最危险的植物”巨型猪笼草,汁液令人的皮肤被阳光烧伤 全球球精选
- 有什么简单又好看的编织包包 试试这50款手工编织包包
- 【库月长篇HE】谎言与真实 剧幕列表
- 广西将建优质高效中医药壮瑶医药服务体系 强化人才培养
- 快讯2023-07-04 22:52:00
- 凉台改装地台图片_旧凉台翻新简单方法 如何对凉台进行简单翻新 全球快看点
- 鸣剑抵掌_关于鸣剑抵掌简述
- 开灯睡觉会对人的身体造成危害吗_开灯睡觉会对人的身体造成伤害吗
- 黑体字体大全 字库_黑体字体大全|观热点
- 比亚迪发布高阶智能驾驶辅助系统,命名为“天神之眼” 当前关注
- 退款养羊毛党买家称好平台-今日快看
- 亚运测试赛激战正酣 老场馆“微改造”焕发“新活力”|世界新视野
- 天天微速讯:北京工业大学举行2023年毕业典礼
- 【视频】江豚的声音你听过吗?"扑哧、扑哧"挺有趣!-每日快讯
- 6月9日丢失电动车的仙桃车主,你的车找到了
- 当前热门:照亮“书香东莞”城市之光!260名志愿者开启“城市少儿阅读点灯人”学习之旅
- 7月8日去巴南二圣镇采梨 8000余亩梨园等你来_环球时讯
- 中电光谷与河源江东新区签约 打造1200亩产业园 环球新消息
- 唏嘘!外媒爆料两届羽毛球世锦赛男单冠军将提前退役,年仅28岁-环球时讯
- 氪公子买单阿森纳新赛季首发⬇️还有哪里要补?还缺个谁
- 速看:频频落子,科蒂借“阿迪”抢占中国市场
- 全球观焦点:侯友宜首度对“九二共识”表态,国台办回应
- 护航青少年快乐健康成长 杭州“阳光护苗”出新招
- 苏州地铁开展工程项目安全生产检查
- 环球播报:中国石油北京项目管理公司:胡继勇已于6月7日起不再履行法定代表人职责
- 速看:银行行长表示:若存款金额达到“这个数”,可以和银行谈利率
- i24?今日状态实在不行!Meiko三局死亡数递增 平均每场8次阵亡 世界报道
- 优刻得镜像市场上线Milvus向量数据库镜像 环球看热讯
- 碧桂园上半年权益销售额近1288亿元
- 热头条丨东证指数创33年新高,关注高度改革预期股和高质量大盘成长股
- 环球今头条!2023武汉体育学院体育科技学院招生计划 武汉体育学院体育科技学院招生简章
- 和评理| 日本勿以IAEA报告为绿灯 排污入海害人害己害世界-世界新资讯
- 天天快消息!10个重点项目集中签约 苏州工业园区苏相合作区(北京)投资推介会举行
- 华脉科技: 股票交易异常波动公告 全球球精选
- 当前热门:全民拍征集|暑假“神兽”咋安排?家长们先看看提示
- 当前资讯!宜信志愿者协会销售创新中心泉州分会
- 坡度系数计算公式图解及推导(坡度系数计算公式图解)|新资讯
- 世界微头条丨东郊到家92和95什么意思
- 大雁往南飞的是什么季节_大雁往南飞是什么季节
- 十三香龙虾的做法大全(十三香龙虾的做法)_时讯
- 麻辣烫底料教程_自制麻辣烫底料的做法|全球快资讯
- 沈阳人事局官网_丹东人事局官网
- 问道手游天外之谜最新_问道手游天外之谜2019 焦点消息
- 全球热讯:穿越火线怎么免费得改名卡
- 今日热讯:湖南黄金:子公司本部华家湾金矿临时停产
- 安阳比高电影院今日影讯(比高电影院 上海有限公司) 当前速讯
- 动态焦点:布鲁日想要迎回比利时国脚穆尼耶 多特蒙德有意出售
- 世界快资讯丨福达合金:重组能否达成一致尚有不确定性
- 2015款凯越防冻液加多少_凯越1.8防冻液要加多少升?
- 自然地面测量标高至设计地坪标高间的平均厚度(工地怎么测量标高) 当前热议
- 热门:真实的“入警第一课”:暴雨中路遇皮卡车侧翻3人被困,19名新警合力撬门救人
- 一起签署房屋合同后卖方不愿出售了,买方起诉解约及赔偿案例|世界资讯
- 凯特冒雨看温网赛!穿绿白配清新养眼,却被陪同小姐姐抢足了风头
- 联想z5gt怎么样_联想z5怎么样值得买吗 环球动态
- 全球要闻:元极舞蹈完整版第二套_元极舞
- 医学论文撰写方法_医学论文撰写方法与技巧
- 天天速递!杨德龙:三重拐点叠加带来布局良机
- 金太阳:董事杜长波拟减持不超1.13万股 全球滚动
- 妖猫传票房回本了吗(妖猫传票房)_报道
- 2xbxb
- 中国人权研究会在日内瓦举行“中国的人权理念与实践”主题边会
- 世界热讯:减脂乌龙茶_乌龙减肥茶相关内容简介介绍
- 制定的班规_详细的班规|当前信息
- 【天天速看料】中国人权研究会在日内瓦举行“中国的人权理念与实践”主题边会
- 朝堂村_对于朝堂村简单介绍|环球快播报
- 滚动:《全境封锁2》玩家利用bug刷经验 育碧严打封号制裁
- Tuttosport:米兰对赫拉芬贝赫感兴趣的传... 天天速读
- 【深入基层】我区开展“国家基本公共卫生服务项目”宣传月活动|今日报
- 环球热门:彩生活拟于7月6日复牌
- 环球热点评!供需两端双发力 促进电影市场持续回暖