Neural network is not predicting correctly - machine-learning

I am making a neural network to predict different kind of vegetables. It keeps predicting the wrong vegetable every time even though my val_accuracy is around 90% .
type import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import cv2
import os
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.preprocessing import image
from tensorflow.keras.optimizers import RMSprop
from keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau
from keras.utils import to_categorical
from keras.models import Sequential
from keras.layers import Dense, Flatten, Conv2D, MaxPool2D, Dropouthere
train = ImageDataGenerator(rescale=1/255)
validation = ImageDataGenerator(rescale=1/255)
train_data_set = train.flow_from_directory(r"C:\Users\roshn\Desktop\Vegetable Images\train",target_size=(200,200),batch_size =15,class_mode='categorical')
Found 15000 images belonging to 15 classes.
val_data_set = train.flow_from_directory(r"C:\Users\roshn\Desktop\Vegetable Images\validation",target_size=(200,200),batch_size =15,class_mode='categorical')
Found 3000 images belonging to 15 classes.
train_data_set.class_indices
{'Bean': 0,
'Bitter_Gourd': 1,
'Bottle_Gourd': 2,
'Brinjal': 3,
'Broccoli': 4,
'Cabbage': 5,
'Capsicum': 6,
'Carrot': 7,
'Cauliflower': 8,
'Cucumber': 9,
'Papaya': 10,
'Potato': 11,
'Pumpkin': 12,
'Radish': 13,
'Tomato': 14}
model = tf.keras.models.Sequential([tf.keras.layers.Conv2D(16,(3,3),activation ='relu',input_shape =(200,200,3)),
tf.keras.layers.MaxPool2D(2,2),
##
tf.keras.layers.Conv2D(32,(3,3),activation ='relu'),
tf.keras.layers.MaxPool2D(2,2),
##
tf.keras.layers.Flatten(),
##
tf.keras.layers.Dense(1000,activation ='relu'),
##
tf.keras.layers.Dropout(0.5),
##
tf.keras.layers.Dense(500,activation='relu'),
##
tf.keras.layers.Dropout(0.5),
##
tf.keras.layers.Dense(250,activation='relu'),
##
tf.keras.layers.Dense(15,activation='softmax')])
model.compile(loss='categorical_crossentropy',optimizer ='adam',metrics=['accuracy'])
es = EarlyStopping(monitor='val_accuracy',patience=2,verbose=1,mode='max')
mc = ModelCheckpoint('checkpoint/',monitor='val_accuracy',mode='max',save_best_only=True,verbose=1)
lr = ReduceLROnPlateau(monitor='val_accuracy',factor=0.1,min_lr=0.001,patience=15,mode='max',verbose=1)
model_fit=model.fit(train_data_set,
epochs=10,
batch_size=64,
validation_data=val_data_set,
callbacks=[es,mc,lr],validation_split =0.2)
model.summary()
Model: "sequential_23"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_63 (Conv2D) (None, 198, 198, 16) 448
max_pooling2d_63 (MaxPoolin (None, 99, 99, 16) 0
g2D)
conv2d_64 (Conv2D) (None, 97, 97, 32) 4640
max_pooling2d_64 (MaxPoolin (None, 48, 48, 32) 0
g2D)
flatten_22 (Flatten) (None, 73728) 0
dense_54 (Dense) (None, 1000) 73729000
dropout_8 (Dropout) (None, 1000) 0
dense_55 (Dense) (None, 500) 500500
dropout_9 (Dropout) (None, 500) 0
dense_56 (Dense) (None, 250) 125250
dense_57 (Dense) (None, 15) 3765
=================================================================
Total params: 74,363,603
Trainable params: 74,363,603
Non-trainable params: 0
___________________________________________________
This is the code I used for prediction.
dir_path =r"C:\Users\roshn\Desktop\Vegetable Images\train\Bitter_Gourd\0001.jpg"
img =image.load_img(dir_path,target_size =(200,200,3))
plt.imshow(img)
plt.show()
x= image.img_to_array(img)
x=np.expand_dims(x,axis =0)
images =np.vstack([x])
vl = model.predict(images)
t = train_data_set.class_indices
classes = list(t.keys())
values = t.values()
list_index=list(values)
x=vl
for i in range(15):
for j in range(15):
if x[0][list_index[i]] > x[0][list_index[j]]:
temp=list_index[i]
list_index[i]=list_index[j]
list_index[j]=temp
print(list_index)
for i in range (5):
print(classes[list_index[i]],':',round(vl[0][list_index[i]])*100,"%")

Related

Add two layers after a hidden layer keras

I am trying to get a neural network model like that:
input
|
hidden
/ \
hidden output2
|
output1
Here is a simple example in code:
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(Flatten()) # from here I would like to add a new neural network
model.add(Dense(128, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
How to get an expected model?
Please sorry if I ask a stupid question, I am a very beginner in artificial intelligence.
You could make use of keras functional APIs instead of sequential APIs to get it done as shown below:
from keras.models import Model
from keras.layers import Input
from keras.layers import Dense
from keras.layers import Flatten
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPooling2D
num_classes = 10
inp= Input(shape=input_shape)
conv1 = Conv2D(32, kernel_size=(3,3), activation='relu')(inp)
conv2 = Conv2D(64, (3, 3), activation='relu')(conv1)
max_pool = MaxPooling2D(pool_size=(2, 2))(conv2)
flat = Flatten()(max_pool)
hidden1 = Dense(128, activation='relu')(flat)
output1 = Dense(num_classes, activation='softmax')(hidden1)
hidden2 = Dense(10, activation='relu')(flat) #specify the number of hidden units
output2 = Dense(3, activation='softmax')(hidden2) #specify the number of classes
model = Model(inputs=inp, outputs=[output1 ,output2])
your network looks like this:
Model: "model_1"
__________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
==================================================================================================
input_7 (InputLayer) (None, 64, 256, 256) 0
__________________________________________________________________________________________________
conv2d_10 (Conv2D) (None, 62, 254, 32) 73760 input_7[0][0]
__________________________________________________________________________________________________
conv2d_11 (Conv2D) (None, 60, 252, 64) 18496 conv2d_10[0][0]
__________________________________________________________________________________________________
max_pooling2d_4 (MaxPooling2D) (None, 30, 126, 64) 0 conv2d_11[0][0]
__________________________________________________________________________________________________
flatten_4 (Flatten) (None, 241920) 0 max_pooling2d_4[0][0]
__________________________________________________________________________________________________
dense_6 (Dense) (None, 128) 30965888 flatten_4[0][0]
__________________________________________________________________________________________________
dense_8 (Dense) (None, 10) 2419210 flatten_4[0][0]
__________________________________________________________________________________________________
dense_7 (Dense) (None, 10) 1290 dense_6[0][0]
__________________________________________________________________________________________________
dense_9 (Dense) (None, 3) 33 dense_8[0][0]
==================================================================================================
Total params: 33,478,677
Trainable params: 33,478,677
Non-trainable params: 0

Why is my CNN overfitting and how can I fix it?

I am finetuning a 3D-CNN called C3D which was originally trained to classify sports from video clips.
I am freezing the convolution (feature extraction) layers and training the fully connected layers using gifs from GIPHY to classify the gifs for sentiment analysis (positive or negative).
Weights are pre loaded for all layers except the final fully connected layer.
I am using 5000 images (2500 positive, 2500 negative) for training with a 70/30 training/testing split using Keras. I am using the Adam optimizer with a learning rate of 0.0001.
The training accuracy increases and the training loss decreases during training but very early on the validation accuracy and loss does not improve as the model starts to overfit.
I believe I have enough training data and am using a dropout of 0.5 on both of the fully connected layers so how can I combat this overfitting?
The model architechture, training code and visualisations of training performance from Keras can be found below.
train_c3d.py
from training.c3d_model import create_c3d_sentiment_model
from ImageSentiment import load_gif_data
import numpy as np
import pathlib
from keras.callbacks import ModelCheckpoint
from keras.optimizers import Adam
def image_generator(files, batch_size):
"""
Generate batches of images for training instead of loading all images into memory
:param files:
:param batch_size:
:return:
"""
while True:
# Select files (paths/indices) for the batch
batch_paths = np.random.choice(a=files,
size=batch_size)
batch_input = []
batch_output = []
# Read in each input, perform preprocessing and get labels
for input_path in batch_paths:
input = load_gif_data(input_path)
if "pos" in input_path: # if file name contains pos
output = np.array([1, 0]) # label
elif "neg" in input_path: # if file name contains neg
output = np.array([0, 1]) # label
batch_input += [input]
batch_output += [output]
# Return a tuple of (input,output) to feed the network
batch_x = np.array(batch_input)
batch_y = np.array(batch_output)
yield (batch_x, batch_y)
model = create_c3d_sentiment_model()
print(model.summary())
model.load_weights('models/C3D_Sport1M_weights_keras_2.2.4.h5', by_name=True)
for layer in model.layers[:14]: # freeze top layers as feature extractor
layer.trainable = False
for layer in model.layers[14:]: # fine tune final layers
layer.trainable = True
train_files = [str(filepath.absolute()) for filepath in pathlib.Path('data/sample_train').glob('**/*')]
val_files = [str(filepath.absolute()) for filepath in pathlib.Path('data/sample_validation').glob('**/*')]
batch_size = 8
train_generator = image_generator(train_files, batch_size)
validation_generator = image_generator(val_files, batch_size)
model.compile(optimizer=Adam(lr=0.0001),
loss='binary_crossentropy',
metrics=['accuracy'])
mc = ModelCheckpoint('best_model.h5', monitor='val_loss', mode='min', verbose=1)
history = model.fit_generator(train_generator, validation_data=validation_generator,
steps_per_epoch=int(np.ceil(len(train_files) / batch_size)),
validation_steps=int(np.ceil(len(val_files) / batch_size)), epochs=5, shuffle=True,
callbacks=[mc])
load_gif_data()
def load_gif_data(file_path):
"""
Load and process gif for input into Keras model
:param file_path:
:return: Mean normalised image in BGR format as numpy array
for more info see -> http://cs231n.github.io/neural-networks-2/
"""
im = Img(fp=file_path)
try:
im.load(limit=16, # Keras image model only requires 16 frames
first=True)
except:
print("Error loading image: " + file_path)
return
im.resize(size=(112, 112))
im.convert('RGB')
im.close()
np_frames = []
frame_index = 0
for i in range(16): # if image is less than 16 frames, repeat the frames until there are 16
frame = im.frames[frame_index]
rgb = np.array(frame)
bgr = rgb[..., ::-1]
mean = np.mean(bgr, axis=0)
np_frames.append(bgr - mean) # C3D model was originally trained on BGR, mean normalised images
# it is important that unseen images are in the same format
if frame_index == (len(im.frames) - 1):
frame_index = 0
else:
frame_index = frame_index + 1
return np.array(np_frames)
model architecture
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv1 (Conv3D) (None, 16, 112, 112, 64) 5248
_________________________________________________________________
pool1 (MaxPooling3D) (None, 16, 56, 56, 64) 0
_________________________________________________________________
conv2 (Conv3D) (None, 16, 56, 56, 128) 221312
_________________________________________________________________
pool2 (MaxPooling3D) (None, 8, 28, 28, 128) 0
_________________________________________________________________
conv3a (Conv3D) (None, 8, 28, 28, 256) 884992
_________________________________________________________________
conv3b (Conv3D) (None, 8, 28, 28, 256) 1769728
_________________________________________________________________
pool3 (MaxPooling3D) (None, 4, 14, 14, 256) 0
_________________________________________________________________
conv4a (Conv3D) (None, 4, 14, 14, 512) 3539456
_________________________________________________________________
conv4b (Conv3D) (None, 4, 14, 14, 512) 7078400
_________________________________________________________________
pool4 (MaxPooling3D) (None, 2, 7, 7, 512) 0
_________________________________________________________________
conv5a (Conv3D) (None, 2, 7, 7, 512) 7078400
_________________________________________________________________
conv5b (Conv3D) (None, 2, 7, 7, 512) 7078400
_________________________________________________________________
zeropad5 (ZeroPadding3D) (None, 2, 8, 8, 512) 0
_________________________________________________________________
pool5 (MaxPooling3D) (None, 1, 4, 4, 512) 0
_________________________________________________________________
flatten_1 (Flatten) (None, 8192) 0
_________________________________________________________________
fc6 (Dense) (None, 4096) 33558528
_________________________________________________________________
dropout_1 (Dropout) (None, 4096) 0
_________________________________________________________________
fc7 (Dense) (None, 4096) 16781312
_________________________________________________________________
dropout_2 (Dropout) (None, 4096) 0
_________________________________________________________________
nfc8 (Dense) (None, 2) 8194
=================================================================
Total params: 78,003,970
Trainable params: 78,003,970
Non-trainable params: 0
_________________________________________________________________
None
training visualisations
I think that the error is in the loss function and in the last Dense layer. As provided in the model summary, the last Dense layer is,
nfc8 (Dense) (None, 2)
The output shape is ( None , 2 ) meaning that the layer has 2 units. As you said earlier, you need to classify GIFs as positive or negative.
Classifying GIFs could be a binary classification problem or a multiclass classification problem ( with two classes ).
Binary classification has only 1 unit in the last Dense layer with a sigmoid activation function. But, here the model has 2 units in the last Dense layer.
Hence, the model is a multiclass classifier, but you have given a loss function of binary_crossentropy which is meant for binary classifiers ( with a single unit in the last layer ).
So, replacing the loss with categorical_crossentropy should work. Or edit the last Dense layer and change the number of units and activation function.
Hope this helps.

ValueError: Error when checking target: expected dense_8 to have 4 dimensions, but got array with shape (37800, 10, 10)

I'm a beginner at machine learning. I am working on mnist dataset which I downloaded from kaggle. I am making this very first project by the help of a tutorial. But I'm facing this issue which I am unable to resolve. Please help. Here's the below.
import keras
import keras.preprocessing
import numpy as np
import matplotlib.pyplot as plt
from keras.models import Sequential
import pandas as pd
from keras.layers import Dense
from keras.optimizers import SGD
from sklearn.model_selection import ShuffleSplit
from sklearn.metrics import accuracy_score, confusion_matrix
X = pd.read_csv(r'C:\Users\faizan\Desktop\ML\Kaggle\MNIST\train.csv')
Y = pd.read_csv(r'C:\Users\faizan\Desktop\ML\Kaggle\MNIST\test.csv')
y = X["label"]
X = X.drop(["label"], 1)
#x = Y.drop(['label'], 1)
print(y.shape)
print(X.shape)
print(Y.shape)
y = keras.utils.to_categorical(y, num_classes = 10)
X = X / 255.0
X = X.values.reshape(-1,28,28,1)
# Shuffle Split Train and Test from original dataset
seed=2
train_index, valid_index = ShuffleSplit(n_splits=1,
train_size=0.9,
test_size=None,
random_state=seed).split(X).__next__()
x_train = X[train_index]
Y_train = y[train_index]
x_test = X[valid_index]
Y_test = y[valid_index]
model = Sequential()
model.add(Dense(units=128,activation="relu", input_shape=(28, 28, 1)))
model.add(Dense(units=128,activation="relu"))
model.add(Dense(units=128,activation="relu"))
model.add(Dense(units=10,activation="softmax"))
## Compiling Model
model.compile(optimizer=SGD(0.001),loss="categorical_crossentropy",metrics=["accuracy"])
## Training
model.fit(x_train,Y_train,batch_size=32, epochs=10,verbose=1)
accuracy = model.evaluate(x=x_test, y=Y_test, batch_size=32)
## Checking Accuracy
print("Accuracy: ", accuracy[1])
You are making some mistake that cause your network to fail.
First i will assume you are working with NMIST data set and that you are trying to classify each image to a class. Your Network is the following:
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_1 (Dense) (None, 28, 28, 128) 256
_________________________________________________________________
dense_2 (Dense) (None, 28, 28, 128) 16512
_________________________________________________________________
dense_3 (Dense) (None, 28, 28, 128) 16512
_________________________________________________________________
dense_4 (Dense) (None, 28, 28, 10) 1290
=================================================================
Total params: 34,570
Trainable params: 34,570
Non-trainable params: 0
_________________________________________________________________
So: You have four dimensions at the output of the network. And that is not right for a classification task. If you add a Flatten Layer just before the last layer:
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_5 (Dense) (None, 28, 28, 128) 256
_________________________________________________________________
dense_6 (Dense) (None, 28, 28, 128) 16512
_________________________________________________________________
dense_7 (Dense) (None, 28, 28, 128) 16512
_________________________________________________________________
flatten_1 (Flatten) (None, 100352) 0
_________________________________________________________________
dense_8 (Dense) (None, 10) 1003530
=================================================================
Total params: 1,036,810
Trainable params: 1,036,810
Non-trainable params: 0
_________________________________________________________________
and here you see that we have the ten classes you wanted. And that you only have two dimensions: one for the batch size (None) and the other for the classes (10). For one sample it will be a vector of probabilities for every class summing to one due to the softmax activation (mutually exclusives classes)
Could you please try to run with the flatten to see if this was your issue.
Then I strongly advice you to look into dealing with images in Keras because the use of Dense layers here (adn only Dense) is not optimal (for example you can see this Kaggle tuto)

Issue with Keras input array when implementing Convolutional Neural Network

I'm trying to implement a convolutional neural network within Keras using a TF backend for image segmentation of 111 images of size 141 x 166. When I run the code below, I get the error message:
Error when checking target: expected dense_36 to have 2 dimensions, but got array with shape (88, 141, 166, 1)
My X_train variable is the shape (88, 141, 166, 1) as well as the y_train variable. My X_test variable is the shape (23, 141, 166, 1) as well as the y_test variable, as split by the function train_test_split from sklearn.
I'm not sure what the error message means as per dense_36. I have tried using the Flatten() function before fitting the model, but it says that I have a ndim = 2 and cannot be flattened.
# set input
batch_size = 111
num_epochs = 50
img_rows = 141
img_cols = 166
input_shape = (img_rows, img_cols, 1)
num_classes = img_rows*img_cols
# split training and test data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 4)
X_train = X_train.astype('float32')
X_test = X_train.astype('float32')
# CNN itself
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.5))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
# compile CNN
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adadelta(), metrics=['accuracy'])
# fit CNN
model.fit(X_train, y_train, batch_size=batch_size, epochs=num_epochs,
verbose=1, validation_data=(X_test, y_test))
My model summary is:
Layer (type) Output Shape Param #
=================================================================
conv2d_35 (Conv2D) (None, 139, 164, 32) 320
_________________________________________________________________
conv2d_36 (Conv2D) (None, 137, 162, 64) 18496
_________________________________________________________________
max_pooling2d_18 (MaxPooling (None, 68, 81, 64) 0
_________________________________________________________________
dropout_35 (Dropout) (None, 68, 81, 64) 0
_________________________________________________________________
flatten_28 (Flatten) (None, 352512) 0
_________________________________________________________________
dense_33 (Dense) (None, 128) 45121664
_________________________________________________________________
dropout_36 (Dropout) (None, 128) 0
_________________________________________________________________
dense_34 (Dense) (None, 2) 258
_________________________________________________________________
Total params: 45,140,738
Trainable params: 45,140,738
Non-trainable params: 0
_________________________________________________________________
None

Cannot create keras model while using flow_from_directory

I am trying to create a model to fit data from the cifar-10 dataset. I have a working convolution neural network from an example but when I try to create a multi layer perceptron I keep getting a shape mismatch problem.
#https://gist.github.com/fchollet/0830affa1f7f19fd47b06d4cf89ed44d
#https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Activation, Dropout, Flatten, Dense
from keras import backend as K
from keras.optimizers import RMSprop
# dimensions of our images.
img_width, img_height = 32, 32
train_data_dir = 'pro-data/train'
validation_data_dir = 'pro-data/test'
nb_train_samples = 2000
nb_validation_samples = 800
epochs = 50
batch_size = 16
if K.image_data_format() == 'channels_first':
input_shape = (3, img_width, img_height)
else:
input_shape = (img_width, img_height, 3)
model = Sequential()
model.add(Dense(512, activation='relu', input_shape=input_shape))
model.add(Dropout(0.2))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(10, activation='softmax'))
model.summary()
model.compile(loss='categorical_crossentropy',
optimizer=RMSprop(),
metrics=['accuracy'])
# this is the augmentation configuration we will use for training
train_datagen = ImageDataGenerator(
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
# this is the augmentation configuration we will use for testing:
# only rescaling
test_datagen = ImageDataGenerator()
train_generator = train_datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
validation_generator = test_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
model.fit_generator(
train_generator,
steps_per_epoch=nb_train_samples // batch_size,
epochs=epochs,
validation_data=validation_generator,
validation_steps=nb_validation_samples // batch_size)
score = model.evaluate_generator(validation_generator, 1000)
print("Accuracy = ", score[1])
The error I am getting is this:
ValueError: Error when checking target: expected dense_3 to have 4 dimensions, but got array with shape (16, 1)
But if if change the input_shape for the input layer to an incorrect value "(784,)", I get this error:
ValueError: Error when checking input: expected dense_1_input to have 2 dimensions, but got array with shape (16, 32, 32, 3)
This is where I got a working cnn model using flow_from_directory:
https://gist.github.com/fchollet/0830affa1f7f19fd47b06d4cf89ed44d
In case anyone is curious I am getting an accuracy of only 10% for cifar10 using the convolution neural network model. Pretty poor I think.
according to your model, your model summary is
dense_1 (Dense) (None, 32, 32, 512) 2048
dropout_1 (Dropout) (None, 32, 32, 512) 0
dense_2 (Dense) (None, 32, 32, 512) 262656
dropout_2 (Dropout) (None, 32, 32, 512) 0
dense_3 (Dense) (None, 32, 32, 10) 5130
Total params: 269,834
Trainable params: 269,834
Non-trainable params: 0
Your output format is (32,32,10)
In the cifar-10 dataset you want to classify into 10 labels
Try adding
model.add(Flatten())
before your last dense layer.
Now your output layer is
Layer (type) Output Shape Param #
dense_1 (Dense) (None, 32, 32, 512) 2048
dropout_1 (Dropout) (None, 32, 32, 512) 0
dense_2 (Dense) (None, 32, 32, 512) 262656
dropout_2 (Dropout) (None, 32, 32, 512) 0
flatten_1 (Flatten) (None, 524288) 0
dense_3 (Dense) (None, 10) 5242890
Total params: 5,507,594
Trainable params: 5,507,594
Non-trainable params: 0
Also, you've just used the dense and dropout layers in your model. To get better accuracy you should google the various CNN architectures which consists of dense and maxpooling layers.

Resources