Concatenate two layers in keras, tensorflow

I want to build the below architecture of neural network layers

enter image description here

I have a cnn layer:

cnn1 = keras.Sequential([
    layers.Input((32, 32, 3)),
    layers.Conv2D(32, (5, 5), activation='relu')
    ]
)

And module:

from tensorflow.keras.layers import Concatenate, Dense

'''Module 1'''
module1_left = keras.Sequential([
    layers.Input((28, 28, 32)),
    layers.Conv2D(32, (1, 1), activation='relu', padding='same')
    ]
)
module1_middle = keras.Sequential([
    layers.Input((28, 28, 32)),
    layers.Conv2D(32, (1, 1), activation='relu', padding='same'),
    layers.Conv2D(64, (3, 3), activation='relu', padding='same')
    ]
)
module1_right = keras.Sequential([
    layers.Input((28, 28, 32)),
    layers.MaxPooling2D((3, 3), padding='same', strides=(1, 1)),
    layers.Conv2D(32, (1, 1), activation='relu', padding='same')
    ]
)
module1 = keras.layers.concatenate([module1_left.outputs[0], module1_middle.outputs[0], module1_right.outputs[0]], axis=-1)

Then I try to combine cnn1 and module 1, by cnn1.add(module1), here’s the error for the last line:

TypeError: The added layer must be an instance of class Layer. Found: Tensor("concatenate_27/Identity:0", shape=(None, 28, 28, 128), dtype=float32)

Then I try another approach to concatenate:

module1 = Concatenate([module1_left, module1_middle, module1_right])

Then I get the error:

ValueError: A `Concatenate` layer should be called on a list of at least 2 inputs

Please let me know what’s wrong with those approaches. Thank you!

Kind Regards.

Answer

The best (most flexible,elegant) solution is to use the Functional API in Keras.

Here is a working solution. Notice I am using the Model() (Functional API) instantiation and not Sequential():

from tensorflow.keras import Model
image_input = keras.layers.Input((32, 32, 3))
output_cnn_1 = cnn1(image_input)
output_left = module1_left(output_cnn_1)
output_middle = module1_middle(output_cnn_1)
output_right = module1_right(output_cnn_1)
concatenated_output = keras.layers.Concatenate()([output_left,output_middle,output_right])
final_model = Model(inputs=image_input, outputs=concatenated_output)
final_model.summary()



Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_29 (InputLayer)           [(None, 32, 32, 3)]  0                                            
__________________________________________________________________________________________________
sequential_11 (Sequential)      (None, 28, 28, 32)   2432        input_29[0][0]                   
__________________________________________________________________________________________________
sequential_12 (Sequential)      (None, 28, 28, 32)   1056        sequential_11[8][0]              
__________________________________________________________________________________________________
sequential_13 (Sequential)      (None, 28, 28, 64)   19552       sequential_11[8][0]              
__________________________________________________________________________________________________
sequential_14 (Sequential)      (None, 28, 28, 32)   1056        sequential_11[8][0]              
__________________________________________________________________________________________________
concatenate_15 (Concatenate)    (None, 28, 28, 128)  0           sequential_12[8][0]              
                                                                 sequential_13[8][0]              
                                                                 sequential_14[8][0]              
==================================================================================================
Total params: 24,096
Trainable params: 24,096
Non-trainable params: 0
__________________________________________________________________________________________________
    

Where the definition has slightly changed (we do not declare the input for each of the modules, since we are using the output of the cnn1).

import tensorflow
from tensorflow import keras
from tensorflow.keras import layers

cnn1 = keras.Sequential([
    layers.Conv2D(32, (5, 5), activation='relu')
    ]
)

'''Module 1'''
module1_left = keras.Sequential([
    layers.Conv2D(32, (1, 1), activation='relu', padding='same')
    ]
)
module1_middle = keras.Sequential([
    layers.Conv2D(32, (1, 1), activation='relu', padding='same'),
    layers.Conv2D(64, (3, 3), activation='relu', padding='same')
    ]
)
module1_right = keras.Sequential([
    layers.MaxPooling2D((3, 3), padding='same', strides=(1, 1)),
    layers.Conv2D(32, (1, 1), activation='relu', padding='same')
    ]
)