How to handle variable input size in CNN using Keras?

I am trying to do the usual classification in the MNIST database, but with randomly truncated digits. Images are cropped as follows: they are deleted randomly first / last and / or row / column.

I would like to use a convoluted neural network using Keras (and Tensorflow backend) to perform convolution and then normal classification.

The inputs are variable in size and I cannot get it to work.

This is how I cut the numbers

import numpy as np
from keras.utils import to_categorical
from sklearn.datasets import load_digits

digits = load_digits()

X = digits.images
X = np.expand_dims(X, axis=3)

X_crop = list()
for index in range(len(X)):
    X_crop.append(X[index, np.random.randint(0,2):np.random.randint(7,9), np.random.randint(0,2):np.random.randint(7,9), :])
X_crop = np.array(X_crop)

y = to_categorical(digits.target)

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X_crop, y, train_size=0.8, test_size=0.2)

And here is the architecture of the model I want to use

from keras.layers import Dense, Dropout
from keras.layers.convolutional import Conv2D
from keras.models import Sequential

model = Sequential()

model.add(Conv2D(filters=10, 
                 kernel_size=(3,3), 
                 input_shape=(None, None, 1), 
                 data_format='channels_last'))

model.add(Dense(128, activation='relu'))
model.add(Dropout(0.2))

model.add(Dense(10, activation='softmax'))


model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])

model.summary()

model.fit(X_train, y_train, epochs=100, batch_size=16, validation_data=(X_test, y_test))
  • Does anyone have an idea on how to process variable input in my neural network?

  • And how to do the classification?

+6
2

TL/DR - 4

- - :

  • - : categorical_crossentropy softmax:

    model.add(Dense(10, activation='softmax'))
    
  • :, , - () (). Dense Conv2D (1, 1). , - - , ( , model.summary(). , GlobalMaxPooling2D GlobalAveragePooling2D :

    model.add(Conv2D(filters=10, 
                 kernel_size=(3, 3), 
                 input_shape=(None, None, 1),
                 padding="same",
                 data_format='channels_last'))
    model.add(GlobalMaxPooling2D())
    model.add(Dense(128, activation='relu'))
    model.add(Dropout(0.2))
    
    model.add(Dense(10, activation='softmax'))
    
  • numpy :, X_crop, , . , . - , numpy.array .

  • : - . - - , . - , fit - - reset. , :

    . , - . a get_cropped_batches_generator, , .

    . train_on_batch. :

    from six import next
    
    batches_generator = get_cropped_batches_generator(X, batch_size=16)
    losses = list()
    for epoch_nb in range(nb_of_epochs):
        epoch_losses = list()
        for batch_nb in range(nb_of_batches):
            # cropped_x has a different shape for different batches (in general)
            cropped_x, cropped_y = next(batches_generator) 
            current_loss = model.train_on_batch(cropped_x, cropped_y)
            epoch_losses.append(current_loss)
        losses.append(epoch_losses.sum() / (1.0 * len(epoch_losses))
    final_loss = losses.sum() / (1.0 * len(losses))
    

, : -, train_on_batch keras. ( ) - . Progbar . - - get_cropped_batches_generator - , . , . : six Python 2 Python 3.

+4

, Dense, , . . , , GlobalMaxPooling2D - GlobalAveragePooling2D. , .

.

numpy, :

from PIL import Image
im = Image.fromarray(imgNumpy)
im = im.resize(newSize,Image.LANCZOS) #you can use options other than LANCZOS as well
imgNumpy = np.asarray(im)

?

. , .

. 1 , . 2 , . , .

@Marcin, , : (batchSize,inputFeatures).

keras . ( ) . .

, : 10 . Flatten, .


( ):

- , , ( )

, :

model.add(Conv2D(filters,kernel_size,...))
#so its output shape is (None,None,None,filters) = (batchSize,side1,side2,filters)

, :

import keras.backend as K

def collapseSides(x):

    axis=1 #if you're using the channels_last format (default)   
    axis=-1 #if you're using the channels_first format

    #x has shape (batchSize, side1, side2, filters)
    step1 = K.mean(x,axis=axis) #mean of side1
    return K.mean(step1,axis=axis) #mean of side2

    #this will result in a tensor shape of (batchSize,filters)

( None), , , :

model.add(Lambda(collapseSides,output_shape=(filters,)))
model.add(Dense.......)
.....

, , 10.

input_shape=(None,None,1)

, , . , , . . : Keras

+2

All Articles