Search code examples
pythontensorflowkeras

Disconnected graph when concatenating two models


Trying to build a new model based on part of pre-trained model,

Here's some cleaned out code.

Let's imagine we got model1 trained, and want to add some layers defined in model2:

import tensorflow.keras as keras
import tensorflow as tf
from tensorflow.keras.layers import Input, Conv2D, Activation
from tensorflow.keras.models import Model, Sequential

model1 = Sequential([
    Conv2D(2, (3,3), padding='same', input_shape=(6,6,1)),
    Activation('relu')
])
model2 = Sequential([
    Conv2D(3, (3,3), padding='same', input_shape=(6,6,2)),
    Activation('softmax')
])

model_merge = Model(inputs=model1.input, 
                    outputs=Activation('softmax')(model2(model1.get_layer('conv2d').output)))

It looks a bit messy, but I want to demonstrate it's not disconnected by adding a softmax activation here.

summary of model1:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 6, 6, 2)           20        
_________________________________________________________________
activation (Activation)      (None, 6, 6, 2)           0         
=================================================================
Total params: 20
Trainable params: 20
Non-trainable params: 0
_________________________________________________________________

summary of model2:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_4 (Conv2D)            (None, 6, 6, 3)           57        
_________________________________________________________________
activation_4 (Activation)    (None, 6, 6, 3)           0         
=================================================================
Total params: 57
Trainable params: 57
Non-trainable params: 0
_________________________ 

And summary of model_merge:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_input (InputLayer)    (None, 6, 6, 1)           0         
_________________________________________________________________
conv2d (Conv2D)              (None, 6, 6, 2)           20        
_________________________________________________________________
sequential_2 (Sequential)    (None, 6, 6, 3)           57        
_________________________________________________________________
activation_4 (Activation)    (None, 6, 6, 3)           0         
=================================================================
Total params: 77
Trainable params: 77
Non-trainable params: 0
_________________________________________________________________

Let's prove this merged model is not disconnected:

layers = [layer.output for layer in model_merge.layers]
test1 = Model(inputs=model_merge.input, outputs=layers[-1])

Everything works just fine.

test1's summary:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_input (InputLayer)    (None, 6, 6, 1)           0         
_________________________________________________________________
conv2d (Conv2D)              (None, 6, 6, 2)           20        
_________________________________________________________________
sequential_2 (Sequential)    (None, 6, 6, 3)           57        
_________________________________________________________________
activation_4 (Activation)    (None, 6, 6, 3)           0         
=================================================================
Total params: 77
Trainable params: 77
Non-trainable params: 0
_________________________________________________________________

Here's the tragedy:

test2 = Model(inputs=model_merge.input, outputs=layers[-2])

The most important feed back:

ValueError: Graph disconnected: cannot obtain value for tensor Tensor("conv2d_2_input:0", shape=(?, 6, 6, 2), dtype=float32) at layer "conv2d_2_input". The following previous layers were accessed without issue: []

full feedback:

ValueErrorTraceback (most recent call last)
<ipython-input-18-946b325081c1> in <module>
----> 1 test = Model(inputs=model_merge.input, outputs=layers[-2])

/usr/local/lib/python3.5/dist-packages/tensorflow/python/keras/engine/training.py in __init__(self, *args, **kwargs)
    119 
    120   def __init__(self, *args, **kwargs):
--> 121     super(Model, self).__init__(*args, **kwargs)
    122     # Create a cache for iterator get_next op.
    123     self._iterator_get_next = weakref.WeakKeyDictionary()

/usr/local/lib/python3.5/dist-packages/tensorflow/python/keras/engine/network.py in __init__(self, *args, **kwargs)
     79         'inputs' in kwargs and 'outputs' in kwargs):
     80       # Graph network
---> 81       self._init_graph_network(*args, **kwargs)
     82     else:
     83       # Subclassed network

/usr/local/lib/python3.5/dist-packages/tensorflow/python/training/checkpointable/base.py in _method_wrapper(self, *args, **kwargs)
    440     self._setattr_tracking = False  # pylint: disable=protected-access
    441     try:
--> 442       method(self, *args, **kwargs)
    443     finally:
    444       self._setattr_tracking = previous_value  # pylint: disable=protected-access

/usr/local/lib/python3.5/dist-packages/tensorflow/python/keras/engine/network.py in _init_graph_network(self, inputs, outputs, name)
    219     # Keep track of the network's nodes and layers.
    220     nodes, nodes_by_depth, layers, layers_by_depth = _map_graph_network(
--> 221         self.inputs, self.outputs)
    222     self._network_nodes = nodes
    223     self._nodes_by_depth = nodes_by_depth

/usr/local/lib/python3.5/dist-packages/tensorflow/python/keras/engine/network.py in _map_graph_network(inputs, outputs)
   1850                              'The following previous layers '
   1851                              'were accessed without issue: ' +
-> 1852                              str(layers_with_complete_input))
   1853         for x in node.output_tensors:
   1854           computable_tensors.append(x)

ValueError: Graph disconnected: cannot obtain value for tensor Tensor("conv2d_2_input:0", shape=(?, 6, 6, 2), dtype=float32) at layer "conv2d_2_input". The following previous layers were accessed without issue: []

It's really driving me crazy,

Any ideas?


Solution

  • The layer you are trying to use as output has two output nodes. The first connects the input of model2 to the output of the model2. The second output node connects the output of the model1 and the first layer of model2. By default, the layer output returns only the first output node. So what is happening is you are tying to connect the input of the model_merge(input of model1) with the first output node.

    To following code shows this. Individual output nodes of the layer can be accessed using the get_output_at() method of the layer.

    layer_output = model_merge.layers[-2].output # The first output node
    layer_output_1 = model_merge.layers[-2].get_output_at(0) # The first output node
    layer_output_2 = model_merge.layers[-2].get_output_at(1) # The second output node
    

    Now the following two codes throws error because the graph is disconnected.

    test2 = Model(inputs=model_merge.input, outputs=layer_output)
    

    and

    test2 = Model(inputs=model_merge.input, outputs=layer_output_1)
    

    But the code below doesnot throw error, because the graph is connected.

    test2 = Model(inputs=model_merge.input, outputs=layer_output_2)