I have a dataset which contains images of 2 different types of lego brick, I've then created a model and trained it. At the end of the training the accurate and val_accurate are both about 98%. (plot of training looks good, does not look like it's overfitting)
In both the training and prediction scripts I pre-process the images by scaling them to 32x32, converting to gray scale and doing img_to_array()
My dataset contains about 1500 images of "0" brick and 1700 images of the "1" brick.
However when I run predict on a set of images (that I did not use in the training process), it always predicts "0" for every image. If the training is 98% accurate, how can the prediction not get any of the class "1" images correct?
Here is my model:
model = Sequential()
# first set of CONV => RELU => POOL layers
model.add(Conv2D(20, (5, 5), padding="same",
input_shape=(32, 32, 1))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
# second set of CONV => RELU => POOL layers
model.add(Conv2D(50, (5, 5), padding="same"))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
# first (and only) set of FC => RELU layers
model.add(Flatten())
model.add(Dense(500))
model.add(Activation("relu"))
# softmax classifier
model.add(Dense(1))
model.add(Activation("sigmoid"))
Here is my training script:
# USAGE
# python lego_trainer.py --dataset dataset
# import the necessary packages
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from pyimagesearch.preprocessing import ImageToArrayPreprocessor
from pyimagesearch.preprocessing import SimplePreprocessor
from pyimagesearch.preprocessing import GrayScale
from pyimagesearch.datasets import SimpleDatasetLoader
from pyimagesearch.nn.conv import LegoNet
from tensorflow.keras.optimizers import SGD
from imutils import paths
import matplotlib.pyplot as plt
import numpy as np
import argparse
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", default="dataset", required=True,
help="path to input dataset")
args = vars(ap.parse_args())
# grab the list of images that we'll be describing
print("[INFO] loading images...")
imagePaths = list(paths.list_images(args["dataset"]))
# initialize the image preprocessors
sp = SimplePreprocessor(32, 32)
gray = GrayScale()
iap = ImageToArrayPreprocessor()
# load the dataset from disk then scale the raw pixel intensities
# to the range [0, 1]
sdl = SimpleDatasetLoader(preprocessors=[sp, gray, iap])
(data, labels) = sdl.load(imagePaths, verbose=500)
data = data.astype("float") / 255.0
# partition the data into training and testing splits using 75% of
# the data for training and the remaining 25% for testing
(trainX, testX, trainY, testY) = train_test_split(data, labels,
test_size=0.25, random_state=42)
# convert the labels from integers to vectors
trainY = LabelBinarizer().fit_transform(trainY)
testY = LabelBinarizer().fit_transform(testY)
# initialize the optimizer and model
print("[INFO] compiling model...")
opt = SGD(lr=0.005)
model = LegoNet.build(width=32, height=32, depth=1)
model.compile(loss="binary_crossentropy", optimizer=opt,
metrics=["accuracy"])
# train the network
print("[INFO] training network...")
H = model.fit(trainX, trainY, validation_data=(testX, testY),
batch_size=16, epochs=100, verbose=1)
model.save("legomodel.hdf5")
# evaluate the network
print("[INFO] evaluating network...")
predictions = model.predict(testX, batch_size=32)
print(classification_report(testY.argmax(axis=1),
predictions.argmax(axis=1)))
# plot the training loss and accuracy
plt.style.use("ggplot")
plt.figure()
plt.plot(np.arange(0, 100), H.history["loss"], label="train_loss")
plt.plot(np.arange(0, 100), H.history["val_loss"], label="val_loss")
plt.plot(np.arange(0, 100), H.history["accuracy"], label="train_acc")
plt.plot(np.arange(0, 100), H.history["val_accuracy"], label="val_acc")
plt.title("Training Loss and Accuracy")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend()
plt.show()
And here is my prediction script:
# USAGE
# python lego_predict.py --dataset sample --model legomodel.hdf5
# import the necessary packages
from pyimagesearch.preprocessing import ImageToArrayPreprocessor
from pyimagesearch.preprocessing import GrayScale
from pyimagesearch.preprocessing import SimplePreprocessor
from pyimagesearch.datasets import SimpleDatasetLoader
from tensorflow.keras.models import load_model
from imutils import paths
import numpy as np
import argparse
import cv2
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
help="path to input dataset")
ap.add_argument("-m", "--model", required=True,
help="path to pre-trained model")
args = vars(ap.parse_args())
# initialize the class labels
# grab the list of images in the dataset then randomly sample
# indexes into the image paths list
print("[INFO] sampling images...")
imagePaths = np.array(list(paths.list_images(args["dataset"])))
# idxs = np.random.randint(0, len(imagePaths), size=(10,))
# imagePaths = imagePaths[idxs]
# initialize the image preprocessors
sp = SimplePreprocessor(32, 32)
gray = GrayScale()
iap = ImageToArrayPreprocessor()
# load the dataset from disk then scale the raw pixel intensities
# to the range [0, 1]
sdl = SimpleDatasetLoader(preprocessors=[sp, gray, iap])
(data, labels) = sdl.load(imagePaths)
data = data.astype("float") / 255.0
# load the pre-trained network
print("[INFO] loading pre-trained network...")
model = load_model(args["model"])
# make predictions on the images
print("[INFO] predicting...")
preds = model.predict(data, batch_size=32).argmax(axis=1)
print(preds)
# loop over the sample images
for (i, imagePath) in enumerate(imagePaths):
# load the example image, draw the prediction, and display it
# to our screen
image = cv2.imread(imagePath)
cv2.putText(image, "Label: {}".format(preds[i]),
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.imshow("Image", image)
cv2.waitKey(0)
CodePudding user response:
The issue is at this point:
preds = model.predict(data, batch_size=32).argmax(axis=1)
You have only one output neuron, and argmaxing, regardless of the prediction of your network, will give you 0 (maximum position of a 1-single element array).
Remove the argmax, and then you could consider the cut-off/threshold at 0.5 or whatever cut-off you like.
CodePudding user response:
I order to get my model working I made the following changes:
Switched loss function from
binary_crossentropytosparse_categorical_crossentropyChanging last layer in model from
model.add(Dense(1))tomodel.add(Dense(2))Changed finally activator from
sigmoidtosoftmax
