了解有状态的 LSTM [关闭]

Posted

技术标签:

【中文标题】了解有状态的 LSTM [关闭]【英文标题】:Understanding stateful LSTM [closed] 【发布时间】:2017-06-01 09:31:45 【问题描述】:

我正在阅读关于 RNN/LSTM 的 tutorial,但我很难理解有状态的 LSTM。我的问题如下:

1。训练批处理大小

在RNNs 上的 Keras 文档中,我发现批处理中位于 i-th 位置的样本的隐藏状态将作为输入隐藏状态提供给位于 i-th 位置的样本下一批。这是否意味着如果我们想将隐藏状态从一个样本传递到另一个样本,我们必须使用大小为 1 的批次,从而执行在线梯度下降?有没有办法在大小>1的批次中传递隐藏状态并对该批次执行梯度下降?

2。单字符映射问题

在教程的段落“用于单字符到单字符映射的有状态 LSTM”中,给出了一个代码,该代码使用 batch_size = 1stateful = True 来学习在给定字母表的情况下预测字母表的下一个字母.在代码的最后一部分(第 53 行到完整代码的末尾),模型从一个随机字母 ('K') 开始进行测试,并预测'B',然后给定'B',它预测'C',等等. 除了'K',它似乎运作良好。但是,我尝试对代码进行以下调整(最后一部分,我保留了第 52 行及以上):

    # demonstrate a random starting point
    letter1 = "M"
    seed1 = [char_to_int[letter1]]
    x = numpy.reshape(seed, (1, len(seed), 1))
    x = x / float(len(alphabet))
    prediction = model.predict(x, verbose=0)
    index = numpy.argmax(prediction)
    print(int_to_char[seed1[0]], "->", int_to_char[index])
    letter2 = "E"
    seed2 = [char_to_int[letter2]]
    seed = seed2
    print("New start: ", letter1, letter2)
    for i in range(0, 5):
        x = numpy.reshape(seed, (1, len(seed), 1))
        x = x / float(len(alphabet))
        prediction = model.predict(x, verbose=0)
        index = numpy.argmax(prediction)
        print(int_to_char[seed[0]], "->", int_to_char[index])
        seed = [index]
    model.reset_states()

and these outputs:

    M -> B
    New start: M E
    E -> C
    C -> D
    D -> E
    E -> F

It looks like the LSTM did not learn the alphabet but just the positions of the letters, and that regardless of the first letter we feed in, the LSTM will always predict B since it's the second letter, then C and so on.

因此,将先前的隐藏状态保持为当前隐藏状态的初始隐藏状态如何帮助我们学习,因为在测试期间,如果我们以字母“K”开头,例如,字母 A 到 J 将不会之前输入,初始隐藏状态不会与训练期间相同?

3。在书籍上训练 LSTM 以生成句子

我想在一整本书上训练我的 LSTM,以学习如何生成句子,也许还要学习作者的风格,我怎样才能自然地在该文本上训练我的 LSTM(输入整个文本并让 LSTM 找出依赖关系在单词之间)而不是自己“人为地”从那本书中创建一批句子来训练我的 LSTM?我相信我应该使用有状态 LSTM 会有所帮助,但我不确定如何。

【问题讨论】:

为了将来参考,这可以分成三个单独的问题。此外,最后一个问题更适合 stats.stackexchange.com。最后,您不应该将标签放在问题标题中。 【参考方案1】:
    在 Keras 中拥有一个有状态的 LSTM 意味着将使用一个 Keras 变量来存储和更新状态,实际上您可以随时检查状态向量的值(也就是说,直到您调用 @ 987654329@)。另一方面,无状态模型将在每次处理批处理时使用初始零状态,因此就好像您总是在 train_on_batchtest_on_batchpredict_on_batch 之后调用 reset_states()。关于状态被重用于下一批有状态模型的解释就是与无状态模型的区别。当然,状态将始终在批次中的每个序列中流动,您确实不需要需要有大小为 1 的批次才能发生这种情况。我看到有状态模型很有用的两种场景:
您希望在拆分的数据序列上进行训练,因为这些数据序列非常长,并且在整个长度上进行训练是不切实际的。 在预测时间,您希望检索序列中每个时间点的输出,而不仅仅是在末尾(因为您想将其反馈到网络中,或者因为您的应用程序需要它)。我个人在导出以供以后集成的模型中执行此操作(这些模型是批量大小为 1 的训练模型的“副本”)。

    我同意字母表的 RNN 示例在实践中似乎并不是很有用;它仅在您以字母 A 开头时才有效。如果您想学习重现从任何字母开始的字母表,则需要使用此类示例(字母表的子序列或旋转)来训练网络。但我认为一个常规的前馈网络可以学习预测字母表的下一个字母,训练像 (A, B), (B, C) 等这样的对。我认为这个例子比其他任何东西都更适合演示目的.

    您可能已经阅读过它,但是热门帖子The Unreasonable Effectiveness of Recurrent Neural Networks 显示了一些有趣的结果,这些结果与您想要做的事情一致(尽管它并没有真正深入到实现细节)。我没有使用文本数据训练 RNN 的个人经验,但是您可以研究许多方法。您可以构建基于字符的模型(如帖子中的模型),您可以在其中一次输入并接收一个字符。更高级的方法是对文本进行一些预处理,并将它们转换为数字序列; Keras 包含一些 text preprocessing functions 来做到这一点。将单个数字作为特征空间可能效果不佳,因此您可以简单地将每个单词转换为具有 one-hot 编码的向量,或者更有趣的是,让网络为每个词学习最佳向量表示,这就是他们所说的 en embedding。您可以进一步进行预处理并查看NLTK 之类的内容,特别是如果您想删除停用词、标点符号等。最后,如果您有不同大小的序列(例如,您使用的是全文而不是固定大小的摘录,这对您来说可能重要也可能不重要),您需要更加小心并使用masking 和/或sample weighting。根据具体问题,您可以相应地设置培训。如果您想学习生成相似的文本,“Y”将类似于“X”(one-hot 编码),仅移动一个(或多个)位置(在这种情况下,您可能需要使用 @987654334 @ 和 TimeDistributed layers)。如果您想确定作者,您的输出可能是softmax Dense layer。

希望对您有所帮助。

【讨论】:

是的,问题 2 只是为了学习,但我想知道在整个示例中,将先前的隐藏状态作为下一个样本的初始隐藏状态如何对我们有帮助,因为在测试期间我们赢了不一定有那个背景。实际上,它似乎降低了性能而不是提高了性能,因为我们学习的权重是在错误的隐藏状态下学习的(尤其是对于序列的前几个元素)。 "当然状态总是在批次内流动" 为什么状态会在批次内流动?!样本往往是独立的,尤其是在打乱后。 @Unknown 我认为我在这里所做的假设是你有一个形状为(batch_size, sequence_length, num_features) 的批次,我的意思是状态总是流经第二维,即在相同的序列,不在不同的序列之间。无论循环层是否有状态,状态都应始终在单个批次中流动(并且使用有状态层,您可以使其流动到下一个)。 "状态应始终在单个批次中流动" 我认为最好在这句话中将“批次”替换为“样本”:) 因为正如您所澄清的那样你的假设,一个批次可以(而且经常)有多个样本。

以上是关于了解有状态的 LSTM [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

keras 有状态 LSTM

有状态 LSTM - 批次之间和批次内的隐藏状态转移 (Keras)

有状态 LSTM 和流预测

将 Pytorch LSTM 的状态参数转换为 Keras LSTM

Keras LSTM TimeDistributed,有状态

在 Keras 中,当我创建具有 N 个“单元”的有状态“LSTM”层时,我到底在配置啥?