0
votes

I recently collected several Keras models for which I'm importing their architecture using keras.Models.model_from_json function (Note that there is no training made yet). My image data generator can be customized to produce batches of samples with different sizes and shapes (varying in the same flow generator). For instance, I may generate data with the shape (*batchsize*,32,32,3) and a total of 6 classes. Currently, the imported models have different input and output shapes, let's say (5*100*100*3) and 2 classes assigned to their layers. My goal is to change the input and output shape of such layers in order to compare different image sizes in the model performance.

First, in the input layer, I have tried:

model.layers[0].input.set_shape((None,32,32,3))

I received the following error:

Dimension 1 in both shapes must be equal, but are 100 and 32. Shapes are [?,100,100,3] and [?,32,32,3].

Similarly for the output layer, using

model.layers[len(model.layers)-1].output.set_shape((None,6))

the same error was throw

Dimension 1 in both shapes must be equal, but are 2 and 6. Shapes are [?,2] and [?,6].

TLDR: Is there a generic function/util to dynamically change the input and output shape of any model architecture in Keras?

PS: If the model has several outputs or the last two layers are, keras.layers.Dense followed by keras.layers.Activation, changing the shape of last layer is a viable solution?

1
The set_shape approach only update existing unknown dimensions of the defined shapes, so it is not viable. Moreover, model.input and model.output output the first and last layers in a Sequential and first and multiple output layers in Model, independently of the layer type. Any help solving this would be tremendously appreciated.André Guerra
from keras.models import clone_model newmodel = clone_model(model,Input(batch_shape=(None,32,32,3))) Still no idea how to change the output class number dynamically.André Guerra

1 Answers

0
votes

I come up with this implementation however far from perfect it works in all models I currently have. I would appreciate further testing with other models. I leave it here for reference.

def modifySISO(model,inp,out): # Modify Single Input Single Output image classification model.

    ci,co = validation(model,inp,out)

    if(ci): #change input
      model = changeInp(model,inp)
    if(co): #change ouput
      model = changeOut(model,out)

    return model, any([ci,co]) # modified or original model, modified


def validation(model,inp,out):

    n_in = len(model.inputs)
    n_out =len(model.outputs) 
    assert (n_in) > 0, 'Model has not detectable inputs.'
    assert (n_out) > 0, 'Model has not detectable outputs.'
    assert (n_in) <= 1, 'Model has multiple %d inputs tensors. Cannot apply input transformation.' % (n_in)
    assert (n_out) <= 1, 'Model has multiple %d output tensors Cannot apply output transformation.' % (n_out)

    inp_old = model.input_shape

    assert len(inp_old) == 4, 'Model input tensor shape != 4: Not a valid image classification model (B x X x X x X).'

    assert isinstance(inp,tuple), 'Input parameter is not a valid tuple.'
    assert len(inp) == 4, 'Input parameter is not a valid 4-rank tensor shape.'

    out_old = model.output_shape
    assert len(out_old) == 2, 'Model output tensor shape !=2: Not a valid image classification model (B x C).'
    assert isinstance(out,tuple), 'Output parameter is not a valid tuple.'
    assert len(out) == 2, 'Output parameter is not a valid 2-rank tensor shape.'

    ci = any([inp[i] != inp_old[i] for i in range(0,len(inp))])
    co = any([out[i] != out_old[i] for i in range(0,len(out))])

    return ci,co

def changeInp(model,inp):
    return clone_model(model,Input(batch_shape=inp))

def changeOut(model,out):
    idx = findPreTop(model) # Finds the pre-topping layer (must be tested more extensively)
    preds = reshapeOutput(model,idx,out)
    model = Model(inputs=model.input, outputs=preds)

def findPreTop(model):
   i = len(model.layers)-1
   cos = model.output_shape
   while(model.layers[i].output_shape == cos):
     i -= 1
   return i

def reshapeOutput(model,i,out): # Reshapes model accordingly to https://keras.io/applications/#usage-examples-for-image-classification-models
    layer=model.layers[i]
    pool = layer.output_shape[-1]
    x = layer.output
    x = Dense(int(pool/2),activation='relu')(x)
    x = Dense(out[1], activation='softmax')(x)
    return x

newmodel = modifySISO(model,(None,100,100,3),(None,6)) #Implementation