pythonkeraskeras-3

For keras layers with unknown sizes is it possible to know the output size for a specific input?


We can create a Convolution Neural Network with variable size inputs

ip = keras.layers.Input((None, None, 3))
op = keras.layers.Conv2D(3, (2, 2))(ip)

model=keras.models.Model(inputs = [ip], outputs = [op])

Is there a way to know the size of the output layer op for a specific input?

I know there is a formula to calculate the size for this simple example. Is there a way I can have the model calculate the size for me?

One way I could do that would be to run some sample data through.

x = numpy.random.random((1, 64, 64, 3))
y = model(x)

Now I can see both of their shapes 1, 64, 64, 3 and 1, 63, 63, 3.

My goal is to be able to use different cnn networks, where I don't know how to calculate the size in general, for example a Resnet101. I have different scale values for the outputs, and I want to be able to scale my ground truth data during training.

Can I get the output size, just from the model and the input data without running a sample through?


Solution

  • UPDATE: as @matt mentioned, just calling model with a new Input is sufficient. No need to create a new model for different inputs. However in this case it is required to keep the respective dimensions unspecified. So this does not work:

    import keras_core as keras
    
    ip = keras.layers.Input((10, 10, 3))
    op = keras.layers.Conv2D(3, (5, 5))(ip)
    model = keras.models.Model(inputs = [ip], outputs = [op])
    
    model(keras.layers.Input((100, 100, 3)))
    

    While this does:

    import keras_core as keras
    
    ip = keras.layers.Input((None, None, 3))
    op = keras.layers.Conv2D(3, (5, 5))(ip)
    model = keras.models.Model(inputs = [ip], outputs = [op])
    
    model(keras.layers.Input((100, 100, 3)))
    

    If you still want a fixed, but different input, you have to implement something along the lines of what I suggested below:

    When you use keras.layers.Input((100, 100, 3)) it actually creates a KerasTensor object, which seem to be a lazy / uninitialized tensor object. Passing it recursively trough the other layers via __call__, actually modifies the output shape (without computing any flops):

    import keras_core as keras
    
    ip = keras.layers.Input((100, 100, 3))
    op = keras.layers.Conv2D(3, (5, 5))(ip)
    
    print(op)
    
    model = keras.models.Model(inputs = [ip], outputs = [op])
    

    Prints:

    <KerasTensor shape=(None, 96, 96, 3), dtype=float32, sparse=False, name=keras_tensor_39>
    

    The same objects is also available via model.output. I guess the solution here is to slightly refactor your code and define a function, that creates the model for a given different input, along the lines of:

    import keras_core as keras
    
    def create_model(ip):
        op = keras.layers.Conv2D(3, (5, 5))(ip)
        return keras.models.Model(inputs = [ip], outputs = [op])
    
    model_1 = create_model(keras.layers.Input((10, 10, 3)))
    model_2 = create_model(keras.layers.Input((100, 100, 3)))
    
    print(model_1.output)
    print(model_2.output)
    

    Which prints:

    [<KerasTensor shape=(None, 6, 6, 3), dtype=float32, sparse=False, name=keras_tensor_54>]
    [<KerasTensor shape=(None, 96, 96, 3), dtype=float32, sparse=False, name=keras_tensor_56>]
    

    I hope this helps.