【问题标题】:Layer.call is not executed eagerlyLayer.call 没有急切地执行
【发布时间】:2022-01-13 09:37:28
【问题描述】:

我写了一个层,它什么都不做

class Fractal2D(tf.keras.layers.Layer):
    def __init__(self, kernel_size_range):
        super(Fractal2D, self).__init__()
        self.kernel_size_range = kernel_size_range
    
    def build(self, inputs):
        print(f'build executes eagerly: {tf.executing_eagerly()}')
        return inputs
    
    def call(self, inputs):
        print(f'call executes eagerly: {tf.executing_eagerly()}')
        return inputs

做了一个模型

model = tf.keras.Sequential([
    tf.keras.layers.InputLayer(input_shape=(224, 224, 3), batch_size=32),
    Fractal2D(kernel_size_range=(3, 41)),
    hub.KerasLayer("https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4", output_shape=[1280],
                   trainable=False),
    tf.keras.layers.Dense(DIAGNOSIS_NUMBER, activation='softmax')
])

单元格的输出是

build executes eagerly: True 
call executes eagerly: False

当我训练模型时

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(training_set, validation_data=validation_set, epochs=20)

我明白了

 Epoch 1/20
 call executes eagerly: False
 call executes eagerly: False

问题:

  1. 为什么要在模型实例化时执行 build 和 call 方法?
  2. 如果急切执行是默认执行方法,为什么不急切执行调用方法?

【问题讨论】:

    标签: python tensorflow machine-learning keras deep-learning


    【解决方案1】:

    我认为即使您使用自定义层也可以运行 Eager 模式。由于“model.fit()”方法,您的模型在图形模式下运行,要在急切模式下运行,您必须从头开始编写自己的训练循环,您可以使用 GradientTape。 [1]: https://www.tensorflow.org/guide/keras/customizing_what_happens_in_fit

    【讨论】:

      【解决方案2】:

      自定义层的call 方法会自动使用@tf.function 进行修饰,它本质上是在第一次调用时创建一个数据流图,然后在所有后续调用中执行此图。为什么这与您的问题有关?因为根据tf.executing_eagerly()上的docs

      默认情况下启用急切执行,并且此 API 在大多数情况下返回 True。但是,此 API 在以下用例中可能会返回 False。

      • 在 tf.function 中执行,除非之前调用了 tf.init_scope 或 tf.config.run_functions_eagerly(True)。
      • 在 tf.dataset 的转换函数内执行。
      • tf.compat.v1.disable_eager_execution() 被调用。

      那么让我们试试看使用tf.init_scope会发生什么:

      import tensorflow_hub as hub
      import tensorflow as tf
      
      class Fractal2D(tf.keras.layers.Layer):
          def __init__(self, kernel_size_range):
              super(Fractal2D, self).__init__()
              self.kernel_size_range = kernel_size_range
          
          def build(self, inputs):
              print(f'build executes eagerly: {tf.executing_eagerly()}')
              return inputs
          
          def call(self, inputs):
              with tf.init_scope():
                print(f'call executes eagerly: {tf.executing_eagerly()}')
              return inputs
      
      model = tf.keras.Sequential([
          tf.keras.layers.InputLayer(input_shape=(224, 224, 3), batch_size=1),
          Fractal2D(kernel_size_range=(3, 41)),
          hub.KerasLayer("https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4", output_shape=[1280],
                         trainable=False),
          tf.keras.layers.Dense(1, activation='sigmoid')
      ])
      training_set = tf.random.normal((1, 224, 224, 3))
      model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
      model.fit(training_set, tf.random.normal((1, 1)), epochs=2)
      
      build executes eagerly: True
      call executes eagerly: True
      Epoch 1/2
      call executes eagerly: True
      call executes eagerly: True
      1/1 [==============================] - 4s 4s/step - loss: 0.2856 - accuracy: 0.0000e+00
      Epoch 2/2
      1/1 [==============================] - 0s 36ms/step - loss: 0.1641 - accuracy: 0.0000e+00
      <keras.callbacks.History at 0x7f8836515710>
      

      似乎与文档一致。

      【讨论】:

      • 你知道吗,为什么在模型描述之后调用 build 和 call。不仅在fit方法之后?
      • 查看文档tensorflow.org/api_docs/python/tf/keras/… 和源代码。在model.compile 期间,模型将被包裹在一个 tf.function 中。
      • 我在编译之前有顺序之后的构建/调用输出。我用的是 Jupyter Notebook。
      • 是的,这里也记录了这种行为:tensorflow.org/api_docs/python/tf/keras/layers/…。可选的build() 方法由层的第一个__call__() 调用。
      猜你喜欢
      • 2011-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-23
      • 1970-01-01
      • 2020-03-14
      • 2019-02-01
      相关资源
      最近更新 更多