Dimension error in feeding Keras with Tensorflow dataset - keras

I have a TFRecords file consisting of 60 examples of six Landsat band values for some pixels plus a label for each pixel, and I want to train a Keras classifier with it. But I get a dimension mismatch when I try to load network with the data.
TFRecords file is generated with below structure:
# TFRecords file contains below features per each example
bands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7','landcover']
columns = [tf.FixedLenFeature(shape=[1], dtype=tf.float32) for k in bands]
featuresDict = dict(zip(bands, columns))
And my code for defining generator function and Keras model is as follows:
def tfdata_generator_training(fileName, batchSize=None):
dataset = tf.data.TFRecordDataset(fileName, compression_type='GZIP')
def parse_tfrecord(example):
features = tf.parse_single_example(example, featuresDict)
# Extract landcover and remove it from dictionary
labels = features.pop('landcover')
labels = tf.one_hot(tf.cast(labels, tf.uint8), 3)
# Return list of dictionary values (to be convertable to numpy array for Keras) and pixel label in one-hot format
return list(features.values()), labels
# Map the parsing function over the dataset
dataset = dataset.map(parse_tfrecord)
dataset = dataset.batch(batchSize)
return dataset
training_data = tfdata_generator_training(fileName=<my_file_path>, batchSize=1)
def keras_model():
from tensorflow.keras.layers import Dense, Input
inputs = Input(shape=(6,1))
x = Dense(5, activation='relu')(inputs)
x = Dense(7, activation='relu')(x)
outputs = Dense(3, activation='softmax')(x)
return tf.keras.Model(inputs, outputs)
model = keras_model()
model.compile('adam', 'categorical_crossentropy', metrics=['acc'])
model.fit(training_data.make_one_shot_iterator(), steps_per_epoch=60, epochs=8)
But I get below error when running the code:
ValueError: Error when checking target: expected dense_2 to have shape (6, 3) but got array with shape (1, 3)
What is the problem with my code? I also tried to get the dimensions of the input layer and the Tensorflow printout was as follows:
(<tf.Tensor 'IteratorGetNext:0' shape=(?, 6, 1) dtype=float32>, <tf.Tensor 'IteratorGetNext:1' shape=(?, 1, 3) dtype=float32>)

Related

How to train a CNN on a dataset stored in pkl file?

I am trying to train a CNN on mini-imagenet dataset that is stored in a pkl file that contains both images and their labels. I am facing a difficulty during the training process where the training data shape (images array) does not match the provided labels shape, both loaded from the pkl file. Here is the relevant code:
train_in = open('/content/drive/My Drive/Few-shot/mini-imagenet-cache-train.pkl', "rb")
train = pickle.load(train_in)
Xtrain = train["image_data"]
Xtrain = Xtrain.reshape([38400, 84, 84, 3])
Ytrain = train['class_dict']
result = Ytrain.values()
Ytrain = list(result)
Ytrain = np.reshape(Ytrain,[38400])
Ytrain = list(Ytrain)
Xtrain = list(Xtrain)
At this stage, the length of both Xtrain and Ytrain is 38400 (=64*600), where 64 is number of classes and 600 is number of images in each class, while [84,84,3] is the image shape.
Then, I create the model:
resnet_model = ResNet50(weights="imagenet", include_top=False, input_shape=(84, 84, 3))
model = Sequential()
model.add(resnet_model)
model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(64, activation='softmax'))
for layer in model.layers:
layer.trainable = True
Finally, I compile and train it:
model.compile(loss='categorical_crossentropy', optimizer= optimizers.SGD(lr = 1e-4, momentum = 0.9), metrics = ['accuracy'])
model.fit(Xtrain, Ytrain,
epochs=200, verbose=2,
shuffle= False)
When I start training, I get the following error:
ValueError: Failed to find data adapter that can handle input: (<class
'list'> containing values of types {"<class 'numpy.ndarray'>"}),
(<class 'list'> containing values of types {"<class 'numpy.int64'>"})
I think this is because items in the Xtrain are arrays (images), while the corresponding label is an integer value. I tried to convert both of them to numpy arrays, but I get:
ValueError: Shapes (32, 1) and (32, 64) are incompatible
How can I fix this?

Keras shape error when given input from the front end

I am trying to build a chatbot using keras and bag of words model. But when i am trying to input the answer from the front end , this is the error that i get :-
ValueError: Input 0 of layer sequential is incompatible with the layer: expected axis -1 of input shape to have value 69 but received input with shape [None, 1]
Here is my code :-
model = tensorflow.keras.Sequential([
tensorflow.keras.layers.Dense(8,input_shape=(len(training[0]), )),
tensorflow.keras.layers.Dense(8),
tensorflow.keras.layers.Dense(len(output[0]), activation = "softmax")
])
model.compile(optimizer="adam", loss="categorical_crossentropy", metrics="accuracy")
model.summary()
try:
tensorflow.keras.models.load_model('heya')
print('Existing model loaded.')
except:
model.fit(training, output, epochs=1000, batch_size=8)
model.save('heya')
Any help would be appreciated
You have to define correctly the input and output shapes of your model
import tensorflow
import numpy as np
training = np.random.uniform(0,1, (24, 69))
output = np.random.randint(0,2, (24, 13))
model = tensorflow.keras.Sequential([
tensorflow.keras.layers.Dense(8,input_shape=(training.shape[1], )),
tensorflow.keras.layers.Dense(8),
tensorflow.keras.layers.Dense(output.shape[1], activation = "softmax")
])
model.compile(optimizer="adam", loss="categorical_crossentropy", metrics="accuracy")
model.fit(training, output, epochs=10, batch_size=8)
the input dimension is the number of features (69 in your case), while the output dim is equivalent to the number of classes (13 in your case)

LSTM input_shape incompatible

I'm trying to build a sequential model using Keras with an LSTM layer as the first layer. train_x has a shape of (21000, 2) and I'm using a batch size of 10
When I try
model = Sequential()
model.add(LSTM(128, activation='relu', input_shape=(
train_x.shape[1:]), return_sequences=True))
I get an error saying
Input 0 is incompatible with layer lstm_1: expected ndim=3, found ndim=2
Then I tried to change input_shape and set it to input_shape=(train_x.shape) and I got another error saying
Error when checking input: expected lstm_1_input to have 3 dimensions, but got array with shape (21000, 2)
What am I doing wrong?
Keras LSTM layer expects the input to be 3 dims as (batch_size, seq_length, input_dims), but you have assigned it wrong. Try this
input_dims = train_x.shape[1]
seq_length = #decide an integer
model = Sequential()
model.add(LSTM(128, activation='relu', input_shape=(seq_length, input_dims), return_sequences=True))
Also you need to reshape your data to three dims, where new dims will represent the sequence, as
I used toy dataset to show an example, here data and labels are of shape ((150, 4), (150,)) initially, using the following script:
seq_length = 10
dataX = []
dataY = []
for i in range(0, 150 - seq_length, 1):
dataX.append(data[i:i+seq_length])
dataY.append(labels[i+seq_length-1])
import numpy as np
dataX = np.reshape(dataX, (-1, seq_length, 4))
dataY = np.reshape(dataY, (-1, 1))
# dataX.shape, dataY.shape
Output: ((140, 10, 4), (140, 1))
Now you can safely feed it to model.
Note: I prepared dataset for many-to-one model, but you can use it appropriately.

ValueError: Error when checking target: expected fc1000 to have shape (30,) but got array with shape (1,)

I was trying to retrain ResNet50 model to classify given images of animals into 30 different classes. To do this, I made a list containing arrays of given images of dimension(after expanding dimensions and preprocessing it):- (1, 224, 224, 3), thereby the shape of given list(after converting it to numpy array) was (300, 1, 224, 224, 3), as initially i took only 300 images. For Ytrain, I Label encoded the classes and one hot encoded the afterwards. For 30 classes, I had an numpy array of dimension (300, 30). Then I used DataGenerator for model.fit_generator, passing Xtrain of shape (1, 224, 224, 3) and Ytrain of shape (30, ), But got the error:-
ValueError: Error when checking target: expected fc1000 to have shape (30,) but got array with shape (1,)
Here is my code:-
inputShape = (224, 224)
preprocess = imagenet_utils.preprocess_input
df = pd.read_csv('DLBeginner/meta-data/train.csv')
df = df.head(300)
imagesData, target = [], []
c = 0
for images in df['Image_id']:
filename = args["target"] + '/' + images
image = load_img(filename, target_size = inputShape)
image = img_to_array(image)
image = np.expand_dims(image, axis = 0)
image = preprocess(image)
imagesData.append(image)
c += 1
print('Count = {}, Image > {} '.format(c, images))
imagesData = np.array(imagesData)
labelEncoder = LabelEncoder()
series = df['Animal'][0:300]
integerEncoded = labelEncoder.fit_transform(series)
Hot = OneHotEncoder(sparse = False)
integerEncoded = integerEncoded.reshape(len(integerEncoded), 1)
oneHot = Hot.fit_transform(integerEncoded)
model = ResNet50(include_top = True, classes = 30, weights = None)
model.compile(optimizer = 'Adam', loss='categorical_crossentropy', metrics = ['accuracy'])
l = len(imagesData)
def DataGenerator(Xtrain, Ytrain):
while(True):
for i in range(l):
arr1 = Xtrain[i]
arr2 = Ytrain[i]
print("arr1.shape : {}".format(arr1.shape))
print("arr2.shape : {}".format(arr2.shape))
yield(arr1, arr2)
and here is the "fitting part"
generator = DataGenerator(imagesData, oneHot)
model.fit_generator(generator = generator, epochs = 5, steps_per_epoch=l)
Where am I going wrong?
Thanks in advance.
Switching from 'categorical_crossentropy' to 'sparse_categorical_crossentropy' solved it for me.
Just want to add little more details.
When you have multi-class classification problem and
(1) if your targets are one-hot encoded then use categorical_crossentropy
(2) if your targets are integers as in MNIST example, use sparse_categorical_crossentropy. When you use this, Tensorflow under the hood, it will convert data into one-hot encoded and classify the data.
Hope that helps. Thanks!

Resnet with Custom Data

I am trying to modify Resnet50 with my custom data as follows:
X = [[1.85, 0.460,... -0.606] ... [0.229, 0.543,... 1.342]]
y = [2, 4, 0, ... 4, 2, 2]
X is a feature vector of length 2000 for 784 images. y is an array of size 784 containing the binary representation of labels.
Here is the code:
def __classifyRenet(self, X, y):
image_input = Input(shape=(2000,1))
num_classes = 5
model = ResNet50(weights='imagenet',include_top=False)
model.summary()
last_layer = model.output
# add a global spatial average pooling layer
x = GlobalAveragePooling2D()(last_layer)
# add fully-connected & dropout layers
x = Dense(512, activation='relu',name='fc-1')(x)
x = Dropout(0.5)(x)
x = Dense(256, activation='relu',name='fc-2')(x)
x = Dropout(0.5)(x)
# a softmax layer for 5 classes
out = Dense(num_classes, activation='softmax',name='output_layer')(x)
# this is the model we will train
custom_resnet_model2 = Model(inputs=model.input, outputs=out)
custom_resnet_model2.summary()
for layer in custom_resnet_model2.layers[:-6]:
layer.trainable = False
custom_resnet_model2.layers[-1].trainable
custom_resnet_model2.compile(loss='categorical_crossentropy',
optimizer='adam',metrics=['accuracy'])
clf = custom_resnet_model2.fit(X, y,
batch_size=32, epochs=32, verbose=1,
validation_data=(X, y))
return clf
I am calling to function as:
clf = self.__classifyRenet(X_train, y_train)
It is giving an error:
ValueError: Error when checking input: expected input_24 to have 4 dimensions, but got array with shape (785, 2000)
Please help. Thank you!
1. First, understand the error.
Your input does not match the input of ResNet, for ResNet, the input should be (n_sample, 224, 224, 3) but you are having (785, 2000). From your question, you have 784 images with array of size 2000, which doesn't really align with the original ResNet50 input shape of (224 x 224) no matter how you reshape it. That means you cannot use the ResNet50 directly with your data. The only thing you did in your code is to take the last layer of ResNet50 and added you output layer to align with your output class size.
2. Then, what you can do.
If you insist to use the ResNet architecture, you will need to change the input layer rather than output layer. Also, you will need to reshape your image data to utilize the convolution layers. That means, you cannot have it in a (2000,) array, but need to be something like (height, width, channel), just like what ResNet and other architectures are doing. Of course you will also need to change the output layer as well just like you did so that you are predicting for your classes. Try something like:
model = ResNet50(input_tensor=image_input_shape, include_top=True,weights='imagenet')
This way, you can specify customized input image shape. You can check the github code for more information (https://github.com/keras-team/keras/blob/master/keras/applications/resnet50.py). Here's part of the docstring:
input_shape: optional shape tuple, only to be specified
if `include_top` is False (otherwise the input shape
has to be `(224, 224, 3)` (with `channels_last` data format)
or `(3, 224, 224)` (with `channels_first` data format).
It should have exactly 3 inputs channels,
and width and height should be no smaller than 197.
E.g. `(200, 200, 3)` would be one valid value.

Resources