使用 Keras 构建多变量、多任务的 LSTM

Posted

技术标签:

【中文标题】使用 Keras 构建多变量、多任务的 LSTM【英文标题】:Building a mutlivariate, multi-task LSTM with Keras 【发布时间】:2018-04-07 10:53:22 【问题描述】:

序言

我目前正在研究一个机器学习问题,我们的任务是使用过去的产品销售数据来预测未来的销售量(以便商店可以更好地计划他们的库存)。我们基本上有时间序列数据,我们知道每种产品在哪几天售出了多少件。我们还提供诸如天气情况、是否有公共假期、是否有任何产品在销售等信息。

我们已经能够使用具有密集层的 MLP 成功地对此进行建模,并且仅使用滑动窗口方法来包含周围几天的销售量。但是,我们相信使用 LSTM 等时间序列方法可以获得更好的结果。

数据

我们掌握的数据基本如下:

编辑:为清楚起见,上图中的“时间”列不正确。我们每天输入一次,而不是每月一次。但其他结构是相同的!)

所以X数据是有形状的:

(numProducts, numTimesteps, numFeatures) = (50 products, 1096 days, 90 features)

Y 数据的形状:

(numProducts, numTimesteps, numTargets) =  (50 products, 1096 days, 3 binary targets)

所以我们有三年(2014 年、2015 年、2016 年)的数据,并希望对此进行训练,以便对 2017 年做出预测。(这当然不是 100% 正确,因为我们实际上有截至 2017 年 10 月的数据,但让我们暂时忽略它)

问题

我想在 Keras 中构建一个 LSTM,让我能够做出这些预测。不过,有几个地方我卡住了。所以我有六个具体的问题(我知道应该尝试将 *** 帖子限制为一个问题,但这些都是相互交织的)。

首先,我将如何对批次的数据进行切片?既然我有整整三年的时间,那么简单地推进三批,每次一年的规模是否有意义?还是小批量(比如 30 天)和使用滑动窗口更有意义? IE。而不是 36 批每批 30 天,我使用 36 * 6 批每批 30 天,每次滑动 5 天?或者这不是真正应该使用 LSTM 的方式吗? (请注意,数据中有相当多的季节性,因此我也需要捕捉这种长期趋势)。

其次,在这里使用return_sequences=True 有意义吗?换句话说,我将我的 Y 数据保持为(50, 1096, 3) 以便(据我所知)在每个时间步都有一个预测,可以针对目标数据计算损失?还是使用return_sequences=False 会更好,以便仅使用每批的最终值来评估损失(即,如果使用年度批次,那么在 2016 年对于产品 1,我们会根据 2016 年 12 月的值 @987654333 进行评估@)。

第三,我应该如何处理这 50 种不同的产品?它们是不同的,但仍然具有很强的相关性,我们已经看到使用其他方法(例如具有简单时间窗的 MLP)当所有产品都在同一个模型中考虑时,结果会更好。目前摆在桌面上的一些想法是:

将目标变量改为不只是3个变量,而是3 * 50 = 150;即每个产品都有三个目标,所有这些目标都是同时训练的。 将 LSTM 层之后的结果拆分为 50 个密集网络,这些网络将 LSTM 的输出以及每个产品特有的一些特征作为输入 - 即我们得到一个具有 50 个损失函数的多任务网络,其中然后我们一起优化。会不会很疯狂? 将产品视为单一观察,并包含 LSTM 层中已有的产品特定特征。仅使用这一层,然后使用大小为 3 的输出层(用于三个目标)。分批推送每个产品。

第四,如何处理验证数据?通常我只会保留一个随机选择的样本来验证,但在这里我们需要保持时间排序。所以我想最好的办法是留几个月?

第五,这可能是我最不清楚的部分 - 如何使用实际结果进行预测?假设我使用了return_sequences=False,并且我在所有三年中分三批(每次到 11 月)进行了训练,目标是训练模型以预测下一个值(2014 年 12 月、2015 年 12 月、2016 年 12 月)。如果我想在 2017 年使用这些结果,这实际上是如何工作的?如果我理解正确,在这种情况下我唯一能做的就是为模型提供 2017 年 1 月至 11 月的所有数据点,它会给我一个 2017 年 12 月的预测。对吗?但是,如果我使用return_sequences=True,然后对截至 2016 年 12 月的所有数据进行训练,那么我是否能够通过为模型提供 2017 年 1 月观察到的特征来获得 2017 年 1 月的预测?或者我还需要在 2017 年 1 月之前的 12 个月内给它吗?那么 2017 年 2 月呢,我是否还需要提供 2017 年的价值,以及在那之前的 11 个月? (如果听起来我很困惑,那是因为我很困惑!)

最后,根据我应该使用的结构,我如何在 Keras 中做到这一点?我目前想到的是以下几点:(尽管这仅适用于一种产品,因此并不能解决将所有产品置于同一模型中的问题):

Keras 代码

trainX = trainingDataReshaped #Data for Product 1, Jan 2014 to Dec 2016
trainY = trainingTargetReshaped
validX = validDataReshaped #Data for Product 1, for ??? Maybe for a few months?
validY = validTargetReshaped    

numSequences = trainX.shape[0]
numTimeSteps = trainX.shape[1]
numFeatures = trainX.shape[2]

numTargets = trainY.shape[2]

model = Sequential()
model.add(LSTM(100, input_shape=(None, numFeatures), return_sequences=True)) 
model.add(Dense(numTargets, activation="softmax"))    

model.compile(loss=stackEntry.params["loss"],
      optimizer="adam",
      metrics=['accuracy'])

history = model.fit(trainX, trainY,
            batch_size=30,
            epochs=20,
            verbose=1,
            validation_data=(validX, validY))               

predictX  = predictionDataReshaped #Data for Product 1, Jan 2017 to Dec 2017

prediction=model.predict(predictX)

【问题讨论】:

这个问题可能会帮助您入门:***.com/questions/46482139/… 一些不构成完整答案但可能有用的随机想法:#1 请参阅github.com/fchollet/keras/issues/8055 re timedistributed issues; #2 我发现拆分序列以尝试捕获整体数据的多个具有代表性的“特征”似乎最适合设置序列长度; #3 参数模型似乎比分类模型更难在 LSTM 上获得好的结果——我在这里尝试了一段时间:babble-rnn.consected.com; #4 在训练期间,我在查看结果时得到了最好的结果,而不仅仅是计算出的损失,这主要是建模噪声! 【参考方案1】:

问题 1

有几种方法可以解决这个问题。您建议的似乎是一个滑动窗口。

但实际上你不需要对时间维度进行切片,你可以一次输入所有 3 年。您可以对产品尺寸进行切片,以防您的批次对内存和速度而言太大。

您可以使用形状为 (products, time, features) 的单个数组

问题 2

是的,使用return_sequences=True 是有意义的。

如果我正确理解了您的问题,那么您每天都有y 预测,对吗?

问题 3

这确实是一个悬而未决的问题。所有方法都有其优点。

但是,如果您正在考虑将所有产品功能放在一起,作为这些不同性质的功能,您可能应该扩展所有可能的功能,就好像存在一个考虑所有产品的所有功能的大单热向量一样。

如果每个产品都具有仅适用于其自身的独立功能,那么为每个产品创建单独模型的想法对我来说似乎并不疯狂。

您还可以将产品 id 设为 one-hot 向量输入,并使用单个模型。

问题 4

根据您选择的方法,您可以:

将部分产品拆分为验证数据 将时间步长的最后部分保留为验证数据 尝试使用交叉验证方法,为训练和测试留出不同的长度(测试数据越长,误差越大,但您可能希望将此测试数据裁剪为固定长度)

问题 5

可能还有很多方法。

有些方法可以使用滑动窗口。您在固定的时间长度内训练您的模型。

还有一些方法可以用整个长度训练 LSTM 层。在这种情况下,您首先要预测整个已知部分,然后开始预测未知部分。

我的问题:X 数据在您必须预测 Y 的时期是否已知? XX在这个时期也是未知数,所以你还要预测X

问题 6

我建议你看看这个问题及其答案:How to deal with multi-step time series forecasting in multivariate LSTM in keras

另请参阅此笔记本,它设法展示了这个想法:https://github.com/danmoller/TestRepo/blob/master/TestBookLSTM.ipynb

不过,在这个笔记本中,我使用了一种将 X 和 Y 作为输入的方法。我们预测未来的 X 和 Y。

您可以尝试创建一个模型(如果是这种情况)仅用于预测 X。然后再创建一个模型来根据 X 预测 Y。

在另一种情况下(如果您已经拥有所有 X 数据,则无需预测 X),您可以创建一个仅从 X 预测 Y 的模型。(您仍然需要遵循笔记本中的部分方法,在首先预测已知的 Y 只是为了让你的模型调整到它在序列中的位置,然后你预测未知的 Y)——这可以在一个单一的全长 X 输入中完成(其中包含训练 X 在开始和最后的测试 X)。

奖励答案

知道选择哪种方法和哪种模型可能是赢得比赛的确切答案......所以,这个问题没有最佳答案,每个竞争对手都在努力找出这个答案。

【讨论】:

【参考方案2】:

所以:

首先,我将如何对批次的数据进行切片?既然我有 整整三年,简单地推过去三年有意义吗? 批次,每次大小一年?还是更有意义 做小批量(比如 30 天)并使用滑动窗口? IE。而不是 36 批每批 30 天,我使用 36 * 6 批 30 每个天,每次滑动5天?或者这不是真正的 应该如何使用 LSTM? (请注意,有相当多的 数据中的季节性,我需要抓住那种长期的 趋势)。

老实说 - 对此类数据进行建模非常困难。首先-我不建议您使用LSTMs,因为它们旨在捕获一些不同类型的数据(例如,对长期依赖建模非常重要的NLP或语音-而不是季节性)和他们需要大量数据才能学习。我宁愿建议您使用GRUSimpleRNN,它们更容易学习,应该更适合您的任务。

谈到批处理 - 我绝对建议您使用固定窗口技术,因为它最终会产生比提供一整年或一整月更多的数据点。尝试将天数设置为元参数,这也将通过在训练中使用不同的值并选择最合适的值来优化。

说到季节性 - 当然,这是一个例子,但是:

您可能收集的数据点和年份太少,无法提供对季节趋势的良好估计, 使用任何类型的循环神经网络来捕捉这种季节性是一个非常糟糕的想法。

我建议你改为:

尝试添加季节性特征(例如,月份变量、日期变量、如果当天有某个假期或距下一个重要假期还有多少天则设置为 true 的变量 - 这是您可能真的很有创意) 使用聚合的去年数据作为一项功能 - 例如,您可以提供去年的结果或它们的聚合,例如去年结果的运行平均值、最大值、最小值等。

其次,这里使用 return_sequences=True 有意义吗?在 换句话说,我将我的 Y 数据保持原样 (50, 1096, 3) 以便(至于 我已经理解了)在每个时间步都有一个预测 可以根据目标数据计算损失吗?或者我会更好 用 return_sequences=False 关闭,这样只有每个的最终值 批次用于评估损失(即,如果使用年度批次,则 在 2016 年,对于产品 1,我们根据 2016 年 12 月的价值评估 (1,1,1))。

使用return_sequences=True 可能有用,但仅限于以下情况:

    当给定的LSTM(或另一个循环层)之后将有另一个循环层。 在一个场景中 - 当您通过在不同时间窗口中同时学习模型的内容提供一个移位的原始系列作为输出时,等等。

第二点中描述的方法可能是一种有趣的方法,但请记住,它可能有点难以实现,因为您需要重写模型才能获得生产结果。更难的是,您需要针对多种类型的时间不稳定性测试您的模型 - 而这种方法可能会使这完全不可行。

第三,我应该如何处理这50种不同的产品?他们是 不同,但仍然密切相关,我们已经看到其他 方法(例如具有简单时间窗的 MLP) 当所有产品都在同一个模型中考虑时,结果会更好。 目前摆在桌面上的一些想法是:

将目标变量改为不只是3个变量,而是3 * 50 = 150;即每个产品都有三个目标,所有这些目标都是同时训练的。 将 LSTM 层之后的结果拆分为 50 个密集网络,这些网络将 LSTM 的输出作为输入,加上一些特征 特定于每个产品 - 即我们得到一个多任务网络 50 个损失函数,然后我们一起优化。那会是 疯了吗? 将产品视为单一观察,并包含 LSTM 层中已有的产品特定特征。仅使用这一层 接着是大小为 3 的输出层(用于三个目标)。推 通过单独批次中的每个产品。

我肯定会选择第一选择,但在提供详细解释之前,我将讨论第 2 和第 3 的缺点:

在第二种方法中:这不会很疯狂,但您会失去很多产品目标之间的相关性, 在第三种方法中:您将丢失许多有趣的模式,这些模式发生在不同时间序列之间的依赖关系中。

在做出我的选择之前 - 让我们讨论另一个问题 - 数据集中的冗余。我猜你有 3 种特征:

产品特定的(假设有“m”个) 一般特征 - 假设有“n”个。

现在您有了(timesteps, m * n, products) 大小的表格。我会将其转换为(timesteps, products * m + n) 形状的表格,因为所有产品的一般特征都是相同的。这将为您节省大量内存,并使馈送到循环网络变得可行(请记住,keras 中的循环层只有一个特征维度 - 而您有两个 - productfeature 一个)。

那么为什么我认为第一种方法是最好的呢?因为它利用了数据中许多有趣的依赖关系。当然 - 这可能会损害训练过程 - 但有一个简单的技巧可以克服这个问题:降维。你可以例如在您的 150 维向量上训练 PCA 并将其大小减小到小得多 - 这要归功于您的依赖项由 PCA 建模,并且您的输出具有更可行的大小。

第四,如何处理验证数据?通常我会 保留随机选择的样本进行验证,但在这里我们 需要保持时间订购到位。所以我想最好的办法是 只保留几个月?

这是一个非常重要的问题。根据我的经验 - 您需要针对多种类型的不稳定性测试您的解决方案,以确保它可以正常工作。因此,您应该牢记一些规则:

您的训练序列和测试序列之间应该没有重叠。如果存在这样的情况 - 您将在训练时将来自测试集的有效值馈送到模型中, 您需要针对多种时间依赖性测试模型时间稳定性。

最后一点可能有点含糊 - 举几个例子:

年份稳定性 - 通过使用两年的每种可能组合对其进行训练来验证您的模型,并在保留的一年中对其进行测试(例如,2015 年、2016 年与 2017 年、2015 年、2017 年与 2016 年等) - 这将向您展示年份变化如何影响您的模型, 未来预测稳定性 - 在几周/月/年的子集上训练您的模型并使用接下来的周/月/年结果对其进行测试(例如,在 2015 年 1 月、2016 年 1 月和 2017 年 1 月训练并测试它使用 2015 年 2 月、2016 年 2 月、2017 年 2 月的数据等) 月份稳定性 - 在测试集中保留某个月份时训练模型。

当然 - 你可以尝试另一种坚持。

第五,这可能是我最不清楚的部分 - 如何使用实际结果进行预测?假设我使用了 return_sequences=False 并且我在三年内训练了所有三年 批次(每次到 11 月),目标是训练模型 预测下一个值(2014 年 12 月、2015 年 12 月、2016 年 12 月)。如果我想 在 2017 年使用这些结果,这实际上是如何工作的?如果我 正确理解它,在这种情况下我唯一能做的就是 然后向模型提供 2017 年 1 月至 11 月的所有数据点,然后 会给我一个 2017 年 12 月的预测。对吗?然而, 如果我要使用 return_sequences=True,然后对所有数据进行训练 2016 年 12 月,然后我能否得到 2017 年 1 月的预测 通过为模型提供 2017 年 1 月观察到的特征?还是我需要 还给它 2017 年 1 月之前的 12 个月吗? 2017 年 2 月怎么样? 另外需要给出 2017 年的值,再加上 11 个月 在那之前? (如果听起来我很困惑,那是因为我很困惑!)

这取决于您构建模型的方式:

如果您使用了return_sequences=True,则需要将其重写为return_sequence=False,或者仅获取输出并仅考虑结果的最后一步, 如果您使用的是固定窗口 - 那么您只需在预测模型之前输入一个窗口,

如果您使用不同的长度 - 您可以提供任何时间步长来处理您想要的预测期(但我建议您至少提供 7 个处理日)。

最后,根据我应该使用什么结构,我如何在 Keras 中做到这一点?我现在想到的是以下几条:(虽然这仅适用于一种产品,所以不能解决所有产品都在同一个型号中)

这里 - 需要更多关于您选择的模型类型的信息。

【讨论】:

很好的答案,谢谢!关于捕捉季节性:您所描述的(为公共假期设置标志、日历周等)是我们已经具备的。当作为 MLP 的输入时,这非常有效。如果窗口期很短(比如 1-2 周),我很难理解这对 LSTM(或 GRU 或 SimpleRNN)有何帮助。如果 LSTM 仅将“Christmas”视为圣诞节前后的变量,它如何学会区分“Christmas time”和“Not-Christmas time”?这就是为什么我考虑使用 365 天的滑动时间窗口。 你不能指望任何类型的神经网络从 3 个数据点中学习年度模式。这个数额简直太小了。这就是为什么我建议您使用这些变量作为网络的某种提示。此外 - 我不会太具体 - holiday 变量将产生比 Christmas 等特定假日变量更多的数据点。在处理此类数据时这是一个大问题 - 我们不需要处理很多案例。

以上是关于使用 Keras 构建多变量、多任务的 LSTM的主要内容,如果未能解决你的问题,请参考以下文章

如何让 Keras LSTM 在多变量设置中对多个时间序列进行预测?

如何为LSTM Keras中的多步和多变量准备时间序列数据

教你搭建多变量时间序列预测模型LSTM(附代码数据集)

深度学习多变量时间序列预测:LSTM算法构建时间序列多变量模型预测交通流量+代码实战

如何使用 keras 堆叠 LSTM 模型正确塑造多类分类的输入

在 LSTM 网络的输入上使用 Masking 时,Keras(TensorFlow 后端)多 GPU 模型(4gpus)失败