3
votes

I am using python 3 with anaconda, and keras with over tensorflow, My goal is to create a network with a Conv layer of variable input size

I found here to use this code

i = Input((None, None, 1))
o = Conv2D(1, 3, 3)(i)
model = Model(i, o)
model.compile('sgd', 'mse')

I have used it to create my own model with this code (I need a flatten layer)

model = Sequential()
I = Input((None, None, 1))
c = Conv2D(filters=1, kernel_size=(1, 1))(I)
f = Flatten()(c)
o = Dense(10, activation="softmax")(f)
m = Model(I, o)
m.compile(loss=categorical_crossentropy, optimizer=SGD(), metrics=["accuracy"])

And I keep getting this error

ValueError: The shape of the input to "Flatten" is not fully defined (got (None, None, 1). Make sure to pass a complete "input_shape" or "batch_input_shape" argument to the first layer in your model.

Seems like the issue is with the input shape for the Flatten layer, When I remove it, it's fine.

How can I make it play well with the variable size?

Thanks

3
You can't. Because you added a Dense layer and the shape of the inputs of a Dense layer should be known and constant. It works when you remove Flatten because Dense layer assumes the last dimension as its input shape and the other dimensions as batch shape, so in this case the Dense layers input shape would be (1) and the batch shape would be (None, None, None) - amin

3 Answers

0
votes

Dense needs fix-sized inputs/outputs because the number of weights variables of it must be fixed.

There are two solutions in your case.

  1. To use GAP(Global Average Pooling) instead of Flatten. GAP's outputs size is the number of channels of the previous layer. so, its size is fixed in your case.
  2. To employ the all convolution net that doesn't have dense layer. In this case, the output of the net is two dimensional, not one. So the size of y should be that size.

below was added for Allen M's request.
Here is a code sample:

# The original number of Conv filters are one.
# But I set it 16 to depict how GAP works.
# And B/H/W means BatchSize/Height/Width.

#1. using GAP
I = Input((None, None, 1)) # output shape=(B, H(None), W(None), 1)
c = Conv2D(filters=16, kernel_size=(1, 1))(I)  # output shape=(B, H, W, 16)
f = GlobalAveragePooling2D()(c) # output shape=(B, 16) <- space data(H/W) are aggregated by average
o = Dense(10, activation="softmax")(f) # output shape = (B, 10)
m = Model(I, o)

#2. all conv
I = Input((None, None, 1)) # output shape=(B, H, W, 1)
c = Conv2D(filters=16, kernel_size=(1, 1))(I) # output shape=(B, H, W, 16)
o = Conv2D(filters=10, kernel_size=(1, 1), activation="softmax")(c)
    # output shape=(B, H, W, 10)
m = Model(I, o)
# The output size of all conv is H * W * 10, where 10 is the number of classes.
# so the shape of y should be (B, H, W, 1) or (B, H, W) or (B, H, W, 10).
# That is pixel-wise classification or semantic segmentation.
-2
votes

Flatten method doesn't take input size as argument.

model = Sequential()
I = Input((None, None, 1))
c = Conv2D(filters=1, kernel_size=(1, 1))(I)
f = Flatten()
o = Dense(10, activation="softmax")(I)
m = Model(I, o)
m.compile(loss="categorical_crossentropy", optimizer=SGD(), metrics=["accuracy"])

This should solve your problem.

-2
votes

I think the problem is due to your variable input_sizes. It says here that you can't vary input_sizes if you're using a fully connected layer. See: How to train images, when they have different size ?