6
$\begingroup$

I'm working on a multi-classification problem - Recognizing flowers.

I trained the mode and I achieved accuracy of 0.99.

To predict, I did:

a = model.predict(train[:6])

output:

array([[5.12799371e-18, 2.08305119e-05, 1.14476855e-07, 1.28556788e-02,
        1.46144101e-08, 1.85072349e-05],
       [7.72907813e-32, 7.86612819e-09, 8.08554124e-13, 1.87227300e-08,
        4.61950422e-10, 6.42609745e-02],
       [0.00000000e+00, 1.34313246e-02, 9.67072342e-13, 2.82699081e-12,
        1.10958222e-10, 4.68058548e-14],
       [7.75535319e-27, 6.51194032e-09, 2.49026186e-07, 1.88803018e-08,
        3.77964647e-03, 7.01414028e-05],
       [7.24011743e-22, 5.85804628e-07, 1.61177505e-09, 2.27746829e-01,
        5.44432410e-09, 3.94427252e-06],
       [1.81492225e-15, 3.36600904e-04, 4.39262622e-05, 8.63518100e-04,
        9.29966700e-06, 9.75337625e-02]], dtype=float32)

How do I interpret this? How do I know get the label it predicted? I have five labels 0-4, which are assigned to 5 types of flowers.

My notebook is here.

What am I doing wrong here?

$\endgroup$
  • $\begingroup$ Why do you have 6 output nodes? Can we get access to the data please? $\endgroup$ – JahKnows Sep 2 '18 at 20:21
  • 1
    $\begingroup$ @JahKnows link to the dataset is provided(1st line). $\endgroup$ – Jagadeesh Kotra Sep 2 '18 at 20:23
10
$\begingroup$

Alright so I rewrote some parts of your model such that it makes more sense for a classification problem. The first and most obvious reason your network was not working is due to the number of output nodes you selected. For a classification task the number of output nodes should be the same as the number of classes in your data. In this case we have 5 kinds of flowers, thus 5 labels which I reassigned to $y \in \{0, 1, 2, 3, 4\}$, thus we will have 5 output nodes.

So let's go through the code. First we bring the data into the notebook using the code you wrote.

from os import listdir
import cv2

daisy_path = "flowers/daisy/"
dandelion_path = "flowers/dandelion/"
rose_path = "flowers/rose/"
sunflower_path = "flowers/sunflower/"
tulip_path = "flowers/tulip/"

def iter_images(images,directory,size,label):
    try:
        for i in range(len(images)):
            img = cv2.imread(directory + images[i])
            img = cv2.resize(img,size)
            img_data.append(img)
            labels.append(label)
    except:
        pass

img_data = []
labels = []
size = 64,64
iter_images(listdir(daisy_path),daisy_path,size,0)
iter_images(listdir(dandelion_path),dandelion_path,size,1)
iter_images(listdir(rose_path),rose_path,size,2)
iter_images(listdir(sunflower_path),sunflower_path,size,3)
iter_images(listdir(tulip_path),tulip_path,size,4)

We can visualize the data to get a better idea of the distribution of the classes.

import matplotlib.pyplot as plt
%matplotlib inline

n_classes = 5

training_counts = [None] * n_classes 
testing_counts = [None] * n_classes
for i in range(n_classes):
    training_counts[i] = len(y_train[y_train == i])/len(y_train)
    testing_counts[i] = len(y_test[y_test == i])/len(y_test)

# the histogram of the data
train_bar = plt.bar(np.arange(n_classes)-0.2, training_counts, align='center', color = 'r', alpha=0.75, width = 0.41, label='Training')
test_bar = plt.bar(np.arange(n_classes)+0.2, testing_counts, align='center', color = 'b', alpha=0.75, width = 0.41, label = 'Testing')

plt.xlabel('Labels')
plt.xticks((0,1,2,3,4))
plt.ylabel('Count (%)')
plt.title('Label distribution in the training and test set')
plt.legend(bbox_to_anchor=(1.05, 1), handles=[train_bar, test_bar], loc=2)
plt.grid(True)
plt.show()

enter image description here

We will now transform the data and the labels to matrices.

import numpy as np
data = np.array(img_data)
data.shape
data = data.astype('float32') / 255.0
labels = np.asarray(labels)

Then we will split the data.. Notice that you do not need to shuffle the data yourself since sklearn can do it for you.

from sklearn.model_selection import train_test_split

# Split the data
x_train, x_test, y_train, y_test = train_test_split(data, labels, test_size=0.33, shuffle= True)

Let's construct our model. I changed the last layer to use the softmax activation function. This will allow the outputs of the network to sum up to a total probability of 1. This is the usual activation function to use for classification tasks.

from keras.models import Sequential
from keras.layers import Dense,Flatten,Convolution2D,MaxPool2D
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.callbacks import ModelCheckpoint
from keras.models import model_from_json
from keras import backend as K

model = Sequential()
model.add(Convolution2D(32, (3,3),input_shape=(64, 64, 3),activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(128,activation='relu'))
model.add(Dense(5,activation='softmax'))

model.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Adadelta(),
              metrics=['accuracy'])

Then we can train our network. This will result in about 60% accuracy on the test set. This is pretty good considering the baseline for this task is 20%.

batch_size = 128
epochs = 10
model.fit(x_train, y_train_binary,
          batch_size=batch_size,
          epochs=epochs,
          verbose=1,
          validation_data=(x_test, y_test_binary))

After the model is trained you can predict instances using. Don't forget that the network needs to take the same shape in. Thus we must maintain the dimensionality of the matrix, that's why I use the [0:1].

print('Predict the classes: ')
prediction = model.predict_classes(x_test[0:1])
print('Predicted class: ', prediction)
print('Real class:  ', y_test[0:1])

This gives

Predict the classes: 1/1
[==============================] - 0s 6ms/step
Predicted class: [4]
Real class: [4]

Some suggestions

The model you are currently using is the one that is most common for MNIST. However, that data only has a single channel thus we don't need as many layers. You can increase the performance by increasing the complexity of your model. Or by reducing the complexity of your data, for example you can train using the grayscale equivalent of the images, thus reducing the problem to a single channel.

|improve this answer|||||
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.