使用Keras建立一个多变量,多任务的LSTM

时间:2017-10-26 07:07:32

标签: tensorflow machine-learning neural-network keras lstm

序言

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

我们已经能够使用具有密集层的MLP取得一些成功,并且仅使用滑动窗口方法来包含周围几天的销售量。但是,我们相信,通过LSTM等时间序列方法,我们能够获得更好的结果。

数据

我们的数据基本如下:

enter image description here

编辑:为了清晰起见,上图中的"时间"列不正确。我们每天输入一次,而不是每月输入一次。但是否则结构是一样!)

所以X数据的形状如下:

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

Y数据的形状如下:

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

enter image description here

因此,我们有三年(2014年,2015年,2016年)的数据,并希望对此进行培训,以便对2017年进行预测。(当然,这不是100%正确,因为我们实际上有数据到2017年10月,但我们暂时忽略这一点)

问题

我想在Keras建立一个LSTM,允许我做出这些预测。有几个地方我被卡住了。所以我有六个具体问题(我知道应该尝试将Stackoverflow帖子限制为一个问题,但这些都是交织在一起的。)

首先,如何为批次分割数据?由于我有三年的时间,所以只需按顺序推进三批,每次大小一年是否合理?或者更小的批次(比如30天)以及使用滑动窗口更有意义吗?即而不是36个批次,每个30天,我使用36 * 6批次,每个30天,每次滑动5天?或者这不是真的应该使用LSTM的方式吗? (请注意,数据中存在相当多的季节性,我需要捕捉这种长期趋势。)

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

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

  • 将目标变量更改为不仅仅是3个变量,而是3 * 50 = 150;即,对于每个产品,有三个目标,所有目标都是同时训练的。
  • 将LSTM层之后的结果分成50个密集网络,将LSTM的输出作为输入,加上每个产品特有的一些功能 - 即我们得到一个具有50个丢失功能的多任务网络,然后我们一起优化。那会很疯狂吗?
  • 将产品视为单一观察,并在LSTM层中包含产品特定功能。仅使用这一层,然后使用大小为3的输出层(对于三个目标)。单独推送每个产品。

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

第五,这是我可能最不清楚的部分 - 如何使用实际结果来执行预测?让我们说我使用了return_sequences=False,我分三批训练了三年(每次都是11月),目的是训练模型以预测下一个值(2014年12月,2015年12月,12月) 2016)。如果我想在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)

3 个答案:

答案 0 :(得分:11)

所以:

  

首先,我如何为批次切割数据?既然我有   完整的三年,简单地通过三个是否有意义   批次,每次大小一年?或者它更有意义   制作较小的批次(比如30天)以及使用推拉窗户?   即而不是36个批次,每个30天,我使用36 * 6批次30   每个日子,每次滑动5天?或者这不是真的   应该使用LSTM吗? (请注意,有很多   在数据的季节性,我需要抓住那种长期   趋势也是如此)。

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

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

当谈到季节性时 - 当然,这是一个案例,但是:

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

我建议你做的是:

  • 尝试添加季节性功能(例如月份变量,日期变量,如果当天有某个假期或者下一个重要假期有多少天,则设置为真的变量 - 这是您的房间可能真的很有创意)
  • 使用汇总的去年数据作为功能 - 例如,您可以提供去年的结果或汇总数据,例如去年的结果平均值,最大值,最小值等等。
  

其次,在这里使用return_sequences = True是否有意义?在   换句话说,我保持我的Y数据不变(50,1096,3)这样(至于   我已经明白了)每个时间步都有预测   可以根据目标数据计算损失吗?或者我会变得更好   off with return_sequences = False,这样只有每个的最终值   批次用于评估损失(即,如果使用年度批次,那么   在2016年的产品1中,我们评估2016年12月的价值   (1,1,1))。

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

  1. 当给定的LSTM(或另一个复发图层)后面还有另一个复发图层时。
  2. 在一个场景中 - 当您通过在不同时间窗口同时学习模型的同时提供移位的原始系列作为输出时,等等。
  3. 第二点中描述的方式可能是一种有趣的方法,但请记住,它可能有点难以实现,因为您需要重写模型才能获得生产结果。还有一点可能更难的是你需要针对许多类型的时间不稳定性来测试你的模型 - 这样的方法可能会使这完全不可行。

      

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

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

    我绝对会选择第一选择,但在提供详细解释之前,我将讨论第二和第三的缺点:

    • 在第二种方法中:它不会生气,但你会失去产品目标之间的很多相关性,
    • 在第三种方法中:你会在不同时间序列之间的依赖关系中丢失很多有趣的模式。

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

    • 产品特定的(让他们说有' m')
    • 一般功能 - 让我们说它们就是“。”

    现在您的表格大小为(timesteps, m * n, products)。我会将其转换为形状表(timesteps, products * m + n),因为所有产品的一般特征都相同。这将为您节省大量内存,并且可以提供给经常性网络(请记住keras中的重复层只有一个要素维度 - 而您有两个 - product和{{ 1}}))。

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

      

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

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

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

    最后一点可能有点模糊 - 所以为你提供一些例子:

    • 年稳定性 - 通过使用两年的每种可能组合对其进行培训来验证您的模型,并对其进行测试(例如2015年,2016年对2017年,2015年,2017年对2016年等) ) - 这将显示年份变化如何影响您的模型,
    • 未来预测稳定性 - 在周/月/年的子集上训练您的模型并使用以下周/月/年结果进行测试(例如,在2015年1月,2016年1月和1月进行训练2017年使用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个月   在那之前? (如果听起来我感到困惑,那是因为我!)

    这取决于您如何构建模型:

    • 如果您使用PCA,则需要将其重写为return_sequences=True,或者仅考虑输出并仅考虑结果中的最后一步,
    • 如果您使用了固定窗口 - 那么您需要在预测之前将窗口送到模型,
    • 如果您使用了不同的长度 - 您可以在任何时间步长处理您想要的预测期(但我建议您至少提供7个处理日)。

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

    此处 - 需要更多关于您选择何种模型的信息。

答案 1 :(得分:4)

问题1

这个问题有几种方法。你提议的那个似乎是一个滑动窗口。

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

您可以使用形状为(products, time, features)

的单个数组

问题2

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

如果我理解你的问题,你每天都有y个预测,对吗?

问题3

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

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

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

您也可以将产品ID作为单热矢量输入,并使用单个模型。

问题4

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

  • 将一些产品拆分为验证数据
  • 将时间步的最后部分保留为验证数据
  • 尝试交叉验证方法,为培训和测试留下不同的长度(测试数据越长,错误越大,但您可能希望裁剪此测试数据以获得固定长度)

问题5

可能还有很多方法。

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

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

  

我的问题:您必须预测X期间的Y数据是否已知? X在此期间也未知,因此您还需要预测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 :(得分:0)

对已经提供的两个答案进行跟进,我认为您应该看一下亚马逊研究院关于使用LSTM进行销售预测的文章,看看他们如何处理您提到的问题:

https://arxiv.org/abs/1704.04110

此外,我还应该指出,在使用循环网络时,正确的正规化非常重要,因为它们的过度拟合能力可能非常引人注目。你可能想看看"变异的复发性辍学"如本文所述

https://arxiv.org/abs/1512.05287

注意:这已经在Tensorflow中实现了!