Keras Concatenate: "Nonetype" object is not subscriptable

Viewed 957

I am trying to concatenate the outputs of two or more models.

Code:

import efficientnet.tfkeras as efn

def build_model(model_name="efficientnet_B0", dim=128,
                normalize_features=True, return_feature_model=False, 
                inp_layer=None):
    
    def get_efficientnet(effnet_model):
        effnet_model = int(effnet_model)
        EFNS = [efn.EfficientNetB0, efn.EfficientNetB1,
                efn.EfficientNetB2, efn.EfficientNetB3, 
                efn.EfficientNetB4, efn.EfficientNetB5,
                efn.EfficientNetB6, efn.EfficientNetB7,]
        return EFNS[effnet_model]

    model_dict = {
        "efficientnet": get_efficientnet,
        "resnet50": tf.keras.applications.ResNet50,
        "vgg19": tf.keras.applications.VGG19,
        "Xception": tf.keras.applications.Xception,
    }   


    # For Image Input
    if model_name.find('efficientnet') != -1:
        base = model_dict['efficientnet'](model_name[-1])(input_shape=(dim,dim,3),
                                                          weights='imagenet',
                                                          include_top=False)(inp_layer)
    else:
        base = model_dict[model_name](input_shape=(dim,dim,3),
                                      weights='imagenet',
                                      include_top=False)(inp_layer)
    
    pooling_layer = keras.layers.GlobalAveragePooling2D()(base)
    normalized_feature = keras.layers.BatchNormalization(name="norm_featvec")(pooling_layer)
    output = keras.layers.Dense(1,activation='sigmoid')(pooling_layer)
    
    if normalize_features:
        feat_output = normalized_feature
    else:
        feat_output = pooling_layer
            
    if return_feature_model:
        featext_model = keras.Model(inputs=[img_inp], outputs=[feat_output])
    model = keras.Model(inputs=[img_inp], outputs=[output])

    if return_feature_model:
        return model, featext_model
    else:
        return model



def get_complete_model(featvec_model_paths, dim=384):
    input_layer = keras.layers.Input(shape=(dim, dim, 3), name="img_input")
    models = list()
    
    for model_path in featvec_model_paths:
        model_name = os.path.basename(model_path)[5:-5]
        _, featvec_model = build_model(model_name=model_name, dim=dim,
                                       return_feature_model=True,
                                       inp_layer=input_layer)
        featvec_model.load_weights(model_path)
        featvec_model.trainable = False
        models.append(featvec_model)
        
    concat_layer = keras.layers.Concatenate()(models)
    dense_1 = keras.layers.Dense(4096, activation="selu")(concat_layer)
    dense_2 = keras.layers.Dense(2048, activation="selu")(dense_1)
    dense_3 = keras.layers.Dense(1024, activation="selu")(dense_2)
    output_layer = keras.layers.Dense(1, activation="sigmoid")(dense_3)
    
    model = keras.Model(inputs=[input_layer], outputs=[output_layer])
    
    model.compile(loss=keras.losses.BinaryCrossentropy(),
                  optimizer=keras.optimizers.Nadam(),
                  metrics=['AUC'])
    return model

featvec_model_paths in get_complete_model are paths to weight files.

Execution Line:

featvec_paths = ['feat_efficientnet_b3_0.h5',
                 'feat_efficientnet_b3_1.h5',
                 'feat_efficientnet_b4_0.h5',
                 'feat_efficientnet_b4_1.h5']
final_model, featvec_model = get_complete_model(featvec_paths, dim=384)

You can run the code by commenting featvec_model.load_weights(model_path).

Error:

TypeError                                 Traceback (most recent call last)
<ipython-input-104-76ecd46bf20d> in <module>
----> 1 final_model, featvec_model = get_complete_model(featvec_paths, dim=384)

<ipython-input-103-d92456535b41> in get_complete_model(featvec_model_paths, dim)
     17         #print(models)
     18 
---> 19     concat_layer = keras.layers.Concatenate()(models)
     20     dense_1 = keras.layers.Dense(4096, activation="selu")(concat_layer)
     21     dense_2 = keras.layers.Dense(2048, activation="selu")(dense_1)

/opt/conda/lib/python3.7/site-packages/tensorflow/python/keras/engine/base_layer.py in __call__(self, *args, **kwargs)
   1006       with ops.name_scope_v2(name_scope):
   1007         if not self.built:
-> 1008           self._maybe_build(inputs)
   1009 
   1010         with autocast_variable.enable_auto_cast_variables(

/opt/conda/lib/python3.7/site-packages/tensorflow/python/keras/engine/base_layer.py in _maybe_build(self, inputs)
   2708         # operations.
   2709         with tf_utils.maybe_init_scope(self):
-> 2710           self.build(input_shapes)  # pylint:disable=not-callable
   2711       # We must set also ensure that the layer is marked as built, and the build
   2712       # shape is stored since user defined build functions may not be calling

/opt/conda/lib/python3.7/site-packages/tensorflow/python/keras/utils/tf_utils.py in wrapper(instance, input_shape)
    270     if input_shape is not None:
    271       input_shape = convert_shapes(input_shape, to_tuples=True)
--> 272     output_shape = fn(instance, input_shape)
    273     # Return shapes from `fn` as TensorShapes.
    274     if output_shape is not None:

/opt/conda/lib/python3.7/site-packages/tensorflow/python/keras/layers/merge.py in build(self, input_shape)
    490   def build(self, input_shape):
    491     # Used purely for shape validation.
--> 492     if not isinstance(input_shape[0], tuple) or len(input_shape) < 2:
    493       raise ValueError('A `Concatenate` layer should be called '
    494                        'on a list of at least 2 inputs')

TypeError: 'NoneType' object is not subscriptable

I am passing a list of models to the concatenation class object. I also tried appending only the last layers of each model: models.append(featvec_model.layers[-1]) but this also gave the same error.

1 Answers

I just had to do this in get_complete_model():

models = models.append(featvec_model)
Related