无法使用tf2.0/keras获取中间子模型层的输出

3

假设我们使用的是 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?非常感谢!

1个回答

1

只需将output更改为get_output_at(0)

inter_model_2 = tf.keras.Model(
    model.input, model.get_layer('A_3').get_output_at(0))


它有效。你能解释一下为什么它有效吗?谢谢。 - ldavid
如果 A_3 层只有一个入站节点,则使用 output。但是,如果 A_3 层有多个入站节点,则应改用 get_output_at(node_index) - Boluoyu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接