【问题标题】:Naming weights of a layer within a custom layer在自定义层中命名层的权重
【发布时间】:2020-05-15 14:42:41
【问题描述】:

我在 Dense 子图层中有一个自定义图层。我希望能够命名这个子层的权重。但是,在子层初始化程序上使用name="my_dense" 似乎并没有这样做;权重只是以外部自定义层命名。

为了说明这个问题,假设我想要一个简单地堆叠两个密集层的自定义层。我将打印这个自定义层的权重名称。

class DoubleDense(keras.layers.Layer):
  def __init__(self, units, **kwargs):
    self.dense1 = keras.layers.Dense(units, name="first_dense")
    self.dense2 = keras.layers.Dense(units, name="second_dense")
    super(DoubleDense, self).__init__(**kwargs)

  def build(self, input_shape):
    self.dense1.build(input_shape)
    self.dense2.build(self.dense1.units)

  def call(self, input):
    hidden = self.dense1(input)
    return self.dense2(hidden)

dd = DoubleDense(3)

# We need to evaluate the layer once to build the weights
trivial_input = tf.ones((1,10))
output = dd(trivial_input)

# Print the names of all variables in the DoubleDense layer
print([weight.name for weight in dd.weights])

输出是这样的:

['double_dense_1/kernel:0',
 'double_dense_1/bias:0',
 'double_dense_1/kernel:0',
 'double_dense_1/bias:0']

...但我期待更多这样的东西:

['double_dense_1/first_dense_1/kernel:0',
 'double_dense_1/first_dense_1/bias:0',
 'double_dense_1/second_dense_1/kernel:0',
 'double_dense_1/second_dense_1/bias:0']

因此,Keras 模糊地命名了这些权重;仅凭名称无法判断权重张量属于dd.dense1 还是dd.dense2。我意识到我可以先选择图层然后然后选择权重 (dd.dense1.weights),但我不希望在我的应用程序中这样做。

有没有办法命名自定义层的子层的权重?

【问题讨论】:

  • 不确定这是否令人满意,但您可以创建一个接受输入、调用两个密集层并返回输出的函数。这不是子层,但您仍然可以在构建模型时将其用作块。
  • 确实,这适用于本示例。但我实际的自定义层是一个 RNN 单元,所以很遗憾,这在这种情况下不起作用。
  • 如果您尝试将其设为Model 而不是图层会怎样? (Model 也是Layer,所以它可能会作为一个单元格工作)
  • 使单元格成为keras.Model 的子类而不是keras.layers.Layer 会抛出ValueError: Weights for model rnn_cell have not yet been created.。我不确定为什么。我尝试通过显式调用.build(input_shape) 来构建单元,但它似乎不起作用。
  • 再更新一次,以防有人遇到同样的问题。这个错误(似乎)不可避免地导致两个变量被分配了相同的名称,从而导致更多问题。特别是模型保存函数.save.save_model 不再起作用(它们似乎要求变量名是唯一的)并抛出错误RuntimeError: Unable to create link (name already exists)。我仍然没有任何答案。我会在 Github 上提出这个问题。

标签: python tensorflow keras


【解决方案1】:

如果您想要子类层的名称,您需要包含name_scope,然后为每个层调用build

下面是修改后的代码,它将为输出中的每一层命名。

class DoubleDense(keras.layers.Layer):
  def __init__(self, units, **kwargs):
    self.dense1 = keras.layers.Dense(units)
    self.dense2 = keras.layers.Dense(units)
    super(DoubleDense, self).__init__( **kwargs)

  def build(self, input_shape):
    with tf.name_scope("first_dense"):
      self.dense1.build(input_shape)
    with tf.name_scope("second_dense"):
      self.dense2.build(self.dense1.units)

  def call(self, input):
    hidden = self.dense1(input)
    return self.dense2(hidden)


dd = DoubleDense(3)


# We need to evaluate the layer once to build the weights
trivial_input = tf.ones((1,10))
output = dd(trivial_input)

# Print the names of all variables in the DoubleDense layer
print([weight.name for weight in dd.weights])  

输出:

['double_dense/first_dense/kernel:0', 'double_dense/first_dense/bias:0', 'double_dense/second_dense/kernel:0', 'double_dense/second_dense/bias:0']  

希望这能回答您的问题,祝您学习愉快!

【讨论】:

  • @Isaac Breen - 如果您认为我已经回答了您的问题,请投票并接受答案。
猜你喜欢
  • 2021-09-30
  • 2017-11-29
  • 2019-08-12
  • 2019-08-21
  • 2016-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多