【问题标题】:How to use keras layers in custom keras layer如何在自定义 keras 层中使用 keras 层
【发布时间】:2021-01-03 15:26:12
【问题描述】:

我正在尝试编写自己的 keras 层。在这一层中,我想使用一些其他的 keras 层。有没有办法做这样的事情:

class MyDenseLayer(tf.keras.layers.Layer):
  def __init__(self, num_outputs):
    super(MyDenseLayer, self).__init__()
    self.num_outputs = num_outputs

  def build(self, input_shape):
    self.fc = tf.keras.layers.Dense(self.num_outputs)

  def call(self, input):
    return self.fc(input)

layer = MyDenseLayer(10)

当我做类似的事情时

input = tf.keras.layers.Input(shape = (16,))
output = MyDenseLayer(10)(input)
model = tf.keras.Model(inputs = [input], outputs = [output])
model.summary()

它输出

我怎样才能让那里的密集人群可以训练?

【问题讨论】:

    标签: tensorflow keras


    【解决方案1】:

    如果您查看有关如何添加自定义层的文档,他们建议您使用.add_weight(...) 方法。此方法在内部将所有权重放在self._trainable_weights 中。所以要做你想做的事,你必须首先定义你想要使用的 keras 层,构建它们,复制权重,然后构建你自己的层。如果我更新您的代码,它应该类似于

    class mylayer(tf.keras.layers.Layer):
        def __init__(self, num_outputs, num_outputs2):
            self.num_outputs = num_outputs
            super(mylayer, self).__init__()
    
        def build(self, input_shape):
            self.fc = tf.keras.layers.Dense(self.num_outputs)
            self.fc.build(input_shape)
            self._trainable_weights = self.fc.trainable_weights
            super(mylayer, self).build(input_shape)
    
        def call(self, input):
            return self.fc(input)
    
    layer = mylayer(10)
    input = tf.keras.layers.Input(shape=(16, ))
    output = layer(input)
    model = tf.keras.Model(inputs=[input], outputs=[output])
    model.summary()
    

    然后你应该得到你想要的

    【讨论】:

    • 感谢尼基·斯卡夫特。我不太确定build 是干什么用的。我查看了 github 代码,似乎 build 的主要目的是将 build 设置为 True,在 Dense 层的情况下,它还为您添加了权重。但是我不太明白为什么我们需要将 build 设置为 True,目的是什么?比你~
    • 主要原因是所有层都需要构建,然后才能调用model.compile(...)。看到这个file
    • num_outputs2 应从__init__ 中删除,以便代码运行
    • 如果在build中使用多个keras层怎么办?如何将他们的可训练权重添加到层的 self._trainable_weights 中?传递一个列表是不适用的。
    • @JunjieChen,你的问题有解决方案吗?
    【解决方案2】:

    将现有层放在 tf.keras.models.Model 类中更加舒适和简洁。如果您定义非自定义层,例如层、conv2d,则默认情况下这些层的参数不可训练。

    class MyDenseLayer(tf.keras.Model):
      def __init__(self, num_outputs):
        super(MyDenseLayer, self).__init__()
        self.num_outputs = num_outputs
        self.fc = tf.keras.layers.Dense(num_outputs)
    
      def call(self, input):
        return self.fc(input)
    
      def compute_output_shape(self, input_shape):
        shape = tf.TensorShape(input_shape).as_list()
        shape[-1] = self.num_outputs
        return tf.TensorShape(shape)
    
    layer = MyDenseLayer(10)
    

    查看本教程:https://www.tensorflow.org/guide/keras#model_subclassing

    【讨论】:

      【解决方案3】:

      TF2 custom layer Guide 中,他们“建议在__init__ 方法中创建此类子层(因为子层通常具有build 方法,它们将在构建外层时构建)。”因此,只需将 self.fc 的创建移动到 __init__ 即可满足您的需求。

      class MyDenseLayer(tf.keras.layers.Layer):
        def __init__(self, num_outputs):
          super(MyDenseLayer, self).__init__()
          self.num_outputs = num_outputs
          self.fc = tf.keras.layers.Dense(self.num_outputs)
      
        def build(self, input_shape):
          self.built = True
      
        def call(self, input):
          return self.fc(input)
      
      input = tf.keras.layers.Input(shape = (16,))
      output = MyDenseLayer(10)(input)
      model = tf.keras.Model(inputs = [input], outputs = [output])
      model.summary()
      
      

      输出:

      Model: "model_1"
      _________________________________________________________________
      Layer (type)                 Output Shape              Param #   
      =================================================================
      input_2 (InputLayer)         [(None, 16)]              0         
      _________________________________________________________________
      my_dense_layer_2 (MyDenseLay (None, 10)                170       
      =================================================================
      Total params: 170
      Trainable params: 170
      Non-trainable params: 0
      

      【讨论】:

      • 我认为在build 没有添加任何功能的这种简单情况下,您不需要为您的类定义功能。如果您确实添加了功能,那么建议在您的build 函数定义的末尾调用super(MyDenseLayer, self).build(input_shape)keras.io/layers/writing-your-own-keras-layers
      • @adamconkey,如果supertf.keras.layers.Layer,则调用super(MyDenseLayer, self).build(input_shape) 相当于self.built = True。如果super是一个更复杂的层,取决于你想要继承基础层的哪一部分,你可能需要检查super().build()的实现,为派生层提取你真正想要的部分,添加新的东西, 并在build 末尾调用self.built = True
      【解决方案4】:

      这对我有用,而且干净、简洁、易读。

      import tensorflow as tf
      
      
      class MyDense(tf.keras.layers.Layer):
          def __init__(self, **kwargs):
              super(MyDense, self).__init__(kwargs)
              self.dense = tf.keras.layers.Dense(2, tf.keras.activations.relu)
      
          def call(self, inputs, training=None):
              return self.dense(inputs)
      
      
      inputs = tf.keras.Input(shape=10)
      outputs = MyDense(trainable=True)(inputs)
      model = tf.keras.Model(inputs=inputs, outputs=outputs, name='test')
      model.compile(loss=tf.keras.losses.MeanSquaredError())
      model.summary()
      

      输出:

      Model: "test"
      _________________________________________________________________
      Layer (type)                 Output Shape              Param #   
      =================================================================
      input_1 (InputLayer)         [(None, 10)]              0         
      _________________________________________________________________
      my_dense (MyDense)           (None, 2)                 22        
      =================================================================
      Total params: 22
      Trainable params: 22
      Non-trainable params: 0
      _________________________________________________________________
      

      请注意,trainable=True 是必需的。我已经发布了一个关于它的问题here

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-02
        • 1970-01-01
        相关资源
        最近更新 更多