企业网站建设排名官网,云一网站公司,个体户做网站有用吗,新开发的app怎么推广目录 I. 前言II. AutoformerIII. 代码3.1 Encoder输入3.1.1 Token Embedding3.1.2 Temporal Embedding 3.2 Decoder输入3.3 Encoder与Decoder3.3.1 初始化3.3.2 Encoder3.3.3 Decoder IV. 实验 I. 前言
前面已经写了很多关于时间序列预测的文章#xff1a;
深入理解PyTorch中… 目录 I. 前言II. AutoformerIII. 代码3.1 Encoder输入3.1.1 Token Embedding3.1.2 Temporal Embedding 3.2 Decoder输入3.3 Encoder与Decoder3.3.1 初始化3.3.2 Encoder3.3.3 Decoder IV. 实验 I. 前言
前面已经写了很多关于时间序列预测的文章
深入理解PyTorch中LSTM的输入和输出从input输入到Linear输出PyTorch搭建LSTM实现时间序列预测负荷预测PyTorch中利用LSTMCell搭建多层LSTM实现时间序列预测PyTorch搭建LSTM实现多变量时间序列预测负荷预测PyTorch搭建双向LSTM实现时间序列预测负荷预测PyTorch搭建LSTM实现多变量多步长时间序列预测一直接多输出PyTorch搭建LSTM实现多变量多步长时间序列预测二单步滚动预测PyTorch搭建LSTM实现多变量多步长时间序列预测三多模型单步预测PyTorch搭建LSTM实现多变量多步长时间序列预测四多模型滚动预测PyTorch搭建LSTM实现多变量多步长时间序列预测五seq2seqPyTorch中实现LSTM多步长时间序列预测的几种方法总结负荷预测PyTorch-LSTM时间序列预测中如何预测真正的未来值PyTorch搭建LSTM实现多变量输入多变量输出时间序列预测多任务学习PyTorch搭建ANN实现时间序列预测风速预测PyTorch搭建CNN实现时间序列预测风速预测PyTorch搭建CNN-LSTM混合模型实现多变量多步长时间序列预测负荷预测PyTorch搭建Transformer实现多变量多步长时间序列预测负荷预测PyTorch时间序列预测系列文章总结代码使用方法TensorFlow搭建LSTM实现时间序列预测负荷预测TensorFlow搭建LSTM实现多变量时间序列预测负荷预测TensorFlow搭建双向LSTM实现时间序列预测负荷预测TensorFlow搭建LSTM实现多变量多步长时间序列预测一直接多输出TensorFlow搭建LSTM实现多变量多步长时间序列预测二单步滚动预测TensorFlow搭建LSTM实现多变量多步长时间序列预测三多模型单步预测TensorFlow搭建LSTM实现多变量多步长时间序列预测四多模型滚动预测TensorFlow搭建LSTM实现多变量多步长时间序列预测五seq2seqTensorFlow搭建LSTM实现多变量输入多变量输出时间序列预测多任务学习TensorFlow搭建ANN实现时间序列预测风速预测TensorFlow搭建CNN实现时间序列预测风速预测TensorFlow搭建CNN-LSTM混合模型实现多变量多步长时间序列预测负荷预测PyG搭建图神经网络实现多变量输入多变量输出时间序列预测PyTorch搭建GNN-LSTM和LSTM-GNN模型实现多变量输入多变量输出时间序列预测PyG Temporal搭建STGCN实现多变量输入多变量输出时间序列预测时序预测中Attention机制是否真的有效盘点LSTM/RNN中24种Attention机制效果对比详解Transformer在时序预测中的Encoder和Decoder过程以负荷预测为例(PyTorch)TCN和RNN/LSTM/GRU结合实现时间序列预测PyTorch搭建Informer实现长序列时间序列预测PyTorch搭建Autoformer实现长序列时间序列预测
上一篇文章讲了长序列时间序列预测的第一个模型InformerInformer发表于AAAI 2021。这一篇文章讲第二个长序列时间预测模型AutoformerAutoformer为NeurIPS 2021中《Autoformer: Decomposition Transformers with Auto-Correlation for Long-Term Series Forecasting》提出的模型比Informer晚了差不多半年。
II. Autoformer
Autoformer的目的是待预测的长度远大于输入长度的长期序列预测问题即就有有限的信息预测更长远的未来。
Autoformer的创新点如下
长序列中的复杂时间模式使得Transformer中的注意力机制难以发现可靠的时序依赖。因此Autoformer提出将时间序列分解嵌入到深度学习模型中在这之前分解一般都是用作数据预处理如EMD分解等。可学习的分解可以帮助模型从复杂的序列数据中分解出可预测性更强的组分。Transformer的时间复杂度较高造成了信息利用的瓶颈。因此Autoformer中基于随机过程理论提出了Auto-correlation机制来代替了Transformer中的基于point-wise的self-attention机制实现序列级(series-wise)连接和 O ( L log L ) O(L \log L) O(LlogL)的时间复杂度打破信息利用瓶颈。
更具体的原理就不做讲解了网上已经有了很多类似的文章这篇文章主要讲解代码的使用重点是如何对作者公开的源代码进行改动以更好地适配大多数人自身的数据使得读者只需要改变少数几个参数就能实现数据集的更换。
III. 代码
3.1 Encoder输入
传统Transformer中在编码阶段需要进行的第一步就是在原始序列的基础上添加位置编码而在Autoformer中输入由2部分组成即Token Embedding和Temporal Embedding没有位置编码。
我们假设输入的序列长度为(batch_size, seq_len, enc_in)如果用过去96个时刻的所有13个变量预测未来时刻的值那么输入即为(batch_size, 96, 13)。
3.1.1 Token Embedding
Autoformer输入的第1部分是对原始输入进行编码本质是利用一个1维卷积对原始序列进行特征提取并且序列的维度从原始的enc_in变换到d_model代码如下
class TokenEmbedding(nn.Module):def __init__(self, c_in, d_model):super(TokenEmbedding, self).__init__()padding 1 if torch.__version__ 1.5.0 else 2self.tokenConv nn.Conv1d(in_channelsc_in, out_channelsd_model,kernel_size3, paddingpadding, padding_modecircular)for m in self.modules():if isinstance(m, nn.Conv1d):nn.init.kaiming_normal_(m.weight, modefan_in, nonlinearityleaky_relu)def forward(self, x):x self.tokenConv(x.permute(0, 2, 1)).transpose(1, 2)return x输入x的大小为(batch_size, seq_len, enc_in)需要先将后两个维度交换以适配1维卷积接着让数据通过tokenConv由于添加了padding因此经过后seq_len维度不改变经过TokenEmbedding后得到大小为(batch_size, seq_len, d_model)的输出。
3.1.2 Temporal Embedding
Autoformer输入的第2部分是对时间戳进行编码即年月日星期时分秒等进行编码。这一部分与Informer中一致使用了两种编码方式我们依次解析。第一种编码方式TemporalEmbedding代码如下
class TemporalEmbedding(nn.Module):def __init__(self, d_model, embed_typefixed, freqh):super(TemporalEmbedding, self).__init__()minute_size 4hour_size 24weekday_size 7day_size 32month_size 13Embed FixedEmbedding if embed_type fixed else nn.Embeddingif freq t:self.minute_embed Embed(minute_size, d_model)self.hour_embed Embed(hour_size, d_model)self.weekday_embed Embed(weekday_size, d_model)self.day_embed Embed(day_size, d_model)self.month_embed Embed(month_size, d_model)def forward(self, x):x x.long()minute_x self.minute_embed(x[:, :, 4]) if hasattr(self, minute_embed) else 0.hour_x self.hour_embed(x[:, :, 3])weekday_x self.weekday_embed(x[:, :, 2])day_x self.day_embed(x[:, :, 1])month_x self.month_embed(x[:, :, 0])return hour_x weekday_x day_x month_x minute_xTemporalEmbedding的输入要求是(batch_size, seq_len, 5),5表示每个时间戳的月、天、星期星期一到星期七、小时以及刻钟数一刻钟15分钟。代码中对五个值分别进行了编码编码方式有两种一种是FixedEmbedding它使用位置编码作为embedding的参数不需要训练参数另一种就是torch自带的nn.Embedding参数是可训练的。
更具体的作者将月、天、星期、小时以及刻钟的范围分别限制在了13、32、7、24以及4。即保证输入每个时间戳的月份数都在0-12天数都在0-31星期都在0-6小时数都在0-23刻钟数都在0-3。例如2024/04/05/12:13星期五输入应该是(4, 5, 5, 13, 0)。注意12:13小时数应该为13小于等于12:00但大于11:00如11:30才为12。
对时间戳进行编码的第二种方式为TimeFeatureEmbedding
class TimeFeatureEmbedding(nn.Module):def __init__(self, d_model, embed_typetimeF, freqh):super(TimeFeatureEmbedding, self).__init__()freq_map {h: 4, t: 5, s: 6, m: 1, a: 1, w: 2, d: 3, b: 3}d_inp freq_map[freq]self.embed nn.Linear(d_inp, d_model)def forward(self, x):return self.embed(x)TimeFeatureEmbedding的输入为(batch_size, seq_len, d_inp)d_inp有多达8种选择。具体来说针对时间戳2024/04/05/12:13以freqh’为例其输入应该是(月份、日期、星期、小时)即(4, 5, 5, 13)然后针对输入通过以下函数将所有数据转换到-0.5到0.5之间
def time_features(dates, timeenc1, freqh): time_features takes in a dates dataframe with a dates column and extracts the date down to freq where freq can be any of the following if timeenc is 0: * m - [month] * w - [month] * d - [month, day, weekday] * b - [month, day, weekday] * h - [month, day, weekday, hour] * t - [month, day, weekday, hour, *minute] If timeenc is 1, a similar, but different list of freq values are supported (all encoded between [-0.5 and 0.5]): * Q - [month] * M - [month] * W - [Day of month, week of year] * D - [Day of week, day of month, day of year] * B - [Day of week, day of month, day of year] * H - [Hour of day, day of week, day of month, day of year] * T - [Minute of hour*, hour of day, day of week, day of month, day of year] * S - [Second of minute, minute of hour, hour of day, day of week, day of month, day of year]*minute returns a number from 0-3 corresponding to the 15 minute period it falls into.if timeenc 0:dates[month] dates.date.apply(lambda row: row.month, 1)dates[day] dates.date.apply(lambda row: row.day, 1)dates[weekday] dates.date.apply(lambda row: row.weekday(), 1)dates[hour] dates.date.apply(lambda row: row.hour, 1)dates[minute] dates.date.apply(lambda row: row.minute, 1)dates[minute] dates.minute.map(lambda x: x // 15)freq_map {y: [], m: [month], w: [month], d: [month, day, weekday],b: [month, day, weekday], h: [month, day, weekday, hour],t: [month, day, weekday, hour, minute],}return dates[freq_map[freq.lower()]].valuesif timeenc 1:dates pd.to_datetime(dates.date.values)return np.vstack([feat(dates) for feat in time_features_from_frequency_str(freq)]).transpose(1, 0)当freq为’t’时输入应该为[‘month’, ‘day’, ‘weekday’, ‘hour’, ‘minute’]其他类似。当通过上述函数将四个数转换为-0.5到0.5之间后再利用TimeFeatureEmbedding中的self.embed nn.Linear(d_inp, d_model)来将维度从4转换到d_model因此最终返回的输出大小也为(batch_size, seq_len, d_model)。
最终代码中通过一个DataEmbedding_wo_pos类来将2种编码放在一起
class DataEmbedding_wo_pos(nn.Module):def __init__(self, c_in, d_model, embed_typefixed, freqh, dropout0.1):super(DataEmbedding_wo_pos, self).__init__()self.value_embedding TokenEmbedding(c_inc_in, d_modeld_model)self.position_embedding PositionalEmbedding(d_modeld_model)self.temporal_embedding TemporalEmbedding(d_modeld_model, embed_typeembed_type,freqfreq) if embed_type ! timeF else TimeFeatureEmbedding(d_modeld_model, embed_typeembed_type, freqfreq)self.dropout nn.Dropout(pdropout)def forward(self, x, x_mark):x self.value_embedding(x) self.temporal_embedding(x_mark)return self.dropout(x)3.2 Decoder输入
在Informer中编码器和解码器的输入大同小异都由三部分组成而在Autoformer中二者存在差别。
在解码器中进行Token Embedding的不是原始的时间序列而是seasonal part这部分在3.3节中进行讲解。
3.3 Encoder与Decoder
完整的Autoformer代码如下
class Autoformer(nn.Module):Autoformer is the first method to achieve the series-wise connection,with inherent O(LlogL) complexitydef __init__(self, args):super(Autoformer, self).__init__()self.seq_len args.seq_lenself.label_len args.label_lenself.pred_len args.pred_lenself.output_attention args.output_attention# Decompkernel_size args.moving_avgself.decomp series_decomp(kernel_size)# Embedding# The series-wise connection inherently contains the sequential information.# Thus, we can discard the position embedding of transformers.self.enc_embedding DataEmbedding_wo_pos(args.enc_in, args.d_model, args.embed, args.freq,args.dropout)self.dec_embedding DataEmbedding_wo_pos(args.dec_in, args.d_model, args.embed, args.freq,args.dropout)# Encoderself.encoder Encoder([EncoderLayer(AutoCorrelationLayer(AutoCorrelation(False, args.factor, attention_dropoutargs.dropout,output_attentionargs.output_attention),args.d_model, args.n_heads),args.d_model,args.d_ff,moving_avgargs.moving_avg,dropoutargs.dropout,activationargs.activation) for l in range(args.e_layers)],norm_layermy_Layernorm(args.d_model))# Decoderself.decoder Decoder([DecoderLayer(AutoCorrelationLayer(AutoCorrelation(True, args.factor, attention_dropoutargs.dropout,output_attentionFalse),args.d_model, args.n_heads),AutoCorrelationLayer(AutoCorrelation(False, args.factor, attention_dropoutargs.dropout,output_attentionFalse),args.d_model, args.n_heads),args.d_model,args.c_out,args.d_ff,moving_avgargs.moving_avg,dropoutargs.dropout,activationargs.activation,)for l in range(args.d_layers)],norm_layermy_Layernorm(args.d_model),projectionnn.Linear(args.d_model, args.c_out, biasTrue))def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec,enc_self_maskNone, dec_self_maskNone, dec_enc_maskNone):# decomp initmean torch.mean(x_enc, dim1).unsqueeze(1).repeat(1, self.pred_len, 1)zeros torch.zeros([x_dec.shape[0], self.pred_len, x_dec.shape[2]], devicex_enc.device)seasonal_init, trend_init self.decomp(x_enc)# decoder inputtrend_init torch.cat([trend_init[:, -self.label_len:, :], mean], dim1)seasonal_init torch.cat([seasonal_init[:, -self.label_len:, :], zeros], dim1)# encenc_out self.enc_embedding(x_enc, x_mark_enc)enc_out, attns self.encoder(enc_out, attn_maskenc_self_mask)# decdec_out self.dec_embedding(seasonal_init, x_mark_dec)seasonal_part, trend_part self.decoder(dec_out, enc_out, x_maskdec_self_mask, cross_maskdec_enc_mask,trendtrend_init)# finaldec_out trend_part seasonal_partif self.output_attention:return dec_out[:, -self.pred_len:, :], attnselse:return dec_out[:, -self.pred_len:, :] # [B, L, D]观察forward主要的输入为x_enc, x_mark_enc, x_dec, x_mark_dec下边依次介绍
x_enc: 编码器输入大小为(batch_size, seq_len, enc_in)在这篇文章中我们使用前96个时刻的所有13个变量预测未来24个时刻的所有13个变量所以这里x_enc的输入应该是(batch_size, 96, 13)。x_mark_enc编码器的时间戳输入大小分情况本文中采用频率freqh’的TimeFeatureEmbedding编码方式所以应该输入[‘month’, ‘day’, ‘weekday’, ‘hour’]大小为(batch_size, 96, 4)。x_dec解码器输入大小为(batch_size, label_lenpred_len, dec_in)其中dec_in为解码器输入的变量个数也为13。在Informer中为了避免step-by-step的解码结构作者直接将x_enc中后label_len个时刻的数据和要预测时刻的数据进行拼接得到解码器输入。在本次实验中由于需要预测未来24个时刻的数据所以pred_len24向前看48个时刻所以label_len48最终解码器的输入维度应该为(batch_size, 482472, 13)。x_mark_dec解码器的时间戳输入大小为(batch_size, 72, 4)。
为了方便理解编码器和解码器的输入给一个具体的例子假设某个样本编码器的输入为1-96时刻的所有13个变量即x_enc大小为(96, 13)x_mark_enc大小为(96, 4)表示每个时刻的[‘month’, ‘day’, ‘weekday’, ‘hour’]解码器输入为编码器输入的后label_len48要预测的pred_len24个时刻的数据即49-120时刻的所有13个变量x_dec大小为(72, 13)同理x_mark_dec大小为(72, 4)。
为了防止数据泄露在预测97-120时刻的数据时解码器输入x_dec中不能包含97-120时刻的真实数据在原文中作者用24个0来代替代码如下
dec_inp torch.zeros_like(batch_y[:, -self.args.pred_len:, :]).float()
dec_inp torch.cat([batch_y[:, :self.args.label_len, :], dec_inp], dim1).float().to(self.device)3.3.1 初始化
这部分代码如下
# decomp init
mean torch.mean(x_enc, dim1).unsqueeze(1).repeat(1, self.pred_len, 1)
zeros torch.zeros([x_dec.shape[0], self.pred_len, x_dec.shape[2]], devicex_enc.device)
seasonal_init, trend_init self.decomp(x_enc)
# decoder input
trend_init torch.cat([trend_init[:, -self.label_len:, :], mean], dim1)
seasonal_init torch.cat([seasonal_init[:, -self.label_len:, :], zeros], dim1)首先是
mean torch.mean(x_enc, dim1).unsqueeze(1).repeat(1, self.pred_len, 1)这一句代码首先将大小为(batch_size, 96, 13)的x_enc沿着seq_len维度求平均然后再repeat变成(batch_size, 24, 13)其中24表示pred_len13表示96个时刻在13个变量上的平均值。
接着初始化大小为(batch_size, 24, 13)的全0矩阵zeros。
接着对x_enc进行分解得到两个趋势分量
seasonal_init, trend_init self.decomp(x_enc)更具体来说首先利用series_decomp模块来对x_enc也就是大小为(batch_size, seq_len96, enc_in13)的编码器输入进行分解series_decomp代码如下所示
class moving_avg(nn.Module):Moving average block to highlight the trend of time seriesdef __init__(self, kernel_size, stride):super(moving_avg, self).__init__()self.kernel_size kernel_sizeself.avg nn.AvgPool1d(kernel_sizekernel_size, stridestride, padding0)def forward(self, x):# padding on the both ends of time seriesfront x[:, 0:1, :].repeat(1, (self.kernel_size - 1) // 2, 1)end x[:, -1:, :].repeat(1, (self.kernel_size - 1) // 2, 1)x torch.cat([front, x, end], dim1)x self.avg(x.permute(0, 2, 1))x x.permute(0, 2, 1)return xclass series_decomp(nn.Module):Series decomposition blockdef __init__(self, kernel_size):super(series_decomp, self).__init__()self.moving_avg moving_avg(kernel_size, stride1)def forward(self, x):moving_mean self.moving_avg(x)res x - moving_meanreturn res, moving_mean输入的x为x_enc大小为(batch_size, seq_len96, enc_in13)所谓的分解就是先利用一个nn.AvgPool1d来对x_enc进行池化针对seq_len这个维度进行平均池化即每kernel_size长度求一次平均。由于添加了padding所以池化后大小不变依旧为(batch_size, seq_len, enc_in)池化后的这部分即为初始的季节趋势seasonal_initx_enc减去seasonal_init即为trend_init反映短期波动。
最后是处理decoder的初始输入
# decoder input
trend_init torch.cat([trend_init[:, -self.label_len:, :], mean], dim1)
seasonal_init torch.cat([seasonal_init[:, -self.label_len:, :], zeros], dim1)trend_init大小为(batch_size, 96, 13)我们只取其后label_len48个数据然后和大小为(batch_size, 24, 13)mean进行拼接大小变成(batch_size, 482472, 13)即trend_init的前部分为x_enc分解得到后部分为x_enc中所有时刻的平均值。seasonal_init大小为(batch_size, 96, 13)我们同样只取其后label_len个数据然后再和0进行拼接得到(batch_size, 482472, 13)即seasonal_init的前部分为x_enc分解得到后部分为0。
3.3.2 Encoder
Encoder过程如下所示
enc_out self.enc_embedding(x_enc, x_mark_enc)
enc_out, attns self.encoder(enc_out, attn_maskenc_self_mask)这部分和上一篇文章讲的Informer类似区别只是将注意力机制换成了AutoCorrelation有关AutoCorrelation这里不做详细介绍。
3.3.3 Decoder
Decoder过程如下所示
# dec
dec_out self.dec_embedding(seasonal_init, x_mark_dec)
seasonal_part, trend_part self.decoder(dec_out, enc_out, x_maskdec_self_mask, cross_maskdec_enc_mask, trendtrend_init)
# final
dec_out trend_part seasonal_part首先是利用seasonal_init进行Token Embedding编码而不是Informer中的x_decseasonal_init大小和x_dec一致都为(batch_size, 482472, 13)。
接着是解码过程
seasonal_part, trend_part self.decoder(dec_out, enc_out, x_maskdec_self_mask, cross_maskdec_enc_mask, trendtrend_init)self.decoder的详细过程
class Decoder(nn.Module):Autoformer encoderdef __init__(self, layers, norm_layerNone, projectionNone):super(Decoder, self).__init__()self.layers nn.ModuleList(layers)self.norm norm_layerself.projection projectiondef forward(self, x, cross, x_maskNone, cross_maskNone, trendNone):for layer in self.layers:x, residual_trend layer(x, cross, x_maskx_mask, cross_maskcross_mask)trend trend residual_trendif self.norm is not None:x self.norm(x)if self.projection is not None:x self.projection(x)return x, trend直接看forwardDecoder中有很多DecoderLayer每个DecoderLayer要求的输入为x, cross和trendx即为dec_out大小为(batch_size, 482472, 13)cross即编码器输出enc_out大小为(batch_size, seq_len96, d_model)。trend即为trend_init大小为(batch_size, 482472, 13)解码器利用dec_out和enc_out做AutoCorrelation得到x和残差
class DecoderLayer(nn.Module):Autoformer decoder layer with the progressive decomposition architecturedef __init__(self, self_attention, cross_attention, d_model, c_out, d_ffNone,moving_avg25, dropout0.1, activationrelu):super(DecoderLayer, self).__init__()d_ff d_ff or 4 * d_modelself.self_attention self_attentionself.cross_attention cross_attentionself.conv1 nn.Conv1d(in_channelsd_model, out_channelsd_ff, kernel_size1, biasFalse)self.conv2 nn.Conv1d(in_channelsd_ff, out_channelsd_model, kernel_size1, biasFalse)self.decomp1 series_decomp(moving_avg)self.decomp2 series_decomp(moving_avg)self.decomp3 series_decomp(moving_avg)self.dropout nn.Dropout(dropout)self.projection nn.Conv1d(in_channelsd_model, out_channelsc_out, kernel_size3, stride1, padding1,padding_modecircular, biasFalse)self.activation F.relu if activation relu else F.geludef forward(self, x, cross, x_maskNone, cross_maskNone):x x self.dropout(self.self_attention(x, x, x,attn_maskx_mask)[0])x, trend1 self.decomp1(x)x x self.dropout(self.cross_attention(x, cross, cross,attn_maskcross_mask)[0])x, trend2 self.decomp2(x)y xy self.dropout(self.activation(self.conv1(y.transpose(-1, 1))))y self.dropout(self.conv2(y).transpose(-1, 1))x, trend3 self.decomp3(x y)residual_trend trend1 trend2 trend3residual_trend self.projection(residual_trend.permute(0, 2, 1)).transpose(1, 2)return x, residual_trend然后将残累加到初始的trend上多层结束后最终返回x和trend。
finally作者将x和trend相加得到解码器的最终输出
dec_out trend_part seasonal_partdec_out大小依旧为(batch_size, 482472, 13)后pred_len24个即为预测值
if self.output_attention:return dec_out[:, -self.pred_len:, :], attns
else:return dec_out[:, -self.pred_len:, :] # [B, L, D]一个细节大小为(batch_size, 482472, 13)的x_dec貌似没有用到可能只是作者在写代码时为了匹配Informer的写法而保留的。
IV. 实验
首先是数据处理原始Autoformer中的数据处理和我之前写的30多篇文章的数据处理过程不太匹配因此这里重写了数据处理过程代码如下
def get_data(args):print(data processing...)data load_data()# splittrain data[:int(len(data) * 0.6)]val data[int(len(data) * 0.6):int(len(data) * 0.8)]test data[int(len(data) * 0.8):len(data)]scaler StandardScaler()def process(dataset, flag, step_size, shuffle):# 对时间列进行编码df_stamp dataset[[date]]df_stamp.date pd.to_datetime(df_stamp.date)data_stamp time_features(df_stamp, timeenc1, freqargs.freq)data_stamp torch.FloatTensor(data_stamp)# 接着归一化# 首先去掉时间列dataset.drop([date], axis1, inplaceTrue)if flag train:dataset scaler.fit_transform(dataset.values)else:dataset scaler.transform(dataset.values)dataset torch.FloatTensor(dataset)# 构造样本samples []for index in range(0, len(dataset) - args.seq_len - args.pred_len 1, step_size):# train_x, x_mark, train_y, y_marks_begin indexs_end s_begin args.seq_lenr_begin s_end - args.label_lenr_end r_begin args.label_len args.pred_lenseq_x dataset[s_begin:s_end]seq_y dataset[r_begin:r_end]seq_x_mark data_stamp[s_begin:s_end]seq_y_mark data_stamp[r_begin:r_end]samples.append((seq_x, seq_y, seq_x_mark, seq_y_mark))samples MyDataset(samples)samples DataLoader(datasetsamples, batch_sizeargs.batch_size, shuffleshuffle, num_workers0, drop_lastFalse)return samplesDtr process(train, flagtrain, step_size1, shuffleTrue)Val process(val, flagval, step_size1, shuffleTrue)Dte process(test, flagtest, step_sizeargs.pred_len, shuffleFalse)return Dtr, Val, Dte, scaler实验设置本次实验选择LSTM、Transformer以及Informer来和Autoformer进行对比其中LSTM采用直接多输出方式Transformer又分为Encoder-Only和Encoder-Decoder架构。
使用前96个时刻的所有13个变量预测未来24个时刻的所有13个变量只给出第一个变量也就是负荷这一变量的MAPE结果
LSTMEncoder-onlyEncoder-DecoderInformerAutoformer10.34%8.01%8.54%7.41%7.01%
由于没有进行调参实验结果仅供参考。可以发现LSTM在长序列预测上表现不好而Transformer和Informer表现都比较优秀Autoformer表现最好但差距不大。