Search code examples
pythonkerasdeep-learningtensorflow2

ValueError: Graph disconnected: cannot obtain value for tensor Tensor…The following previous layers were accessed without issue:


I want to obtain the output of intermediate sub-model layers with tf2.keras.Here is a model composed of two sub-modules:

    input_shape = (100, 100, 3)



    def model1():
        input = tf.keras.layers.Input(input_shape)
        cov = tf.keras.layers.Conv2D(filters=32, kernel_size=3, strides=1,name='cov1')(input)
        embedding_model = tf.keras.Model(input,cov,name='model1')
        return embedding_model


    def model2(embedding_model):

        input_sequence = tf.keras.layers.Input((None,) + input_shape)

        sequence_embedding = tf.keras.layers.TimeDistributed(embedding_model,name='time_dis1')

        emb = sequence_embedding(input_sequence)
        att = tf.keras.layers.Attention()([emb,emb])
        dense1 = tf.keras.layers.Dense(64,name='dense1')(att)
        outputs = tf.keras.layers.Softmax()(dense1)

        final_model = tf.keras.Model(inputs=input_sequence, outputs=outputs,name='model2')
        return final_model

    embedding_model = model1()

    model2 = model2(embedding_model)
    print(model2.summary())

output:

Model: "model2"
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_2 (InputLayer)            [(None, None, 100, 1 0                                            
__________________________________________________________________________________________________
time_dis1 (TimeDistributed)     (None, None, 98, 98, 896         input_2[0][0]                    
__________________________________________________________________________________________________
attention (Attention)           (None, None, 98, 98, 0           time_dis1[0][0]                  
                                                                 time_dis1[0][0]                  
__________________________________________________________________________________________________
dense1 (Dense)                  (None, None, 98, 98, 2112        attention[0][0]                  
__________________________________________________________________________________________________
softmax (Softmax)               (None, None, 98, 98, 0           dense1[0][0]                     
==================================================================================================
Total params: 3,008
Trainable params: 3,008
Non-trainable params: 0

and then,I want to get output intermediate layer of model1 and model2:

    model1_output_layer = model2.get_layer('time_dis1').layer.get_layer('cov1')
    output1 = model1_output_layer.get_output_at(0)
    output2 = model2.get_layer('dense1').get_output_at(0)

    output_tensors = [output1,output2]
    model2_input = model2.input
    submodel = tf.keras.Model([model2_input],output_tensors)
    input_data2 = np.zeros((1,10,100,100,3))

    result = submodel.predict([input_data2])
    print(result)

Running in tf2.3 ,the error I am getting is:

  File "/Users/bouluoyu/anaconda/envs/tf2/lib/python3.6/site-packages/tensorflow/python/keras/engine/functional.py", line 115, in __init__
    self._init_graph_network(inputs, outputs)
  File "/Users/bouluoyu/anaconda/envs/tf2/lib/python3.6/site-packages/tensorflow/python/training/tracking/base.py", line 457, in _method_wrapper
    result = method(self, *args, **kwargs)
  File "/Users/bouluoyu/anaconda/envs/tf2/lib/python3.6/site-packages/tensorflow/python/keras/engine/functional.py", line 191, in _init_graph_network
    self.inputs, self.outputs)
  File "/Users/bouluoyu/anaconda/envs/tf2/lib/python3.6/site-packages/tensorflow/python/keras/engine/functional.py", line 931, in _map_graph_network
    str(layers_with_complete_input))
ValueError: Graph disconnected: cannot obtain value for tensor Tensor("input_1:0", shape=(None, 100, 100, 3), dtype=float32) at layer "cov1". The following previous layers were accessed without issue: ['time_dis1', 'attention', 'dense1']

But the following code works:

    model1_input = embedding_model.input
    model2_input = model2.input

    submodel = tf.keras.Model([model1_input,model2_input],output_tensors)

    input_data1 = np.zeros((1,100,100,3))
    input_data2 = np.zeros((1,10,100,100,3))

    result = submodel.predict([input_data1,input_data2])

    print(result)

But not what I want.This is strange, model1 is part of model2, so why do we need to input an extra tensor.Sometimes,it is hard to get an extra tensor,especially for complex models.


Solution

  • so why do we need to input an extra tensor

    Short answer is, TensorFlow doesn't know to make the connection between the inputs you expect it to make. The problem arises because you're passing a Model (instead of a Layer) to your TimeDistributed layer. This leave the Input layer of your model1 hanging, unless you explicitly pass it an input. The TimeDistributed layer is not smart enough to handle models in this way.

    My solution would depend on the answer to the following question,

    Why do you need model1? All it has is a Conv2D layer. You can easily do

    sequence_embedding = tf.keras.layers.TimeDistributed(
        tf.keras.layers.Conv2D(filters=32, kernel_size=3, strides=1,name='cov1'),
        name='time_dis1'
    )
    

    If you do this, now you gotta change the following lines,

    model1_output_layer = model2.get_layer('time_dis1').layer.get_layer('cov1')
    output1 = model1_output_layer.get_output_at(0)
    

    to something like (the exact output you want will depend on what you're actually after)

    model1_output_layer = model2.get_layer('time_dis1')
    output1 = model1_output_layer.output
    
    # This output1 may need further processing depending on what you need
    # e.g. if you need mean embeddings over time axis
    output_mean = tf.keras.layers.Average(output1, axis=1)
    

    This is because you can't access the output of the layer nested by a TimeDistributed layer. Because the layer passed to the TimeDistributed layer doesn't actually do anything. And it doesn't have a defined output. It's just sitting there as a template for the TimeDistributed layer to compute the output using it. So, to get the output from a TimeDistributed layer, you need to access it via that layer.

    You try to do it as you have it (instead of my way), you'll get,

    AttributeError: Layer cov1 has no inbound nodes.
    

    You may ask, "why did it work before"?

    It's because, before you had a Model there instead of a Layer. Because the Conv2D layer was wrapped by the model, the layer output was defined (because it had an Input layer). And this feeds back to the reason, why it complained about the missing Input from model1 when trying to define the submodel.

    I know this explanation may make your head spin as the reasons behind this error are quite convoluted. But going through it a few times will hopefully help.