【问题标题】:Keras custom layer not returning weights, unlike normal layer与普通层不同,Keras 自定义层不返回权重
【发布时间】:2019-08-21 20:21:18
【问题描述】:

我正在尝试获取图层的权重。当使用 keras 层并且输入连接到它时,它似乎可以正常工作。 但是,在将它包装到我的自定义层中时,它不再起作用了。这是一个错误还是我错过了什么?

编辑:注意事项:

我读到可以在自定义层的 build() 中定义可训练变量。但是,由于自定义层由 keras 层 Dense (以及以后可能更多的 keras 层)组成,那些应该已经定义了可训练变量和权重/偏差初始化器。 (在 TestLayer 的 init() 中,我看不到用将在 TestLayer 的 build() 中定义的变量来覆盖它们的方法。

class TestLayer(layers.Layer):
    def __init__(self):
        super(TestLayer, self).__init__()
        self.test_nn = layers.Dense(3)

    def build(self, input_shape):
        super(TestLayer, self).build(input_shape)


    def call(self, inputs, **kwargs):
        test_out = test_nn(inputs) # which is test_in
        return test_out


test_in = layers.Input((2,))
test_nn = layers.Dense(3)
print(test_nn.get_weights()) # empty, since no connection to the layer
test_out = test_nn(test_in)
print(test_nn.get_weights()) # layer returns weights+biases

testLayer = TestLayer()
features = testLayer(test_in)
print(testLayer.get_weights()) # Problem: still empty, even though connected to input.

【问题讨论】:

    标签: tensorflow deep-learning keras-layer tensorflow-layers


    【解决方案1】:

    不幸的是,Keras 不支持在其他层中使用层。 我以前也遇到过这个问题,开了一个issuehere,但是团队向我确认这是故意的。

    您可以在自定义层中定义一个方法,例如:

    def dense(X, f_in, f_out):
        W = self.add_weight(name='kernel',
                            shape=(f_in, f_out))
        b = self.add_weight(name='bias',
                            shape=(f_out, ))
        return K.dot(X, W) + b
    

    或子类化 Dense 层并使用super().call() 的输出。

    【讨论】:

      【解决方案2】:

      documentation 表示 build() 方法应该调用您没有的 add_weight()

      应该有add_weight()的调用,然后调用super的build()

      如果您对layers.Layer 进行子类化,您也不需要在类中定义密集层。 这就是你应该继承的方式:

      import tensorflow as tf
      from tensorflow.keras import layers
      
      class TestLayer(layers.Layer):
          def __init__(self, outshape=3):
              super(TestLayer, self).__init__()
              self.outshape = outshape
      
          def build(self, input_shape):
              self.kernel = self.add_weight(name='kernel',
                                            shape=(int(input_shape[1]), self.outshape),
                                            trainable=True)
      
              super(TestLayer, self).build(input_shape)
      
      
          def call(self, inputs, **kwargs):
              return tf.matmul(inputs, self.kernel)
      
      test_in = layers.Input((2,))
      
      testLayer = TestLayer()
      features = testLayer(test_in)
      print(testLayer.get_weights())
      #[array([[-0.68516827, -0.01990592,  0.88364804],
      #       [-0.459718  ,  0.19161093,  0.39982545]], dtype=float32)]
      

      HereLayer 类的更多子类示例。

      然而,如果你坚持以自己的方式实现它并且如果你想使用get_weights(),你必须重写它(在这种情况下你可以只创建一个没有子类的类):

      import tensorflow as tf
      from tensorflow.keras import layers
      
      class TestLayer(layers.Layer):
          def __init__(self, outshape=3):
              super(TestLayer, self).__init__()
              self.test_nn = layers.Dense(outshape)
              self.outshape = outshape
      
          def build(self, input_shape):
              super(TestLayer, self).build(input_shape)
      
          def call(self, inputs, **kwargs):
              return self.test_nn(inputs)
      
          def get_weights(self):
              with tf.Session() as sess:
                  sess.run([x.initializer for x in self.test_nn.trainable_variables])
                  return sess.run(self.test_nn.trainable_variables)
      
      test_in = layers.Input((2,))
      
      testLayer = TestLayer()
      features = testLayer(test_in)
      print(testLayer.get_weights())
      #[array([[ 0.5692867 ,  0.726858  ,  0.37790012],
      #       [ 0.2897135 , -0.7677493 , -0.58776844]], dtype=float32), #array([0., 0., 0.], dtype=float32)]
      

      【讨论】:

      • 谢谢!一个问题是,如果我在 Dense 之后有 layers.BatchNormalization,那么实现会是什么样子?我想自己在 call() 中的实现也是必要的,但这似乎并不简单。 (我也想知道这是否适用于自定义图层。)
      • 你写它的方式不是使用自定义层的方式。预期的方式是我提供的方式,这就是官方文档所述的方式。但同样,如果您不在某个 keras 对象(例如Sequential())中使用它,那也没关系。否则,您必须覆盖所有必需的方法(get_weights() 是其中之一)才能使其工作。我真的建议你通过官方网站上的教程。 + 我想对 BN 进行子类化吗?仅当您了解实现时才这样做。它不像tf.matmul() + bias那么微不足道。
      • how would the implementation then look like if I had layers.BatchNormalization after Dense? - 像这样:` bn = tf.keras.layers.BatchNormalization()(features)`
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-12
      • 2018-08-01
      • 2020-06-02
      • 1970-01-01
      • 2022-12-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多