Search code examples
keraskeras-layer

How to make the enabling of a given layer, in a keras model, trainable?


I have the following siamese model:

enter image description here

I would like to make the enabling/disabling of layers a-L1 and b-L1 trainable. ie: a-L1 and/or b-L1 should be transparent (not used or disabled) for the current input if necessary. So, the model after training, will learn when it should enable/disable one or both of the layers a-L1 and b-L1.
I managed to train this model with 4 cases, so I got 4 different models accordingly:

  • model-1: without a-L1 and b-L1
  • model-2: without a-L1
  • model-3: without b-L1
  • model-4: with both a-L1 and b-L1

the performances of these models complement each other and I would like to combine them. Do you have some suggestions, please?


Solution

  • Let's consider you have trained four models and them let's call them m1, m2, m3 and m4

    first define the input layer which is common for all of them.

    inputs = Input(shape=your_inputs_shape)
    
    model_1_output = m1(inputs)
    model_2_output = m2(inputs)
    model_3_output = m3(inputs)
    model_4_output = m4(inputs)
    merged_layer = Concatenate(axis=your_concatanation_axis)([model_1_output, model_2_output, model_3_output,model_4_output)
    new_model = Model(inputs=inputs, outputs=merged_layer)
    

    I hope this will solve your problem.

    EDIT:

    To answer your question on comment, It is possible to combine only the layers before L2. But you have to decide which model's layers starting from L2, you are going to use(Since you are not combining layers starting from L2). Let's assume you want to use m1 model's layers after L2. In addition I want to add the weighting mechanism I've specified above in comments of the answer.

    First let's define new models with common new inputs

    new_inputs = Input(shape=(inputs_shape))
    new_m1 = keras.models.Model(inputs = new_inputs, outputs = m1(new_inputs))
    new_m2 = keras.models.Model(inputs = new_inputs, outputs = m2(new_inputs))
    new_m3 = keras.models.Model(inputs = new_inputs, outputs = m3(new_inputs))
    new_m4 = keras.models.Model(inputs = new_inputs, outputs = m4(new_inputs))
    

    Now get the L2 layer for all models

    model1_l2 = new_m1.layers[1].get_layer("L2").output
    model2_l2 = new_m2.layers[1].get_layer("L2").output
    model3_l2 = new_m3.layers[1].get_layer("L2").output
    model4_l2 = new_m4.layers[1].get_layer("L2").output
    

    weighted merge

    merged = Concatenate(axis=your_concatanation_axis)([model1_l2, model2_l2, model3_l2,model4_l2])
    merged_layer_shape = merged.get_shape().as_list()
    
    # specify number of channels you want the output to have after merging
    
    desired_output_channels = 32
    
    new_trainable_weights =  keras.backend.random_normal_variable(shape=(merged_layer_shape[-1], desired_output_channels),mean=0,scale=1)
    weighted_output = keras.backend.dot(merged,new_trainable_weights)
    

    now connect the layer of model1(m1) next to L2 with this new weighted_output

    # I'm using some protected properties of layer. But it is not recommended way to do it.
    # get the index of l2 layer in new_m1
    for i in range(len(new_m1.layers[1].layers)):
        if new_m1.layers[1].layers[i].name=="L2":
            index = i
    x = weighted_output
    for i in range(index+1, len(new_m1.layers[1].layers)):
        x = new_m1.layers[1].layers[i](x)
    
    new_model = keras.models.Model(inputs=new_inputs, outputs=x)