Keras dimension mismatch with ImageDataGenerator - tensorflow

I am attempting to 'flow' my data into a neural network with Keras. I am using the .flow_from_directory method and the process is giving me fits. I am using the basic example from the keras documentation (I am using tensorflow):
ROWS = 64
COLS = 64
CHANNELS = 3
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(
rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
'train',
target_size=(64, 64),
batch_size=32,
class_mode='binary')
validation_generator = test_datagen.flow_from_directory(
'../tutorial/l1/kaggle_solutions/dogs_vs_cats/valid',
target_size=(64, 64),
batch_size=1,
class_mode='binary')
from keras.models import Sequential
from keras.layers import Convolution2D
from keras.layers import Dense, Activation, Flatten, Dropout, MaxPooling2D
from keras.regularizers import l2
model = Sequential()
model.add(Convolution2D(4, 4, 4, border_mode='same', input_shape=(64, 64,3), activation='relu'))
from keras.utils.np_utils import to_categorical
from keras.optimizers import SGD, RMSprop
model.compile(loss='binary_crossentropy', optimizer=RMSprop(lr=1e-4), metrics=['accuracy'])
model.fit_generator(
train_generator,
samples_per_epoch=2500,
nb_epoch=20,
validation_data=validation_generator,
nb_val_samples=3100)
Running this i get the following error:
Exception: Error when checking model target: expected convolution2d_84 to have 4 dimensions, but got array with shape (32, 1)
I have been tinkering around for a long time and found the following--switching the 'model.add' to grayscale input
model.add(Convolution2D(4, 4, 4, border_mode='same', input_shape=(64, 64,3), activation='relu'))
gives me the following error (as expected--but appears to confirm my original input was correct):
Error when checking model input: expected convolution2d_input_49 to have shape (None, 64, 64, 1) but got array with shape (32, 64, 64, 3)
So I am passing (in the original) a 4-d array of 32,64,64,3 with the original, but I am getting the error that I THINK means
Expected (1,64,64,3) and got (32,64,64,3)
As I am sending data in batches of 32. Curiously enough if I set the batch to zero (to give a 0,64,64,3 input) I get:
Exception: Error when checking model target: expected convolution2d_87 to have 4 dimensions, but got array with shape (0, 1)
Based on the documentation, I cannot figure out the proper way to flow the data into the model--i cannot pass the batch size to the model when using fit_generator, and it appears that the batch_size (num of samples) is the problem.
Any help would be greatly appreciated.

There is no problem with your ImageDataGenerator. As stated in the error message there is a mismatch between the shape of your model output and the shape of its targets. You use class_mode = 'binary', so expected output of your model is a single value, but instead it yields output of shape (batch_size, 64, 64, 4) since you have one convolutional layer and nothing else in your model.
Try something like this:
model.add(Convolution2D(4, 4, 4, border_mode='same', input_shape=(64, 64,3), activation='relu'))
model.add(Flatten())
model.add(Dense(1))
model.add(Activation('sigmoid'))

Related

How many nodes should I have in the last layer of neural network for binary classification?

I believed that, if I have a binary-classification problem then I should always have only 1 node in the last layer, since the last layer has to decide about the classification. However, in the following code it is not true.
Let's download the pizza/steak datasets (image dataset) and prepare the data using the ImageDataGenerator:
import zipfile
import tensorflow as tf
from tensorflow.keras.layers import Input, Dense, Dropout, Conv2D, MaxPooling2D, Flatten
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.preprocessing import image_dataset_from_directory
from tensorflow.keras.applications import EfficientNetB0, resnet50
from tensorflow.keras.models import Sequential
import numpy as np
import pandas as pd
!wget https://storage.googleapis.com/ztm_tf_course/food_vision/pizza_steak.zip
zip_ref = zipfile.ZipFile("pizza_steak.zip", "r")
zip_ref.extractall()
zip_ref.close()
train_directory = './pizza_steak/train/'
test_directory = './pizza_steak/test/'
IMAGE_SIZE = (224, 224)
image_data_generator = ImageDataGenerator(rescale=1. / 255,
zoom_range=0.2,
shear_range=0.2,
rotation_range=0.2)
train_dt = image_data_generator.flow_from_directory(directory=train_directory,
class_mode='categorical',
batch_size=32,
target_size=IMAGE_SIZE)
test_dt = image_data_generator.flow_from_directory(directory=test_directory,
class_mode='categorical',
batch_size=32,
target_size=IMAGE_SIZE)
and then build, compile a neural-network and fit the data on it:
model = Sequential()
model.add(Conv2D(filters=16, kernel_size=3, activation='relu'))
model.add(Conv2D(filters=16, kernel_size=3, activation='relu'))
model.add(MaxPooling2D())
model.add(Conv2D(filters=16, kernel_size=3, activation='relu'))
model.add(Conv2D(filters=16, kernel_size=3, activation='relu'))
model.add(MaxPooling2D())
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model.fit(train_dt,
epochs=5,
validation_data=test_dt,
validation_steps=len(test_dt)
As you can see the val_accuracy is not better than 0.5000, which is very bad!
And now if you just change the last layer to model.add(Dense(2, activation='sigmoid')) and run the same model with 2 nodes in the last layer, you will end up with a far better result, such as val_accuracy: 0.8680.
How should know, how many nodes should I have in the last layer when I have a binary-classification model?
Thanks to #Dr.Snoopy, i add an answer here jut to complete the question.
The point is how do we label our data using the image_data_generator.flow_from_directory().
If we set the class_mode='categorical' then the target is ONE_HOT and the number of nodes in the last layer is equal to "number of classes of target feature". In my case, it is a binary feature, so i need to have 2 nodes in the last layer.
However, if we use class_mode='binary' then the target is indexed and we can have only one node in the last layer.

Tensorflow - keras - shapes and loss for multilabel classification

X_np_new.shape, y.shape
((50876, 2304), (50876, 9))
Code:
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation
from tensorflow.keras.optimizers import SGD
model = Sequential()
model.add(Dense(5000, activation='relu', input_dim=X_np_new.shape[1]))
model.add(Dropout(0.1))
model.add(Dense(600, activation='relu'))
model.add(Dropout(0.1))
model.add(Dense(X_np_new.shape[1], activation='sigmoid'))
sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy',
optimizer=sgd)
model.fit(X_np_new, y, epochs=5, batch_size=2000)
preds = model.predict(X_np_new)
I get error:
ValueError: Shapes (None, 9) and (None, 2304) are incompatible
What went wrong here?
Replace
model.add(Dense(X_np_new.shape[1], activation='sigmoid'))
With
model.add(Dense(y.shape[1], activation='sigmoid'))
Explanation:
Putting X_np_new.shape[1] in the last layer means you have 2304 classes because X_np_new.shape[1]=2304 but you actually have 9 classes that you can get that from y.shape[1].
ValueError: Shapes (None, 9) and (None, 2304) are incompatible
means that your model is expecting labels of Size [*, 2304] but your labels size is [*, 9].

InvalidArgumentError: Incompatible shapes: [29] vs. [29,7,7,2]

so I'm new right here and in Python also. I'm trying to make my own network. I found some pictures of docs and cats 15x15 and unfortunatly couldn't make this basic network...
So, these are libraries which I'm using
from tensorflow.keras.models import Sequential
from tensorflow.keras import utils
from tensorflow.keras.datasets import mnist
from tensorflow.keras.layers import Dense
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
import keras
from tensorflow.keras.layers import Conv2D
from tensorflow.keras.layers import MaxPooling2D
from tensorflow.keras.layers import GlobalMaxPooling2D
Body
train_dataset = tf.keras.preprocessing.image_dataset_from_directory(
'drive/MyDrive/cats vs dogs/cats vs dogs/training',
color_mode="rgb",
batch_size=32,
image_size=(150, 150),
shuffle=True,
seed=42,
validation_split=0.1,
subset='training',
interpolation="bilinear",
follow_links=False,
)
validation_dataset = tf.keras.preprocessing.image_dataset_from_directory(
'drive/MyDrive/cats vs dogs/cats vs dogs/training',
color_mode="rgb",
batch_size=32,
image_size=(150, 150),
shuffle=True,
seed=42,
validation_split=0.1,
subset='validation',
interpolation="bilinear",
follow_links=False,
)
test_dataset = tf.keras.preprocessing.image_dataset_from_directory(
'drive/MyDrive/cats vs dogs/cats vs dogs/test',
batch_size = 32,
image_size = (150, 150),
interpolation="bilinear"
)
model = Sequential()
model.add(keras.Input(shape=(150, 150, 3)))
model.add(Conv2D(32, 5, strides=2, activation="relu"))
model.add(Conv2D(32, 3, activation="relu"))
model.add(MaxPooling2D(3))
model.add(Dense(250, activation='sigmoid'))
model.add(Dense(100))
model.add(MaxPooling2D(3))
model.add(Dense(2))
model.summary()
model.compile(loss='binary_crossentropy',
optimizer='adam',
metrics=['accuracy'])
history = model.fit(train_dataset, validation_data=validation_dataset, epochs=5, verbose=2)
And I get this error
Incompatible shapes: [29] vs. [29,7,7,2]
[[node gradient_tape/binary_crossentropy/mul_1/BroadcastGradientArgs
(defined at /usr/local/lib/python3.7/dist-packages/keras/optimizer_v2/optimizer_v2.py:464)
]] [Op:__inference_train_function_4364]
Errors may have originated from an input operation.
Input Source operations connected to node
gradient_tape/binary_crossentropy/mul_1/BroadcastGradientArgs:
In[0] gradient_tape/binary_crossentropy/mul_1/Shape:
In[1] gradient_tape/binary_crossentropy/mul_1/Shape_1
I was trying to change from binary_crossentropy to categorical_crossentrapy but it didn't help, I suppose my mistake is in datasets or inputs but I don't know how to solve it :(
Really hope to find help here!
[my architecture][1]
[1]: https://i.stack.imgur.com/w4Y9N.png
You need to flatten your prediction somewhere, otherwise you are outputing an image (29 samples of size 7x7 with 2 channels), while you simply want a flat 2 dimensional logits (so shape 29x2). The architecture you are using is somewhat odd, did you mean to have flattening operation before first Dense layer, and then no "maxpooling2d" (as it makes no sense for flattened signal)? Mixing relu and sigmoid activations is also quite non standard, I would encourage you to start with established architectures rather than try to compose your own to get some intuitions.
model = Sequential()
model.add(keras.Input(shape=(150, 150, 3)))
model.add(Conv2D(32, 5, strides=2, activation="relu"))
model.add(Conv2D(32, 3, activation="relu"))
model.add(MaxPooling2D(3))
model.add(Flatten())
model.add(Dense(250, activation="relu"))
model.add(Dense(100, activation="relu"))
model.add(Dense(2))
model.summary()

Wrong CIFAR-10 data format in convolution neural network

i have imported data as following
from keras.datasets import cifar10
import matplotlib.pyplot as plt
(X_train,y_train),(X_test,y_test) =cifar10.load_data()
for i in range(9):
plt.subplot(330+1+i)
plt.imshow(X_train[i])
plt.show()
it works fine as it is given in result :
next i have defined following convolution neural network structure
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.constraints import max_norm
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.layers import Convolution2D
from tensorflow.keras.layers import MaxPooling2D
from keras.utils import np_utils
model =Sequential()
model.add(Convolution2D(filters=32,kernel_size=3,input_shape=(3,32,32),padding='same',activation='relu',data_format='channels_first',kernel_constraint=max_norm(3)))
model.add(Dropout(0.2))
model.add(Convolution2D(filters=32,kernel_size=3,activation='relu',padding='same',kernel_constraint=max_norm(3)))
model.add(MaxPooling2D(pool_size=2))
model.add(Flatten())
model.add(Dense(units=512,activation='relu',kernel_constraint=max_norm(3)))
model.add(Dropout(0.5))
model.add(Dense(num_classes,activation='softmax'))
i have done all necessary compile procedures
Epochs=25
lrate =0.01
decay =lrate /epochs
sgd =SGD(learning_rate=decay,momentum=0.9,nesterov=False)
model.compile(loss='categorical_crossentropy' , optimizer='sgd', metrics=['accuracy' ])
print(model.summary())
and result is here:
after runing following code
model.fit(X_train, y_train, validation_data=(X_test, y_test),epochs=Epochs,batch_size=32, verbose=2)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("Accuracy: %.2f%%" % (scores[1]*100))
it gives me error :
ValueError: Input 0 of layer sequential_7 is incompatible with the layer: expected axis 1 of input shape to have value 3 but received input with shape [None, 32, 32, 3]
please help me to fix this error
The input shape in your first convolutional layer should be input_shape=(32,32,3) instead of input_shape=(3,32,32). You should also set the data_format to the default "channels_last". The reason for setting it up like this is that the shape of cifar10 images is (32,32,3) and not (3,32,32)
you should always be careful about the input shape of the first layer of CNN using Conv2D. In tensorflow the input shape parameters are given as (batch_size, img_h, img_w, channels).
In contrary to pytorch it is (batch_size, channels, img_h, img_w). So, it should be (32,32,3) not (3, 32, 32).

Error with Cats and Dog Convolutional Network: model.fit_generator

I'm using a PDF to build my first Convolutional Nerual Network using cats and dogs and am encountering a consistent error. The text is: WARNING:tensorflow:sample_weight modes were
coerced from
...
to
['...']
WARNING:tensorflow:sample_weight modes were coerced from
...
to
['...']
The relevant code is pasted in two sections below. Any help would be appreciated because I'm hitting a wall in regards to this.
This top bit is working but may be relevant:
#Build the network
#Import needed layers and models from tensorflow.keras
import tensorflow as tf
from tensorflow.keras.layers import Dense, Activation, Flatten, Conv2D, MaxPooling2D, Dropout
from tensorflow.keras.models import Sequential
#Build model--Use sequential value--Most common
model = models.Sequential()
#Input layer
model.add(layers.Conv2D(32, (3,3), activation = 'relu',
input_shape = (150, 150, 3)))
model.add(layers.MaxPooling2D(2,2))
#First hidden layer
model.add(layers.Conv2D(64, (3,3), activation = 'relu'))
model.add(layers.MaxPooling2D(2,2))
#Second hidden layer
model.add(layers.Conv2D(128, (3,3), activation = 'relu'))
model.add(layers.MaxPooling2D(2,2))
#Third hidden layer
model.add(layers.Conv2D(128, (3,3), activation = 'relu'))
model.add(layers.MaxPooling2D(2,2))
#Fourth hidden layer
model.add(layers.Flatten())
model.add(layers.Dense(512, activation = 'relu'))
#Output layer
model.add(layers.Dense(1, activation = 'sigmoid'))
#
from tensorflow.keras import optimizers
#Compilation step
model.compile(loss = 'binary_crossentropy',
optimizer= 'adam',
metrics=['acc'])
#Read images from directories
from tensorflow.keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale = 1./255)
test_datagen = ImageDataGenerator(rescale = 1./255)
train_generator = test_datagen.flow_from_directory(
train_dir,
target_size = (150, 150),
batch_size = 20,
class_mode = 'binary')
validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size = (150, 150),
batch_size = 20,
class_mode = 'binary')
Fit model with a batch generator
This part of the code is what causes the error
history = model.fit_generator(
train_generator,
steps_per_epoch = 100,
epochs = 30,
validation_data = validation_generator,
validation_steps = 50)
As a final note, this code is in Python 3 and uses the kagglecatsanddogs database from Microsoft
The below Warning is fixed in the Nightly Version of Tensorflow and will be included in the Next Stable Version, Tensorflow 2.2
WARNING:tensorflow:sample_weight modes were coerced from ... to
['...'] WARNING:tensorflow:sample_weight modes were coerced from ... to
['...']
Currently, to make if work, please install Tensorflow Nightly Version as shown below:
!pip install tf-nightly
For more details, please refer this Github Issue.