假设我们使用的是 TensorFlow r2.0,而且我们想在 Keras 中使用子模型,那么我们会有一个如下所示的模型A:
def create_model_A(in_num_units, name):
x = tf.keras.Input(shape=(in_num_units))
y = tf.keras.layers.Dense(in_num_units, activation='relu')(x)
y = tf.keras.layers.BatchNormalization()(y)
y = tf.keras.layers.Dense(in_num_units, activation='relu')(y)
y = tf.keras.layers.BatchNormalization()(y)
y = x + y
return tf.keras.Model(x, y, name=name)
使用模型A的模型B:
def create_model_B(in_num_units):
x = tf.keras.Input(shape=(in_num_units))
y = create_model_A(x.shape[-1], name='A_1')(x)
y = tf.keras.layers.Dense(in_num_units // 2, name='downsize_1')(y)
y = tf.keras.layers.BatchNormalization()(y)
y = create_model_A(y.shape[-1], name='A_2')(y)
y = tf.keras.layers.Dense(in_num_units // 2, name='downsize_2')(y)
y = tf.keras.layers.BatchNormalization()(y)
y = create_model_A(y.shape[-1], name='A_3')(y)
y = tf.keras.layers.Dense(in_num_units // 2, name='downsize_3')(y)
y = tf.keras.layers.BatchNormalization()(y)
y = create_model_A(y.shape[-1], name='A_4')(y)
return tf.keras.Model(x, y)
这个方法非常有效。我们可以像这样实例化一个模型B:
num_in_units = 500
model = create_model_B(num_in_units) # Works!
可以享受到 tf.keras.Model 的所有优点。但是,当我们想要获得子模型A的中间层结果时,问题就出现了。如果这个层是模型B的一部分,那么一切都正常:
inter_model_1 = tf.keras.Model(
model.input, model.get_layer('downsize_1').output) # Works!
但如果该层是子模型 A 的一部分,则会崩溃并出现 ValueError
错误。这个命令:
inter_model_2 = tf.keras.Model(
model.input, model.get_layer('A_3').output) # Does not work!
提供:
ValueError: Graph disconnected: cannot obtain value for tensor Tensor("input_4:0", shape=(None, 250), dtype=float32) at layer "input_4". The following previous layers were accessed without issue: []
我不确定是否完全理解keras的内部机制。但是当我深入源代码时,我理解到使用这种方法的子模型有两个输入张量对象被创建。可以这样打印它们:
print([n.input_tensors.name for n in model.get_layer('A_3').inbound_nodes])
['input_4:0', 'batch_normalization_5/Identity:0']
其中之一是子模型tf.keras.Input
,另一个是连接到顶层模型的输入。建立从顶层模型B输入张量到顶层模型B输出张量的新模型时,图中的路径似乎正确地经过了'batch_normalization_5'
输入,并且两个张量在图形中正确地连接了起来。
然而,当尝试将顶层模型B输入张量链接到子模型A输出张量时,输出张量似乎连接到了子模型的tf.keras.Input
,而两个张量则断开了连接。
目前我找到的解决方法是使用张量的顶层模型版本model.get_layer('A_3').output
:
model.get_layer('A_3')._outbound_nodes[0].input_tensors
但这似乎过于复杂且不够简洁...此外,它不允许我们利用模型A内部的层。
我想知道是否有人能对这个特定的tf.keras
行为给我一些精确的解释。我这样做是正确的吗?这是预期的行为吗?还是一个bug?非常感谢!
A_3
层只有一个入站节点,则使用output
。但是,如果A_3
层有多个入站节点,则应改用get_output_at(node_index)
。 - Boluoyu