Prediction using Keras - python

I learned to implement an image classifier from a code which i got from a post and it was very helpful,but i don't know how to predict on an image.I tried but its giving a Value Error.I am still a beginner
Keras Code:-
from __future__ import print_function
from keras.datasets import cifar10
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, MaxPooling2D
from keras.optimizers import SGD, Adam
from keras.utils import np_utils
import numpy as np
#seed = 7
#np.random.seed(seed)
batch_size = 50
nb_classes = 10
nb_epoch = 150
data_augmentation = False
# input image dimensions
img_rows, img_cols = 32, 32
# the CIFAR10 images are RGB
img_channels = 3
# the data, shuffled and split between train and test sets
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
print('X_train shape:', X_train.shape)
print(X_train.shape[0], 'train samples')
print(X_test.shape[0], 'test samples')
# convert class vectors to binary class matrices
Y_train = np_utils.to_categorical(y_train, nb_classes)
Y_test = np_utils.to_categorical(y_test, nb_classes)
model = Sequential()
model.add(Convolution2D(32, 3, 3, border_mode='same',
input_shape=X_train.shape[1:]))
model.add(Activation('relu'))
model.add(Convolution2D(32, 3, 3, border_mode='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Convolution2D(64, 3, 3, border_mode='same'))
model.add(Activation('relu'))
model.add(Convolution2D(64, 3, 3, border_mode='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(nb_classes))
model.add(Activation('softmax'))
# let's train the model using SGD + momentum (how original).
#sgd = SGD(lr=0.001, decay=1e-6, momentum=0.9, nesterov=True)
sgd= Adam(lr=0.0001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0)
model.compile(loss='categorical_crossentropy',
optimizer=sgd,
metrics=['accuracy'])
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_test /= 255
if not data_augmentation:
print('Not using data augmentation.')
model.fit(X_train, Y_train,
batch_size=batch_size,
nb_epoch=nb_epoch,
validation_data=(X_test, Y_test),
shuffle=True)
else:
print('Using real-time data augmentation.')
# this will do preprocessing and realtime data augmentation
datagen = ImageDataGenerator(
featurewise_center=False, # set input mean to 0 over the dataset
samplewise_center=False, # set each sample mean to 0
featurewise_std_normalization=False, # divide inputs by std of the dataset
samplewise_std_normalization=False, # divide each input by its std
zca_whitening=False, # apply ZCA whitening
rotation_range=0, # randomly rotate images in the range (degrees, 0 to 180)
width_shift_range=0.1, # randomly shift images horizontally (fraction of total width)
height_shift_range=0.1, # randomly shift images vertically (fraction of total height)
horizontal_flip=True, # randomly flip images
vertical_flip=False) # randomly flip images
# compute quantities required for featurewise normalization
# (std, mean, and principal components if ZCA whitening is applied)
datagen.fit(X_train)
# fit the model on the batches generated by datagen.flow()
model.fit_generator(datagen.flow(X_train, Y_train,
batch_size=batch_size),
samples_per_epoch=X_train.shape[0],
nb_epoch=nb_epoch,
validation_data=(X_test, Y_test))
model.save('CIFAR10.h5')
My Prediction Code:-
from __future__ import print_function
from keras.models import load_model
from keras.utils import np_utils
import numpy as np
import cv2
img_rows, img_cols = 32, 32
model = load_model('CIFAR10.h5')
img = cv2.imread('D:/Study_Material/Python_3_Tutorial/PythonScripts/Machine_Learning/Project/Images/Deer.jpg')
img = cv2.resize(img,(img_rows,img_cols))
Image = np.array(img)
print(model.predict(Image))
Error:-
Warning (from warnings module):
File "C:\Users\Na462\AppData\Local\Programs\Python\Python35\lib\site-packages\h5py\__init__.py", line 36
from ._conv import register_converters as _register_converters
FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
Using TensorFlow backend.
Traceback (most recent call last):
File "D:\Study_Material\Python_3_Tutorial\PythonScripts\Machine_Learning\Project\Keras(Prediction).py", line 12, in <module>
print(model.predict(Image))
File "C:\Users\Na462\AppData\Local\Programs\Python\Python35\lib\site-packages\keras\models.py", line 1025, in predict
steps=steps)
File "C:\Users\Na462\AppData\Local\Programs\Python\Python35\lib\site-packages\keras\engine\training.py", line 1817, in predict
check_batch_axis=False)
File "C:\Users\Na462\AppData\Local\Programs\Python\Python35\lib\site-packages\keras\engine\training.py", line 113, in _standardize_input_data
'with shape ' + str(data_shape))
ValueError: Error when checking : expected conv2d_1_input to have 4 dimensions, but got array with shape (32, 32, 3)
Please Tell me the right way to Predict in Keras so that i can implement it on different test cases.

The error you are getting is because all the frameworks assume an image input is a batch of images making it a 4d tensor, instead of one image (3d tensor). To just do single image batches, expand the input to be of size (1, 32, 32, 3), the 1 in the beginning being the batch size of 1.
I do not know keras specifically very well, but since you are passing in a numpy array, you can modify your 'Image' object like so (see second to last line):
img_rows, img_cols = 32, 32
model = load_model('CIFAR10.h5')
img = cv2.imread('D:/Study_Material/Python_3_Tutorial/PythonScripts/Machine_Learning/Project/Images/Deer.jpg')
img = cv2.resize(img,(img_rows,img_cols))
Image = np.expand_dims(np.array(img), axis=0)
print(model.predict(Image))

Related

Keras image classification prediction error on image resize

I have a trained model, which has been trained to recognize different documents, I got the dataset from http://www.cs.cmu.edu/~aharley/rvl-cdip/.
Below is how I built my model
import numpy as np
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
import pickle
from keras.optimizers import SGD
from keras.models import Sequential, save_model
from keras.layers import Dense, Dropout, Flatten, Activation
from keras.layers.convolutional import Conv2D, MaxPooling2D
# Set image information
channels = 1
height = 1000
width = 754
model = Sequential()
# Add a Conv2D layer with 32 nodes to the model
model.add(Conv2D(32, (3, 3), input_shape=(1000, 754, 3)))
# Add the reLU activation function to the model
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten()) # this converts our 3D feature maps to 1D feature vectors
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('relu'))
model.compile(loss='categorical_crossentropy', # sparse_categorical_crossentropy
# Adam(lr=.0001) SGD variation with learning rate
optimizer='adam',
metrics=['accuracy'])
# Image data generator to import iamges from data folder
datagen = ImageDataGenerator()
# Flowing images from folders sorting by labels, and generates batches of images
train_it = datagen.flow_from_directory(
"data/train/", batch_size=16, target_size=(height, width), shuffle=True, class_mode='categorical')
test_it = datagen.flow_from_directory(
"data/test/", batch_size=16, target_size=(height, width), shuffle=True, class_mode='categorical')
val_it = datagen.flow_from_directory(
"data/validate/", batch_size=16, target_size=(height, width), shuffle=True, class_mode='categorical')
history = model.fit(
train_it,
epochs=2,
batch_size=16,
validation_data=val_it,
shuffle=True,
steps_per_epoch=2000 // 16,
validation_steps=800 // 16)
save_model(model, "./ComplexDocumentModel")
model.save("my_model", save_format='h5')
As in the last line, I saved my model in an h5 format.
I am trying now to use that trained model to predict on a single image, to see on which category it belongs with the below script.
from keras.models import load_model
import cv2
import numpy as np
import keras
from keras.preprocessing import image
model = load_model('my_model')
# First try
def prepare(file):
img_array = cv2.imread(file, cv2.IMREAD_GRAYSCALE)
new_array = cv2.resize(img_array, (1000, 754))
return new_array.reshape(3, 1000, 754, 1)
# Second try
img = image.load_img(
"/home/user1/Desktop/Office/image-process/test/0000113760.tif")
img = image.img_to_array(img)
img = np.expand_dims(img, axis=-1)
prediction = model.predict(
[prepare("/home/user1/Desktop/Office/image-process/test/0000113760.tif")])
print(prediction)
I tried predicting the image in two ways, but both give the error
ValueError: Input 0 of layer sequential is incompatible with the layer: expected axis -1 of input shape to have value 3 but received input with shape (None, 762, 3, 1)
I have also tried opening the image with PIL and converting it to NumPy array, an approach found on google. Unfortunately no other answer, blog, or video tutorial that I found, helped me.
You are trying to feed a grayscale image to a network that expects an image with 3 channels. You can stack the last channel 3 times to have a compatible shape, but it is possible that the prediction will be poor:
def prepare(file):
img_array = cv2.imread(file, cv2.IMREAD_GRAYSCALE)
new_array = cv2.resize(img_array, (1000, 754)) # shape is (1000,754)
# converting to RGB
array_color = cv2.cvtColor(new_array, cv2.COLOR_GRAY2RGB) # shape is (1000,754,3)
array_with_batch_dim = np.expand_dims(array_color, axis=0) # shape is (1,1000,754,3)
return array_with_batch_dim
Another solution is to not convert your image to grayscale when you read it, by omitting the flag cv2.IMREAD_GRAYSCALE. The default behaviour of opencv is to load an image with 3 channels.
def prepare(file):
img_array = cv2.imread(file)
new_array = cv2.resize(img_array, (1000, 754)) # shape is (1000,754, 3)
# converting to RGB
array_with_batch_dim = np.expand_dims(new_array, axis=0) # shape is (1,1000,754,3)
return array_with_batch_dim
Note: Depending on your preprocessing, you might need to normalize your image between 0 and 1 by dividing it by 255 before feeding it to the network.

the prediction function gives the same output everytime

from keras.datasets import mnist
from keras.models import Sequential, load_model
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Flatten
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.utils import np_utils
from keras.preprocessing import image
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
import cv2
(X_train, y_train), (X_test, y_test) = mnist.load_data()
X_train = X_train.reshape((X_train.shape[0], 28, 28, 1)).astype('float32')
X_test = X_test.reshape((X_test.shape[0], 28, 28, 1)).astype('float32')
X_train = X_train / 255
X_test = X_test / 255
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
num_classes = y_test.shape[1]
def larger_model():
model = Sequential()
model.add(Conv2D(30, (5, 5), input_shape=(28, 28, 1), activation='relu'))
model.add(MaxPooling2D())
model.add(Conv2D(15, (3, 3), activation='relu'))
model.add(MaxPooling2D())
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(50, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
return model
model = larger_model()
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=200)
scores = model.evaluate(X_test, y_test, verbose=0)
print("Large CNN Error: %.2f%%" % (100-scores[1]*100))
model.save('good_model.h5')
print("Model saved")
After running this code, we get a '.h5' model, then to predict this image
i added this code:
import cv2
model = load_model('good_model.h5')
file = cv2.imread('screenshot.png')
file = cv2.resize(file, (28, 28))
file = cv2.cvtColor(file, cv2.COLOR_BGR2GRAY)
file = file.reshape((-1, 28, 28,1))
result = model.predict(file)
print(result[0])
t = (np.argmax(result[0]))
print("I predict this number is a:", t)
But I always get the same answer which is 4. above I tried to load the image with cv and convert it to gray and then reshape to the size of the input. It takes the input correctly but the answer is always the same no matter what image I give it as input
You need to invert the image before prediction. Once you invert the image, it will predict correctly. The given example is predicting as "2" but I checked with other images such as "7" and it is correctly predicting.
file = cv2.bitwise_not(file)
Other than the above, I made one change. I imported modules from Tensorflow 2.x. Please check the full code here.

ValueError: Error when checking input: expected conv2d_1_input to have 4 dimensions, but got array with shape (454, 512, 512)

I used this code to produce my dataset in keras. but when I implement my code it produces this error:
ValueError: Error when checking input: expected conv2d_1_input to
have 4 dimensions, but got array with shape (454, 512, 512)
and I can not solve it. could you please tell me what is the problem? I expand the dimension before using in network but it does not work! could you please answer me fast, due to I search for several days but I could not find the solution and I do not have enough time:
import os,cv2
import numpy as np
import matplotlib.pyplot as plt
from sklearn.utils import shuffle
from sklearn.cross_validation import train_test_split
from keras import backend as K
#K.set_image_dim_ordering('th')
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.layers.convolutional import Convolution2D, MaxPooling2D
from keras.optimizers import SGD,RMSprop,adam
#%%
PATH = os.getcwd()
# Define data path
data_path = r"E:\PhD\thesis\deepwatermark\databasetest\train"
data_dir_list = os.listdir(data_path)
img_rows=512
img_cols=512
num_channel=1
num_epoch=20
# Define the number of classes
num_classes = 7
labels_name={'CRP':0,'GF':1,'GN':2,'JPG':3,'MED':4,'ROT':5,'SP':6}
img_data_list=[]
labels_list = []
for dataset in data_dir_list:
img_list=os.listdir(data_path+'/'+ dataset)
print ('Loading the images of dataset-'+'{}\n'.format(dataset))
label = labels_name[dataset]
for img in img_list:
input_img=cv2.imread(data_path + '/'+ dataset + '/'+ img )
input_img=cv2.cvtColor(input_img, cv2.COLOR_BGR2GRAY)
input_img_resize=cv2.resize(input_img,(512,512))
img_data_list.append(input_img_resize)
labels_list.append(label)
img_data = np.array(img_data_list)
img_data = img_data.astype('float32')
img_data /= 255
print (img_data.shape)
labels = np.array(labels_list)
# print the count of number of samples for different classes
print(np.unique(labels,return_counts=True))
# convert class labels to on-hot encoding
Y = np_utils.to_categorical(labels, num_classes)
#Shuffle the dataset
x,y = shuffle(img_data,Y, random_state=2)
# Split the dataset
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=2)
img_data= np.expand_dims(img_data, axis=4)**
print (img_data.shape)
# Defining the model
input_shape=img_data[0].shape
model = Sequential()
model.add(Convolution2D(32, 3,3,border_mode='same',input_shape=input_shape))
model.add(Activation('relu'))
model.add(Convolution2D(32, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
model.add(Convolution2D(64, 3, 3))
model.add(Activation('relu'))
#model.add(Convolution2D(64, 3, 3))
#model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes))
model.add(Activation('softmax'))
#sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
#model.compile(loss='categorical_crossentropy', optimizer=sgd,metrics=["accuracy"])
model.compile(loss='categorical_crossentropy', optimizer='rmsprop',metrics=["accuracy"])
# Viewing model_configuration
model.summary()
model.get_config()
model.layers[0].get_config()
model.layers[0].input_shape
model.layers[0].output_shape
model.layers[0].get_weights()
np.shape(model.layers[0].get_weights()[0])
model.layers[0].trainable
#%%
# Training
hist = model.fit(X_train, y_train, batch_size=16, nb_epoch=num_epoch, verbose=1, validation_data=(X_test, y_test))
my new code with generator is here, did you see any problem? my dataset is the same as before.
import numpy as np
import matplotlib.pyplot as plt
from keras.preprocessing.image import ImageDataGenerator
from sklearn.utils import shuffle
from sklearn.cross_validation import train_test_split
from keras import backend as K
#K.set_image_dim_ordering('th')
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.optimizers import SGD,RMSprop,adam
train_datagen = ImageDataGenerator(
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
#
valid_datagen = ImageDataGenerator(
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
#
test_datagen = ImageDataGenerator(rescale=1./255)
#
train_generator = train_datagen.flow_from_directory(
directory=r"E:\databasetest\train",
target_size=(512, 512),
color_mode="grayscale",
batch_size=32,
class_mode="categorical",
shuffle=True,
seed=42
)
#
valid_generator = valid_datagen.flow_from_directory(
directory=r"E:\databasetest\validation",
target_size=(512, 512),
color_mode="grayscale",
batch_size=32,
class_mode="categorical",
shuffle=True,
seed=42
)
#
test_generator = test_datagen.flow_from_directory(
directory=r"E:\databasetest\test",
target_size=(512, 512),
color_mode="grayscale",
batch_size=16,
class_mode=None,
shuffle=False,
seed=42
)
#
## neural network model
model = Sequential()
model.add(Conv2D(32, (3,3),border_mode='same', input_shape = (512, 512, 1), activation = 'relu'))
model.add(Activation('relu'))
model.add(Conv2D(32, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
model.add(Conv2D(64, 3, 3))
model.add(Activation('relu'))
#model.add(Convolution2D(64, 3, 3))
#model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(7))
model.add(Activation('softmax'))
model.summary()
model.compile(loss = 'categorical_crossentropy',
optimizer = 'rmsprop',
metrics = ['accuracy'])
STEP_SIZE_TRAIN=train_generator.n//train_generator.batch_size
STEP_SIZE_VALID=valid_generator.n//valid_generator.batch_size
model.fit_generator(generator=train_generator,
steps_per_epoch=STEP_SIZE_TRAIN,
validation_data=valid_generator,
validation_steps=STEP_SIZE_VALID,
epochs=10
)
but when I implement it I received this error again:
ResourceExhaustedError: OOM when allocating tensor with shape[32,32,512,512] and type float on /job:localhost/replica:0/task:0/device:GPU:0 by allocator GPU_0_bfc
[[Node: conv2d_1/convolution = Conv2D[T=DT_FLOAT, data_format="NCHW", dilations=[1, 1, 1, 1], padding="SAME", strides=[1, 1, 1, 1], use_cudnn_on_gpu=true, _device="/job:localhost/replica:0/task:0/device:GPU:0"](conv2d_1/convolution-0-TransposeNHWCToNCHW-LayoutOptimizer, conv2d_1/kernel/read)]]
for img in img_list:
input_img=cv2.imread(data_path + '/'+ dataset + '/'+ img )
input_img=cv2.cvtColor(input_img, cv2.COLOR_BGR2GRAY)
input_img_resize=cv2.resize(input_img,(512,512))
--->input_img_resize = np.expand_dims(input_img_resize, axis=-1)
img_data_list.append(input_img_resize)
labels_list.append(label)
this will make all your arrays 512x512x1, which should do the trick and ends up zith an array of shape (454, 512, 512, 1). You sure you want to use grayscaled images though?
Another thing is this snippet of code
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, `random_state=2)`
img_data= np.expand_dims(img_data, axis=4)**
print (img_data.shape)
You apply another dimension to your img_data, after you've already declared x_train, etc. And in the end you feed x_train, which is not extended, hence the error. If you do it in the beginning, and remove the expanding in the end, then your code should work.
EDIT OOM
I recommend creating a separate question for the OOM problem, so more people see it. Possible problems are the size of the images and the batch size. Reduce the image size to 64 x 64 and change the batch size to 5. If that still raises the error, try also kicking out this dense layer.
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
If these reductions still cause the error then I have the following questions: are you running on GPU/CPU, and which one?
Just to repeat myself: the code is fine, just needs a few changes perhaps.

format image data to predict a number in the image for MNIST data model

I'm having problems in trying Keras with MNIST. I have a saved model that has more than 99% accuracy but when I use it to predict some images it always predics a 1. I think it's due to me reshaping the image data input in the wrong way in the test.py file.
I got the error:
ValueError: Error when checking : expected conv2d_1_input to have 4 dimensions, but got array with shape (28, 28)
Or if I try a random reshape (1, 1, 28, 28) I get this error:
ValueError: Error when checking : expected conv2d_1_input to have shape (None, 28, 28, 1) but got array with shape (1, 1, 28, 28)
So I tried adding the following in my image_to_data function:
image_data = image_data.reshape((1, 28, 28, 1))
Now the code runs but always predicts the same values. How can I reshape the image data 28 x 28 pixels to that it fits the first layer in the model in the correct way for predicting the class of one image?
train.py
from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K
batch_size = 128
num_classes = 10
epochs = 20
# input image dimensions
img_rows, img_cols = 28, 28
# the data, shuffled and split between train and test sets
(x_train, y_train), (x_test, y_test) = mnist.load_data()
if K.image_data_format() == 'channels_first':
x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
input_shape = (1, img_rows, img_cols)
else:
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
# convert class vectors to binary class matrices
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
activation='relu',
input_shape=input_shape))
model.add(Conv2D(64, (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(num_classes, activation='softmax'))
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adadelta(),
metrics=['accuracy'])
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test))
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
# serialize model to YAML
model_yaml = model.to_yaml()
with open("model-new.yaml", "w") as yaml_file:
yaml_file.write(model_yaml)
# serialize weights to HDF5
model.save_weights("model-new.h5")
print("Saved model to disk")
test.py
from PIL import Image
from keras.models import model_from_yaml
import numpy as np
def load_model():
# load YAML and create model
yaml_file = open('model.yaml', 'r')
model_yaml = yaml_file.read()
yaml_file.close()
model = model_from_yaml(model_yaml)
# load weights into new model
model.load_weights("model.h5")
print("Loaded model from disk")
model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
return model
def image_to_data(image):
image_data = np.array(image) / 255
image_data = image_data.reshape((1, 28, 28, 1))
return image_data
def predict(model, image):
data = image_to_data(image)
prediction = model.predict_classes(data)
return prediction
def predict_image(model, filename):
image = Image.open(filename)
data = image_to_data(image)
prediction = predict(model, data)
return prediction
model = load_model()
print(predict_image(model, '3.png'))
print(predict_image(model, '6.png'))
print(predict_image(model, '8.png'))
Possible problems:
(not your case) MNIST data is normalized between 0 and 1, and your image may be from 0 to 255 as usual (compare image_data.max() with x_train.max())
MNIST data may have black and white colors inverted in relation to your images. After assuring everything is normalized between 0 and 1, use a tool to plot an image from x_train and to plot image_data. See if the colors are inverted. Or try predicing with image_data = 1 - image_data.
Depending on the way you're loading your images, you may have it transposed. After checking the two previous items, you may try to image_data = numpy.swapaxes(image_data,1,2)
Overfitting, as mentioned by #hi_im_vinzent. If all the three previous items are ok, try predicting with the training images to see if the model is doing it right.
If none of the previous worked, then you've probably got a problem when saving/loading the model.

How does data normalization work in keras during prediction?

I see that the imageDataGenerator allows me to specify different styles of data normalization, e.g. featurewise_center, samplewise_center, etc.
I see from the examples that if I specify one of these options, then I need to call the fit method on the generator in order to allow the generator to compute statistics like the mean image on the generator.
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
Y_train = np_utils.to_categorical(y_train, nb_classes)
Y_test = np_utils.to_categorical(y_test, nb_classes)
datagen = ImageDataGenerator(
featurewise_center=True,
featurewise_std_normalization=True,
rotation_range=20,
width_shift_range=0.2,
height_shift_range=0.2,
horizontal_flip=True)
# compute quantities required for featurewise normalization
# (std, mean, and principal components if ZCA whitening is applied)
datagen.fit(X_train)
# fits the model on batches with real-time data augmentation:
model.fit_generator(datagen.flow(X_train, Y_train, batch_size=32),
samples_per_epoch=len(X_train), nb_epoch=nb_epoch)
My question is, how does prediction work if I have specified data normalization during training? I can't see how in the framework I would even pass knowledge of the training set mean/std deviation along to predict to allow me to normalize my test data myself, but I also don't see in the training code where this information is stored.
Are the image statistics needed for normalization stored in the model so that they can be used during prediction?
Yes - this is a really huge downside of Keras.ImageDataGenerator that you couldn't provide the standarization statistics on your own. But - there is an easy method on how to overcome this issue.
Assuming that you have a function normalize(x) which is normalizing an image batch (remember that generator is not providing a simple image but an array of images - a batch with shape (nr_of_examples_in_batch, image_dims ..) you could make your own generator with normalization by using:
def gen_with_norm(gen, normalize):
for x, y in gen:
yield normalize(x), y
Then you might simply use gen_with_norm(datagen.flow, normalize) instead of datagen.flow.
Moreover - you might recover the mean and std computed by a fit method by getting it from appropriate fields in datagen (e.g. datagen.mean and datagen.std).
Use the standardize method of the generator for each element. Here is a complete example for CIFAR 10:
#!/usr/bin/env python
import keras
from keras.datasets import cifar10
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
# input image dimensions
img_rows, img_cols, img_channels = 32, 32, 3
num_classes = 10
batch_size = 32
epochs = 1
# The data, shuffled and split between train and test sets:
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
# Convert class vectors to binary class matrices.
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
model = Sequential()
model.add(Conv2D(32, (3, 3), padding='same', activation='relu',
input_shape=x_train.shape[1:]))
model.add(Conv2D(32, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(64, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='rmsprop',
metrics=['accuracy'])
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
datagen = ImageDataGenerator(zca_whitening=True)
# Compute principal components required for ZCA
datagen.fit(x_train)
# Apply normalization (ZCA and others)
print(x_test.shape)
for i in range(len(x_test)):
# this is what you are looking for
x_test[i] = datagen.standardize(x_test[i])
print(x_test.shape)
# Fit the model on the batches generated by datagen.flow().
model.fit_generator(datagen.flow(x_train, y_train,
batch_size=batch_size),
steps_per_epoch=x_train.shape[0] // batch_size,
epochs=epochs,
validation_data=(x_test, y_test))
I also had the same issue and I solved it using the same functionality, that the ImageDataGenerator used:
# Load Cifar-10 dataset
(trainX, trainY), (testX, testY) = cifar10.load_data()
generator = ImageDataGenerator(featurewise_center=True,
featurewise_std_normalization=True)
# Calculate statistics on train dataset
generator.fit(trainX)
# Apply featurewise_center to test-data with statistics from train data
testX -= generator.mean
# Apply featurewise_std_normalization to test-data with statistics from train data
testX /= (generator.std + K.epsilon())
# Do your regular fitting
model.fit_generator(..., validation_data=(testX, testY), ...)
Note that this is only possible if you have a reasonable small dataset, like CIFAR-10. Otherwise the solution proposed by Marcin sounds good more reasonable.
I am using the datagen.fit function itself.
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(
featurewise_center=True,
featurewise_std_normalization=True)
train_datagen.fit(train_data)
test_datagen = ImageDataGenerator(
featurewise_center=True,
featurewise_std_normalization=True)
test_datagen.fit(train_data)
Ideally with this, test_datagen fitted on training dataset will learn the training datasets statistics. Then it will use these statistics to normalize testing data.

Categories