I am getting into Convolutional Neural Networks and want to create one for MNIST data. Whenever I add a convolutional Layer to my CNN, I get an error:
Input 0 is incompatible with layer conv2d_4: expected ndim=4, found ndim=5
I have attemped to reshape X_Train data set but was not successful
I tried to add a flatten layer first but that returns this error:
Input 0 is incompatible with layer conv2d_5: expected ndim=4, found ndim=2
import keras
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Convolution2D
from keras.layers import Flatten, Dense, Dropout
img_width, img_height = 28, 28
mnist = keras.datasets.mnist
(X_train, Y_train), (X_test, Y_test) = mnist.load_data()
(X_train, y_train), (X_test, y_test) = mnist.load_data()
X_train = keras.utils.normalize(X_train, axis=1) #Normalizes from 0-1 (originally each pixel is valued 0-255)
X_test = keras.utils.normalize(X_test, axis=1) #Normalizes from 0-1 (originally each pixel is valued 0-255)
Y_train = keras.utils.to_categorical(Y_train) #Reshapes to allow ytrain to work with x train
Y_test = keras.utils.to_categorical(Y_test)
from sklearn import preprocessing
lb = preprocessing.LabelBinarizer()
Y_train = lb.fit_transform(Y_train)
Y_test = lb.fit_transform(Y_test)
#Model
model = Sequential()
model.add(Flatten())
model.add(Convolution2D(16, 5, 5, activation='relu', input_shape=(1,img_width, img_height, 1)))
model.add(Dense(128, activation='relu'))
model.add(Dense(128, activation='relu'))
model.add(Dropout(.2))
model.add(Dense(64, activation='relu'))
model.add(Dense(10, activation='softmax'))
model.compile(optimizer = 'adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit(X_train, Y_train, epochs=3, verbose=2)
val_loss, val_acc = model.evaluate(X_test, Y_test) #Check to see if model fits test
print(val_loss, val_acc)
If I comment out the Convolutional layer, it works very well (accuracy>95%), but I am planning on making a more complex neural network that requires Convolution in the future and this is my starting point
Keras is looking for a tensor of dimension 4 but it's getting ndim as number of dimension as 2.
first make sure you kernel size in Conv2D layer is in parenthesis
model.add(Convolution2D(32, (3, 3), activation='relu', input_shape=(img_height, img_height, 1)))
Second you need to reshape the X_train, X_test variable as Conv2D layer is expecting a tensor input.
X_train = X_train.reshape(-1,28, 28, 1) #Reshape for CNN - should work!!
X_test = X_test.reshape(-1,28, 28, 1)
model.fit(X_train, Y_train, epochs=3, verbose=2)
For more information about Conv2D you can look into Keras Documentation here
Hope this helps.
There are two issues in your code.
You are encoding your labels two times, once using to_categorical, and another time using LabelBinarizer. The latter is no needed here, so just encode your labels into categorical once, using to_categorical.
2.- Your input shape is incorrect, it should be (28, 28, 1).
Also you should add a Flatten layer after the convolutional layers so the Dense layer works properly.
Related
I am trying to use an Artificial Neural Network for multi-class classification using Tensorflow with Keras.
I am buildung a model with the following shape:
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape`
(2000, 5, 5) (800, 5, 5) (2000, 4) (800, 4)
Labels are one-hot encoded.
Here is my model:
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
model = Sequential()
model.add(Dense(64, input_shape=(X_train.shape[1], X_train.shape[2],), activation='relu'))
model.add(Dense(32, activation='relu'))
model.add(Dense(y_train.shape[1], activation='softmax'))
model.compile(optimizer = 'adam', loss='categorical_crossentropy', metrics=['accuracy'])
# model.summary()
model.fit(X_train, y_train, epochs=5, batch_size=32, verbose=1, validation_data=(X_test, y_test)`
I get this error:
ValueError: A target array with shape (2000, 4) was passed for an output of shape (None, 5, 4) while using as loss `categorical_crossentropy`. This loss expects targets to have the same shape as the output.
Where does the problem come from ?
You should probably reduce the dimension within your network. You have to go from 3d to 2d to match your goal. You can do this by using a global merge or smoothing layer. Try using Flatten () before the output level or (GlobalAveragePooling1D() or GlobalMaxPooling1D())
I am a newbie in Convents, I designed a three-layer network, with 2 hidden layers to classify images.
I was wondering how can I add 2 layers to the network?
I understand that early stopping might be a bit hard to tune. I just want to plot training loss and the validation error to do the comparison with the one that does not have convnet (The code that I already wrote posted here)
Where do you want to add conv layer?
Conv2D gets (N, H, W, C) as inputs and outputs,
where N is batch size, H is height, W is width and C is channel size.
Your network has all (N, C) tensor. So, You need Reshape vector into images, or Flatten images into vector.
Here is an example that get (NHWC) tensor, so you don't need x_train.reshape to flatten. Many famous network like VGG, ResNet has Conv layer first, and Dense layer at last. It aims to get feature from conv layers, and predict class by Dense layer.
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Conv2D, Flatten
from keras import regularizers
import numpy as np
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# MNIST shape has lacks of channels, so add it. MNIST is gray scale so channel size is 1.
# (60000, 28, 28) -> (60000, 28, 28, 1)
# If you have color image, it shoud be 3 channels, RGB: [BATCH_SIZE, H, W, 3]
x_train = np.expand_dims(x_train, axis=-1)
x_test = np.expand_dims(x_test, axis=-1)
num_classes = 10
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
model_3 = Sequential()
model_3.add(Conv2D(32, kernel_size=2, padding='same', activation='relu', input_shape=(28, 28, 1)))
model_3.add(Conv2D(64, kernel_size=2, padding='same', activation='relu'))
model_3.add(Flatten())
model_3.add(Dense(256, activation='relu',kernel_regularizer=regularizers.l2(0.01)))
model_3.add(Dropout(0.2))
model_3.add(Dense(128, activation='relu',kernel_regularizer=regularizers.l2(0.01)))
model_3.add(Dropout(0.2))
model_3.add(Dense(64, activation='relu',kernel_regularizer=regularizers.l2(0.01)))
model_3.add(Dropout(0.2))
model_3.add(Dense(10, activation='softmax'))
model_3.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adam(),
metrics=['accuracy'])
history = model_3.fit(
x_train, y_train,
batch_size=128,
epochs=250,
verbose=1,
validation_data=(x_test, y_test))
For Reshape, https://keras.io/layers/core/
And There is Conv2D MNIST sample.
https://github.com/keras-team/keras/blob/master/examples/mnist_cnn.py
I want to change my model architecture a bit on the LSTM so it accepts the same exact flattened inputs the full connected approach does.
Working Dnn model from Keras examples
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.utils import to_categorical
# import the data
from keras.datasets import mnist
# read the data
(x_train, y_train), (x_test, y_test) = mnist.load_data()
num_pixels = x_train.shape[1] * x_train.shape[2] # find size of one-dimensional vector
x_train = x_train.reshape(x_train.shape[0], num_pixels).astype('float32') # flatten training images
x_test = x_test.reshape(x_test.shape[0], num_pixels).astype('float32') # flatten test images
# normalize inputs from 0-255 to 0-1
x_train = x_train / 255
x_test = x_test / 255
# one hot encode outputs
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
num_classes = y_test.shape[1]
print(num_classes)
# define classification model
def classification_model():
# create model
model = Sequential()
model.add(Dense(num_pixels, activation='relu', input_shape=(num_pixels,)))
model.add(Dense(100, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
# compile model
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
return model
# build the model
model = classification_model()
# fit the model
model.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=10, verbose=2)
# evaluate the model
scores = model.evaluate(x_test, y_test, verbose=0)
Same problem but trying LSTM (syntax error still)
def kaggle_LSTM_model():
model = Sequential()
model.add(LSTM(128, input_shape=(x_train.shape[1:]), activation='relu', return_sequences=True))
# What does return_sequences=True do?
model.add(Dropout(0.2))
model.add(Dense(32, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(10, activation='softmax'))
opt = tf.keras.optimizers.Adam(lr=1e-3, decay=1e-5)
model.compile(loss='sparse_categorical_crossentropy', optimizer=opt,
metrics=['accuracy'])
return model
model_kaggle_LSTM = kaggle_LSTM_model()
# fit the model
model_kaggle_LSTM.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=10, verbose=2)
# evaluate the model
scores = model_kaggle_LSTM.evaluate(x_test, y_test, verbose=0)
Problem is here:
model.add(LSTM(128, input_shape=(x_train.shape[1:]), activation='relu', return_sequences=True))
ValueError: Input 0 is incompatible with layer lstm_17: expected
ndim=3, found ndim=2
If I go back and don't flatten x_train and y_train, it works. However, I'd like this to be "just another model choice" that feeds off the same pre-processed input. I thought passing shape[1:] would work as that it the real flattened input_shape. I'm sure it's something easy I'm missing about the dimensionality, but I couldn't get it after an hour of twiddling and debugging, although did figure out not flattening the 28x28 to 784 works, but I don't understand why it works. Thanks a lot!
For bonus points, an example of how to do either DNN or LSTM in either 1D (784,) or 2D (28, 28) would be the best.
RNN layers such as LSTM are meant for sequence processing (i.e. a series of vectors which their order of appearance matters). You can look at an image from top to bottom, and consider each row of pixels as a vector. Therefore, the image would be a sequence of vectors and can be fed to the RNN layer. Therefore, according to this description, you should expect that the RNN layer take an input of shape (sequence_length, number_of_features). That's why when you feed the images to the LSTM network in their original shape, i.e. (28,28), it works.
Now if you insist on feeding the LSTM model the flattened image, i.e. with shape (784,), you have at least two options: either you can consider this as a sequence of length one, i.e. (1, 748), which does not make much sense; or you can add a Reshape layer to your model to reshape back the input to its original shape suitable for the input shape of a LSTM layer, like this:
from keras.layers import Reshape
def kaggle_LSTM_model():
model = Sequential()
model.add(Reshape((28,28), input_shape=x_train.shape[1:]))
# the rest is the same...
I am using Keras 2.04 with tensorflow backend. I am trying to train a simple model with ImageDataGenerator on MNIST images. However, I keep getting the following error from fit_generator:
ValueError: Error when checking input: expected input_1 to have 2
dimensions, but got array with shape (8, 28, 28, 1).
This is the code:
#loading data & reshaping
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(x_train.shape[0], 28, 28,1)
#building the model
input_img = Input(shape=(784,))
encoded = Dense(30, activation='relu')(input_img)
decoded = Dense(784, activation='sigmoid')(encoded)
autoencoder = Model(input_img, decoded)
autoencoder.compile(optimizer='adam', loss='mse')
#creating ImageDataGenerator
datagen = ImageDataGenerator(featurewise_center=True, featurewise_std_normalization=True)
datagen.fit(x_train)
autoencoder.fit_generator(
#x_train, x_train because the target is to reconstruct the input
datagen.flow(x_train, x_train, batch_size=8),
steps_per_epoch=int(len(x_train)/8),
epochs=64,
)
As far as I understand ImageDataGenerator should generate a batch of training examples each iteration, as it actually does (in this case, batch_size=8) but from the error it seems as if it expects a single training example.
Thanks!
Solved - it should have been:
autoencoder = Sequential()
autoencoder.add(Reshape((784,), input_shape=(28,28,1)))
autoencoder.add(Dense(30, activation='relu'))
autoencoder.add(Dense(784, activation='relu'))
.
.
.
autoencoder.fit_generator(
datagen.flow(x_train, x_train.reshape(len(x_train),784,), batch_size=8),
steps_per_epoch=int(len(x_train)/8),
epochs=64,
)
I want to use the code below with my own input images instead of the mnist images. However I am having a hard time inputting several color .jpg images into a numpy array similar to the X_train used in the code below. I have a folder called data with another folder called train that includes several images that I would like to use as my X_train. I can generate the labels for them and one-hot encode them. I just don't know how to make all my images go into a nice array like X_train. Help? I did look here, but I got a Value Error: setting an array element with a sequence when I just copied and pasted the summarized code.
import numpy as np
np.random.seed(123) # for reproducibility
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, MaxPooling2D
from keras.utils import np_utils
from keras.datasets import mnist
# 4. Load pre-shuffled MNIST data into train and test sets
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# 5. Preprocess input data
X_train = X_train.reshape(X_train.shape[0], 1, 28, 28)
X_test = X_test.reshape(X_test.shape[0], 1, 28, 28)
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_test /= 255
# 6. Preprocess class labels
Y_train = np_utils.to_categorical(y_train, 10)
Y_test = np_utils.to_categorical(y_test, 10)
# 7. Define model architecture
model = Sequential()
model.add(Convolution2D(32, 3, 3, activation='relu', input_shape=(1,28,28)))
model.add(Convolution2D(32, 3, 3, activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))
# 8. Compile model
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
# 9. Fit model on training data
model.fit(X_train, Y_train,
batch_size=32, nb_epoch=10, verbose=1)
# 10. Evaluate model on test data
score = model.evaluate(X_test, Y_test, verbose=0)
I am assuming that you are using Theano and that your jpgs have 3 bands. In addition, your jpgs should have the same input shape as the input shape that you indicate in the first convolutional model (28x28 pixels). In that case you can reshape all your jpes with the following lines:
#create random data
no_of_jpgs = 10
jpgs = [np.random.randint(0,255,(28,28,3)) for i in range(no_of_jpgs)]
jpgs = np.array(jpgs)
#reshape data
jpgs.reshape(no_of_jpgs, jpgs.shape[1], jpgs.shape[2], 3)
now you have an array with: (features, n_bands, x, y)
In addition you should change your input_shape so that it supports 3 bands:
model.add(Convolution2D(32, 3, 3, activation='relu', input_shape=(3, 28,28)))
If you have jpgs with a different shape or more bands, just change the input_shape values in the first convolutional layer.