【问题标题】:TensorFlow 2 GRU Layer with multiple hidden layers具有多个隐藏层的 TensorFlow 2 GRU 层
【发布时间】:2020-04-05 20:18:03
【问题描述】:

我正在尝试将一些 TensorFlow 1 代码移植到 TensorFlow 2。旧代码使用现已弃用的 MultiRNNCell 创建具有多个隐藏层的 GRU 层。在 TensorFlow 2 中,我想使用内置的 GRU Layer,但似乎没有允许该类具有多个隐藏层的选项。 PyTorch equivalent 有一个作为初始化参数公开的选项,num_layers

我的解决方法是使用 TensorFlow RNN 层并为我想要的每个隐藏层传递一个 GRU 单元 - 这是文档中推荐的方式:

dim = 1024
num_layers = 4
cells = [tf.keras.layers.GRUCell(dim) for _ in range(num_layers)]
gru_layer = tf.keras.layers.RNN(
  cells,
  return_sequences=True,
  stateful=True
)

但是内置的 GRU 层支持 CuDNN,这是普通 RNN 似乎缺乏的,引用 the docs

在数学上,RNN(LSTMCell(10)) 产生的结果与 LSTM(10)。事实上,在 TF v1.x 中这一层的实现是 只需创建相应的 RNN 单元并将其包装在 RNN 中 层。然而,使用内置的 GRU 和 LSTM 层可以使用 的 CuDNN,您可能会看到更好的性能。

那么我该如何实现呢?如何获得同时支持多个隐藏层并支持 CuDNN 的 GRU 层?鉴于 TensorFlow 中内置的 GRU 层缺少这样的选项,是否真的有必要?或者,获得深度 GRU 网络的唯一方法是按顺序堆叠多个 GRU 层?

编辑: 似乎,根据this answer 的类似问题,确实没有内置方法来创建具有多个隐藏层的 GRU 层,它们必须是手动堆叠。

【问题讨论】:

  • 从概念上讲,这些隐藏层是什么?它们是平行的吗?它们是连续的吗?他们是做什么的?
  • 谢谢。我认为这可以使用顺序模型来完成,包装多个 GRU 层实例。所以它是串行/顺序的,我猜。就像我编辑中链接的答案一样。我正在尝试使用带有单元列表的 RNN 类来实现已经可以实现的目标 - 层堆栈,更深的网络。但是通过 CuDNN 优化。文档指出后者仅适用于内置的 GRU Layer 类。

标签: tensorflow keras deep-learning neural-network recurrent-neural-network


【解决方案1】:

好的,看来实现这一点的唯一方法是定义一堆 GRU 层实例。这就是我想出的(注意我只需要返回序列的有状态 GRU 层,不需要最后一层的返回状态):

class RNN(tf.keras.layers.Layer):

    def __init__(self, dim, num_layers=1):
        super(RNN, self).__init__()
        self.dim = dim
        self.num_layers = num_layers
        def layer():
            return tf.keras.layers.GRU(
                self.dim,
                return_sequences=True,
                return_state=True,
                stateful=True)
        self._layer_names = ['layer_' + str(i) for i in range(self.num_layers)]
        for name in self._layer_names:
             self.__setattr__(name, layer())

    def call(self, inputs):
        seqs = inputs
        state = None
        for name in self._layer_names:
            rnn = self.__getattribute__(name)
            (seqs, state) = rnn(seqs, initial_state=state)
        return seqs

需要使用__setattr__手动将内部rnn层添加到父层。似乎将 rnns 添加到列表中并将 that 设置为层属性将不允许父层跟踪内部层(请参阅thisthis 问题的回答)。

我希望这会加快我的网络速度。到目前为止,在 Colab 上的测试没有显示出任何差异,如果有的话,它实际上比使用使用 GRU 单元列表初始化的直接 RNN 稍微。我认为将批量大小从 10 增加到 64 可能会有所不同,但不,它们似乎仍然以大致相同的速度执行。

更新:事实上,确实似乎有明显的加速,但前提是我不使用tf.function 装饰我的训练步骤函数(我有自定义训练循环,我不使用Model.fit)。速度并没有太大的提高 - 可能快了大约 33%,批量大小为 96。小得多的批量大小(10 到 20 之间)提供了更大的速度提升,大约 70%。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-14
    • 1970-01-01
    • 2019-06-12
    • 2014-07-24
    • 2021-12-08
    • 2020-07-15
    • 2018-01-25
    • 1970-01-01
    相关资源
    最近更新 更多