【问题标题】:How to lay out training data with stateful LSTMs and batch_size > 1如何使用有状态 LSTM 和 batch_size > 1 布置训练数据
【发布时间】:2018-02-02 07:15:52
【问题描述】:

背景

我想在 Keras 中对“有状态”LSTM 进行小批量训练。我的输入训练数据位于一个大矩阵“X”中,其维度为 m x n,其中

m = number-of-subsequences
n = number-of-time-steps-per-sequence

X 的每一行都包含一个子序列,该子序列从前一行的子序列离开的地方开始。所以给定一长串数据,

Data = ( t01, t02, t03, ... )

其中“tK”表示原始数据中位置K处的token,序列在X中的布局如下:

X = [
  t01 t02 t03 t04
  t05 t06 t07 t08
  t09 t10 t11 t12
  t13 t14 t15 t16
  t17 t18 t19 t20
  t21 t22 t23 t24
]

问题

我的问题是,当我使用有状态 LSTM 对以这种方式布局的数据进行小批量训练时会发生什么。具体来说,小批量训练通常一次训练“连续”的行组。因此,如果我使用 2 的 mini-batch 大小,那么 X 将被分成三个 mini-batch X1、X2 和 X3,其中

X1 = [
  t01 t02 t03 t04
  t05 t06 t07 t08
]

X2 = [
  t09 t10 t11 t12
  t13 t14 t15 t16
]

X3 = [
  t17 t18 t19 t20
  t21 t22 t23 t25
]

请注意,这种类型的 mini-batching 不适合训练 stateful LSTM,因为通过处理前一批的最后一列产生的隐藏状态不是对应于时间的隐藏状态-在后续批次的第一列之前执行。

要看到这一点,请注意小批量将像这样从左到右进行处理:

------ X1 ------+------- X2 ------+------- X3 -----
t01 t02 t03 t04 | t09 t10 t11 t12 | t17 t18 t19 t20
t05 t06 t07 t08 | t13 t14 t15 t16 | t21 t22 t23 t24

暗示

- Token t04 comes immediately before t09
- Token t08 comes immediately before t13
- Token t12 comes immediately before t17
- Token t16 comes immediately before t21

但我希望小批量对行进行分组,以便我们在小批量之间获得这种时间对齐:

------ X1 ------+------- X2 ------+------- X3 -----
t01 t02 t03 t04 | t05 t06 t07 t08 | t09 t10 t11 t12
t13 t14 t15 t16 | t17 t18 t19 t20 | t21 t22 t23 t24

在 Keras 中训练 LSTM 时完成此任务的标准方法是什么?

感谢您的指点。

【问题讨论】:

    标签: tensorflow machine-learning keras theano lstm


    【解决方案1】:

    解决方案 1 - 批量大小 = 1

    好吧,因为看起来你实际上只有一个序列(虽然被分割,但它仍然是一个单一的序列,对吧?),你确实必须以等于 1 的批大小进行训练。

    如果您不想更改或重组您的数据,只需:

     X = X.reshape((-1,length,features))
    
         #where
             #length = 4 by your description    
             #features = 1 (if you have only one var over time, as it seems)
    

    解决方案 2 - 重新组合长度 = 8

    仍然使用 1 的批量大小,重塑您的输入数据(在将其传递给模型之前),使其具有双倍长度。

    最终结果将与您使用所描述的大小为 2 的小批量进行训练时完全相同。(但请确保在模型的输入形状中将批量大小设置为 1,否则这会给您带来错误结果)。

    X = X.reshape((-1, 2 * length, features)) 
    

    这会给你:

    X = [
      [t01 t02 t03 t04 t05 t06 t07 t08]
      [t09 t10 t11 t12 t13 t14 t15 t16]
      [t17 t18 t19 t20 t21 t22 t23 t24]
    ]
    

    解决方案 3 - 只有当您实际上有两个不同的序列时才有可能

    根据您的描述,您似乎只有一个序列。如果您确实有两个不同/独立的序列,则可以制作一批大小为 2 的序列。

    如果将您的序列一分为二(并失去它们之间的连接)不成问题,您可以重新排列您的数据:

    X = X.reshape((2,-1,length, features))
    

    然后:

    X0 = X[:,0]
    X1 = X[:,1]
    ...
    

    您可以尝试将其分组到一个数组中:

    X = X.reshape((2,-1,length, features))
    X = np.swapaxes(X,0,1).reshape((-1,length,features))
    

    然后:

    X0 = X[0]
    X1 = X[1]
    ...
    

    并且您可以尝试将完整的X 传递给训练,只要您在模型的输入形状中明确将批大小设置为 2。

    【讨论】:

    • 解决方案#2 似乎并不等同于我的要求,因为它将串行处理每个子序列(长度是原来的两倍)。但我希望训练能够并行处理完整序列的多个子序列(即,作为“小批量”)。
    • 并行?但是,模型永远不会将数据理解为一个完整的序列。它不会在第 2 段开始的状态下理解它继续第 1 段。
    • 我的序列很长。有效地 1MM 时间步长(来自各种文章的单词),我已将它们连接成一个长序列。因此,如果我将这个长序列分成 32 个子序列,每个子序列包含 1MM 除以 32 个时间步长,那么我会得到 32 个“独立”和并行序列,我可以在每批上训练它们。我不想使用掩码并打破文档边界的序列,因为文档的长度非常不同。因此,我将浪费大量的 GPU 操作训练来处理掩码值。如果您有想法,请评论我提出的答案。谢谢!
    • 你会遇到很多这样的不一致。你告诉模型一篇文章的开头是另一篇文章的结尾。你真的应该考虑使用像(divisions * number_of_articles, length // divisions, features) 这样的形状。
    • 我有一个“新文档开始”功能,当令牌开始新文档时发出信号。希望 LSTM 在接收到这个信号后学会重置。顺便说一句,这种类型的连接很常见。请参阅 Zaremba 和 Sutskever 在本文中使用的 PTB 数据集:arxiv.org/abs/1409.2329
    【解决方案2】:

    谢谢。似乎 Daniel 暗示如果我像这样重新组织 X,我可以使用 2 的批量大小:

    X = [
      t01 t02 t03 t04 
      t13 t14 t15 t16
      t05 t06 t07 t08
      t17 t18 t19 t20 
      t09 t10 t11 t12
      t21 t22 t23 t24
    ]
    

    这是正确的解释吗?

    【讨论】:

    • 缺点是模型无法识别t13,如下t12
    • 谢谢。这对我来说很好!在实践中,我所拥有的数据几乎不会出现这种不连续性。
    猜你喜欢
    • 2020-03-07
    • 2017-06-07
    • 2020-04-22
    • 2018-07-01
    • 2017-08-06
    • 1970-01-01
    • 2020-12-15
    • 1970-01-01
    • 2018-01-30
    相关资源
    最近更新 更多