当前位置: 首页 > news >正文

做服装批发网站免费培训课程

做服装批发网站,免费培训课程,市场调研公司收费标准,签名设计在线生成器Encoder-decoder 模型在序列到序列的自然语言处理任务(如语言翻译等)中提供了最先进的结果。多步时间序列预测也可以被视为一个 seq2seq 任务,可以使用 encoder-decoder 模型来处理。本文提供了一个用于解决 Kaggle 时间序列预测任务的 encod…

Encoder-decoder 模型在序列到序列的自然语言处理任务(如语言翻译等)中提供了最先进的结果。多步时间序列预测也可以被视为一个 seq2seq 任务,可以使用 encoder-decoder 模型来处理。本文提供了一个用于解决 Kaggle 时间序列预测任务的 encoder-decoder 模型,并介绍了获得前 10% 结果所涉及的步骤。

数据集

所使用的数据集来自过去的 Kaggle 竞赛 —— Store Item demand forecasting challenge,给定过去 5 年的销售数据(从 2013 年到 2017 年)的 50 个商品来自 10 家不同的商店,预测接下来 3 个月(2018 年 1 月 1 日至 2018 年 3 月 31 日)每个商品的销售情况。这是一个多步多元的时间序列预测问题。

特征也非常的少

有500个商店组合,这意味着要预测500个时间序列。

数据预处理

深度学习模型擅长自行发现特征,因此可以将特征工程简化到最少。

从图表中可以看出,我们的数据具有每周和每月的季节性以及每年的趋势,为了捕捉这些特性,可以向模型提供DateTime 特征。为了更好地捕捉每个商品销售的年度趋势,还提供了年度自相关性。

时间的特征是有周期性的,为了将这些信息提供给模型,对 DateTime 特征应用了正弦和余弦变换。

最终的特征如下所示。

神经网络期望所有特征的值都在相同的尺度上,因此数据缩放变得必不可少。每个时间序列的值都是独立归一化的。年度自相关和年份也进行了归一化。

Encoder-decoder 模型接受一个序列作为输入并返回一个序列作为输出,所以需要将数据转为序列

输出序列的长度固定为 90 天,而输入序列的长度必须根据问题的复杂性和可用的计算资源来选择。对于这个问题,可以选择 180 天(6 个月)的输入序列长度。通过在数据集中的每个时间序列上应用滑动窗口来构建序列数据。

数据集和数据加载器

Pytorch 提供了方便的抽象 —— Dataset 和 Dataloader —— 用于将数据输入模型。Dataset 接受序列数据作为输入,并负责构建每个数据点以输入到模型中。Dataloader 则可以读取Dataset 生成批量的数据

 class StoreItemDataset(Dataset):def __init__(self, cat_columns=[], num_columns=[], embed_vector_size=None, decoder_input=True, ohe_cat_columns=False):super().__init__()self.sequence_data = Noneself.cat_columns = cat_columnsself.num_columns = num_columnsself.cat_classes = {}self.cat_embed_shape = []self.cat_embed_vector_size = embed_vector_size if embed_vector_size is not None else {}self.pass_decoder_input=decoder_inputself.ohe_cat_columns = ohe_cat_columnsself.cat_columns_to_decoder = Falsedef get_embedding_shape(self):return self.cat_embed_shapedef load_sequence_data(self, processed_data):self.sequence_data = processed_datadef process_cat_columns(self, column_map=None):column_map = column_map if column_map is not None else {}for col in self.cat_columns:self.sequence_data[col] = self.sequence_data[col].astype('category')if col in column_map:self.sequence_data[col] = self.sequence_data[col].cat.set_categories(column_map[col]).fillna('#NA#')else:self.sequence_data[col].cat.add_categories('#NA#', inplace=True)self.cat_embed_shape.append((len(self.sequence_data[col].cat.categories), self.cat_embed_vector_size.get(col, 50)))def __len__(self):return len(self.sequence_data)def __getitem__(self, idx):row = self.sequence_data.iloc[[idx]]x_inputs = [torch.tensor(row['x_sequence'].values[0], dtype=torch.float32)]y = torch.tensor(row['y_sequence'].values[0], dtype=torch.float32)if self.pass_decoder_input:decoder_input = torch.tensor(row['y_sequence'].values[0][:, 1:], dtype=torch.float32)if len(self.num_columns) > 0:for col in self.num_columns:num_tensor = torch.tensor([row[col].values[0]], dtype=torch.float32)x_inputs[0] = torch.cat((x_inputs[0], num_tensor.repeat(x_inputs[0].size(0)).unsqueeze(1)), axis=1)decoder_input = torch.cat((decoder_input, num_tensor.repeat(decoder_input.size(0)).unsqueeze(1)), axis=1)if len(self.cat_columns) > 0:if self.ohe_cat_columns:for ci, (num_classes, _) in enumerate(self.cat_embed_shape):col_tensor = torch.zeros(num_classes, dtype=torch.float32)col_tensor[row[self.cat_columns[ci]].cat.codes.values[0]] = 1.0col_tensor_x = col_tensor.repeat(x_inputs[0].size(0), 1)x_inputs[0] = torch.cat((x_inputs[0], col_tensor_x), axis=1)if self.pass_decoder_input and self.cat_columns_to_decoder:col_tensor_y = col_tensor.repeat(decoder_input.size(0), 1)decoder_input = torch.cat((decoder_input, col_tensor_y), axis=1)else:cat_tensor = torch.tensor([row[col].cat.codes.values[0] for col in self.cat_columns],dtype=torch.long)x_inputs.append(cat_tensor)if self.pass_decoder_input:x_inputs.append(decoder_input)y = torch.tensor(row['y_sequence'].values[0][:, 0], dtype=torch.float32)if len(x_inputs) > 1:return tuple(x_inputs), yreturn x_inputs[0], y

模型架构

Encoder-decoder 模型是一种用于解决序列到序列问题的循环神经网络(RNN)。

Encoder-decoder 模型由两个网络组成——编码器(Encoder)和解码器(Decoder)。编码器网络学习(编码)输入序列的表示,捕捉其特征或上下文,并输出一个向量。这个向量被称为上下文向量。解码器网络接收上下文向量,并学习读取并提取(解码)输出序列。

在编码器和解码器中,编码和解码序列的任务由一系列循环单元处理。

编码器

编码器网络的输入形状为(序列长度,特征维度),因此序列中的每个项目由 n 个值组成。在构建这些值时,不同类型的特征被不同对待。

时间依赖特征 — 这些是随时间变化的特征,如销售和 DateTime 特征。在编码器中,每个连续的时间依赖值被输入到一个 RNN 单元中。

数值特征 — 不随时间变化的静态特征,如序列的年度自相关。这些特征在序列的长度中重复,并被输入到 RNN 中。重复和合并值的过程在 Dataset 中处理。

分类特征 — 如商店 ID 和商品 ID 等特征,可以通过多种方式处理,每种方法的实现可以在 encoders.py 中找到。对于最终模型,分类变量进行了独热编码,跨序列重复,并被输入到 RNN 中,这也在 Dataset 中处理。

带有这些特征的输入序列被输入到循环网络 — GRU 中。下面给出了使用的编码器网络的代码。

 class RNNEncoder(nn.Module):def __init__(self, rnn_num_layers=1, input_feature_len=1, sequence_len=168, hidden_size=100, bidirectional=False, device='cpu', rnn_dropout=0.2):super().__init__()self.sequence_len = sequence_lenself.hidden_size = hidden_sizeself.input_feature_len = input_feature_lenself.num_layers = rnn_num_layersself.rnn_directions = 2 if bidirectional else 1self.gru = nn.GRU(num_layers=rnn_num_layers,input_size=input_feature_len,hidden_size=hidden_size,batch_first=True,bidirectional=bidirectional,dropout=rnn_dropout)self.device = devicedef forward(self, input_seq):ht = torch.zeros(self.num_layers * self.rnn_directions, input_seq.size(0), self.hidden_size, device=self.device)if input_seq.ndim < 3:input_seq.unsqueeze_(2)gru_out, hidden = self.gru(input_seq, ht)print(gru_out.shape)print(hidden.shape)if self.rnn_directions * self.num_layers > 1:num_layers = self.rnn_directions * self.num_layersif self.rnn_directions > 1:gru_out = gru_out.view(input_seq.size(0), self.sequence_len, self.rnn_directions, self.hidden_size)gru_out = torch.sum(gru_out, axis=2)hidden = hidden.view(self.num_layers, self.rnn_directions, input_seq.size(0), self.hidden_size)if self.num_layers > 0:hidden = hidden[-1]else:hidden = hidden.squeeze(0)hidden = hidden.sum(axis=0)else:hidden.squeeze_(0)return gru_out, hidden

解码器

解码器接收来自编码器的上下文向量,解码器的输入还包括未来的 DateTime 特征和滞后特征。模型中使用的滞后特征是前一年的值。使用滞后特征的原因是,鉴于输入序列仅限于 180 天,提供超出此时间的重要数据点将有助于模型。

不同于直接使用循环网络(GRU)的编码器,解码器是通过循环一个解码器单元来构建的。这是因为从每个解码器单元获得的预测作为输入传递给下一个解码器单元。每个解码器单元由一个 GRUCell 组成,其输出被输入到一个全连接层,该层提供预测。每个解码器单元的预测被组合形成输出序列。

 class DecoderCell(nn.Module):def __init__(self, input_feature_len, hidden_size, dropout=0.2):super().__init__()self.decoder_rnn_cell = nn.GRUCell(input_size=input_feature_len,hidden_size=hidden_size,)self.out = nn.Linear(hidden_size, 1)self.attention = Falseself.dropout = nn.Dropout(dropout)def forward(self, prev_hidden, y):rnn_hidden = self.decoder_rnn_cell(y, prev_hidden)output = self.out(rnn_hidden)return output, self.dropout(rnn_hidden)

Encoder-Decoder模型

下面代码将上面2个模型整合完成完整的seq2seq模型

 class EncoderDecoderWrapper(nn.Module):def __init__(self, encoder, decoder_cell, output_size=3, teacher_forcing=0.3, sequence_len=336, decoder_input=True, device='cpu'):super().__init__()self.encoder = encoderself.decoder_cell = decoder_cellself.output_size = output_sizeself.teacher_forcing = teacher_forcingself.sequence_length = sequence_lenself.decoder_input = decoder_inputself.device = devicedef forward(self, xb, yb=None):if self.decoder_input:decoder_input = xb[-1]input_seq = xb[0]if len(xb) > 2:encoder_output, encoder_hidden = self.encoder(input_seq, *xb[1:-1])else:encoder_output, encoder_hidden = self.encoder(input_seq)else:if type(xb) is list and len(xb) > 1:input_seq = xb[0]encoder_output, encoder_hidden = self.encoder(*xb)else:input_seq = xbencoder_output, encoder_hidden = self.encoder(input_seq)prev_hidden = encoder_hiddenoutputs = torch.zeros(input_seq.size(0), self.output_size, device=self.device)y_prev = input_seq[:, -1, 0].unsqueeze(1)for i in range(self.output_size):step_decoder_input = torch.cat((y_prev, decoder_input[:, i]), axis=1)if (yb is not None) and (i > 0) and (torch.rand(1) < self.teacher_forcing):step_decoder_input = torch.cat((yb[:, i].unsqueeze(1), decoder_input[:, i]), axis=1)rnn_output, prev_hidden = self.decoder_cell(prev_hidden, step_decoder_input)y_prev = rnn_outputoutputs[:, i] = rnn_output.squeeze(1)return outputs

训练

模型的性能高度依赖于优化、学习率等超参数和策略

  1. 验证策略 —— 由于我们的数据是时间依赖的,交叉的训练-验证-测试分割不适用。时间依赖的训练-验证-测试分割存在一个问题,即模型没有在最近的验证数据上进行训练,这影响了模型在测试数据上的表现。为了解决这个问题,模型在过去 3 年的数据(2014 到 2016 年)上进行训练,并预测 2017 年的前 3 个月,这用于验证和实验。最终模型在 2014 到 2017 年的数据上进行训练,并预测 2018 年的前 3 个月。最终模型基于验证模型训练的学习成果,以盲模式(无验证)进行训练。
  2. 优化器 —— 使用的优化器是 AdamW,它在许多学习任务中提供了最佳结果。另一个探索的优化器是 COCOBOptimizer,它不显式设置学习率。在使用 COCOBOptimizer 训练时,我观察到它比 AdamW 尤其是在初始迭代时收敛更快。但使用 AdamW 和单周期学习得到了最佳结果。
  3. 学习率调度 —— 使用了 1cycle 学习率调度器。通过使用循环学习的学习率查找器确定了周期中的最大学习率。
  4. 损失函数 —— 使用的损失函数是均方误差损失(MSE),这与最终测试的损失 —— SMAPE 不同。MSE 损失提供了更稳定的收敛性,优于使用 SMAPE。
  5. 为编码器和解码器网络使用了不同的优化器和调度器,这带来了结果的改进。
  6. 除了权重衰减外,还在编码器和解码器中使用了 dropout 来对抗过拟合。

结果

下图显示了该模型对2018年前3个月某家商店单品的预测。

通过绘制所有商品的平均销售额,以及均值预测来去除噪声,可以更好地评估模型。下图来自验证模型对特定日期的预测,可以与实际销售数据进行比较。

这个结果在竞赛排行榜中提供前10%的排名。

总结

本文演示了使用Encoder-Decoder 模型创建多步时间序列预测的完整步骤,但是为了达到这个结果(10%),作者还做了超参数调优。并且这个模型还没有增加注意力机制,所以还可以通过探索注意机制来进一步改进模型,进一步提高模型的记忆能力,应该能获得更好的分数。

本文代码:

https://avoid.overfit.cn/post/242a897692244172ae44adc15a569647

作者:Gautham Kumaran

http://www.hkea.cn/news/514455/

相关文章:

  • 涞水县住房和城乡建设局网站厦门seo专业培训学校
  • 网站建设销售招聘德阳seo
  • 平台网站建设的公司seozou是什么意思
  • wordpress 相册 主题seo整站优化技术培训
  • 做窗帘网站图片百度自动点击器下载
  • 飘雪影视大全免费观看视频快推达seo
  • 做网站的装饰标语seo宣传网站
  • 国外 平面设计 网站百度收录
  • 做网站话术简述搜索引擎的工作原理
  • 现在建设网站赚钱吗seo外链论坛
  • 青海网站建设企业海南百度竞价推广
  • 南京做网站yuanmus电脑突然多了windows优化大师
  • 美国做deals的网站软文营销经典案例优秀软文
  • 招标网站怎么做吴江seo网站优化软件
  • 苏州建设工程协会网站seo去哪里学
  • 上海正规网站制作价格可口可乐软文营销案例
  • 番禺网站 建设信科网络站长之家ping
  • 建筑工程施工承包合同关键词优化报价推荐
  • 网站可以免费看企业网站系统
  • 中华人民共和国建设部网站seo怎么快速提高排名
  • 南宁做网站的有几家东莞网络营销网站建设
  • 苏州知名网站建设开发新区seo整站优化公司
  • 政府建设网站计划书品牌营销策略包括哪些内容
  • 深圳市做网站百度seo排名点击器app
  • 五莲网站建设维护推广网络营销推广及优化方案
  • 重庆网红整站多关键词优化
  • 动易网站cms一级消防工程师考试
  • wordpress更新报错想找搜索引擎优化
  • 提供网站建设费用资源网
  • wordpress怎么使用主题seo优化评论