1

I'm attempting to follow along on what I'm thinking is the 5th or 6th simple introductory tutorial for keras that almost but never quite works. Stripping everything out, I appear to come down to a problem with the format of my input. I read in an array of images, and extract two types, images of sign language ones and images of sign language zeros. I then set up an array of ones and zeros to correspond to what the images actually are, then make sure of sizes and types.

import numpy as np 
from subprocess import check_output

print(check_output(["ls", "../data/keras/"]).decode("utf8"))
## load dataset of images of sign language numbers
x = np.load('../data/keras/npy_dataset/X.npy')
# Get the zeros and ones, construct a list of known values (Y)
X = np.concatenate((x[204:409], x[822:1027] ), axis=0) # from 0 to 204 is zero sign and from 205 to 410 is one sign 
Y = np.concatenate((np.zeros(205), np.ones(205)), axis=0).reshape(X.shape[0],1)

# test shape and type
print("X shape: " , X.shape)
print("X class: " , type(X))
print("Y shape: " , Y.shape)
print("Y type: " , type(Y))

This gives me:

X shape:  (410, 64, 64)
X class:  <class 'numpy.ndarray'>
Y shape:  (410, 1)
Y type:  <class 'numpy.ndarray'>

which is all good. I then load the relevant bits from Keras, using Tensorflow as the backend and try to construct a classifier.

# get the relevant keras bits. 
from keras.models import Sequential
from keras.layers import Convolution2D 
# construct a classifier

classifier = Sequential() # initialize neural network
classifier.add(Convolution2D(32, (3, 3), input_shape=(410, 64, 64), activation="relu", data_format="channels_last"))
classifier.compile(optimizer = 'adam', loss = 'categorical_crossentropy', metrics = ['accuracy'])

classifier.fit(X, Y, batch_size=32, epochs=10, verbose=1)

This results in:

ValueError: Error when checking input: expected conv2d_1_input to have 4 dimensions, but got array with shape (410, 64, 64)

This SO question, I think, suggests that my input shape needs to be altered to have a 4th dimension added to it - though it also says it's the output shape that needs to altered, I haven't been able to find anywhere to specify an output shape, so I'm assuming it is meant that I should alter the input shape to input_shape=(1, 64, 64, 1). If I change my input shape however, then I immeadiately get this:

ValueError: Input 0 is incompatible with layer conv2d_1: expected ndim=4, found ndim=5

Which this github issue suggests is because I no longer need to specify the number of samples. So I'm left with the situation of using one input shape and getting one error, or changing it and getting another error. Reading this and this made me think I might need to reshape my data to include information about the channels in X, but if I add in

X = X.reshape(X.shape[0], 64, 64, 1)
print(X.shape)

Then I get

ValueError: Error when checking target: expected conv2d_1 to have 4 dimensions, but got array with shape (410, 1)

If I change the reshape to anything else, i.e.

X = X.reshape(X.shape[0], 64, 64, 2)

Then I get a message saying it's unable to reshape the data, so I'm obviously doing something wrong with that, if that is, indeed, the problem.

I have read the suggested Conv2d docs which shed exactly zero light on the matter for me. Anyone else able to?

Ben
  • 401
  • 2
  • 6
  • 15

1 Answers1

0

At first I used the following data sets (similar to your case):

import numpy as np
import keras

X = np.random.randint(256, size=(410, 64, 64))
Y = np.random.randint(10, size=(410, 1))
x_train = X[:, :, :, np.newaxis]
y_train = keras.utils.to_categorical(Y, num_classes=10)

And then modified your code as follows to work:

from keras.models import Sequential
from keras.layers import Convolution2D, Flatten, Dense 

classifier = Sequential() # initialize neural network
classifier.add(Convolution2D(32, (3, 3), input_shape=(64, 64, 1), activation="relu", data_format="channels_last"))
classifier.add(Flatten())
classifier.add(Dense(10, activation='softmax'))
classifier.compile(optimizer = 'adam', loss = 'categorical_crossentropy', metrics = ['accuracy'])
classifier.fit(x_train, y_train, batch_size=32, epochs=10, verbose=1)
  1. Changed the shape of X from 410 x 64 x 64 to 410 x 64 x 64 x 1 (with channel 1).

  2. input_shape be the shape of a sample data, that is, 64 x 64 x 1.

  3. Changed the shape of Y using keras.utils.to_categorical() (one-hot encoding with num_classes=10).

  4. Before compiling, Flatten() and Dense() were applied because you want categorical_crossentropy.

ChoF
  • 568
  • 1
  • 4
  • 9
  • This works (thanks). I'm yet to comprehend out why it works. – Ben May 21 '18 at 00:05
  • @Ben The examples in [Getting started with the Keras Sequential model](https://keras.io/getting-started/sequential-model-guide/) will be helpful for your case, especially check **Multilayer Perceptron (MLP) for multi-class softmax classification** and **VGG-like convnet**. – ChoF May 21 '18 at 00:14
  • To be honest ... no, they're not. This was an example, I was trying to run a basic piece of code just to see how it all fitted together, not because it's the thing I want to eventually do. The problem I had, was with inputting data - which neither that page nor the examples talk about in a fleeting manner at best. No worries though, I'll keep reading and get it eventually. – Ben May 22 '18 at 02:05