Trouble with model.predict()

Hey
So I am doing the machine learning with python course with free code camp and I’m stuck with this problem for days. I finished the pretrained model section and I wanted to try and use predict on the model after I saved it and loaded it on another file. I take a path from the user and it is supposed to give some output but instead an error pops:

ValueError: Input 0 is incompatible with layer sequential: expected shape=(None, 160, 160, 3), found shape=(32, 160, 3)

I know it has to do with the shape of the input image, but even after i resize it i get the same:

import tensorflow as tf
import cv2

input_path = input('enter dog or cat pic path: ')
image = cv2.imread(f'{input_path}', cv2.IMREAD_UNCHANGED)

print(image.shape)
image = tf.image.resize(image, (160, 160))
print(image.shape)

model = tf.keras.models.load_model('dogs_vs_cats.h5')
model.predict(image)

the output of the print statements gives this:

(183, 275, 3)
(160, 160, 3)

Here you can see how the image is reshaped but the error still pops up and even says that the found shape is (32, 160, 3) for some reason.
Here is the code of the model that I copied from tech with tim’s lesson on Free Code Camp about using pretrained models:

import tensorflow as tf
import tensorflow_datasets as tfds

keras = tf.keras

# split the data manually into 80% training, 10% testing, 10% validation
(raw_train, raw_validation, raw_test), metadata = tfds.load(
    'cats_vs_dogs',
    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],
    with_info=True,
    as_supervised=True,
)

get_label_name = metadata.features['label'].int2str  # creates a function object that we can use to get labels

"""""
Since the sizes of our images are all different, we need to convert them all to the same size. 
We can create a function that will do that for us below.
"""""

IMG_SIZE = 160  # All images will be resized to 160x160


def format_example(image, label):
    """
    returns an image that is reshaped to IMG_SIZE
    """
    image = tf.cast(image, tf.float32)
    image = (image / 127.5) - 1
    image = tf.image.resize(image, (IMG_SIZE, IMG_SIZE))
    print(image.shape)
    return image, label


# Now we can apply this function to all our images using .map().
# .map() takes every single example in raw_train, raw_validation, etc and applies the function to it
train = raw_train.map(format_example)
validation = raw_validation.map(format_example)
test = raw_test.map(format_example)


BATCH_SIZE = 32
SHUFFLE_BUFFER_SIZE = 1000

# Finally we will shuffle and batch the images
train_batches = train.shuffle(SHUFFLE_BUFFER_SIZE).batch(BATCH_SIZE)
validation_batches = validation.batch(BATCH_SIZE)
test_batches = test.batch(BATCH_SIZE)

"""""
Picking a Pretrained Model
The model we are going to use as the convolutional base for our model is the MobileNet V2 developed at Google. 
This model is trained on 1.4 million images and has 1000 different classes.

We want to use this model but only its convolutional base. So, when we load in the model, 
we'll specify that we don't want to load the top (classification) layer. We'll tell the model what input 
shape to expect and to use the predetermined weights from imagenet (Googles dataset).
"""""

IMG_SHAPE = (IMG_SIZE, IMG_SIZE, 3)

# Create the base model from the pre-trained model MobileNet V2
base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
                                               include_top=False,  # we don't want to load the top layer
                                               weights='imagenet')

"""""
Freezing the Base
The term freezing refers to disabling the training property of a layer. It simply means we won’t make any 
changes to the weights of any layers that are frozen during training. 
This is important as we don't want to change the convolutional base that already has learned weights.
"""""
base_model.trainable = False

"""""
Adding OUR Classifier
Now that we have our base layer setup, we can add the classifier. Instead of flattening the feature map 
of the base layer we will use a global average pooling layer that will average the entire 5x5 area of each 
2D feature map and return to us a single 1280 element vector per filter.
"""""
global_average_layer = tf.keras.layers.GlobalAveragePooling2D()

# Finally, we will add the prediction layer that will be a single dense neuron. We can do this because we
# only have two classes to predict for.
prediction_layer = keras.layers.Dense(1)

# Now we will combine these layers together in a model.
model = tf.keras.Sequential([
  base_model,
  global_average_layer,
  prediction_layer
])

# TRAINING THE MODEL
"""""
Now we will train and compile the model. We will use a very small learning rate to ensure that the model 
does not have any major changes made to it.
"""""
base_learning_rate = 0.0001
model.compile(optimizer=tf.keras.optimizers.RMSprop(lr=base_learning_rate),
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])

# Now we can train it on our images
initial_epochs = 3
history = model.fit(train_batches,
                    epochs=initial_epochs,
                    validation_data=validation_batches)

acc = history.history['accuracy']
print(acc)

# you can save a model and load a model with this syntax so you don't have to train it again every time
model.save("dogs_vs_cats.h5")  # we can save the model and reload it at anytime in the future

Notice that the predict method is used in a different file after the model is saved and loaded again to avoid trainig the model everytime.

Thank you in advance!

Hello, @solgeller3
Tough I’m not very familiar with Tensorflow, I will try to help:

ValueError: Input 0 is incompatible with layer sequential: expected shape=(None, 160, 160, 3), found shape=(32, 160, 3)

The input layers of your model needs a 4 dimension tensor to work with but the x_train tensor you are defining , it has only 3 dimensions. I know you are conscious about this problem, and tried to solve it.

but AFAK, you could try to reshape your training set with .reshape(n_images, 160, 160, 3). Adding an extra dimension without changing the data of your model.

This is more used with Scikit learn, but If I’m not wrong, it works in Tensorflow too.

x_train = x_train.reshape

Hope this helps

1 Like

I mean, for a start, you could try if the code works within your training-file.
Like, pull a single image from the training data and see if you can run it through the model. As you have saved the model, you can skip the fitting entirely because you only want to see if it is compatible.

1 Like

Hey @Jagaya , you are right. I tried running model.predict(test) inside the training file and it gave me the same error. I am really confused about this problem since all the code is copied from the freecodecamp videos. Maybe you know what the problem is?

Hey @AndyG, .reshape didn’t work and it kept giving the same error. If i printed the shape of the image it would give (160, 160, 3) but when the error pops up it shows that (32, 160, 3) was found which is pretty weird. I understand I need to add another dimension but I don’t know how.
And also, do you think the source of the problem is in the code i copied from the freecodecamp video or the other file which i loaded the model to?

In my limited knowledge, is possible to use tf.expand_dims to add a dimension,

xtrain = tf.expand_dims(xtrain, axis=-1)

Option 2:
Try to resize the

with OpenCV, using
import cv2
then use cv2.resize
image = cv2.resize(image, ( 160 , 160 ))

I think we could help you more if you share the specific video.
But, by the moment these are the options that I can give you.
Hope this helps

2 Likes