具有多个隐藏层的 TensorFlow 2 GRU 层
TensorFlow 2 GRU Layer with multiple hidden layers
我正在尝试将一些 TensorFlow 1 代码移植到 TensorFlow 2。使用现已弃用的旧代码 MultiRNNCell to create a GRU layer with multiple hidden layers. In TensorFlow 2 I want to use the in-built GRU Layer, but there doesn't seem to be an option which allows for multiple hidden layers with that class. The 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:
Mathematically, RNN(LSTMCell(10)) produces the same result as
LSTM(10). In fact, the implementation of this layer in TF v1.x was
just creating the corresponding RNN cell and wrapping it in a RNN
layer. However using the built-in GRU and LSTM layers enables the use
of CuDNN and you may see better performance.
那么我该如何实现呢?如何获得既支持多个隐藏层又支持 CuDNN 的 GRU 层?鉴于 TensorFlow 中内置的 GRU 层缺少这样的选项,实际上是否有必要?还是获得深度 GRU 网络的唯一方法是按顺序堆叠多个 GRU 层?
编辑: 根据 类似的问题,似乎确实没有内置的方法来创建具有多个隐藏层的 GRU 层,并且必须手动堆叠它们。
好的,看来实现这一目标的唯一方法是定义一堆 GRU 层实例。这就是我想出的(请注意,我只需要 return 序列的有状态 GRU 层,不需要最后一层的 return 状态):
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 设置为图层属性将不允许父图层跟踪内部图层(请参阅 this answer to this 问题)。
我希望这会加快我的网络速度。到目前为止,对 Colab 的测试没有显示任何差异,如果有的话,它实际上比使用使用 GRU 单元列表初始化的直接 RNN 稍微 慢 。我认为将批量大小从 10 增加到 64 可能会有所不同,但不,它们似乎仍然以大约相同的速度执行。
UPDATE:事实上 似乎有明显的加速,但前提是我不装饰我的训练步骤使用 tf.function
函数(我有一个自定义训练循环,我不使用 Model.fit
)。速度并没有太大的提高——可能快了大约 33%,批大小为 96。更小的批大小(在 10 到 20 之间)提供了更大的速度,大约 70%。
我正在尝试将一些 TensorFlow 1 代码移植到 TensorFlow 2。使用现已弃用的旧代码 MultiRNNCell to create a GRU layer with multiple hidden layers. In TensorFlow 2 I want to use the in-built GRU Layer, but there doesn't seem to be an option which allows for multiple hidden layers with that class. The 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:
Mathematically, RNN(LSTMCell(10)) produces the same result as LSTM(10). In fact, the implementation of this layer in TF v1.x was just creating the corresponding RNN cell and wrapping it in a RNN layer. However using the built-in GRU and LSTM layers enables the use of CuDNN and you may see better performance.
那么我该如何实现呢?如何获得既支持多个隐藏层又支持 CuDNN 的 GRU 层?鉴于 TensorFlow 中内置的 GRU 层缺少这样的选项,实际上是否有必要?还是获得深度 GRU 网络的唯一方法是按顺序堆叠多个 GRU 层?
编辑: 根据
好的,看来实现这一目标的唯一方法是定义一堆 GRU 层实例。这就是我想出的(请注意,我只需要 return 序列的有状态 GRU 层,不需要最后一层的 return 状态):
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 设置为图层属性将不允许父图层跟踪内部图层(请参阅 this answer to this 问题)。
我希望这会加快我的网络速度。到目前为止,对 Colab 的测试没有显示任何差异,如果有的话,它实际上比使用使用 GRU 单元列表初始化的直接 RNN 稍微 慢 。我认为将批量大小从 10 增加到 64 可能会有所不同,但不,它们似乎仍然以大约相同的速度执行。
UPDATE:事实上 似乎有明显的加速,但前提是我不装饰我的训练步骤使用 tf.function
函数(我有一个自定义训练循环,我不使用 Model.fit
)。速度并没有太大的提高——可能快了大约 33%,批大小为 96。更小的批大小(在 10 到 20 之间)提供了更大的速度,大约 70%。