In Tensorflow/ Keras CNN Image Classification, predictions are less accurate than train/ test accuracy, why?

Viewed 19

===I am trying to set up a Tensorflow/ Keras CNN image classification model. I am using around 21k train images, 6k test images, and making a prediction against those same 6k test images. The create model code is as follows:

stage = "TEST"
if stage == "DEV":
    epochs = 1
elif stage == "DEV2":
    epochs = 50
elif stage == "TEST":
    epochs = 250
else:
    epochs = 1000

# Input the size of your sample images
img_width, img_height = 240,172
# Enter the number of samples, training + validation
#nb_train_samples = 13204
#nb_validation_samples = 1412
nb_filters1 = 32
nb_filters2 = 32
nb_filters3 = 64
conv1_size = 3
conv2_size = 2
conv3_size = 5
pool_size = 2
# We have 2 classes, buy and sell
classes_num = 2
batch_size = 128
lr = 0.001
chanDim =3

model = Sequential()
model.add(Convolution2D(nb_filters1, conv1_size, conv1_size, padding ='same', input_shape=(img_height, img_width , 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(pool_size, pool_size)))

model.add(Convolution2D(nb_filters2, conv2_size, conv2_size, padding ="same"))
model.add(Activation('relu'))
#model.add(MaxPooling2D(pool_size=(pool_size, pool_size), data_format="channels_first"))     #for GPU
model.add(MaxPooling2D(pool_size=(pool_size, pool_size), data_format="channels_last"))       #for CPU

model.add(Convolution2D(nb_filters3, conv3_size, conv3_size, padding ='same'))
model.add(Activation('relu'))
#model.add(MaxPooling2D(pool_size=(pool_size, pool_size), data_format="channels_first"))     #for GPU
model.add(MaxPooling2D(pool_size=(pool_size, pool_size), data_format="channels_last"))       #for CPU

model.add(Flatten())
model.add(Dense(1024))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(classes_num, activation='softmax'))

model.summary()
model.compile(loss='categorical_crossentropy',
    optimizer= optimizers.RMSprop(),
    metrics=['accuracy'])



#get class names
train_dir = pathlib.Path(folder_path + "/train/")
class_names = list([item.name for item in train_dir.glob('*')])
print("We have the following classes:", class_names)


#get number of images
no_trainbuy = len([name for name in os.listdir(folder_path + "/train/buy") if os.path.isfile(os.path.join(folder_path + "/train/buy", name))]) 
no_trainsell = len([name for name in os.listdir(folder_path + "/train/sell") if os.path.isfile(os.path.join(folder_path + "/train/sell", name))]) 
no_train = no_trainbuy + no_trainsell
no_testbuy = len([name for name in os.listdir(folder_path + "/test/buy") if os.path.isfile(os.path.join(folder_path + "/test/buy", name))]) 
no_testsell = len([name for name in os.listdir(folder_path + "/test/sell") if os.path.isfile(os.path.join(folder_path + "/test/sell", name))]) 
no_test = no_testbuy + no_testsell
nb_train_samples = no_train
nb_validation_samples = no_test
print ("number of images. no_train: " + str(no_train) + " no_test: " + str(no_test)  )

train_datagen = ImageDataGenerator(    rescale=1./255,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=False)

test_datagen = ImageDataGenerator(    rescale=1./255,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=False)


train_generator = train_datagen.flow_from_directory(
    folder_path + "/train",
    target_size = (img_height, img_width),
    batch_size=batch_size,
    shuffle=True,
    class_mode='categorical' )


test_generator = test_datagen.flow_from_directory(
    folder_path + "/train",
    target_size = (img_height, img_width),
    batch_size=batch_size,
    shuffle=True,
    class_mode='categorical' )

#early stopping, prevents additional runtime when not needed
early_stopping = EarlyStopping(monitor='val_loss', patience=3)


model.fit_generator(
    train_generator,
    steps_per_epoch=nb_train_samples//batch_size,
    epochs=epochs,
    shuffle=True,
    validation_data=test_generator,
    #callbacks=callbacks_list,
    validation_steps=nb_validation_samples//batch_size)

===The result after epoch 250 is as follows:

Epoch 250/250 165/165 [==============================] - 179s 1s/step - loss: 0.6427 - accuracy: 0.6245 - val_loss: 0.6383 - val_accuracy: 0.6297

===I have tried 2 methods of making predictions - first method:

img_width, img_height = 240,172


images = []
image_file_names= []
for img in os.listdir(folder_path + '/pred/samples/' ):
    image_file_names.append (  img)
    img = os.path.join(folder_path + '/pred/samples/', img)
    img = image.load_img(img )
    img = image.img_to_array(img)/255
    img = np.expand_dims(img, axis=0)
    images.append(img)

image.array_to_img(img[0]).show()
#print ("image file names: ", image_file_names)

images = np.vstack(images)
pred = model.predict(images, verbose=1) 
#print ("predictions:", pred)

class_names = ['buy', 'sell']
class_list = [] 
prob_list = []
for x in pred:
    #print ("array: " + str(x) )
    #print("This image most likely belongs to {} with a {:.2f} percent confidence." .format( class_names[np.argmax(x)], 100 * np.max(x)) )
    class_list.append( class_names[np.argmax(x)] )
    prob_list.append( 100 * np.max(x) )

#correct indicator
correct = []
for a in range (0, len(image_file_names)):
    if image_file_names[a].find("buy") != -1:
        if class_list[a] == "buy":
            correct.append(1)
        else:
            correct.append(0)

    if image_file_names[a].find("sell") != -1:
        if class_list[a] == "sell":
            correct.append(1)
        else:
            correct.append(0)


#create df from lists
df = pd.DataFrame({'image_file_names': image_file_names, 'class_list': class_list, 'prob_list': prob_list, 'correct': correct})
print (df)

total_correct = df['correct'].sum()
correct_pc = ( total_correct / len(df) ) * 100
print ("the number of correct predictions is: " + str(total_correct) + " and percentage correct is " + str(correct_pc)   )

===This provides a prediction accuracy of arount 50%

The second method I have used is as follows:

train_dir = pathlib.Path(folder_path + "/train/")
class_names = list([item.name for item in train_dir.glob('*')])
print("We have the following classes:", class_names)


batch_size=1
img_width, img_height = 240,172

pred_datagen = ImageDataGenerator(    rescale=1./255,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=False)

pred_generator = pred_datagen.flow_from_directory(
    folder_path + "/pred/",
    target_size=(img_height, img_width),
    batch_size=batch_size,
    shuffle=True,
    class_mode='categorical'  )

#pred generator classes
#print ( pred_generator.class_indices )


image_file_names = pred_generator.filenames
#print (image_file_names)
nb_samples = len(image_file_names)


image_batch, label_batch = next(pred_generator)
plt.imshow(image_batch[0])
plt.show()


#pred_generator.reset()
pred = model.predict_generator(pred_generator, steps = nb_samples // batch_size)
score = tf.nn.softmax(pred)
#print (score)


class_list = [] 
prob_list = []
v=0
for x in score:
    #print("-----------------------------------------")
    #print ("array: " + str(x) )
    #print ("image file: " + str(image_file_names[v])  )
    v=v+1
    #print("This image most likely belongs to {} with a {:.2f} percent confidence." .format( class_names[np.argmax(x)], 100 * np.max(x)) )
    class_list.append( class_names[np.argmax(x)] )
    prob_list.append( 100 * np.max(x) )


#correct indicator
correct = []
for a in range (0, len(image_file_names)):
    if image_file_names[a].find("buy") != -1:
        if class_list[a] == "buy":
            correct.append(1)
        else:
            correct.append(0)

    if image_file_names[a].find("sell") != -1:
        if class_list[a] == "sell":
            correct.append(1)
        else:
            correct.append(0)


#print prediction list results
print ( image_file_names)
print ( class_list )
print ( prob_list )
print ( correct) 

#create df from lists
print ("\n\nall results df: ")
df = pd.DataFrame({'image_file_names': image_file_names, 'class_list': class_list, 'prob_list': prob_list, 'correct': correct})
print (df)

total_correct = df['correct'].sum()
correct_pc = ( total_correct / len(df) ) * 100
print ("the number of correct predictions is: " + str(total_correct) + " and percentage correct is " + str(correct_pc)   )

=== And this second method also gives a prediction accuracy of about 50%.

What am I doing wrong?

1 Answers

If the images in your directory folder_path + '/pred/samples/ are not already in the shape 240 X 172 then in the code for your first attempt at prediction you need to resize the images. In your second code for predictions you should not use augmentation in the generator, just rescale the images. Please define the structure of the directory folder_path + '/pred/samples. IS there 2 sub directories within it (buy and sell)?

Related