'Tensorflow:Model was constructed with shape (None, 28, 28) , but it was called on an input with incompatible shape (None, 28)

I am solving the digit recognition task using the MNIST dataset in keras. The task itself runs smoothly but afterwards I have tried to use the same model for some other handwritten digits that I created with 'paint'. Since the original size was (192, 188, 3), I specifically resized to (28, 28). However, once I try the model on this newly created digit (see attachment), this is the Warning message I get:

WARNING:tensorflow:Model was constructed with shape (None, 28, 28) for input KerasTensor(type_spec=TensorSpec(shape=(None, 28, 28), dtype=tf.float32, name='flatten_input'), name='flatten_input', description="created by layer 'flatten_input'"), but it was called on an input with incompatible shape (None, 28)

In addition to this error message:

ValueError: Input 0 of layer dense is incompatible with the layer: expected axis -1 of input shape to have value 784 but received input with shape (None, 28)

Here is my code:

import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
# %matplotlib inline
import numpy as np
import pandas as pd
import cv2 as cv

(X_train, y_train),(X_test, y_test)=keras.datasets.mnist.load_data()
# Normalize the train dataset
X_train = tf.keras.utils.normalize(X_train, axis=1)
# Normalize the test dataset
X_test = tf.keras.utils.normalize(X_test, axis=1)

#Build the model object
model = tf.keras.models.Sequential()
# Add the Flatten Layer
model.add(tf.keras.layers.Flatten())
# Build the input and the hidden layers
model.add(tf.keras.layers.Dense(128, activation=tf.nn.relu))
model.add(tf.keras.layers.Dense(128, activation=tf.nn.relu))
# Build the output layer
model.add(tf.keras.layers.Dense(10, activation=tf.nn.softmax))

# Compile the model
model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", 
metrics=["accuracy"]) 
model.fit(x=X_train, y=y_train, epochs=20) # Start training process

# Evaluate the model performance
test_loss, test_acc = model.evaluate(x=X_test, y=y_test)
# Print out the model accuracy 
print('\nTest accuracy:', test_acc)

predictions = model.predict([X_test]) # Make prediction

# TRY SAME MODEL WITH NEW DIGIT 

img_6 =  cv.imread("6.png")
img_7 =  cv.imread("7.png")
img_2 =  cv.imread("2.png")


from tensorflow.keras.preprocessing import image

img =  img_7 

img=cv.resize(img, X_train[0].shape, 
            interpolation = cv.INTER_AREA) 
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY) 

plt.imshow(img)
plt.show()
img=np.invert(np.array([img]))
img=np.reshape(img, ( 784, 1))
print(img.shape,'fghjkljkhjgfgfgcgvhbjnmnbjv')
plt.imshow(img)
plt.show()

img=np.expand_dims(img, axis=0) # will move it to (1,784)
print(img.shape,'fghjkljkhjgfgfgcgvhbjnmnbjv')
plt.imshow(img)
plt.show()
prediction=model.predict(img) # predict
print ('prediction=',np.argmax(prediction))
plt.imshow(img)
plt.show()

6 7 2



Solution 1:[1]

The problem with your code is that your model is expecting a 3-dimensional input (batch_size, width, height), while you're giving it a single 2-dimensional image (width, height).

You can first reshape your input image to the correct shape, like so:

np.reshape(img_6, (1, 28, 28))

Solution 2:[2]

The first layer on your model is tf.keras.layers.Flatten() i.e flatten. means it's like an array. what is that array length is 784(28X28X1 ~ length x width x channel). so if you put model.summary() the first layer is :

Layer (type)                 Output Shape              Param #   
=================================================================
flatten (Flatten)            (None, 784)               0   

so it means that predict is expecting input data as (1,784). you are on right track to resize and gray out the input image, few more steps are needed. please refer to the below code and comment against each line:

from tensorflow.keras.preprocessing import image # import image preprocessing
img_6 =  cv.imread("6.png") # shape if (352, 324, 3) for screen snap, this could be different based on read image.
img_6=cv.resize(img_6, X_train[0].shape, 
                interpolation = cv.INTER_AREA) # now its in shape (28, 28, 3) which is~ 2352(28x28x3)
img_6 = cv.cvtColor(img_6, cv.COLOR_BGR2GRAY) # now gray image
img_6=image.img_to_array(img_6) # shape (28, 28, 1) i.e channel 1
img_6= img_6.flatten() # flatten it as model is expecting (None,784) , this will be (784,) i.e 28x28x1 =
img_6=np.expand_dims(img_6, axis=0) # will move it to (1,784)
prediction=model.predict(im1) # predict
print (np.argmax(prediction))

Solution 3:[3]

Indeed the keras model has first layer Flatten, but since the training is done on X_train of shape (60000,28,28) and the first successful prediction is done on X_test of shape (10000,28,28), what you need for prediction is a pandas array of shape (1,28,28).

Also be sure that the images in the taining MINST database are on black background (0 color) written with white nuances (closer to 1), so you need to normalize the img array with img = (255-img) / 255

So with the following additional code I could predict successfuly 2 and 6 image :

img =  img2
img=cv.resize(img, X_train[0].shape, interpolation = cv.INTER_AREA) 
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # now gray image (28,28)
img = (255-img) / 255                # normalize as white on black
img=np.expand_dims(img, axis=0) # will move it to (1,28,28)
pred=model.predict(img) # predict
print(pred)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ehab Ibrahim
Solution 2 simpleApp
Solution 3 Cristian