Layer.call 没有急切地执行
Posted
技术标签:
【中文标题】Layer.call 没有急切地执行【英文标题】:Layer.call is not executed eagerly 【发布时间】: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
问题:
-
为什么要在模型实例化时执行 build 和 call 方法?
如果急切执行是默认执行方法,为什么不急切执行调用方法?
【问题讨论】:
【参考方案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__() 调用。以上是关于Layer.call 没有急切地执行的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法通过 QueryDSL 中的谓词 API 急切地获取惰性关系?