Colonder
Colonder

Reputation: 1576

How to flatten the varying-sized data in Keras and use it in the next layers

I'd like to build a CNN that can be feed matrices with the constant number of rows but the varying number of columns. I started from this blog but it uses Flatten layer at some point. According to this GitHub issue, the Flatten layer cannot be used with not fully-shape-defined data. I used this answer to build a CNN like this:

from keras import Input, Model
from keras.layers import Conv2D, MaxPooling2D, Dense, Dropout, Lambda, Activation
from keras.optimizers import SGD
import keras.backend as K

input = Input(shape=(None, 60, 1))
        x = Conv2D(list_of_neurons[0], (3, 3), padding='same', activation='relu')(input)
        x = MaxPooling2D(pool_size=(2, 2))(x) # None x 30

        x = Conv2D(list_of_neurons[1], (3, 3), padding='same', activation='relu')(x)
        x = MaxPooling2D(pool_size=(2, 2))(x) # None x 15

        x = Conv2D(list_of_neurons[2], (3, 3), padding='same', activation='relu')(x)
        x = MaxPooling2D(pool_size=(3, 3))(x) # None x 5

        x = Lambda(lambda k: K.batch_flatten(k))(x)
        x = Dense(list_of_neurons[3])(x)
        x = Activation("relu")(x)
        x = Dropout(dropout)(x)
        output = Dense(1, activation='sigmoid')(x)

        self._model = Model(inputs=input, outputs=output)
        self._model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
        self._model.summary()

However, when I try to run a script an error occurs:

Traceback (most recent call last):
  File "/home/kuba/Dropbox/MGR Jakub Kustra/implementacja/first_cnn.py", line 66, in <module>
    mlp = MLP([60, 60, 120, 120], 0.3)
  File "/home/kuba/Dropbox/MGR Jakub Kustra/implementacja/models.py", line 22, in __init__
    x = Dense(list_of_neurons[3])(x)
  File "/home/kuba/anaconda3/lib/python3.6/site-packages/keras/engine/topology.py", line 576, in __call__
    self.build(input_shapes[0])
  File "/home/kuba/anaconda3/lib/python3.6/site-packages/keras/layers/core.py", line 830, in build
    constraint=self.kernel_constraint)
  File "/home/kuba/anaconda3/lib/python3.6/site-packages/keras/legacy/interfaces.py", line 87, in wrapper
    return func(*args, **kwargs)
  File "/home/kuba/anaconda3/lib/python3.6/site-packages/keras/engine/topology.py", line 397, in add_weight
    weight = K.variable(initializer(shape),
  File "/home/kuba/anaconda3/lib/python3.6/site-packages/keras/initializers.py", line 204, in __call__
    scale /= max(1., float(fan_in + fan_out) / 2)
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'

The error occurs in this line in initializers.py:

def __call__(self, shape, dtype=None):
    fan_in, fan_out = _compute_fans(shape)
    scale = self.scale
    if self.mode == 'fan_in':
        scale /= max(1., fan_in)
    elif self.mode == 'fan_out':
        scale /= max(1., fan_out)
    else:
        scale /= max(1., float(fan_in + fan_out) / 2) # <<<<<<<< HERE
    if self.distribution == 'normal':
        stddev = np.sqrt(scale)
        return K.truncated_normal(shape, 0., stddev,
                                  dtype=dtype, seed=self.seed)
    else:
        limit = np.sqrt(3. * scale)
        return K.random_uniform(shape, -limit, limit,
                                dtype=dtype, seed=self.seed)

the fan_in variable is None. I thought that a Dense layer can be feed with the varying size data. How can I overcome this?

Upvotes: 2

Views: 741

Answers (1)

Marcin Możejko
Marcin Możejko

Reputation: 40516

Unfortunately, your scenario is impossible to achieve because of a simple reason: your Flatten is followed by a Dense layer. In order to allocate tensor for a Dense layer, why should now the input shape - as allocator should allocate a matrix of weights of shape (input_shape, output_shape). This where your error comes from.

The solution presented in the issue you provided solved a little bit different task. The problem there was connected to the fact that sometimes - shape of the batch needs to be specified, and this is the problem which batch_flatten is aiming to solve.

Upvotes: 2

Related Questions